qxLib
sbo_bytes.inl
Go to the documentation of this file.
1 /**
2 
3  @file sbo_bytes.inl
4  @author Khrapov
5  @date 20.12.2025
6  @copyright © Nick Khrapov, 2025. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 template<class traits_t>
14 sbo_bytes<traits_t>::sbo_bytes(sbo_bytes&& other) noexcept
15 {
16  *this = std::move(other);
17 }
18 
19 template<class traits_t>
20 sbo_bytes<traits_t>::~sbo_bytes() noexcept
21 {
22  QX_STATIC_ASSERT_EQ(sizeof(sbo_bytes), nSBOSize);
23  free();
24 }
25 
26 template<class traits_t>
27 sbo_bytes<traits_t>& sbo_bytes<traits_t>::operator=(sbo_bytes&& other) noexcept
28 {
29  if (!is_small() && !other.is_small())
30  {
31  std::swap(m_pData, other.m_pData);
32  }
33  else if (is_small() && other.is_small())
34  {
35  std::swap(m_Buffer, other.m_Buffer);
36  }
37  else if (is_small() && !other.is_small())
38  {
39  buffer thisBuffer = std::move(m_Buffer);
40  m_pData = other.m_pData;
41  other.m_Buffer = std::move(thisBuffer);
42  }
43  else if (!is_small() && other.is_small())
44  {
45  std::byte* thisAllocated = m_pData;
46  m_Buffer = std::move(other.m_Buffer);
47  other.m_pData = thisAllocated;
48  }
49 
50  std::swap(m_nSize, other.m_nSize);
51  std::swap(m_nAllocatedSize, other.m_nAllocatedSize);
52 
53  return *this;
54 }
55 
56 QX_PUSH_SUPPRESS_MSVC_WARNINGS(4701);
57 template<class traits_t>
59  size_type nNewSize,
60  size_type nAlignment,
61  sbo_resize_type eSboResizeType,
62  bool bMemmove) noexcept
63 {
64  bool bRet = true;
65 
66  const size_type nSizeToAllocate =
67  eSboResizeType != sbo_resize_type::shrink_to_fit ? (nNewSize + nAlignment - 1) & ~(nAlignment - 1) : nNewSize;
68 
69  const bool bSmallAtStart = is_small();
70 
71  if (eSboResizeType == sbo_resize_type::shrink_to_fit // need to decrease a size
72  || eSboResizeType == sbo_resize_type::common && !bSmallAtStart && bShrinkToFitWhenSmall
73  || m_nSize == 0 // SBO is empty
74  || nSizeToAllocate > capacity()) // need to increase a size
75  {
76  buffer buff;
77 
78  if (nSizeToAllocate <= m_Buffer.size())
79  {
80  if (!bSmallAtStart && (bShrinkToFitWhenSmall || eSboResizeType == sbo_resize_type::shrink_to_fit))
81  {
82  // free allocated memory and move SBO to buffer
83 
84  if (bMemmove)
85  std::memmove(buff.data(), m_pData, nSizeToAllocate);
86 
87  free();
88 
89  m_Buffer = buff;
90  }
91 
92  m_nSize = nSizeToAllocate;
93  }
94  else
95  {
96  size_type nStartSize = 0;
97  if (bSmallAtStart)
98  {
99  buff = m_Buffer;
100  nStartSize = m_nSize;
101  }
102 
103  if (void* pNewBlock = std::realloc(bSmallAtStart ? nullptr : m_pData, nSizeToAllocate))
104  {
105  m_nAllocatedSize = nSizeToAllocate;
106  m_pData = static_cast<std::byte*>(pNewBlock);
107 
108  if (bMemmove && bSmallAtStart && m_nSize > 0)
109  std::memmove(m_pData, buff.data(), nStartSize);
110  }
111  else
112  {
113  bRet = false;
114  }
115  }
116  }
117 
118  if (bRet && eSboResizeType == sbo_resize_type::common)
119  m_nSize = nNewSize;
120 
121  return bRet;
122 }
123 QX_POP_SUPPRESS_WARNINGS();
124 
125 template<class traits_t>
127 {
128  if (!is_small())
129  {
130  std::free(m_pData);
131  m_pData = nullptr;
132  }
133 
134  m_nSize = 0;
135  m_nAllocatedSize = 0;
136 }
137 
138 template<class traits_t>
139 std::byte* sbo_bytes<traits_t>::data() noexcept
140 {
141  if (is_small())
142  return m_Buffer.data();
143  else
144  return m_pData;
145 }
146 
147 template<class traits_t>
148 const std::byte* sbo_bytes<traits_t>::data() const noexcept
149 {
150  return QX_CONST_CAST_THIS()->data();
151 }
152 
153 template<class traits_t>
154 typename sbo_bytes<traits_t>::size_type sbo_bytes<traits_t>::size() const noexcept
155 {
156  return m_nSize;
157 }
158 
159 template<class traits_t>
160 typename sbo_bytes<traits_t>::size_type sbo_bytes<traits_t>::capacity() const noexcept
161 {
162  if (is_small())
163  return m_Buffer.size();
164  else
165  return m_nAllocatedSize;
166 }
167 
168 template<class traits_t>
169 bool sbo_bytes<traits_t>::is_small() const noexcept
170 {
171  return m_nAllocatedSize == 0;
172 }
173 
174 } // namespace qx
size_type size() const noexcept
Get SBO size (bytes)
Definition: sbo_bytes.inl:154
bool resize(size_type nNewSize, size_type nAlignment, sbo_resize_type eSboResizeType, bool bMemmove) noexcept
Resize SBO.
Definition: sbo_bytes.inl:58
void free() noexcept
Free allocated memory.
Definition: sbo_bytes.inl:126
size_type capacity() const noexcept
Get SBO capacity (bytes)
Definition: sbo_bytes.inl:160
bool is_small() const noexcept
Is the SBO small and fits into the local buffer.
Definition: sbo_bytes.inl:169
std::byte * data() noexcept
Get SBO data: from a buffer or from a heap.
Definition: sbo_bytes.inl:139
#define QX_CONST_CAST_THIS()
This macro is made for situations where you have a const method, and you need exactly the same method...
Definition: common.h:57