From df46ef09c9565dabb0455601d4fbf0332b4a2f23 Mon Sep 17 00:00:00 2001 From: Remotion Date: Thu, 10 May 2018 16:11:00 +0200 Subject: [PATCH 01/10] Add support for ranges, containers and types tuple interface in fmt/ranges.h and some tests. --- include/fmt/ranges.h | 224 +++++++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/ranges-test.cc | 53 ++++++++++ 3 files changed, 278 insertions(+) create mode 100644 include/fmt/ranges.h create mode 100644 test/ranges-test.cc diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h new file mode 100644 index 00000000..e8465475 --- /dev/null +++ b/include/fmt/ranges.h @@ -0,0 +1,224 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. +// +// Copyright (c) 2018 - present, Remotion (Igor Schulz) +// All Rights Reserved +// {fmt} support for ranges, containers and types tuple interface. + +#ifndef FMT_RANGES_H_ +#define FMT_RANGES_H_ + +#include "format.h" +#include + +// output only up to N items from the range. +#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT +#define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 +#endif + +namespace fmt { + +template +struct formatting_base { + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); } +}; + +template +struct formatting_range : formatting_base +{ + Char prefix = '{'; + Char delimiter = ','; + Char postfix = '}'; + bool add_spaces = true; +}; + +template +struct formatting_tuple : formatting_base +{ + Char prefix = '['; + Char delimiter = ','; + Char postfix = ']'; + bool add_spaces = true; +}; + +template +void copy(const RangeT &range, OutputIterator out) { + for (const auto& it : range) { + *out++ = it; + } +} + +template +void copy(const char *str, OutputIterator out) { + const char* p_curr = str; + while (*p_curr) { + *out++ = *p_curr++; + } +} + +template +void copy(const char ch, OutputIterator out) { + *out++ = ch; +} + +} // namespace fmt + + +namespace fmt { +namespace meta { + +/// Return true value if T has std::string interface, like std::string_view. +template +class is_like_std_string { + template static auto check(U* p) -> decltype( + p->find('a') + , p->length() + , p->data() + , int()); + template static void check(...); +public: + static const bool value = !std::is_void< decltype(check(nullptr)) >::value; +}; + +template +constexpr bool is_like_std_string_v = is_like_std_string::value; + +template +struct conditional_helper {}; + +template +struct is_range_ : std::false_type {}; + +template +struct is_range_().begin()), + decltype(std::declval().end()) + >, void> +> : std::true_type {}; + +template +constexpr bool is_range_v = is_range_::value && !is_like_std_string::value; + + +/// tuple_size and tuple_element check. +template +class is_tuple_like_ { + template static auto check(U* p) -> decltype( + std::tuple_size< U >::value, + std::declval::type>(), + int()); + template static void check(...); +public: + static constexpr bool value = !std::is_void< decltype(check(nullptr)) >::value; +}; + +template +constexpr bool is_tuple_like_v = is_tuple_like_::value && !is_range_::value; + + +//=-------------------------------------------------------------------------------------------------------------------- +template +void for_each(std::index_sequence, Tuple&& tup, F&& f) noexcept { + using std::get; + // using free function get(T) now. + const int _[] = { 0, + ((void)f(get(tup)), + 0)... }; + (void)_; // blocks warnings +} +//=-------------------------------------------------------------------------------------------------------------------- +template +constexpr std::make_index_sequence::value> +get_indexes(T const&) { return {}; } + +//=-------------------------------------------------------------------------------------------------------------------- +template +void for_each(Tuple&& tup, F&& f) { + const auto indexes = get_indexes(tup); + for_each(indexes, std::forward(tup), std::forward(f)); +} + +} // namespace meta +} // namespace fmt + +namespace fmt { + +// ===================================================================================================================== +template +struct formatter< TupleT, Char + , std::enable_if_t> > +{ + fmt::formatting_tuple formating; + + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return formating.parse(ctx); + } + + template + auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) { + auto out = ctx.out(); + std::ptrdiff_t i = 0; + fmt::copy(formating.prefix, out); + fmt::meta::for_each(values, [&](const auto &v) { + if (i++ > 0) { fmt::copy(formating.delimiter, out); } + if (formating.add_spaces) { format_to(out, " {}", v); } + else { format_to(out, "{}", v); } + }); + if (formating.add_spaces) { *out++ = ' '; } + fmt::copy(formating.postfix, out); + + return ctx.out(); + } +}; + +} // namespace fmt + + + +namespace fmt { + + +template +struct formatter > > +{ + static constexpr std::ptrdiff_t range_length_limit = FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. + + fmt::formatting_range formating; + + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return formating.parse(ctx); + } + + template + auto format(const RangeT &values, FormatContext &ctx) -> decltype(ctx.out()) { + auto out = ctx.out(); + fmt::copy(formating.prefix, out); + std::ptrdiff_t i = 0; + for (const auto& it : values) { + if (i > 0) { fmt::copy(formating.delimiter, out); } + if (formating.add_spaces) { format_to(out, " {}", it); } + else { format_to(out, "{}", it); } + if (++i > range_length_limit) { + format_to(out, " ... "); + break; + } + } + if (formating.add_spaces) { *out++ = ' '; } + fmt::copy(formating.postfix, out); + return ctx.out(); + } +}; + +} // namespace fmt + + +#endif // FMT_RANGES_H_ \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b0c479cb..07b10a0a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -92,6 +92,7 @@ add_fmt_test(printf-test) add_fmt_test(time-test) add_fmt_test(util-test mock-allocator.h) add_fmt_test(custom-formatter-test) +add_fmt_test(ranges-test) # Enable stricter options for one test to make sure that the header is free of # warnings. diff --git a/test/ranges-test.cc b/test/ranges-test.cc new file mode 100644 index 00000000..7dc770bf --- /dev/null +++ b/test/ranges-test.cc @@ -0,0 +1,53 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. +// +// Copyright (c) 2018 - present, Remotion (Igor Schulz) +// All Rights Reserved +// {fmt} support for ranges, containers and types tuple interface. + +#ifdef WIN32 +#define _CRT_SECURE_NO_WARNINGS +#endif + +#define FMT_HEADER_ONLY 1 +#include "fmt/ranges.h" + +#include "gtest/gtest.h" + + +#include +#include +#include +#include + +TEST(RangesTest, FormatVector) { + std::vector iv{ 1,2,3,5,7,11 }; + auto ivf = fmt::format("{}", iv); + EXPECT_EQ("{ 1, 2, 3, 5, 7, 11 }", ivf); +} + +TEST(RangesTest, FormatVector2) { + std::vector> ivv{ {1,2},{3,5},{7,11} }; + auto ivf = fmt::format("{}", ivv); + EXPECT_EQ("{ { 1, 2 }, { 3, 5 }, { 7, 11 } }", ivf); +} + +TEST(RangesTest, FormatMap) { + std::map simap{ {"one",1}, {"two",2} }; + EXPECT_EQ("{ [ one, 1 ], [ two, 2 ] }", fmt::format("{}", simap)); +} + +TEST(RangesTest, FormatPair) { + std::pair pa1{42, 3.14159265358979f}; + EXPECT_EQ("[ 42, 3.14159 ]", fmt::format("{}", pa1)); +} + +TEST(RangesTest, FormatTuple) { + std::tuple tu1{42, 3.14159265358979f, "this is tuple"}; + EXPECT_EQ("[ 42, 3.14159, this is tuple ]", fmt::format("{}", tu1)); +} + From 50ee89b223f5b19071dfe48f7160a6d1f2a1fca7 Mon Sep 17 00:00:00 2001 From: Remotion Date: Thu, 10 May 2018 16:16:47 +0200 Subject: [PATCH 02/10] Removed string_view --- test/ranges-test.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 7dc770bf..00a33b7b 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -13,16 +13,14 @@ #define _CRT_SECURE_NO_WARNINGS #endif -#define FMT_HEADER_ONLY 1 #include "fmt/ranges.h" #include "gtest/gtest.h" - #include #include #include -#include + TEST(RangesTest, FormatVector) { std::vector iv{ 1,2,3,5,7,11 }; From 951b743e8d46e9467f3c1aeefad331ad18e27472 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 12 May 2018 13:12:04 -0700 Subject: [PATCH 03/10] Fix docs, take 2 --- doc/build.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/build.py b/doc/build.py index da9bc774..06363877 100755 --- a/doc/build.py +++ b/doc/build.py @@ -90,8 +90,8 @@ def build_docs(version='dev', **kwargs): FMT_USE_RVALUE_REFERENCES=1 \ FMT_USE_USER_DEFINED_LITERALS=1 \ FMT_API= \ - FMT_BEGIN_NAMESPACE=namespace fmt { \ - FMT_END_NAMESPACE=} + "FMT_BEGIN_NAMESPACE=namespace fmt {" \ + "FMT_END_NAMESPACE=}" EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str '''.format(include_dir, doxyxml_dir).encode('UTF-8')) if p.returncode != 0: From a442c77c9a3a7e089537d08895610888fd71484e Mon Sep 17 00:00:00 2001 From: Remotion Date: Sat, 12 May 2018 22:55:51 +0200 Subject: [PATCH 04/10] Changes code style to Google Style. Renames namespace meta to internal and put copy functions int it. Replaced constexpr by FMT_CONSTEXPR. Replaced std::ptrdiff_t by std::size_t. --- include/fmt/ranges.h | 281 +++++++++++++++++++++---------------------- test/ranges-test.cc | 59 +++++++-- 2 files changed, 187 insertions(+), 153 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index e8465475..78f09622 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -24,201 +24,196 @@ namespace fmt { template struct formatting_base { - template - FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); } + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } }; template -struct formatting_range : formatting_base -{ - Char prefix = '{'; - Char delimiter = ','; - Char postfix = '}'; - bool add_spaces = true; +struct formatting_range : formatting_base { + Char prefix = '{'; + Char delimiter = ','; + Char postfix = '}'; + static FMT_CONSTEXPR bool add_spaces = false; }; template -struct formatting_tuple : formatting_base -{ - Char prefix = '['; - Char delimiter = ','; - Char postfix = ']'; - bool add_spaces = true; +struct formatting_tuple : formatting_base { + Char prefix = '['; + Char delimiter = ','; + Char postfix = ']'; + static FMT_CONSTEXPR bool add_spaces = false; }; -template +namespace internal { + +template void copy(const RangeT &range, OutputIterator out) { - for (const auto& it : range) { - *out++ = it; - } + for (const auto &it : range) { + *out++ = it; + } } -template +template void copy(const char *str, OutputIterator out) { - const char* p_curr = str; - while (*p_curr) { - *out++ = *p_curr++; - } + const char *p_curr = str; + while (*p_curr) { + *out++ = *p_curr++; + } } -template -void copy(const char ch, OutputIterator out) { - *out++ = ch; +template +void copy(char ch, OutputIterator out) { + *out++ = ch; } -} // namespace fmt +} // namespace internal - -namespace fmt { -namespace meta { +namespace internal { /// Return true value if T has std::string interface, like std::string_view. -template +template class is_like_std_string { - template static auto check(U* p) -> decltype( - p->find('a') - , p->length() - , p->data() - , int()); - template static void check(...); -public: - static const bool value = !std::is_void< decltype(check(nullptr)) >::value; + template + static auto check(U *p) -> decltype(p->find('a'), p->length(), p->data(), int()); + template + static void check(...); + + public: + static FMT_CONSTEXPR bool value = !std::is_void(nullptr))>::value; }; -template -constexpr bool is_like_std_string_v = is_like_std_string::value; +template +FMT_CONSTEXPR bool is_like_std_string_v = is_like_std_string::value; -template +template struct conditional_helper {}; -template +template struct is_range_ : std::false_type {}; -template -struct is_range_().begin()), - decltype(std::declval().end()) - >, void> -> : std::true_type {}; - -template -constexpr bool is_range_v = is_range_::value && !is_like_std_string::value; +template +struct is_range_().begin()), + decltype(std::declval().end())>, + void>> : std::true_type {}; +template +FMT_CONSTEXPR bool is_range_v = is_range_::value && !is_like_std_string::value; /// tuple_size and tuple_element check. -template +template class is_tuple_like_ { - template static auto check(U* p) -> decltype( - std::tuple_size< U >::value, - std::declval::type>(), - int()); - template static void check(...); -public: - static constexpr bool value = !std::is_void< decltype(check(nullptr)) >::value; + template + static auto check(U *p) + -> decltype(std::tuple_size::value, + std::declval::type>(), int()); + template + static void check(...); + + public: + static FMT_CONSTEXPR bool value = !std::is_void(nullptr))>::value; }; -template -constexpr bool is_tuple_like_v = is_tuple_like_::value && !is_range_::value; - +template +FMT_CONSTEXPR bool is_tuple_like_v = is_tuple_like_::value && !is_range_::value; //=-------------------------------------------------------------------------------------------------------------------- -template -void for_each(std::index_sequence, Tuple&& tup, F&& f) noexcept { - using std::get; - // using free function get(T) now. - const int _[] = { 0, - ((void)f(get(tup)), - 0)... }; - (void)_; // blocks warnings +template +void for_each(std::index_sequence, Tuple &&tup, F &&f) noexcept { + using std::get; + // using free function get(T) now. + const int _[] = {0, ((void)f(get(tup)), 0)...}; + (void)_; // blocks warnings } //=-------------------------------------------------------------------------------------------------------------------- -template -constexpr std::make_index_sequence::value> -get_indexes(T const&) { return {}; } +template +FMT_CONSTEXPR std::make_index_sequence::value> +get_indexes(T const &) { return {}; } //=-------------------------------------------------------------------------------------------------------------------- -template -void for_each(Tuple&& tup, F&& f) { - const auto indexes = get_indexes(tup); - for_each(indexes, std::forward(tup), std::forward(f)); +template +void for_each(Tuple &&tup, F &&f) { + const auto indexes = get_indexes(tup); + for_each(indexes, std::forward(tup), std::forward(f)); } -} // namespace meta -} // namespace fmt - -namespace fmt { +} // namespace internal // ===================================================================================================================== -template -struct formatter< TupleT, Char - , std::enable_if_t> > -{ - fmt::formatting_tuple formating; +template +struct formatter>> { + fmt::formatting_tuple formating; - template - FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { - return formating.parse(ctx); - } + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return formating.parse(ctx); + } - template - auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) { - auto out = ctx.out(); - std::ptrdiff_t i = 0; - fmt::copy(formating.prefix, out); - fmt::meta::for_each(values, [&](const auto &v) { - if (i++ > 0) { fmt::copy(formating.delimiter, out); } - if (formating.add_spaces) { format_to(out, " {}", v); } - else { format_to(out, "{}", v); } - }); - if (formating.add_spaces) { *out++ = ' '; } - fmt::copy(formating.postfix, out); + template + auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) { + auto out = ctx.out(); + std::size_t i = 0; + internal::copy(formating.prefix, out); + internal::for_each(values, [&](const auto &v) { + if (i++ > 0) { + internal::copy(formating.delimiter, out); + } + if (formating.add_spaces) { + format_to(out, " {}", v); + } else { + format_to(out, "{}", v); + } + }); + if (formating.add_spaces) { + *out++ = ' '; + } + internal::copy(formating.postfix, out); - return ctx.out(); - } + return ctx.out(); + } }; -} // namespace fmt +template +struct formatter>> { + static FMT_CONSTEXPR std::size_t range_length_limit = + FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. + fmt::formatting_range formating; + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return formating.parse(ctx); + } -namespace fmt { - - -template -struct formatter > > -{ - static constexpr std::ptrdiff_t range_length_limit = FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. - - fmt::formatting_range formating; - - template - FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { - return formating.parse(ctx); - } - - template - auto format(const RangeT &values, FormatContext &ctx) -> decltype(ctx.out()) { - auto out = ctx.out(); - fmt::copy(formating.prefix, out); - std::ptrdiff_t i = 0; - for (const auto& it : values) { - if (i > 0) { fmt::copy(formating.delimiter, out); } - if (formating.add_spaces) { format_to(out, " {}", it); } - else { format_to(out, "{}", it); } - if (++i > range_length_limit) { - format_to(out, " ... "); - break; - } - } - if (formating.add_spaces) { *out++ = ' '; } - fmt::copy(formating.postfix, out); - return ctx.out(); - } + template + auto format(const RangeT &values, FormatContext &ctx) -> decltype(ctx.out()) { + auto out = ctx.out(); + internal::copy(formating.prefix, out); + std::size_t i = 0; + for (const auto &it : values) { + if (i > 0) { + internal::copy(formating.delimiter, out); + } + if (formating.add_spaces) { + format_to(out, " {}", it); + } else { + format_to(out, "{}", it); + } + if (++i > range_length_limit) { + format_to(out, " ... "); + break; + } + } + if (formating.add_spaces) { + *out++ = ' '; + } + internal::copy(formating.postfix, out); + return ctx.out(); + } }; -} // namespace fmt - +} // namespace fmt #endif // FMT_RANGES_H_ \ No newline at end of file diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 00a33b7b..49d87080 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -20,32 +20,71 @@ #include #include #include - +#include TEST(RangesTest, FormatVector) { - std::vector iv{ 1,2,3,5,7,11 }; + std::vector iv{1, 2, 3, 5, 7, 11}; auto ivf = fmt::format("{}", iv); - EXPECT_EQ("{ 1, 2, 3, 5, 7, 11 }", ivf); + EXPECT_EQ("{1,2,3,5,7,11}", ivf); } TEST(RangesTest, FormatVector2) { - std::vector> ivv{ {1,2},{3,5},{7,11} }; + std::vector> ivv{{1, 2}, {3, 5}, {7, 11}}; auto ivf = fmt::format("{}", ivv); - EXPECT_EQ("{ { 1, 2 }, { 3, 5 }, { 7, 11 } }", ivf); + EXPECT_EQ("{{1,2},{3,5},{7,11}}", ivf); } TEST(RangesTest, FormatMap) { - std::map simap{ {"one",1}, {"two",2} }; - EXPECT_EQ("{ [ one, 1 ], [ two, 2 ] }", fmt::format("{}", simap)); + std::map simap{{"one", 1}, {"two", 2}}; + EXPECT_EQ("{[one,1],[two,2]}", fmt::format("{}", simap)); } TEST(RangesTest, FormatPair) { std::pair pa1{42, 3.14159265358979f}; - EXPECT_EQ("[ 42, 3.14159 ]", fmt::format("{}", pa1)); + EXPECT_EQ("[42,3.14159]", fmt::format("{}", pa1)); } TEST(RangesTest, FormatTuple) { - std::tuple tu1{42, 3.14159265358979f, "this is tuple"}; - EXPECT_EQ("[ 42, 3.14159, this is tuple ]", fmt::format("{}", tu1)); + std::tuple tu1{42, 3.14159265358979f, + "this is tuple"}; + EXPECT_EQ("[42,3.14159,this is tuple]", fmt::format("{}", tu1)); } +#if (__cplusplus > 201402L) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) + +struct my_struct { + int32_t i; + std::string str; // can throw + template + decltype(auto) get() const noexcept { + if constexpr (N == 0) + return i; + else if constexpr (N == 1) + return fmt::string_view{str}; + } +}; + +template +decltype(auto) get(const my_struct& s) noexcept { + return s.get(); +} + +namespace std { + +template <> +struct tuple_size : std::integral_constant {}; + +template +struct tuple_element { + using type = decltype(std::declval().get()); +}; + +} // namespace std + +TEST(RangesTest, FormatStruct) { + my_struct mst{13, "my struct"}; + EXPECT_EQ("[13,my struct]", fmt::format("{}", mst)); +} + +#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) \ No newline at end of file From 4cfc6c4c76fa5501c3ccfb544926e1183b7a9c2d Mon Sep 17 00:00:00 2001 From: Remotion Date: Sat, 12 May 2018 23:02:22 +0200 Subject: [PATCH 05/10] Using FMT_BEGIN_NAMESPACE and FMT_END_NAMESPACE now. --- include/fmt/ranges.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 78f09622..1f4da818 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -20,7 +20,7 @@ #define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 #endif -namespace fmt { +FMT_BEGIN_NAMESPACE template struct formatting_base { @@ -214,6 +214,6 @@ struct formatter Date: Sat, 12 May 2018 23:05:28 +0200 Subject: [PATCH 06/10] Fixed build.py conflict. --- doc/build.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/build.py b/doc/build.py index 06363877..cfa52b0d 100755 --- a/doc/build.py +++ b/doc/build.py @@ -90,8 +90,8 @@ def build_docs(version='dev', **kwargs): FMT_USE_RVALUE_REFERENCES=1 \ FMT_USE_USER_DEFINED_LITERALS=1 \ FMT_API= \ - "FMT_BEGIN_NAMESPACE=namespace fmt {" \ - "FMT_END_NAMESPACE=}" + "FMT_BEGIN_NAMESPACE=namespace fmt {{" \ + "FMT_END_NAMESPACE=}}" EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str '''.format(include_dir, doxyxml_dir).encode('UTF-8')) if p.returncode != 0: From f101d628337b31f6e9774a6c9306b5da809f01b8 Mon Sep 17 00:00:00 2001 From: Remotion Date: Sat, 12 May 2018 23:23:54 +0200 Subject: [PATCH 07/10] Fixed typo. --- include/fmt/ranges.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 1f4da818..37157188 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -144,32 +144,33 @@ void for_each(Tuple &&tup, F &&f) { // ===================================================================================================================== template struct formatter>> { - fmt::formatting_tuple formating; + + fmt::formatting_tuple formatting; template FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { - return formating.parse(ctx); + return formatting.parse(ctx); } template auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) { auto out = ctx.out(); std::size_t i = 0; - internal::copy(formating.prefix, out); + internal::copy(formatting.prefix, out); internal::for_each(values, [&](const auto &v) { if (i++ > 0) { - internal::copy(formating.delimiter, out); + internal::copy(formatting.delimiter, out); } - if (formating.add_spaces) { + if (formatting.add_spaces) { format_to(out, " {}", v); } else { format_to(out, "{}", v); } }); - if (formating.add_spaces) { + if (formatting.add_spaces) { *out++ = ' '; } - internal::copy(formating.postfix, out); + internal::copy(formatting.postfix, out); return ctx.out(); } @@ -177,26 +178,27 @@ struct formatter struct formatter>> { + static FMT_CONSTEXPR std::size_t range_length_limit = FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. - fmt::formatting_range formating; + fmt::formatting_range formatting; template FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { - return formating.parse(ctx); + return formatting.parse(ctx); } template auto format(const RangeT &values, FormatContext &ctx) -> decltype(ctx.out()) { auto out = ctx.out(); - internal::copy(formating.prefix, out); + internal::copy(formatting.prefix, out); std::size_t i = 0; for (const auto &it : values) { if (i > 0) { - internal::copy(formating.delimiter, out); + internal::copy(formatting.delimiter, out); } - if (formating.add_spaces) { + if (formatting.add_spaces) { format_to(out, " {}", it); } else { format_to(out, "{}", it); @@ -206,10 +208,10 @@ struct formatter Date: Sun, 13 May 2018 00:04:30 +0200 Subject: [PATCH 08/10] Using FMT_CONSTEXPR_DECL for variables. Replaced std::enable_if_t by std::std::enable_if<>::type. Replaced variable templates by structs. --- include/fmt/ranges.h | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 37157188..02e69001 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -35,7 +35,7 @@ struct formatting_range : formatting_base { Char prefix = '{'; Char delimiter = ','; Char postfix = '}'; - static FMT_CONSTEXPR bool add_spaces = false; + static FMT_CONSTEXPR_DECL const bool add_spaces = false; }; template @@ -43,7 +43,7 @@ struct formatting_tuple : formatting_base { Char prefix = '['; Char delimiter = ','; Char postfix = ']'; - static FMT_CONSTEXPR bool add_spaces = false; + static FMT_CONSTEXPR_DECL const bool add_spaces = false; }; namespace internal { @@ -81,11 +81,9 @@ class is_like_std_string { static void check(...); public: - static FMT_CONSTEXPR bool value = !std::is_void(nullptr))>::value; + static FMT_CONSTEXPR_DECL const bool value = !std::is_void(nullptr))>::value; }; -template -FMT_CONSTEXPR bool is_like_std_string_v = is_like_std_string::value; template struct conditional_helper {}; @@ -100,7 +98,10 @@ struct is_range_> : std::true_type {}; template -FMT_CONSTEXPR bool is_range_v = is_range_::value && !is_like_std_string::value; +struct is_range { + static FMT_CONSTEXPR_DECL const bool value = is_range_::value && !is_like_std_string::value; +}; + /// tuple_size and tuple_element check. template @@ -113,11 +114,13 @@ class is_tuple_like_ { static void check(...); public: - static FMT_CONSTEXPR bool value = !std::is_void(nullptr))>::value; + static FMT_CONSTEXPR_DECL const bool value = !std::is_void(nullptr))>::value; }; template -FMT_CONSTEXPR bool is_tuple_like_v = is_tuple_like_::value && !is_range_::value; +struct is_tuple_like { + static FMT_CONSTEXPR_DECL const bool value = is_tuple_like_::value && !is_range_::value; +}; //=-------------------------------------------------------------------------------------------------------------------- template @@ -143,7 +146,8 @@ void for_each(Tuple &&tup, F &&f) { // ===================================================================================================================== template -struct formatter>> { +struct formatter::value>::type> { fmt::formatting_tuple formatting; @@ -177,10 +181,11 @@ struct formatter -struct formatter>> { +struct formatter< RangeT, Char, + typename std::enable_if::value>::type> { - static FMT_CONSTEXPR std::size_t range_length_limit = - FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. + static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = + FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. fmt::formatting_range formatting; From a70b48023f674526ec7acc535435adf646c2a950 Mon Sep 17 00:00:00 2001 From: Remotion Date: Sun, 13 May 2018 18:50:04 +0200 Subject: [PATCH 09/10] Moved range_length_limit to formatting_range. Added add_delimiter_spaces and add_prepostfix_space. --- include/fmt/ranges.h | 42 ++++++++++++++++++++++++++---------------- test/ranges-test.cc | 16 +++++++--------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 02e69001..ae14907e 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -32,18 +32,22 @@ struct formatting_base { template struct formatting_range : formatting_base { + static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = + FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. Char prefix = '{'; Char delimiter = ','; Char postfix = '}'; - static FMT_CONSTEXPR_DECL const bool add_spaces = false; + static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; + static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; }; template struct formatting_tuple : formatting_base { - Char prefix = '['; + Char prefix = '('; Char delimiter = ','; - Char postfix = ']'; - static FMT_CONSTEXPR_DECL const bool add_spaces = false; + Char postfix = ')'; + static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; + static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; }; namespace internal { @@ -92,10 +96,11 @@ template struct is_range_ : std::false_type {}; template -struct is_range_().begin()), - decltype(std::declval().end())>, - void>> : std::true_type {}; +struct is_range_().begin()), + decltype(std::declval().end())>, + void>::type> : std::true_type {}; template struct is_range { @@ -162,16 +167,20 @@ struct formatter 0) { + if (i > 0) { + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } internal::copy(formatting.delimiter, out); } - if (formatting.add_spaces) { + if (formatting.add_delimiter_spaces && i > 0) { format_to(out, " {}", v); } else { format_to(out, "{}", v); } + ++i; }); - if (formatting.add_spaces) { + if (formatting.add_prepostfix_space) { *out++ = ' '; } internal::copy(formatting.postfix, out); @@ -184,8 +193,6 @@ template struct formatter< RangeT, Char, typename std::enable_if::value>::type> { - static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = - FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. fmt::formatting_range formatting; @@ -201,19 +208,22 @@ struct formatter< RangeT, Char, std::size_t i = 0; for (const auto &it : values) { if (i > 0) { + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } internal::copy(formatting.delimiter, out); } - if (formatting.add_spaces) { + if (formatting.add_delimiter_spaces && i > 0) { format_to(out, " {}", it); } else { format_to(out, "{}", it); } - if (++i > range_length_limit) { + if (++i > formatting.range_length_limit) { format_to(out, " ... "); break; } } - if (formatting.add_spaces) { + if (formatting.add_prepostfix_space) { *out++ = ' '; } internal::copy(formatting.postfix, out); diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 49d87080..1944173e 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -9,10 +9,6 @@ // All Rights Reserved // {fmt} support for ranges, containers and types tuple interface. -#ifdef WIN32 -#define _CRT_SECURE_NO_WARNINGS -#endif - #include "fmt/ranges.h" #include "gtest/gtest.h" @@ -36,20 +32,21 @@ TEST(RangesTest, FormatVector2) { TEST(RangesTest, FormatMap) { std::map simap{{"one", 1}, {"two", 2}}; - EXPECT_EQ("{[one,1],[two,2]}", fmt::format("{}", simap)); + EXPECT_EQ("{(one,1),(two,2)}", fmt::format("{}", simap)); } TEST(RangesTest, FormatPair) { std::pair pa1{42, 3.14159265358979f}; - EXPECT_EQ("[42,3.14159]", fmt::format("{}", pa1)); + EXPECT_EQ("(42,3.14159)", fmt::format("{}", pa1)); } TEST(RangesTest, FormatTuple) { std::tuple tu1{42, 3.14159265358979f, "this is tuple"}; - EXPECT_EQ("[42,3.14159,this is tuple]", fmt::format("{}", tu1)); + EXPECT_EQ("(42,3.14159,this is tuple)", fmt::format("{}", tu1)); } +/// check if 'if constexpr' is supported. #if (__cplusplus > 201402L) || \ (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) @@ -84,7 +81,8 @@ struct tuple_element { TEST(RangesTest, FormatStruct) { my_struct mst{13, "my struct"}; - EXPECT_EQ("[13,my struct]", fmt::format("{}", mst)); + EXPECT_EQ("(13, my struct)", fmt::format("{}", mst)); } -#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) \ No newline at end of file +#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > + // 201402L && _MSC_VER >= 1910) \ No newline at end of file From f65bcb8b08832076f73c572b0b19fec31c8320ea Mon Sep 17 00:00:00 2001 From: Remotion Date: Sun, 13 May 2018 18:58:25 +0200 Subject: [PATCH 10/10] Updated ranges-test.cc. --- test/ranges-test.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 1944173e..b7519747 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -21,29 +21,29 @@ TEST(RangesTest, FormatVector) { std::vector iv{1, 2, 3, 5, 7, 11}; auto ivf = fmt::format("{}", iv); - EXPECT_EQ("{1,2,3,5,7,11}", ivf); + EXPECT_EQ("{1, 2, 3, 5, 7, 11}", ivf); } TEST(RangesTest, FormatVector2) { std::vector> ivv{{1, 2}, {3, 5}, {7, 11}}; auto ivf = fmt::format("{}", ivv); - EXPECT_EQ("{{1,2},{3,5},{7,11}}", ivf); + EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf); } TEST(RangesTest, FormatMap) { std::map simap{{"one", 1}, {"two", 2}}; - EXPECT_EQ("{(one,1),(two,2)}", fmt::format("{}", simap)); + EXPECT_EQ("{(one, 1), (two, 2)}", fmt::format("{}", simap)); } TEST(RangesTest, FormatPair) { std::pair pa1{42, 3.14159265358979f}; - EXPECT_EQ("(42,3.14159)", fmt::format("{}", pa1)); + EXPECT_EQ("(42, 3.14159)", fmt::format("{}", pa1)); } TEST(RangesTest, FormatTuple) { std::tuple tu1{42, 3.14159265358979f, "this is tuple"}; - EXPECT_EQ("(42,3.14159,this is tuple)", fmt::format("{}", tu1)); + EXPECT_EQ("(42, 3.14159, this is tuple)", fmt::format("{}", tu1)); } /// check if 'if constexpr' is supported.