Repository: fmtlib/fmt
File: include/fmt/format.h (C/C++)

Code before:
    self.set(new_data, new_capacity);
    // deallocate must not throw according to the standard, but even if it does,
    // the buffer already uses the new storage and will deallocate it in
    // destructor.
    if (old_data != self.store_) self.alloc_.deallocate(old_data, old_capacity);
  }

 public:
  using value_type = T;
  using const_reference = const T&;

  FMT_CONSTEXPR explicit basic_memory_buffer(
      const Allocator& alloc = Allocator())
      : detail::buffer<T>(grow), alloc_(alloc) {
    this->set(store_, SIZE);
    if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
  }
  FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }

 private:
  // Move data from other to this buffer.
  FMT_CONSTEXPR20 void move(basic_memory_buffer& other) {
    using alloc_traits = std::allocator_traits<Allocator>;
    T* data = other.data();
    size_t size = other.size(), capacity = other.capacity();
    if constexpr (alloc_traits::propagate_on_container_move_assignment::value) {
      alloc_ = std::move(other.alloc_);
    } else {
      if (alloc_ != other.alloc_) {
        this->reserve(capacity);
        detail::copy<T>(data, data + size, this->data());
        this->resize(size);
        return;
      }
    }

    if (data == other.store_) {
      this->set(store_, capacity);
      detail::copy<T>(other.store_, other.store_ + size, store_);
    } else {
      this->set(data, capacity);
      // Set pointer to the inline array so that delete is not called
      // when deallocating.
      other.set(other.store_, 0);
      other.clear();
    }
    this->resize(size);
  }

 public:
  /// Constructs a `basic_memory_buffer` object moving the content of the other

Review comment (suggestion):
`if constexpr` is a C++17 feature, and {fmt} compatibility depth is C++11, I believe. However `std::pmr::polymorphic_allocator` (which is the primary case for the non-propagating allocators problem) is a C++17 feature as well. So I think it's ok to limit this entire new code block to C++17 (`__cpp_if_constexpr` might have been the right feature guard to check, but I'm concerned of older C++17 compilers not supporting feature guards yet).

Code after:
    T* new_data = self.alloc_.allocate(new_capacity);
    // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481).
    detail::assume(buf.size() <= new_capacity);
    // The following code doesn't throw, so the raw pointer above doesn't leak.
    memcpy(new_data, old_data, buf.size() * sizeof(T));
    self.set(new_data, new_capacity);
    // deallocate must not throw according to the standard, but even if it does,
    // the buffer already uses the new storage and will deallocate it in
    // destructor.
    if (old_data != self.store_) self.alloc_.deallocate(old_data, old_capacity);
  }

 public:
  using value_type = T;
  using const_reference = const T&;

  FMT_CONSTEXPR explicit basic_memory_buffer(
      const Allocator& alloc = Allocator())
      : detail::buffer<T>(grow), alloc_(alloc) {
    this->set(store_, SIZE);
    if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
  }
  FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }

 private:
  template <typename Alloc = Allocator>
  FMT_CONSTEXPR20
      typename std::enable_if<std::allocator_traits<Alloc>::
                                  propagate_on_container_move_assignment::value,
                              bool>::type
      allocator_move_impl(basic_memory_buffer& other) {
    alloc_ = std::move(other.alloc_);
    return true;
  }
  // If the allocator does not propagate,
  // then copy the content from source buffer.
  template <typename Alloc = Allocator>
  FMT_CONSTEXPR20
      typename std::enable_if<!std::allocator_traits<Alloc>::
                                  propagate_on_container_move_assignment::value,
                              bool>::type
      allocator_move_impl(basic_memory_buffer& other) {
    T* data = other.data();
    if (alloc_ != other.alloc_ && data != other.store_) {
      size_t size = other.size();
      // Perform copy operation, allocators are different
      this->resize(size);
      detail::copy<T>(data, data + size, this->data());
      return false;
    }
    return true;