-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for ranges, containers and types tuple interface... #735
Closed
Closed
Changes from 1 commit
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
df46ef0
Add support for ranges, containers and types tuple interface in fmt/r…
Remotion 50ee89b
Removed string_view
Remotion 951b743
Fix docs, take 2
vitaut a442c77
Changes code style to Google Style.
Remotion 5717bd2
Merge branch 'master' of https://github.com/fmtlib/fmt
Remotion 4cfc6c4
Using FMT_BEGIN_NAMESPACE and FMT_END_NAMESPACE now.
Remotion 648b937
Fixed build.py conflict.
Remotion f101d62
Fixed typo.
Remotion 7a2099e
Using FMT_CONSTEXPR_DECL for variables.
Remotion a7041e9
Merge branch 'master' of https://github.com/fmtlib/fmt
Remotion a70b480
Moved range_length_limit to formatting_range.
Remotion d2ef18c
Merge branch 'master' of https://github.com/fmtlib/fmt
Remotion f65bcb8
Updated ranges-test.cc.
Remotion File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
- Loading branch information
commit a442c77c9a3a7e089537d08895610888fd71484e
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,201 +24,196 @@ namespace fmt { | |
|
||
template <typename Char> | ||
struct formatting_base { | ||
template <typename ParseContext> | ||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); } | ||
template <typename ParseContext> | ||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { | ||
return ctx.begin(); | ||
} | ||
}; | ||
|
||
template <typename Char, typename Enable = void> | ||
struct formatting_range : formatting_base<Char> | ||
{ | ||
Char prefix = '{'; | ||
Char delimiter = ','; | ||
Char postfix = '}'; | ||
bool add_spaces = true; | ||
struct formatting_range : formatting_base<Char> { | ||
Char prefix = '{'; | ||
Char delimiter = ','; | ||
Char postfix = '}'; | ||
static FMT_CONSTEXPR bool add_spaces = false; | ||
}; | ||
|
||
template <typename Char, typename Enable = void> | ||
struct formatting_tuple : formatting_base<Char> | ||
{ | ||
Char prefix = '['; | ||
Char delimiter = ','; | ||
Char postfix = ']'; | ||
bool add_spaces = true; | ||
struct formatting_tuple : formatting_base<Char> { | ||
Char prefix = '['; | ||
Char delimiter = ','; | ||
Char postfix = ']'; | ||
static FMT_CONSTEXPR bool add_spaces = false; | ||
}; | ||
|
||
template<typename RangeT, typename OutputIterator> | ||
namespace internal { | ||
|
||
template <typename RangeT, typename OutputIterator> | ||
void copy(const RangeT &range, OutputIterator out) { | ||
for (const auto& it : range) { | ||
*out++ = it; | ||
} | ||
for (const auto &it : range) { | ||
*out++ = it; | ||
} | ||
} | ||
|
||
template<typename OutputIterator> | ||
template <typename OutputIterator> | ||
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<typename OutputIterator> | ||
void copy(const char ch, OutputIterator out) { | ||
*out++ = ch; | ||
template <typename OutputIterator> | ||
void copy(char ch, OutputIterator out) { | ||
*out++ = ch; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest putting all of the above in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
||
} // namespace fmt | ||
|
||
} // namespace internal | ||
|
||
namespace fmt { | ||
namespace meta { | ||
namespace internal { | ||
|
||
/// Return true value if T has std::string interface, like std::string_view. | ||
template<typename T> | ||
template <typename T> | ||
class is_like_std_string { | ||
template<typename U> static auto check(U* p) -> decltype( | ||
p->find('a') | ||
, p->length() | ||
, p->data() | ||
, int()); | ||
template<typename > static void check(...); | ||
public: | ||
static const bool value = !std::is_void< decltype(check<T>(nullptr)) >::value; | ||
template <typename U> | ||
static auto check(U *p) -> decltype(p->find('a'), p->length(), p->data(), int()); | ||
template <typename> | ||
static void check(...); | ||
|
||
public: | ||
static FMT_CONSTEXPR bool value = !std::is_void<decltype(check<T>(nullptr))>::value; | ||
}; | ||
|
||
template<typename T> | ||
constexpr bool is_like_std_string_v = is_like_std_string<T>::value; | ||
template <typename T> | ||
FMT_CONSTEXPR bool is_like_std_string_v = is_like_std_string<T>::value; | ||
|
||
template<typename... Ts> | ||
template <typename... Ts> | ||
struct conditional_helper {}; | ||
|
||
template<typename T, typename _ = void> | ||
template <typename T, typename _ = void> | ||
struct is_range_ : std::false_type {}; | ||
|
||
template<typename T> | ||
struct is_range_<T, | ||
std::conditional_t< false, | ||
conditional_helper< | ||
decltype(std::declval<T>().begin()), | ||
decltype(std::declval<T>().end()) | ||
>, void> | ||
> : std::true_type {}; | ||
|
||
template<typename T> | ||
constexpr bool is_range_v = is_range_<T>::value && !is_like_std_string<T>::value; | ||
template <typename T> | ||
struct is_range_<T, std::conditional_t<false, | ||
conditional_helper<decltype(std::declval<T>().begin()), | ||
decltype(std::declval<T>().end())>, | ||
void>> : std::true_type {}; | ||
|
||
template <typename T> | ||
FMT_CONSTEXPR bool is_range_v = is_range_<T>::value && !is_like_std_string<T>::value; | ||
|
||
/// tuple_size and tuple_element check. | ||
template<typename T> | ||
template <typename T> | ||
class is_tuple_like_ { | ||
template<typename U> static auto check(U* p) -> decltype( | ||
std::tuple_size< U >::value, | ||
std::declval<typename std::tuple_element<0, U>::type>(), | ||
int()); | ||
template<typename > static void check(...); | ||
public: | ||
static constexpr bool value = !std::is_void< decltype(check<T>(nullptr)) >::value; | ||
template <typename U> | ||
static auto check(U *p) | ||
-> decltype(std::tuple_size<U>::value, | ||
std::declval<typename std::tuple_element<0, U>::type>(), int()); | ||
template <typename> | ||
static void check(...); | ||
|
||
public: | ||
static FMT_CONSTEXPR bool value = !std::is_void<decltype(check<T>(nullptr))>::value; | ||
}; | ||
|
||
template<typename T> | ||
constexpr bool is_tuple_like_v = is_tuple_like_<T>::value && !is_range_<T>::value; | ||
|
||
template <typename T> | ||
FMT_CONSTEXPR bool is_tuple_like_v = is_tuple_like_<T>::value && !is_range_<T>::value; | ||
|
||
//=-------------------------------------------------------------------------------------------------------------------- | ||
template<size_t... Is, class Tuple, class F> | ||
void for_each(std::index_sequence<Is...>, Tuple&& tup, F&& f) noexcept { | ||
using std::get; | ||
// using free function get<I>(T) now. | ||
const int _[] = { 0, | ||
((void)f(get<Is>(tup)), | ||
0)... }; | ||
(void)_; // blocks warnings | ||
template <size_t... Is, class Tuple, class F> | ||
void for_each(std::index_sequence<Is...>, Tuple &&tup, F &&f) noexcept { | ||
using std::get; | ||
// using free function get<I>(T) now. | ||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; | ||
(void)_; // blocks warnings | ||
} | ||
//=-------------------------------------------------------------------------------------------------------------------- | ||
template<class T> | ||
constexpr std::make_index_sequence<std::tuple_size<T>::value> | ||
get_indexes(T const&) { return {}; } | ||
template <class T> | ||
FMT_CONSTEXPR std::make_index_sequence<std::tuple_size<T>::value> | ||
get_indexes(T const &) { return {}; } | ||
|
||
//=-------------------------------------------------------------------------------------------------------------------- | ||
template<class Tuple, class F> | ||
void for_each(Tuple&& tup, F&& f) { | ||
const auto indexes = get_indexes(tup); | ||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); | ||
template <class Tuple, class F> | ||
void for_each(Tuple &&tup, F &&f) { | ||
const auto indexes = get_indexes(tup); | ||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); | ||
} | ||
|
||
} // namespace meta | ||
} // namespace fmt | ||
|
||
namespace fmt { | ||
} // namespace internal | ||
|
||
// ===================================================================================================================== | ||
template<typename TupleT, typename Char> | ||
struct formatter< TupleT, Char | ||
, std::enable_if_t<fmt::meta::is_tuple_like_v<TupleT>> > | ||
{ | ||
fmt::formatting_tuple<Char> formating; | ||
|
||
template <typename ParseContext> | ||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { | ||
return formating.parse(ctx); | ||
} | ||
|
||
template <typename FormatContext = format_context> | ||
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(); | ||
} | ||
template <typename TupleT, typename Char> | ||
struct formatter<TupleT, Char, std::enable_if_t<fmt::internal::is_tuple_like_v<TupleT>>> { | ||
fmt::formatting_tuple<Char> formating; | ||
|
||
template <typename ParseContext> | ||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { | ||
return formating.parse(ctx); | ||
} | ||
|
||
template <typename FormatContext = format_context> | ||
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(); | ||
} | ||
}; | ||
|
||
} // namespace fmt | ||
|
||
|
||
|
||
namespace fmt { | ||
|
||
|
||
template<typename RangeT, typename Char> | ||
struct formatter <RangeT, Char, std::enable_if_t<fmt::meta::is_range_v<RangeT>> > | ||
{ | ||
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<Char> formating; | ||
|
||
template <typename ParseContext> | ||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { | ||
return formating.parse(ctx); | ||
} | ||
|
||
template <typename FormatContext> | ||
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, " ... <other elements>"); | ||
break; | ||
} | ||
} | ||
if (formating.add_spaces) { *out++ = ' '; } | ||
fmt::copy(formating.postfix, out); | ||
return ctx.out(); | ||
} | ||
template <typename RangeT, typename Char> | ||
struct formatter<RangeT, Char, std::enable_if_t<fmt::internal::is_range_v<RangeT>>> { | ||
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<Char> formating; | ||
|
||
template <typename ParseContext> | ||
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { | ||
return formating.parse(ctx); | ||
} | ||
|
||
template <typename FormatContext> | ||
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, " ... <other elements>"); | ||
break; | ||
} | ||
} | ||
if (formating.add_spaces) { | ||
*out++ = ' '; | ||
} | ||
internal::copy(formating.postfix, out); | ||
return ctx.out(); | ||
} | ||
}; | ||
|
||
} // namespace fmt | ||
|
||
} // namespace fmt | ||
|
||
#endif // FMT_RANGES_H_ |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tuples are normally delimited by parentheses
()
rather than square brackets[]
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
()
in last commit now.