qxLib
sbo_poly.inl
Go to the documentation of this file.
1 /**
2 
3  @file sbo_poly.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 base_t, size_t nSBOSize_>
14 template<sbo_poly_assignable_c<base_t> derived_t>
15 sbo_poly<base_t, nSBOSize_>::sbo_poly(derived_t object) noexcept
16 {
17  assign(std::move(object));
18 }
19 
20 template<class base_t, size_t nSBOSize_>
22 {
23  *this = std::move(other);
24 }
25 
26 template<class base_t, size_t nSBOSize_>
27 sbo_poly<base_t, nSBOSize_>::~sbo_poly() noexcept
28 {
29  // may be empty if an object was moved
30  if (m_Deleter)
31  m_Deleter(m_Data);
32 }
33 
34 template<class base_t, size_t nSBOSize_>
35 template<sbo_poly_assignable_c<base_t> derived_t>
36 sbo_poly<base_t, nSBOSize_>& sbo_poly<base_t, nSBOSize_>::operator=(derived_t object) noexcept
37 {
38  assign(std::move(object));
39  return *this;
40 }
41 
42 template<class base_t, size_t nSBOSize_>
43 sbo_poly<base_t, nSBOSize_>& sbo_poly<base_t, nSBOSize_>::operator=(sbo_poly&& other) noexcept
44 {
45  if (!m_Data.is_small() && !other.m_Data.is_small())
46  {
47  // both objects are big, it's safe to simply swap pointers
48  std::swap(m_Data, other.m_Data);
49  }
50  else
51  {
52  // one or both objects is small, we should call move constructors for them,
53  // because it isn't safe to use memmove for them.
54  // do it that way that we avoid allocations.
55 
56  sbo_bytes<sbo_poly_traits> temp;
57 
58  if (m_Data.is_small() && other.m_Data.is_small())
59  {
60  if (m_Assigner)
61  m_Assigner(m_Data, temp);
62 
63  other.m_Assigner(other.m_Data, m_Data);
64 
65  if (m_Assigner)
66  m_Assigner(temp, other.m_Data);
67  }
68  else if (m_Data.is_small())
69  {
70  if (m_Assigner)
71  m_Assigner(m_Data, temp);
72 
73  other.m_Data = std::move(m_Data);
74 
75  if (m_Assigner)
76  m_Assigner(temp, other.m_Data);
77  }
78  else
79  {
80  other.m_Assigner(other.m_Data, temp);
81  m_Data = std::move(other.m_Data);
82  other.m_Assigner(temp, m_Data);
83  }
84  }
85 
86  std::swap(m_Assigner, other.m_Assigner);
87  std::swap(m_Deleter, other.m_Deleter);
88 
89  return *this;
90 }
91 
92 template<class base_t, size_t nSBOSize_>
93 template<sbo_poly_assignable_c<base_t> derived_t>
94 void sbo_poly<base_t, nSBOSize_>::assign(derived_t object) noexcept
95 {
96  if (m_Data.size() > 0)
97  get().~base_t();
98 
99  m_Data.resize(sizeof(derived_t), std::alignment_of_v<derived_t>, sbo_resize_type::common, false);
100  new (m_Data.data()) derived_t(std::move(object));
101 
102  m_Assigner = [](sbo_bytes_type& from, sbo_bytes_type& to)
103  {
104  to.resize(sizeof(derived_t), std::alignment_of_v<derived_t>, sbo_resize_type::common, false);
105  new (to.data()) derived_t(std::move(*reinterpret_cast<derived_t*>(from.data())));
106  };
107 
108  m_Deleter = [](sbo_bytes_type& object)
109  {
110  reinterpret_cast<derived_t*>(object.data())->~derived_t();
111  };
112 }
113 
114 template<class base_t, size_t nSBOSize_>
116 {
117  return &get();
118 }
119 
120 template<class base_t, size_t nSBOSize_>
121 const base_t* sbo_poly<base_t, nSBOSize_>::operator->() const noexcept
122 {
123  return &get();
124 }
125 
126 template<class base_t, size_t nSBOSize_>
128 {
129  return *reinterpret_cast<base_t*>(m_Data.data());
130 }
131 
132 template<class base_t, size_t nSBOSize_>
133 const base_t& sbo_poly<base_t, nSBOSize_>::get() const noexcept
134 {
135  return QX_CONST_CAST_THIS()->get();
136 }
137 
138 } // namespace qx
std::byte * data() noexcept
Get SBO data: from a buffer or from a heap.
Definition: sbo_bytes.inl:139
Small Buffer Object for polymorphic classes.
Definition: sbo_poly.h:58
base_t & get() noexcept
Get object reference. Always valid.
Definition: sbo_poly.inl:127
sbo_poly(derived_t object) noexcept
sbo_poly object constructor
Definition: sbo_poly.inl:15
sbo_poly & operator=(derived_t object) noexcept
operator=
void assign(derived_t object) noexcept
Assign a new object to this SBO.
Definition: sbo_poly.inl:94
#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:63