Skip to content

Commit 26bac2c

Browse files
committed
Use std::allocator_traits
Signed-off-by: Vladislav Shchapov <[email protected]>
1 parent 1b55d10 commit 26bac2c

File tree

2 files changed

+35
-30
lines changed

2 files changed

+35
-30
lines changed

include/fmt/format.h

+14-16
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,13 @@
4343
#include <cstring> // std::memcpy
4444
#include <initializer_list> // std::initializer_list
4545
#include <limits> // std::numeric_limits
46-
#include <stdexcept> // std::runtime_error
47-
#include <string> // std::string
48-
#include <system_error> // std::system_error
46+
#if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)
47+
// Workaround for pre gcc 5 libstdc++.
48+
# include <memory> // std::allocator_traits
49+
#endif
50+
#include <stdexcept> // std::runtime_error
51+
#include <string> // std::string
52+
#include <system_error> // std::system_error
4953

5054
#include "base.h"
5155

@@ -508,14 +512,6 @@ FMT_INLINE void assume(bool condition) {
508512
#endif
509513
}
510514

511-
template <typename Allocator, typename Enable = void> struct allocator_size {
512-
using type = size_t;
513-
};
514-
template <typename Allocator>
515-
struct allocator_size<Allocator, void_t<typename Allocator::size_type>> {
516-
using type = typename Allocator::size_type;
517-
};
518-
519515
template <typename Char, typename InputIt>
520516
auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
521517
get_container(out).append(begin, end);
@@ -914,17 +910,17 @@ class basic_memory_buffer : public detail::buffer<T> {
914910
static FMT_CONSTEXPR20 void grow(detail::buffer<T>& buf, size_t size) {
915911
detail::abort_fuzzing_if(size > 5000);
916912
auto& self = static_cast<basic_memory_buffer&>(buf);
917-
constexpr size_t max_size =
918-
detail::max_value<typename detail::allocator_size<Allocator>::type>() /
919-
sizeof(T);
913+
const size_t max_size =
914+
std::allocator_traits<Allocator>::max_size(self.alloc_);
920915
size_t old_capacity = buf.capacity();
921916
size_t new_capacity = old_capacity + old_capacity / 2;
922917
if (size > new_capacity)
923918
new_capacity = size;
924919
else if (new_capacity > max_size)
925920
new_capacity = size > max_size ? size : max_size;
926921
T* old_data = buf.data();
927-
T* new_data = self.alloc_.allocate(new_capacity);
922+
T* new_data =
923+
std::allocator_traits<Allocator>::allocate(self.alloc_, new_capacity);
928924
// Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481).
929925
detail::assume(buf.size() <= new_capacity);
930926
// The following code doesn't throw, so the raw pointer above doesn't leak.
@@ -933,7 +929,9 @@ class basic_memory_buffer : public detail::buffer<T> {
933929
// deallocate must not throw according to the standard, but even if it does,
934930
// the buffer already uses the new storage and will deallocate it in
935931
// destructor.
936-
if (old_data != self.store_) self.alloc_.deallocate(old_data, old_capacity);
932+
if (old_data != self.store_)
933+
std::allocator_traits<Allocator>::deallocate(self.alloc_, old_data,
934+
old_capacity);
937935
}
938936

939937
public:

test/format-test.cc

+21-14
Original file line numberDiff line numberDiff line change
@@ -413,30 +413,37 @@ TEST(memory_buffer_test, exception_in_deallocate) {
413413
EXPECT_CALL(alloc, deallocate(&mem2[0], 2 * size));
414414
}
415415

416-
class smol_allocator : public std::allocator<char> {
416+
template <typename Allocator, size_t MaxSize>
417+
class max_size_allocator : public Allocator {
417418
public:
418-
using size_type = unsigned char;
419-
420-
auto allocate(size_t n) -> value_type* {
421-
if (n > fmt::detail::max_value<size_type>())
419+
using typename Allocator::value_type;
420+
size_t max_size() const noexcept { return MaxSize; }
421+
value_type* allocate(size_t n) {
422+
if (n > max_size()) {
422423
throw std::length_error("size > max_size");
423-
return std::allocator<char>::allocate(n);
424+
}
425+
return std::allocator_traits<Allocator>::allocate(
426+
*static_cast<Allocator*>(this), n);
424427
}
425428
void deallocate(value_type* p, size_t n) {
426-
std::allocator<char>::deallocate(p, n);
429+
std::allocator_traits<Allocator>::deallocate(*static_cast<Allocator*>(this),
430+
p, n);
427431
}
428432
};
429433

430434
TEST(memory_buffer_test, max_size_allocator) {
431-
basic_memory_buffer<char, 10, smol_allocator> buffer;
432-
buffer.resize(200);
433-
// new_capacity = 200 + 200/2 = 300 > 256
434-
buffer.resize(255); // Shouldn't throw.
435+
// 160 = 128 + 32
436+
using test_allocator = max_size_allocator<std::allocator<char>, 160>;
437+
basic_memory_buffer<char, 10, test_allocator> buffer;
438+
buffer.resize(128);
439+
// new_capacity = 128 + 128/2 = 192 > 160
440+
buffer.resize(160); // Shouldn't throw.
435441
}
436442

437443
TEST(memory_buffer_test, max_size_allocator_overflow) {
438-
basic_memory_buffer<char, 10, smol_allocator> buffer;
439-
EXPECT_THROW(buffer.resize(256), std::exception);
444+
using test_allocator = max_size_allocator<std::allocator<char>, 160>;
445+
basic_memory_buffer<char, 10, test_allocator> buffer;
446+
EXPECT_THROW(buffer.resize(161), std::exception);
440447
}
441448

442449
TEST(format_test, exception_from_lib) {
@@ -2152,7 +2159,7 @@ TEST(format_int_test, format_int) {
21522159
EXPECT_EQ(fmt::format_int(42ul).str(), "42");
21532160
EXPECT_EQ(fmt::format_int(-42l).str(), "-42");
21542161
EXPECT_EQ(fmt::format_int(42ull).str(), "42");
2155-
EXPECT_EQ(fmt::format_int(-42ll).str(), "-42");\
2162+
EXPECT_EQ(fmt::format_int(-42ll).str(), "-42");
21562163
EXPECT_EQ(fmt::format_int(max_value<int64_t>()).str(),
21572164
std::to_string(max_value<int64_t>()));
21582165
}

0 commit comments

Comments
 (0)