merge dyn-args.h to core.h
This commit is contained in:
parent
6e047c2a45
commit
70bc839b24
@ -10,9 +10,12 @@
|
|||||||
|
|
||||||
#include <cstdio> // std::FILE
|
#include <cstdio> // std::FILE
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||||
#define FMT_VERSION 60103
|
#define FMT_VERSION 60103
|
||||||
@ -1626,6 +1629,194 @@ inline void print(const S& format_str, Args&&... args) {
|
|||||||
internal::make_args_checked<Args...>(format_str, args...));
|
internal::make_args_checked<Args...>(format_str, args...));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <typename T, typename Char> struct is_string_view : std::false_type {};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct is_string_view<basic_string_view<Char>, Char> : std::true_type {};
|
||||||
|
|
||||||
|
#ifdef FMT_USE_STRING_VIEW
|
||||||
|
template <typename Traits, typename Char>
|
||||||
|
struct is_string_view<std::basic_string_view<Char, Traits>, Char>
|
||||||
|
: std::true_type {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FMT_USE_EXPERIMENTAL_STRING_VIEW
|
||||||
|
template <typename Traits, typename Char>
|
||||||
|
struct is_string_view<std::experimental::basic_string_view<Char, Traits>, Char>
|
||||||
|
: std::true_type {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename T> struct is_ref_wrapper : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename T, typename Context> struct need_dyn_copy {
|
||||||
|
using mapped_type = mapped_type_constant<T, Context>;
|
||||||
|
static_assert(mapped_type::value != internal::type::named_arg_type,
|
||||||
|
"Bug indicator. Named arguments must be processed separately");
|
||||||
|
|
||||||
|
using type = std::integral_constant<
|
||||||
|
bool, !(is_ref_wrapper<T>::value ||
|
||||||
|
is_string_view<T, typename Context::char_type>::value ||
|
||||||
|
(mapped_type::value != internal::type::cstring_type &&
|
||||||
|
mapped_type::value != internal::type::custom_type &&
|
||||||
|
mapped_type::value != internal::type::string_type))>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Context>
|
||||||
|
using need_dyn_copy_t = typename need_dyn_copy<T, Context>::type;
|
||||||
|
|
||||||
|
class dyn_arg_storage {
|
||||||
|
// Workaround clang's -Wweak-vtables. For templates (unlike regular classes
|
||||||
|
// doesn't complain about inability to deduce translation unit to place vtable
|
||||||
|
// So dyn_arg_node_base is made a fake template
|
||||||
|
|
||||||
|
template <typename = void> struct storage_node_base {
|
||||||
|
using owning_ptr = std::unique_ptr<storage_node_base<>>;
|
||||||
|
virtual ~storage_node_base() = default;
|
||||||
|
owning_ptr next_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using owning_ptr = storage_node_base<>::owning_ptr;
|
||||||
|
|
||||||
|
template <typename T> struct storage_node : storage_node_base<> {
|
||||||
|
T value_;
|
||||||
|
FMT_CONSTEXPR explicit storage_node(const T& arg, owning_ptr&& next)
|
||||||
|
: value_{arg} {
|
||||||
|
// Must be initialised after value_
|
||||||
|
next_ = std::move(next);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
owning_ptr head_{nullptr};
|
||||||
|
|
||||||
|
public:
|
||||||
|
dyn_arg_storage() = default;
|
||||||
|
dyn_arg_storage(const dyn_arg_storage&) = delete;
|
||||||
|
dyn_arg_storage(dyn_arg_storage&&) = default;
|
||||||
|
|
||||||
|
dyn_arg_storage& operator=(const dyn_arg_storage&) = delete;
|
||||||
|
dyn_arg_storage& operator=(dyn_arg_storage&&) = default;
|
||||||
|
|
||||||
|
template <typename T, typename Arg> const T& push(const Arg& arg) {
|
||||||
|
auto node = new storage_node<T>{arg, std::move(head_)};
|
||||||
|
head_.reset(node);
|
||||||
|
return node->value_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
A dynamic version of `fmt::format_arg_store<>`.
|
||||||
|
It's equipped with a storage to potentially temporary objects which lifetime
|
||||||
|
could be shorter than the format arguments object.
|
||||||
|
|
||||||
|
It can be implicitly converted into `~fmt::basic_format_args` for passing
|
||||||
|
into type-erased formatting functions such as `~fmt::vformat`.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename Context>
|
||||||
|
class dynamic_format_arg_store
|
||||||
|
#if FMT_GCC_VERSION < 409
|
||||||
|
// Workaround a GCC template argument substitution bug.
|
||||||
|
: public basic_format_args<Context>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using char_type = typename Context::char_type;
|
||||||
|
using string_type = std::basic_string<char_type>;
|
||||||
|
using value_type = basic_format_arg<Context>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using stored_type =
|
||||||
|
conditional_t<internal::is_string<T>::value, string_type, T>;
|
||||||
|
|
||||||
|
// Storage of basic_format_arg must be contiguous
|
||||||
|
// Required by basic_format_args::args_ which is just a pointer
|
||||||
|
std::vector<value_type> data_;
|
||||||
|
|
||||||
|
// Storage of arguments not fitting into basic_format_arg must grow
|
||||||
|
// without relocation because items in data_ refer to it.
|
||||||
|
|
||||||
|
internal::dyn_arg_storage storage_;
|
||||||
|
|
||||||
|
friend class basic_format_args<Context>;
|
||||||
|
|
||||||
|
unsigned long long get_types() const {
|
||||||
|
return internal::is_unpacked_bit | data_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> const T& stored_value(const T& arg, std::false_type) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T& stored_value(const std::reference_wrapper<T>& arg, std::false_type) {
|
||||||
|
return arg.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const stored_type<T>& stored_value(const T& arg, std::true_type) {
|
||||||
|
return storage_.push<stored_type<T>>(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void emplace_arg(const T& arg) {
|
||||||
|
data_.emplace_back(internal::make_arg<Context>(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
dynamic_format_arg_store() = default;
|
||||||
|
~dynamic_format_arg_store() = default;
|
||||||
|
|
||||||
|
dynamic_format_arg_store(const dynamic_format_arg_store&) = delete;
|
||||||
|
dynamic_format_arg_store& operator=(const dynamic_format_arg_store&) = delete;
|
||||||
|
|
||||||
|
dynamic_format_arg_store(dynamic_format_arg_store&&) = default;
|
||||||
|
dynamic_format_arg_store& operator=(dynamic_format_arg_store&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Adds an argument into the dynamic store for later passing to a formating
|
||||||
|
function.
|
||||||
|
|
||||||
|
Note that custom types and string types (but not string views!) are copied
|
||||||
|
into the store with dynamic memory (in addition to resizing vector).
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
|
store.push_back(42);
|
||||||
|
store.push_back("abc1");
|
||||||
|
store.push_back(1.5f);
|
||||||
|
std::string result = fmt::vformat("{} and {} and {}", store);
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T> void push_back(const T& arg) {
|
||||||
|
static_assert(
|
||||||
|
!std::is_base_of<internal::named_arg_base<char_type>, T>::value,
|
||||||
|
"Named arguments are not supported yet");
|
||||||
|
emplace_arg(stored_value(arg, internal::need_dyn_copy_t<T, Context>{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Adds an argument into the dynamic store for later passing to a formating
|
||||||
|
function without copying into type-erasing list.
|
||||||
|
|
||||||
|
Note that primitive type values are copied into basic_format_arg<>.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T> void push_back(std::reference_wrapper<T> arg) {
|
||||||
|
emplace_arg(arg.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_CORE_H_
|
#endif // FMT_CORE_H_
|
||||||
|
|||||||
@ -1,180 +0,0 @@
|
|||||||
// Copyright (c) 2020 Vladimir Solontsov
|
|
||||||
// SPDX-License-Identifier: MIT Licence
|
|
||||||
|
|
||||||
#ifndef FMT_DYN_ARGS_H_
|
|
||||||
#define FMT_DYN_ARGS_H_
|
|
||||||
|
|
||||||
#include <forward_list>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "core.h"
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
template <typename T, typename Char> struct is_string_view : std::false_type {};
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
struct is_string_view<basic_string_view<Char>, Char> : std::true_type {};
|
|
||||||
|
|
||||||
#ifdef FMT_USE_STRING_VIEW
|
|
||||||
template <typename Traits, typename Char>
|
|
||||||
struct is_string_view<std::basic_string_view<Char, Traits>, Char>
|
|
||||||
: std::true_type {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FMT_USE_EXPERIMENTAL_STRING_VIEW
|
|
||||||
template <typename Traits, typename Char>
|
|
||||||
struct is_string_view<std::experimental::basic_string_view<Char, Traits>, Char>
|
|
||||||
: std::true_type {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename T> struct is_ref_wrapper : std::false_type {};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
|
||||||
|
|
||||||
template <typename T, typename Context> struct need_dyn_copy {
|
|
||||||
using mapped_type = mapped_type_constant<T, Context>;
|
|
||||||
static_assert(mapped_type::value != internal::type::named_arg_type,
|
|
||||||
"Bug indicator. Named arguments must be processed separately");
|
|
||||||
|
|
||||||
using type = std::integral_constant<
|
|
||||||
bool, !(is_ref_wrapper<T>::value ||
|
|
||||||
is_string_view<T, typename Context::char_type>::value ||
|
|
||||||
(mapped_type::value != internal::type::cstring_type &&
|
|
||||||
mapped_type::value != internal::type::custom_type &&
|
|
||||||
mapped_type::value != internal::type::string_type))>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename Context>
|
|
||||||
using need_dyn_copy_t = typename need_dyn_copy<T, Context>::type;
|
|
||||||
|
|
||||||
class dyn_arg_storage {
|
|
||||||
// Workaround clang's -Wweak-vtables. For templates (unlike regular classes
|
|
||||||
// doesn't complain about inability to deduce translation unit to place vtable
|
|
||||||
// So dyn_arg_node_base is made a fake template
|
|
||||||
|
|
||||||
template <typename = void> struct storage_node_base {
|
|
||||||
using owning_ptr = std::unique_ptr<storage_node_base<>>;
|
|
||||||
virtual ~storage_node_base() = default;
|
|
||||||
owning_ptr next_;
|
|
||||||
};
|
|
||||||
|
|
||||||
using owning_ptr = storage_node_base<>::owning_ptr;
|
|
||||||
|
|
||||||
template <typename T> struct storage_node : storage_node_base<> {
|
|
||||||
T value_;
|
|
||||||
FMT_CONSTEXPR explicit storage_node(const T& arg, owning_ptr&& next)
|
|
||||||
: value_{arg} {
|
|
||||||
// Must be initialised after value_
|
|
||||||
next_ = std::move(next);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
owning_ptr head_{nullptr};
|
|
||||||
|
|
||||||
public:
|
|
||||||
dyn_arg_storage() = default;
|
|
||||||
dyn_arg_storage(const dyn_arg_storage&) = delete;
|
|
||||||
dyn_arg_storage(dyn_arg_storage&&) = default;
|
|
||||||
|
|
||||||
dyn_arg_storage& operator=(const dyn_arg_storage&) = delete;
|
|
||||||
dyn_arg_storage& operator=(dyn_arg_storage&&) = default;
|
|
||||||
|
|
||||||
template <typename T, typename Arg> const T& push(const Arg& arg) {
|
|
||||||
auto node = new storage_node<T>{arg, std::move(head_)};
|
|
||||||
head_.reset(node);
|
|
||||||
return node->value_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
A dynamic version of `fmt::format_arg_store<>`.
|
|
||||||
It's equipped with a storage to potentially temporary objects which lifetime
|
|
||||||
could be shorter than the format arguments object.
|
|
||||||
|
|
||||||
It can be implicitly converted into `~fmt::basic_format_args` for passing
|
|
||||||
into type-erased formatting functions such as `~fmt::vformat`.
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
template <typename Context>
|
|
||||||
class dynamic_format_arg_store
|
|
||||||
#if FMT_GCC_VERSION < 409
|
|
||||||
// Workaround a GCC template argument substitution bug.
|
|
||||||
: public basic_format_args<Context>
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using char_type = typename Context::char_type;
|
|
||||||
using string_type = std::basic_string<char_type>;
|
|
||||||
using value_type = basic_format_arg<Context>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using stored_type =
|
|
||||||
conditional_t<internal::is_string<T>::value, string_type, T>;
|
|
||||||
|
|
||||||
// Storage of basic_format_arg must be contiguous
|
|
||||||
// Required by basic_format_args::args_ which is just a pointer
|
|
||||||
std::vector<value_type> data_;
|
|
||||||
|
|
||||||
// Storage of arguments not fitting into basic_format_arg must grow
|
|
||||||
// without relocation because items in data_ refer to it.
|
|
||||||
|
|
||||||
internal::dyn_arg_storage storage_;
|
|
||||||
|
|
||||||
friend class basic_format_args<Context>;
|
|
||||||
|
|
||||||
unsigned long long get_types() const {
|
|
||||||
return internal::is_unpacked_bit | data_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> const T& stored_value(const T& arg, std::false_type) {
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const T& stored_value(const std::reference_wrapper<T>& arg, std::false_type) {
|
|
||||||
return arg.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const stored_type<T>& stored_value(const T& arg, std::true_type) {
|
|
||||||
return storage_.push<stored_type<T>>(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> void emplace_arg(const T& arg) {
|
|
||||||
data_.emplace_back(internal::make_arg<Context>(arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
dynamic_format_arg_store() = default;
|
|
||||||
~dynamic_format_arg_store() = default;
|
|
||||||
|
|
||||||
dynamic_format_arg_store(const dynamic_format_arg_store&) = delete;
|
|
||||||
dynamic_format_arg_store& operator=(const dynamic_format_arg_store&) = delete;
|
|
||||||
|
|
||||||
dynamic_format_arg_store(dynamic_format_arg_store&&) = default;
|
|
||||||
dynamic_format_arg_store& operator=(dynamic_format_arg_store&&) = default;
|
|
||||||
|
|
||||||
template <typename T> void push_back(const T& arg) {
|
|
||||||
static_assert(
|
|
||||||
!std::is_base_of<internal::named_arg_base<char_type>, T>::value,
|
|
||||||
"Named arguments are not supported yet");
|
|
||||||
emplace_arg(stored_value(arg, internal::need_dyn_copy_t<T, Context>{}));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> void push_back(std::reference_wrapper<T> arg) {
|
|
||||||
emplace_arg(arg.get());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
|
|
||||||
#endif /* FMT_DYN_ARGS_H_ */
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2020 Vladimir Solontsov
|
// Copyright (c) 2020 Vladimir Solontsov
|
||||||
// SPDX-License-Identifier: MIT Licence
|
// SPDX-License-Identifier: MIT Licence
|
||||||
|
|
||||||
#include <fmt/dyn-args.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user