Cleanup base API

This commit is contained in:
Victor Zverovich 2024-09-02 08:22:01 -07:00
parent d980dd7171
commit 4fa533c70e
4 changed files with 52 additions and 70 deletions

View File

@ -112,13 +112,6 @@ class dynamic_format_arg_store
friend class basic_format_args<Context>; friend class basic_format_args<Context>;
auto get_types() const -> unsigned long long {
return detail::is_unpacked_bit | data_.size() |
(named_info_.empty()
? 0ULL
: static_cast<unsigned long long>(detail::has_named_args_bit));
}
auto data() const -> const basic_format_arg<Context>* { auto data() const -> const basic_format_arg<Context>* {
return named_info_.empty() ? data_.data() : data_.data() + 1; return named_info_.empty() ? data_.data() : data_.data() + 1;
} }
@ -140,13 +133,18 @@ class dynamic_format_arg_store
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)> std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
guard{&data_, pop_one}; guard{&data_, pop_one};
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)}); named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; data_[0] = {named_info_.data(), named_info_.size()};
guard.release(); guard.release();
} }
public: public:
constexpr dynamic_format_arg_store() = default; constexpr dynamic_format_arg_store() = default;
operator basic_format_args<Context>() const {
return basic_format_args<Context>(data(), static_cast<int>(data_.size()),
!named_info_.empty());
}
/** /**
* Adds an argument into the dynamic store for later passing to a formatting * Adds an argument into the dynamic store for later passing to a formatting
* function. * function.
@ -217,7 +215,7 @@ class dynamic_format_arg_store
/// `new_cap_named` named arguments. /// `new_cap_named` named arguments.
void reserve(size_t new_cap, size_t new_cap_named) { void reserve(size_t new_cap, size_t new_cap_named) {
FMT_ASSERT(new_cap >= new_cap_named, FMT_ASSERT(new_cap >= new_cap_named,
"Set of arguments includes set of named arguments"); "set of arguments includes set of named arguments");
data_.reserve(new_cap); data_.reserve(new_cap);
named_info_.reserve(new_cap_named); named_info_.reserve(new_cap_named);
} }

View File

@ -216,20 +216,6 @@
# define FMT_DEPRECATED /* deprecated */ # define FMT_DEPRECATED /* deprecated */
#endif #endif
#ifdef FMT_NO_UNIQUE_ADDRESS
// Use the provided definition.
#elif FMT_CPLUSPLUS < 202002L
// Not supported.
#elif FMT_HAS_CPP_ATTRIBUTE(no_unique_address)
# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]]
// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485).
#elif FMT_MSC_VERSION >= 1929 && !FMT_CLANG_VERSION
# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#endif
#ifndef FMT_NO_UNIQUE_ADDRESS
# define FMT_NO_UNIQUE_ADDRESS
#endif
#ifdef FMT_ALWAYS_INLINE #ifdef FMT_ALWAYS_INLINE
// Use the provided definition. // Use the provided definition.
#elif FMT_GCC_VERSION || FMT_CLANG_VERSION #elif FMT_GCC_VERSION || FMT_CLANG_VERSION
@ -652,7 +638,6 @@ using buffered_context =
template <typename Context> class basic_format_arg; template <typename Context> class basic_format_arg;
template <typename Context> class basic_format_args; template <typename Context> class basic_format_args;
template <typename Context> class dynamic_format_arg_store;
// A separate type would result in shorter symbols but break ABI compatibility // A separate type would result in shorter symbols but break ABI compatibility
// between clang and gcc on ARM (#1919). // between clang and gcc on ARM (#1919).
@ -790,18 +775,22 @@ enum {
struct view {}; struct view {};
template <typename Char, typename T> struct named_arg : view { template <typename Char, typename T> struct named_arg;
const Char* name;
const T& value;
named_arg(const Char* n, const T& v) : name(n), value(v) {}
};
template <typename T> struct is_named_arg : std::false_type {}; template <typename T> struct is_named_arg : std::false_type {};
template <typename T> struct is_static_named_arg : std::false_type {}; template <typename T> struct is_static_named_arg : std::false_type {};
template <typename Char, typename T> template <typename Char, typename T>
struct is_named_arg<named_arg<Char, T>> : std::true_type {}; struct is_named_arg<named_arg<Char, T>> : std::true_type {};
template <typename Char, typename T> struct named_arg : view {
const Char* name;
const T& value;
named_arg(const Char* n, const T& v) : name(n), value(v) {}
static_assert(!is_named_arg<T>::value, "nested named arguments");
};
template <typename Char, typename T> template <typename Char, typename T>
auto unwrap_named_arg(const named_arg<Char, T>& arg) -> const T& { auto unwrap_named_arg(const named_arg<Char, T>& arg) -> const T& {
return arg.value; return arg.value;
@ -2407,7 +2396,7 @@ FMT_CONSTEXPR auto make_arg(T& val) -> value<Context> {
enum { enum {
formattable_char = !std::is_same<arg_type, unformattable_char>::value formattable_char = !std::is_same<arg_type, unformattable_char>::value
}; };
static_assert(formattable_char, "Mixing character types is disallowed."); static_assert(formattable_char, "mixing character types is disallowed");
// Formatting of arbitrary pointers is disallowed. If you want to format a // Formatting of arbitrary pointers is disallowed. If you want to format a
// pointer cast it to `void*` or `const void*`. In particular, this forbids // pointer cast it to `void*` or `const void*`. In particular, this forbids
@ -2416,7 +2405,7 @@ FMT_CONSTEXPR auto make_arg(T& val) -> value<Context> {
formattable_pointer = !std::is_same<arg_type, unformattable_pointer>::value formattable_pointer = !std::is_same<arg_type, unformattable_pointer>::value
}; };
static_assert(formattable_pointer, static_assert(formattable_pointer,
"Formatting of non-void pointers is disallowed."); "formatting of non-void pointers is disallowed");
enum { formattable = !std::is_same<arg_type, unformattable>::value }; enum { formattable = !std::is_same<arg_type, unformattable>::value };
#if defined(__cpp_if_constexpr) #if defined(__cpp_if_constexpr)
@ -2426,7 +2415,7 @@ FMT_CONSTEXPR auto make_arg(T& val) -> value<Context> {
#endif #endif
static_assert( static_assert(
formattable, formattable,
"Cannot format an argument. To make type T formattable provide a " "cannot format an argument; to make type T formattable provide a "
"formatter<T> specialization: https://fmt.dev/latest/api.html#udt"); "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
return {arg_mapper<char_type>::map(val)}; return {arg_mapper<char_type>::map(val)};
} }
@ -2562,22 +2551,12 @@ template <typename Context> class basic_format_arg {
detail::value<Context> value_; detail::value<Context> value_;
detail::type type_; detail::type type_;
template <typename ContextType, typename T> template <typename Ctx, typename T>
friend FMT_CONSTEXPR auto detail::make_arg(T& value) friend FMT_CONSTEXPR auto detail::make_arg(T& value) -> basic_format_arg<Ctx>;
-> basic_format_arg<ContextType>;
friend class basic_format_args<Context>; friend class basic_format_args<Context>;
friend class dynamic_format_arg_store<Context>;
friend class loc_value;
using char_type = typename Context::char_type; using char_type = typename Context::char_type;
template <typename, size_t, size_t, unsigned long long>
friend struct detail::format_arg_store;
basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size)
: value_(args, size) {}
public: public:
class handle { class handle {
private: private:
@ -2592,15 +2571,14 @@ template <typename Context> class basic_format_arg {
}; };
constexpr basic_format_arg() : type_(detail::type::none_type) {} constexpr basic_format_arg() : type_(detail::type::none_type) {}
basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size)
: value_(args, size) {}
constexpr explicit operator bool() const noexcept { constexpr explicit operator bool() const noexcept {
return type_ != detail::type::none_type; return type_ != detail::type::none_type;
} }
auto type() const -> detail::type { return type_; } auto type() const -> detail::type { return type_; }
auto is_integral() const -> bool { return detail::is_integral_type(type_); }
/** /**
* Visits an argument dispatching to the appropriate visit method based on * Visits an argument dispatching to the appropriate visit method based on
* the argument type. For example, if the argument type is `double` then * the argument type. For example, if the argument type is `double` then
@ -2714,18 +2692,16 @@ template <typename Context> class basic_format_args {
store) store)
: desc_(DESC), args_(store.args + (NUM_NAMED_ARGS != 0 ? 1 : 0)) {} : desc_(DESC), args_(store.args + (NUM_NAMED_ARGS != 0 ? 1 : 0)) {}
/// Constructs a `basic_format_args` object from `dynamic_format_arg_store`.
constexpr basic_format_args(const dynamic_format_arg_store<Context>& store)
: desc_(store.get_types()), args_(store.data()) {}
/// Constructs a `basic_format_args` object from a dynamic list of arguments. /// Constructs a `basic_format_args` object from a dynamic list of arguments.
constexpr basic_format_args(const format_arg* args, int count) constexpr basic_format_args(const format_arg* args, int count,
: desc_(detail::is_unpacked_bit | detail::to_unsigned(count)), bool has_named = false)
: desc_(detail::is_unpacked_bit | detail::to_unsigned(count) |
(has_named ? +detail::has_named_args_bit : 0ULL)),
args_(args) {} args_(args) {}
/// Returns the argument with the specified id. /// Returns the argument with the specified id.
FMT_CONSTEXPR auto get(int id) const -> format_arg { FMT_CONSTEXPR auto get(int id) const -> format_arg {
format_arg arg; auto arg = format_arg();
if (!is_packed()) { if (!is_packed()) {
if (id < max_size()) arg = args_[id]; if (id < max_size()) arg = args_[id];
return arg; return arg;
@ -2761,11 +2737,10 @@ template <typename Context> class basic_format_args {
}; };
// A formatting context. // A formatting context.
class context { class context : private detail::locale_ref {
private: private:
appender out_; appender out_;
format_args args_; format_args args_;
FMT_NO_UNIQUE_ADDRESS detail::locale_ref loc_;
public: public:
/// The character type for the output. /// The character type for the output.
@ -2780,7 +2755,7 @@ class context {
/// Constructs a `context` object. References to the arguments are stored /// Constructs a `context` object. References to the arguments are stored
/// in the object so make sure they have appropriate lifetimes. /// in the object so make sure they have appropriate lifetimes.
FMT_CONSTEXPR context(iterator out, format_args a, detail::locale_ref l = {}) FMT_CONSTEXPR context(iterator out, format_args a, detail::locale_ref l = {})
: out_(out), args_(a), loc_(l) {} : locale_ref(l), out_(out), args_(a) {}
context(context&&) = default; context(context&&) = default;
context(const context&) = delete; context(const context&) = delete;
void operator=(const context&) = delete; void operator=(const context&) = delete;
@ -2797,7 +2772,7 @@ class context {
// Advances the begin iterator to `it`. // Advances the begin iterator to `it`.
void advance_to(iterator) {} void advance_to(iterator) {}
FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } FMT_CONSTEXPR auto locale() -> detail::locale_ref { return *this; }
}; };
template <typename Char = char> struct runtime_format_string { template <typename Char = char> struct runtime_format_string {
@ -2844,7 +2819,7 @@ template <typename Char, typename... Args> class basic_format_string {
static_assert( static_assert(
FMT_USE_CONSTEVAL && sizeof(S) != 0, FMT_USE_CONSTEVAL && sizeof(S) != 0,
"FMT_ENFORCE_COMPILE_STRING requires all format strings to use " "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
"FMT_STRING."); "FMT_STRING");
#endif #endif
} }
template <typename S, template <typename S,
@ -2918,8 +2893,7 @@ constexpr auto make_format_args(T&... args)
/** /**
* Returns a named argument to be used in a formatting function. * Returns a named argument to be used in a formatting function.
* It should only be used in a call to a formatting function or * It should only be used in a call to a formatting function.
* `dynamic_format_arg_store::push_back`.
* *
* **Example**: * **Example**:
* *
@ -2927,7 +2901,6 @@ constexpr auto make_format_args(T&... args)
*/ */
template <typename Char, typename T> template <typename Char, typename T>
inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> { inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> {
static_assert(!detail::is_named_arg<T>(), "nested named arguments");
return {name, arg}; return {name, arg};
} }

View File

@ -124,6 +124,20 @@ FMT_END_NAMESPACE
# endif # endif
#endif #endif
#ifdef FMT_NO_UNIQUE_ADDRESS
// Use the provided definition.
#elif FMT_CPLUSPLUS < 202002L
// Not supported.
#elif FMT_HAS_CPP_ATTRIBUTE(no_unique_address)
# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]]
// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485).
#elif FMT_MSC_VERSION >= 1929 && !FMT_CLANG_VERSION
# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#endif
#ifndef FMT_NO_UNIQUE_ADDRESS
# define FMT_NO_UNIQUE_ADDRESS
#endif
#ifndef FMT_MAYBE_UNUSED #ifndef FMT_MAYBE_UNUSED
# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) # if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused)
# define FMT_MAYBE_UNUSED [[maybe_unused]] # define FMT_MAYBE_UNUSED [[maybe_unused]]
@ -1077,14 +1091,11 @@ template <typename OutputIt, typename Char> class generic_context {
class loc_value { class loc_value {
private: private:
basic_format_arg<format_context> value_; basic_format_arg<context> value_;
public: public:
template <typename T, FMT_ENABLE_IF(!detail::is_float128<T>::value)> template <typename T, FMT_ENABLE_IF(!detail::is_float128<T>::value)>
loc_value(T value) { loc_value(T value) : value_(detail::make_arg<context>(value)) {}
value_.type_ = detail::mapped_type_constant<T>::value;
value_.value_ = detail::arg_mapper<char>::map(value);
}
template <typename T, FMT_ENABLE_IF(detail::is_float128<T>::value)> template <typename T, FMT_ENABLE_IF(detail::is_float128<T>::value)>
loc_value(T) {} loc_value(T) {}

View File

@ -491,7 +491,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
auto arg = get_arg(arg_index); auto arg = get_arg(arg_index);
// For d, i, o, u, x, and X conversion specifiers, if a precision is // For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored // specified, the '0' flag is ignored
if (specs.precision >= 0 && arg.is_integral()) { if (specs.precision >= 0 && is_integral_type(arg.type())) {
// Ignore '0' for non-numeric types or if '-' present. // Ignore '0' for non-numeric types or if '-' present.
specs.set_fill(' '); specs.set_fill(' ');
} }
@ -556,7 +556,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
// Parse type. // Parse type.
if (it == end) report_error("invalid format string"); if (it == end) report_error("invalid format string");
char type = static_cast<char>(*it++); char type = static_cast<char>(*it++);
if (arg.is_integral()) { if (is_integral_type(arg.type())) {
// Normalize type. // Normalize type.
switch (type) { switch (type) {
case 'i': case 'i':