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  get().~base_t();
30 }
31 
32 template<class base_t, size_t nSBOSize_>
33 template<sbo_poly_assignable_c<base_t> derived_t>
34 sbo_poly<base_t, nSBOSize_>& sbo_poly<base_t, nSBOSize_>::operator=(derived_t object) noexcept
35 {
36  assign(std::move(object));
37  return *this;
38 }
39 
40 template<class base_t, size_t nSBOSize_>
41 sbo_poly<base_t, nSBOSize_>& sbo_poly<base_t, nSBOSize_>::operator=(sbo_poly&& other) noexcept
42 {
43  if (!m_Data.is_small() && !other.m_Data.is_small())
44  {
45  // both objects are big, it's safe to simply swap pointers
46  std::swap(m_Data, other.m_Data);
47  }
48  else
49  {
50  // one or both objects is small, we should call move constructors for them,
51  // because it isn't safe to use memmove for them.
52  // do it that way that we avoid allocations.
53 
54  sbo_bytes<sbo_poly_traits> temp;
55 
56  if (m_Data.is_small() && other.m_Data.is_small())
57  {
58  if (m_Assigner)
59  m_Assigner(m_Data, temp);
60 
61  other.m_Assigner(other.m_Data, m_Data);
62 
63  if (m_Assigner)
64  m_Assigner(temp, other.m_Data);
65  }
66  else if (m_Data.is_small())
67  {
68  if (m_Assigner)
69  m_Assigner(m_Data, temp);
70 
71  other.m_Data = std::move(m_Data);
72 
73  if (m_Assigner)
74  m_Assigner(temp, other.m_Data);
75  }
76  else
77  {
78  other.m_Assigner(other.m_Data, temp);
79  m_Data = std::move(other.m_Data);
80  other.m_Assigner(temp, m_Data);
81  }
82  }
83 
84  std::swap(m_Assigner, other.m_Assigner);
85 
86  return *this;
87 }
88 
89 template<class base_t, size_t nSBOSize_>
90 template<sbo_poly_assignable_c<base_t> derived_t>
91 void sbo_poly<base_t, nSBOSize_>::assign(derived_t object) noexcept
92 {
93  if (m_Data.size() > 0)
94  get().~base_t();
95 
96  m_Data.resize(sizeof(derived_t), std::alignment_of_v<derived_t>, sbo_resize_type::common, false);
97  new (m_Data.data()) derived_t(std::move(object));
98 
99  m_Assigner = [](sbo_bytes_type& from, sbo_bytes_type& to)
100  {
101  to.resize(sizeof(derived_t), std::alignment_of_v<derived_t>, sbo_resize_type::common, false);
102  new (to.data()) derived_t(std::move(*reinterpret_cast<derived_t*>(from.data())));
103  };
104 }
105 
106 template<class base_t, size_t nSBOSize_>
108 {
109  return &get();
110 }
111 
112 template<class base_t, size_t nSBOSize_>
113 const base_t* sbo_poly<base_t, nSBOSize_>::operator->() const noexcept
114 {
115  return &get();
116 }
117 
118 template<class base_t, size_t nSBOSize_>
120 {
121  return *reinterpret_cast<base_t*>(m_Data.data());
122 }
123 
124 template<class base_t, size_t nSBOSize_>
125 const base_t& sbo_poly<base_t, nSBOSize_>::get() const noexcept
126 {
127  return QX_CONST_CAST_THIS()->get();
128 }
129 
130 } // 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:36
base_t & get() noexcept
Get object reference. Always valid.
Definition: sbo_poly.inl:119
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:91
#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