23
23
#endif
24
24
25
25
// The fmt library version in the form major * 10000 + minor * 100 + patch.
26
- #define FMT_VERSION 110001
26
+ #define FMT_VERSION 110002
27
27
28
28
// Detect compiler versions.
29
29
#if defined(__clang__) && !defined(__ibmxl__)
@@ -441,7 +441,8 @@ struct is_std_string_like : std::false_type {};
441
441
template <typename T>
442
442
struct is_std_string_like <T, void_t <decltype (std::declval<T>().find_first_of(
443
443
typename T::value_type (), 0))>>
444
- : std::true_type {};
444
+ : std::is_convertible<decltype(std::declval<T>().data()),
445
+ const typename T::value_type*> {};
445
446
446
447
// Returns true iff the literal encoding is UTF-8.
447
448
constexpr auto is_utf8_enabled () -> bool {
@@ -466,21 +467,30 @@ template <typename Char> FMT_CONSTEXPR auto length(const Char* s) -> size_t {
466
467
template <typename Char>
467
468
FMT_CONSTEXPR auto compare (const Char* s1, const Char* s2, std::size_t n)
468
469
-> int {
470
+ if (!is_constant_evaluated () && sizeof (Char) == 1 ) return memcmp (s1, s2, n);
469
471
for (; n != 0 ; ++s1, ++s2, --n) {
470
472
if (*s1 < *s2) return -1 ;
471
473
if (*s1 > *s2) return 1 ;
472
474
}
473
475
return 0 ;
474
476
}
475
477
478
+ namespace adl {
479
+ using namespace std ;
480
+
481
+ template <typename Container>
482
+ auto invoke_back_inserter ()
483
+ -> decltype(back_inserter(std::declval<Container&>()));
484
+ } // namespace adl
485
+
476
486
template <typename It, typename Enable = std::true_type>
477
487
struct is_back_insert_iterator : std::false_type {};
488
+
478
489
template <typename It>
479
490
struct is_back_insert_iterator <
480
- It,
481
- bool_constant<std::is_same<
482
- decltype (back_inserter(std::declval<typename It::container_type&>())),
483
- It>::value>> : std::true_type {};
491
+ It, bool_constant<std::is_same<
492
+ decltype (adl::invoke_back_inserter<typename It::container_type>()),
493
+ It>::value>> : std::true_type {};
484
494
485
495
// Extracts a reference to the container from *insert_iterator.
486
496
template <typename OutputIt>
@@ -611,11 +621,12 @@ namespace detail {
611
621
// to it, deducing Char. Explicitly convertible types such as the ones returned
612
622
// from FMT_STRING are intentionally excluded.
613
623
template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
614
- auto to_string_view (const Char* s) -> basic_string_view<Char> {
624
+ constexpr auto to_string_view (const Char* s) -> basic_string_view<Char> {
615
625
return s;
616
626
}
617
627
template <typename T, FMT_ENABLE_IF(is_std_string_like<T>::value)>
618
- auto to_string_view (const T& s) -> basic_string_view<typename T::value_type> {
628
+ constexpr auto to_string_view (const T& s)
629
+ -> basic_string_view<typename T::value_type> {
619
630
return s;
620
631
}
621
632
template <typename Char>
@@ -919,12 +930,9 @@ template <typename T> class buffer {
919
930
try_reserve (size_ + count);
920
931
auto free_cap = capacity_ - size_;
921
932
if (free_cap < count) count = free_cap;
922
- if (std::is_same<T, U>::value) {
923
- memcpy (ptr_ + size_, begin, count * sizeof (T));
924
- } else {
925
- T* out = ptr_ + size_;
926
- for (size_t i = 0 ; i < count; ++i) out[i] = begin[i];
927
- }
933
+ // A loop is faster than memcpy on small sizes.
934
+ T* out = ptr_ + size_;
935
+ for (size_t i = 0 ; i < count; ++i) out[i] = begin[i];
928
936
size_ += count;
929
937
begin += count;
930
938
}
@@ -1157,6 +1165,7 @@ template <typename T> class basic_appender {
1157
1165
using difference_type = ptrdiff_t ;
1158
1166
using pointer = T*;
1159
1167
using reference = T&;
1168
+ using container_type = detail::buffer<T>;
1160
1169
FMT_UNCHECKED_ITERATOR (basic_appender);
1161
1170
1162
1171
FMT_CONSTEXPR basic_appender (detail::buffer<T>& buf) : buffer_(&buf) {}
@@ -1173,6 +1182,8 @@ template <typename T> class basic_appender {
1173
1182
using appender = basic_appender<char >;
1174
1183
1175
1184
namespace detail {
1185
+ template <typename T>
1186
+ struct is_back_insert_iterator <basic_appender<T>> : std::true_type {};
1176
1187
1177
1188
template <typename T, typename Enable = void >
1178
1189
struct locking : std::true_type {};
@@ -1189,12 +1200,6 @@ FMT_CONSTEXPR inline auto is_locking() -> bool {
1189
1200
}
1190
1201
1191
1202
// An optimized version of std::copy with the output value type (T).
1192
- template <typename T, typename InputIt>
1193
- auto copy (InputIt begin, InputIt end, appender out) -> appender {
1194
- get_container (out).append (begin, end);
1195
- return out;
1196
- }
1197
-
1198
1203
template <typename T, typename InputIt, typename OutputIt,
1199
1204
FMT_ENABLE_IF (is_back_insert_iterator<OutputIt>::value)>
1200
1205
auto copy (InputIt begin, InputIt end, OutputIt out) -> OutputIt {
@@ -1209,14 +1214,6 @@ FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
1209
1214
return out;
1210
1215
}
1211
1216
1212
- template <typename T>
1213
- FMT_CONSTEXPR auto copy (const T* begin, const T* end, T* out) -> T* {
1214
- if (is_constant_evaluated ()) return copy<T, const T*, T*>(begin, end, out);
1215
- auto size = to_unsigned (end - begin);
1216
- if (size > 0 ) memcpy (out, begin, size * sizeof (T));
1217
- return out + size;
1218
- }
1219
-
1220
1217
template <typename T, typename V, typename OutputIt>
1221
1218
FMT_CONSTEXPR auto copy (basic_string_view<V> s, OutputIt out) -> OutputIt {
1222
1219
return copy<T>(s.begin (), s.end (), out);
@@ -1238,12 +1235,25 @@ constexpr auto has_const_formatter() -> bool {
1238
1235
return has_const_formatter_impl<Context>(static_cast <T*>(nullptr ));
1239
1236
}
1240
1237
1238
+ template <typename It, typename Enable = std::true_type>
1239
+ struct is_buffer_appender : std::false_type {};
1240
+ template <typename It>
1241
+ struct is_buffer_appender <
1242
+ It, bool_constant<
1243
+ is_back_insert_iterator<It>::value &&
1244
+ std::is_base_of<buffer<typename It::container_type::value_type>,
1245
+ typename It::container_type>::value>>
1246
+ : std::true_type {};
1247
+
1241
1248
// Maps an output iterator to a buffer.
1242
- template <typename T, typename OutputIt>
1249
+ template <typename T, typename OutputIt,
1250
+ FMT_ENABLE_IF (!is_buffer_appender<OutputIt>::value)>
1243
1251
auto get_buffer (OutputIt out) -> iterator_buffer<OutputIt, T> {
1244
1252
return iterator_buffer<OutputIt, T>(out);
1245
1253
}
1246
- template <typename T> auto get_buffer (basic_appender<T> out) -> buffer<T>& {
1254
+ template <typename T, typename OutputIt,
1255
+ FMT_ENABLE_IF (is_buffer_appender<OutputIt>::value)>
1256
+ auto get_buffer (OutputIt out) -> buffer<T>& {
1247
1257
return get_container (out);
1248
1258
}
1249
1259
@@ -1475,6 +1485,12 @@ template <typename Context> struct arg_mapper {
1475
1485
1476
1486
FMT_MAP_API auto map (void * val) -> const void* { return val; }
1477
1487
FMT_MAP_API auto map (const void * val) -> const void* { return val; }
1488
+ FMT_MAP_API auto map (volatile void * val) -> const void* {
1489
+ return const_cast <const void *>(val);
1490
+ }
1491
+ FMT_MAP_API auto map (const volatile void * val) -> const void* {
1492
+ return const_cast <const void *>(val);
1493
+ }
1478
1494
FMT_MAP_API auto map (std::nullptr_t val) -> const void* { return val; }
1479
1495
1480
1496
// Use SFINAE instead of a const T* parameter to avoid a conflict with the
@@ -1760,7 +1776,7 @@ template <typename Context> class basic_format_arg {
1760
1776
* `vis(value)` will be called with the value of type `double`.
1761
1777
*/
1762
1778
template <typename Visitor>
1763
- FMT_CONSTEXPR auto visit (Visitor&& vis) const -> decltype(vis(0 )) {
1779
+ FMT_CONSTEXPR FMT_INLINE auto visit (Visitor&& vis) const -> decltype(vis(0 )) {
1764
1780
switch (type_) {
1765
1781
case detail::type::none_type:
1766
1782
break ;
0 commit comments