Files
fmt/test/mock-allocator.h
Murat Toprak 0d145936ec Handle allocator propagation in basic_memory_buffer::move, Fix #4487 (#4490)
* Handle allocator propagation in basic_memory_buffer::move

Update `basic_memory_buffer::move` to respect `propagate_on_container_move_assignment`allocator trait.
If the allocator should not propagate and differs from the target's allocator,
fallback to copying the buffer instead of transferring ownership.

This avoids potential allocator mismatch issues and ensures exception safety.

* Add test cases for the updated move ctor

- Added two test cases `move_ctor_inline_buffer_non_propagating` and `move_ctor_dynamic_buffer_non_propagating`
- Added `PropageteOnMove` template parameter to `allocator_ref` class to be compatible with the old test cases
- `allocator_ref` now implements `!=` and `==` operators
2025-08-09 08:14:15 -07:00

95 lines
2.4 KiB
C++

// Formatting library for C++ - mock allocator
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_MOCK_ALLOCATOR_H_
#define FMT_MOCK_ALLOCATOR_H_
#include <assert.h> // assert
#include <stddef.h> // size_t
#include <memory> // std::allocator_traits
#include "gmock/gmock.h"
template <typename T> class mock_allocator {
public:
using value_type = T;
using size_type = size_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using difference_type = ptrdiff_t;
template <typename U> struct rebind {
using other = mock_allocator<U>;
};
mock_allocator() {}
mock_allocator(const mock_allocator&) {}
MOCK_METHOD(T*, allocate, (size_t));
MOCK_METHOD(void, deallocate, (T*, size_t));
};
template <typename Allocator, bool PropagateOnMove = false>
class allocator_ref {
private:
Allocator* alloc_;
void move(allocator_ref& other) {
alloc_ = other.alloc_;
other.alloc_ = nullptr;
}
public:
using value_type = typename Allocator::value_type;
using propagate_on_container_move_assignment =
typename std::conditional<PropagateOnMove, std::true_type,
std::false_type>::type;
explicit allocator_ref(Allocator* alloc = nullptr) : alloc_(alloc) {}
allocator_ref(const allocator_ref& other) : alloc_(other.alloc_) {}
allocator_ref(allocator_ref&& other) { move(other); }
allocator_ref& operator=(allocator_ref&& other) {
assert(this != &other);
move(other);
return *this;
}
allocator_ref& operator=(const allocator_ref& other) {
alloc_ = other.alloc_;
return *this;
}
public:
Allocator* get() const { return alloc_; }
value_type* allocate(size_t n) {
return std::allocator_traits<Allocator>::allocate(*alloc_, n);
}
void deallocate(value_type* p, size_t n) { alloc_->deallocate(p, n); }
FMT_CONSTEXPR20 friend bool operator==(const allocator_ref& a,
const allocator_ref& b) noexcept {
if (a.alloc_ == b.alloc_) return true;
if (a.alloc_ == nullptr || b.alloc_ == nullptr) return false;
return *a.alloc_ == *b.alloc_;
}
FMT_CONSTEXPR20 friend bool operator!=(const allocator_ref& a,
const allocator_ref& b) noexcept {
return !(a == b);
}
};
#endif // FMT_MOCK_ALLOCATOR_H_