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