Added formatter for bit_reference-like types (#3570)
* Add test for std::vector<bool>::reference Co-authored-by: Felix <felix-antoine.constantin@polymtl.ca> Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru> * Add test for std::bitset<N>::reference Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru> * Add test for const std::bitset<N>::reference and const std::vector<bool>::reference Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru> * Add bit_reference-like formatter Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru> * Use std::addressof Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru> --------- Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru> Co-authored-by: Felix <felix-antoine.constantin@polymtl.ca>
This commit is contained in:
parent
96d1fa22d4
commit
aeb6ad4dd0
@ -13,6 +13,7 @@
|
|||||||
#include <cstring> // std::strlen
|
#include <cstring> // std::strlen
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <memory> // std::addressof
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -1281,9 +1282,9 @@ template <typename Context> class value {
|
|||||||
FMT_INLINE value(const named_arg_info<char_type>* args, size_t size)
|
FMT_INLINE value(const named_arg_info<char_type>* args, size_t size)
|
||||||
: named_args{args, size} {}
|
: named_args{args, size} {}
|
||||||
|
|
||||||
template <typename T> FMT_CONSTEXPR FMT_INLINE value(T& val) {
|
template <typename T> FMT_CONSTEXPR20 FMT_INLINE value(T& val) {
|
||||||
using value_type = remove_const_t<T>;
|
using value_type = remove_const_t<T>;
|
||||||
custom.value = const_cast<value_type*>(&val);
|
custom.value = const_cast<value_type*>(std::addressof(val));
|
||||||
// Get the formatter type through the context to allow different contexts
|
// Get the formatter type through the context to allow different contexts
|
||||||
// have different extension points, e.g. `formatter<T>` for `format` and
|
// have different extension points, e.g. `formatter<T>` for `format` and
|
||||||
// `printf_formatter<T>` for `printf`.
|
// `printf_formatter<T>` for `printf`.
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#ifndef FMT_STD_H_
|
#ifndef FMT_STD_H_
|
||||||
#define FMT_STD_H_
|
#define FMT_STD_H_
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -15,6 +16,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "ostream.h"
|
#include "ostream.h"
|
||||||
@ -389,6 +391,50 @@ struct formatter<
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_flip : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> struct is_bit_reference_like {
|
||||||
|
static constexpr const bool value =
|
||||||
|
std::is_convertible<T, bool>::value &&
|
||||||
|
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _LIBCPP_VERSION
|
||||||
|
|
||||||
|
// Workaround for libc++ incompatibility with C++ standard.
|
||||||
|
// According to the Standard, `bitset::operator[] const` returns bool.
|
||||||
|
template <typename C>
|
||||||
|
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
||||||
|
static constexpr const bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// We can't use std::vector<bool, Allocator>::reference and
|
||||||
|
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
|
||||||
|
// in partial specialization.
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename BitRef, typename Char>
|
||||||
|
struct formatter<BitRef, Char,
|
||||||
|
enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
|
||||||
|
: formatter<bool, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return formatter<bool, Char>::format(v, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_STD_H_
|
#endif // FMT_STD_H_
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "fmt/std.h"
|
#include "fmt/std.h"
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -221,3 +222,17 @@ TEST(std_test, exception) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(std_test, format_bit_reference) {
|
||||||
|
std::bitset<2> bs(1);
|
||||||
|
EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false");
|
||||||
|
std::vector<bool> v = {true, false};
|
||||||
|
EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(std_test, format_const_bit_reference) {
|
||||||
|
const std::bitset<2> bs(1);
|
||||||
|
EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false");
|
||||||
|
const std::vector<bool> v = {true, false};
|
||||||
|
EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false");
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user