make detail::basic_memory_buffer constexpr with C++20

This commit is contained in:
Alexey Ochapov 2021-08-27 00:52:41 +03:00 committed by Victor Zverovich
parent 6d597e39c3
commit fd34a3d246
2 changed files with 46 additions and 32 deletions

View File

@ -100,6 +100,13 @@
# define FMT_CONSTEXPR_DECL # define FMT_CONSTEXPR_DECL
#endif #endif
#if __cplusplus >= 202002L || \
(__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002)
# define FMT_CONSTEXPR20 constexpr
#else
# define FMT_CONSTEXPR20
#endif
// Check if constexpr std::char_traits<>::compare,length is supported. // Check if constexpr std::char_traits<>::compare,length is supported.
#if defined(__GLIBCXX__) #if defined(__GLIBCXX__)
# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ # if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \
@ -773,22 +780,22 @@ template <typename T> class buffer {
FMT_MSC_WARNING(suppress : 26495) FMT_MSC_WARNING(suppress : 26495)
buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0,
: ptr_(p), size_t cap = 0) FMT_NOEXCEPT : ptr_(p),
size_(sz), size_(sz),
capacity_(cap) {} capacity_(cap) {}
~buffer() = default; FMT_CONSTEXPR20 ~buffer() = default;
buffer(buffer&&) = default; buffer(buffer&&) = default;
/** Sets the buffer data and capacity. */ /** Sets the buffer data and capacity. */
void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
ptr_ = buf_data; ptr_ = buf_data;
capacity_ = buf_capacity; capacity_ = buf_capacity;
} }
/** Increases the buffer capacity to hold at least *capacity* elements. */ /** Increases the buffer capacity to hold at least *capacity* elements. */
virtual void grow(size_t capacity) = 0; virtual FMT_CONSTEXPR20 void grow(size_t capacity) = 0;
public: public:
using value_type = T; using value_type = T;
@ -804,23 +811,23 @@ template <typename T> class buffer {
auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; } auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; }
/** Returns the size of this buffer. */ /** Returns the size of this buffer. */
auto size() const FMT_NOEXCEPT -> size_t { return size_; } constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; }
/** Returns the capacity of this buffer. */ /** Returns the capacity of this buffer. */
auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; } constexpr auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; }
/** Returns a pointer to the buffer data. */ /** Returns a pointer to the buffer data. */
auto data() FMT_NOEXCEPT -> T* { return ptr_; } FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T* { return ptr_; }
/** Returns a pointer to the buffer data. */ /** Returns a pointer to the buffer data. */
auto data() const FMT_NOEXCEPT -> const T* { return ptr_; } FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T* { return ptr_; }
/** Clears this buffer. */ /** Clears this buffer. */
void clear() { size_ = 0; } void clear() { size_ = 0; }
// Tries resizing the buffer to contain *count* elements. If T is a POD type // Tries resizing the buffer to contain *count* elements. If T is a POD type
// the new elements may not be initialized. // the new elements may not be initialized.
void try_resize(size_t count) { FMT_CONSTEXPR20 void try_resize(size_t count) {
try_reserve(count); try_reserve(count);
size_ = count <= capacity_ ? count : capacity_; size_ = count <= capacity_ ? count : capacity_;
} }
@ -829,11 +836,11 @@ template <typename T> class buffer {
// capacity by a smaller amount than requested but guarantees there is space // capacity by a smaller amount than requested but guarantees there is space
// for at least one additional element either by increasing the capacity or by // for at least one additional element either by increasing the capacity or by
// flushing the buffer if it is full. // flushing the buffer if it is full.
void try_reserve(size_t new_capacity) { FMT_CONSTEXPR20 void try_reserve(size_t new_capacity) {
if (new_capacity > capacity_) grow(new_capacity); if (new_capacity > capacity_) grow(new_capacity);
} }
void push_back(const T& value) { FMT_CONSTEXPR20 void push_back(const T& value) {
try_reserve(size_ + 1); try_reserve(size_ + 1);
ptr_[size_++] = value; ptr_[size_++] = value;
} }
@ -841,8 +848,11 @@ template <typename T> class buffer {
/** Appends data to the end of the buffer. */ /** Appends data to the end of the buffer. */
template <typename U> void append(const U* begin, const U* end); template <typename U> void append(const U* begin, const U* end);
template <typename I> auto operator[](I index) -> T& { return ptr_[index]; } template <typename I> FMT_CONSTEXPR auto operator[](I index) -> T& {
template <typename I> auto operator[](I index) const -> const T& { return ptr_[index];
}
template <typename I>
FMT_CONSTEXPR auto operator[](I index) const -> const T& {
return ptr_[index]; return ptr_[index];
} }
}; };

View File

@ -249,14 +249,6 @@ FMT_END_NAMESPACE
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace detail { namespace detail {
#if __cplusplus >= 202002L || \
(__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002)
# define FMT_CONSTEXPR20 constexpr
#else
# define FMT_CONSTEXPR20
#endif
// An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have // An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have
// undefined behavior (e.g. due to type aliasing). // undefined behavior (e.g. due to type aliasing).
// Example: uint64_t d = bit_cast<uint64_t>(2.718); // Example: uint64_t d = bit_cast<uint64_t>(2.718);
@ -644,7 +636,7 @@ class basic_memory_buffer final : public detail::buffer<T> {
Allocator alloc_; Allocator alloc_;
// Deallocate memory allocated by the buffer. // Deallocate memory allocated by the buffer.
void deallocate() { FMT_CONSTEXPR20 void deallocate() {
T* data = this->data(); T* data = this->data();
if (data != store_) alloc_.deallocate(data, this->capacity()); if (data != store_) alloc_.deallocate(data, this->capacity());
} }
@ -656,22 +648,31 @@ class basic_memory_buffer final : public detail::buffer<T> {
using value_type = T; using value_type = T;
using const_reference = const T&; using const_reference = const T&;
explicit basic_memory_buffer(const Allocator& alloc = Allocator()) FMT_CONSTEXPR20 explicit basic_memory_buffer(
const Allocator& alloc = Allocator())
: alloc_(alloc) { : alloc_(alloc) {
this->set(store_, SIZE); this->set(store_, SIZE);
if (detail::is_constant_evaluated()) {
detail::fill_n(store_, SIZE, T{});
} }
~basic_memory_buffer() { deallocate(); } }
FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }
private: private:
// Move data from other to this buffer. // Move data from other to this buffer.
void move(basic_memory_buffer& other) { FMT_CONSTEXPR20 void move(basic_memory_buffer& other) {
alloc_ = std::move(other.alloc_); alloc_ = std::move(other.alloc_);
T* data = other.data(); T* data = other.data();
size_t size = other.size(), capacity = other.capacity(); size_t size = other.size(), capacity = other.capacity();
if (data == other.store_) { if (data == other.store_) {
this->set(store_, capacity); this->set(store_, capacity);
if (detail::is_constant_evaluated()) {
detail::copy_str<T>(other.store_, other.store_ + size,
detail::make_checked(store_, capacity));
} else {
std::uninitialized_copy(other.store_, other.store_ + size, std::uninitialized_copy(other.store_, other.store_ + size,
detail::make_checked(store_, capacity)); detail::make_checked(store_, capacity));
}
} else { } else {
this->set(data, capacity); this->set(data, capacity);
// Set pointer to the inline array so that delete is not called // Set pointer to the inline array so that delete is not called
@ -688,7 +689,10 @@ class basic_memory_buffer final : public detail::buffer<T> {
of the other object to it. of the other object to it.
\endrst \endrst
*/ */
basic_memory_buffer(basic_memory_buffer&& other) FMT_NOEXCEPT { move(other); } FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other)
FMT_NOEXCEPT {
move(other);
}
/** /**
\rst \rst
@ -710,7 +714,7 @@ class basic_memory_buffer final : public detail::buffer<T> {
Resizes the buffer to contain *count* elements. If T is a POD type new Resizes the buffer to contain *count* elements. If T is a POD type new
elements may not be initialized. elements may not be initialized.
*/ */
void resize(size_t count) { this->try_resize(count); } FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); }
/** Increases the buffer capacity to *new_capacity*. */ /** Increases the buffer capacity to *new_capacity*. */
void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } void reserve(size_t new_capacity) { this->try_reserve(new_capacity); }