qxLib
sbo_bytes.h
Go to the documentation of this file.
1 /**
2 
3  @file sbo_bytes.h
4  @author Khrapov
5  @date 20.12.2025
6  @copyright © Nick Khrapov, 2025. All right reserved.
7 
8 **/
9 #pragma once
10 
11 #include <array>
12 #include <cstddef>
13 
14 #include <qx/macros/common.h>
15 
16 namespace qx
17 {
18 
19 /**
20 
21  @class sbo_bytes
22  @brief A type erased small buffer object that works with raw data
23  @tparam traits_t - SBO traits type
24  @author Khrapov
25  @date 20.12.2025
26 
27 **/
28 template<class traits_t>
29 class sbo_bytes
30 {
31 public:
32  using traits_type = traits_t;
33  using size_type = typename traits_type::size_type;
34 
35  // the final size of the whole sbo_bytes object, including internal data
36  static constexpr size_type nSBOSize = traits_type::nSBOSize;
37  static_assert(nSBOSize >= 32);
38 
39  // when the size changes so it becomes less or equal a buffer size, should we free a memory and move back to a buffer?
40  static constexpr bool bShrinkToFitWhenSmall = traits_type::bShrinkToFitWhenSmall;
41 
42  // Whether to preserve contents using memcpy when resizing from small to big and back
43  // Keep in mind, that std::realloc (big -> big and small -> big) preserves contents always, adding some performance overhead
44  static constexpr bool bPreserveContents = traits_type::bPreserveContents;
45 
46  static constexpr size_type nBufferSize = nSBOSize - 2 * sizeof(size_type);
47  using buffer_type = std::array<std::byte, nBufferSize>;
48 
49 public:
50  sbo_bytes() noexcept = default;
51  sbo_bytes(sbo_bytes&& other) noexcept;
52 
53  ~sbo_bytes() noexcept;
54 
55  sbo_bytes& operator=(sbo_bytes&& other) noexcept;
56 
57  /**
58  @brief Make sure the capacity is at least nRequestedSize and allocate memory if needed, and change the size to nRequestedSize
59  @param nRequestedSize - required size (bytes)
60  @retval - false if memory allocation failed, true otherwise
61  **/
62  bool resize(size_type nRequestedSize) noexcept;
63 
64  /**
65  @brief Make sure the capacity is at least nRequestedSize and allocate memory if needed, but do not change the size
66  @param nRequestedSize - required size (bytes)
67  @retval - false if memory allocation failed, true otherwise
68  **/
69  bool reserve(size_type nRequestedSize) noexcept;
70 
71  /**
72  @brief Reduce capacity to fit the size, possibly moving data to the internal buffer if the size becomes small
73  @retval - false if memory allocation failed, SBO remains valid in this case, true otherwise
74  **/
75  bool shrink_to_fit() noexcept;
76 
77  /**
78  @brief Free allocated memory
79  **/
80  void free() noexcept;
81 
82  /**
83  @brief Get SBO data: from a buffer or from a heap
84  @retval - SBO data pointer
85  **/
86  QX_FORCE_INLINE std::byte* data() noexcept;
87 
88  /**
89  @brief Get SBO data: from a buffer or from a heap
90  @retval - SBO data pointer
91  **/
92  QX_FORCE_INLINE const std::byte* data() const noexcept;
93 
94  /**
95  @brief Get SBO size (bytes)
96  @retval - SBO size (bytes)
97  **/
98  QX_FORCE_INLINE size_type size() const noexcept;
99 
100  /**
101  @brief Get SBO capacity (bytes)
102  @retval - SBO capacity (bytes), can't be less than nBufferSize
103  **/
104  QX_FORCE_INLINE size_type capacity() const noexcept;
105 
106  /**
107  @brief Is the SBO small and fits into the local buffer
108  @retval - true if the SBO is small and fits into the local buffer
109  **/
110  QX_FORCE_INLINE bool is_small() const noexcept;
111 
112 private:
113  /**
114  @brief Resize SBO using heap memory
115  @details The initial state can be either small or big, but the final state will be big.
116  If the initial state is small, data will be preserved if bPreserveContents is true.
117  @param nNewSize - required size (bytes)
118  @retval - false if memory allocation failed, true otherwise
119  **/
120  bool reallocate_to_big(size_type nNewSize) noexcept;
121 
122  /**
123  @brief Resize SBO using local buffer
124  @details The initial state must be big, but the final state will be small and fit into the local buffer.
125  Data will be preserved if bPreserveContents is true.
126  @param nNewSize - required size (bytes)
127  **/
128  void reallocate_to_small(size_type nNewSize) noexcept;
129 
130  /**
131  @brief Get new size according to the growth strategy
132  @param nRequestedSize - required size (bytes)
133  @retval - new size
134  **/
135  QX_FORCE_INLINE size_type get_new_size(size_type nRequestedSize) const noexcept;
136 
137 private:
138  union
139  {
140  buffer_type buffer = buffer_type();
141  std::byte* pData;
142  } m_Data;
143 
144  size_type m_nSize = 0;
145  size_type m_nAllocatedSize = 0;
146 };
147 
148 } // namespace qx
149 
150 #include <qx/memory/sbo_bytes.inl>
A type erased small buffer object that works with raw data.
Definition: sbo_bytes.h:30
QX_FORCE_INLINE size_type capacity() const noexcept
Get SBO capacity (bytes)
Definition: sbo_bytes.inl:118
QX_FORCE_INLINE bool is_small() const noexcept
Is the SBO small and fits into the local buffer.
Definition: sbo_bytes.inl:124
bool reserve(size_type nRequestedSize) noexcept
Make sure the capacity is at least nRequestedSize and allocate memory if needed, but do not change th...
Definition: sbo_bytes.inl:60
bool shrink_to_fit() noexcept
Reduce capacity to fit the size, possibly moving data to the internal buffer if the size becomes smal...
Definition: sbo_bytes.inl:69
void free() noexcept
Free allocated memory.
Definition: sbo_bytes.inl:85
QX_FORCE_INLINE std::byte * data() noexcept
Get SBO data: from a buffer or from a heap.
Definition: sbo_bytes.inl:97
QX_FORCE_INLINE size_type size() const noexcept
Get SBO size (bytes)
Definition: sbo_bytes.inl:112
bool resize(size_type nRequestedSize) noexcept
Make sure the capacity is at least nRequestedSize and allocate memory if needed, and change the size ...
Definition: sbo_bytes.inl:39
#define QX_FORCE_INLINE
Make this function forcefully inlined (except for QX_DEBUG build)
Definition: common.h:92