Stroika Library 3.0d23x
 
Loading...
Searching...
No Matches
BlockAllocated.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Memory_BlockAllocated_h_
5#define _Stroika_Foundation_Memory_BlockAllocated_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <memory>
10
11#include "Stroika/Foundation/Common/Concepts.h"
14
15/**
16 * \file
17 *
18 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
19 *
20 * @todo Document why we didn't use BlockAllocated<T> : T ... issue is that wouldn't work for non-class T, such
21 * as int.
22 *
23 * @todo We should either add a VARIANT or template parameter to BlockAllocated<> saying whether we
24 * should force block allocation, or ONLY block-allocate if size is appropriate to one of our
25 * preformed pools.
26 *
27 * The reason for this option is for better use in templates like LinkedList<> - where we might
28 * want to blockallocate for small sizes of T, but not for ALL.
29 */
30
31/**
32 * \def qStroika_Foundation_Memory_PreferBlockAllocation
33 *
34 * \brief Allow use of block-allocation in classes which uses DECLARE_USE_BLOCK_ALLOCATION(), or UseBlockAllocationIfAppropriate etc
35 *
36 * Allow use of block-allocation. The main reason to disable it indiscriminately
37 * is for debugging purposes (looking for memory leaks). But others may have other
38 * reasons.
39 *
40 * Defaults to 1
41 */
42#ifndef qStroika_Foundation_Memory_PreferBlockAllocation
43#define qStroika_Foundation_Memory_PreferBlockAllocation 1
44#endif
45
46namespace Stroika::Foundation::Memory {
47
48 /**
49 * Use this to force use of block allocation for a given type, by inheriting this class from that type (this ignores qStroika_Foundation_Memory_PreferBlockAllocation).
50 *
51 * \note - typically DONT use this, but use UseBlockAllocationIfAppropriate instead.
52 *
53 * \par Example Usage:
54 * \code
55 * struct MyIterRep_ : Iterator<Character>::IRep, public Memory::BlockAllocationUseHelper<MyIterRep_> {
56 * _SharedPtrIRep fStr; // effectively RO, since if anyone modifies, our copy will remain unchanged
57 * size_t fCurIdx;
58 * MyIterRep_ (const _SharedPtrIRep& r, size_t idx = 0)
59 * : fStr (r)
60 * , fCurIdx (idx)
61 * {
62 * Require (fCurIdx <= fStr->_GetLength ());
63 * }
64 * ...
65 * };
66 * \endcode
67 *
68 * \note See also
69 * @see UsesBlockAllocation<T> ()
70 */
71 template <typename T>
73 static void* operator new (size_t n);
74 static void* operator new (size_t n, int, const char*, int);
75 static void operator delete (void* p);
76 static void operator delete (void* p, int, const char*, int);
77 };
78
79 /**
80 */
81 template <typename T>
82 constexpr bool UsesBlockAllocation ();
83
84 /**
85 * \brief same as make_shared, but if type T has block allocation, then use block allocation for the 'shared part' of T as well.
86 *
87 * \note this is helpful for shared_ptr (performance), but not for unique_ptr<>.
88 * \note perfectly safe to use on types with no block allocation - just the same as make_shared then.
89 */
90 template <typename T, typename... ARGS_TYPE>
91 auto MakeSharedPtr (ARGS_TYPE&&... args) -> shared_ptr<T>;
92
93 /**
94 * Use this to (roughly) undo the effect of BlockAllocationUseHelper<> or UseBlockAllocationIfAppropriate<> for a subclass.
95 */
96 template <typename T>
98 static void* operator new (size_t n);
99 static void* operator new (size_t n, int, const char*, int);
100 static void operator delete (void* p);
101 static void operator delete (void* p, int, const char*, int);
102 };
103
104 /**
105 * \brief Use this to enable block allocation for a particular class. *Beware* of subclassing.
106 *
107 * This utility class can be used to avoid some of the C++ gorp required in declaring that you are
108 * using block-allocation with a given class.
109 *
110 * \par Example Usage:
111 * \code
112 * struct MyIterRep_ : Iterator<Character>::IRep, public Memory::UseBlockAllocationIfAppropriate<MyIterRep_> {
113 * _SharedPtrIRep fStr; // effectively RO, since if anyone modifies, our copy will remain unchanged
114 * size_t fCurIdx;
115 * MyIterRep_ (const _SharedPtrIRep& r, size_t idx = 0)
116 * : fStr{r}
117 * , fCurIdx{idx}
118 * {
119 * Require (fCurIdx <= fStr->_GetLength ());
120 * }
121 * ...
122 * };
123 * \endcode
124 *
125 * If qStroika_Foundation_Memory_PreferBlockAllocation true (default) - this will use the optimized block allocation store, but if qStroika_Foundation_Memory_PreferBlockAllocation is
126 * false (0), this will just default to the global ::new/::delete
127 *
128 * @see Stroika::Foundation::Memory::BlockAllocationUseHelper
129 * @see Stroika::Foundation::Memory::BlockAllocator
130 * @see Stroika::Foundation::Memory::AutomaticallyBlockAllocated
131 * @see Stroika::Foundation::Memory::ManuallyBlockAllocated
132 */
133 template <typename T, bool andTrueCheck = true>
135 conditional_t<qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper<T>, Common::Empty>;
136
137 /**
138 * \brief same idea as UseBlockAllocationIfAppropriate, except always 'inherits' from BASE_REP, so hides any existing static operator new/delete
139 * methods.
140 *
141 * more CRTP style
142 *
143 * @todo - somewhat confusing implmentation - not sure why cannot be simpler?? -- LGP 2023-12-25
144 * // couldn't get concepots working for this - on g++
145 *
146
1471>C:\Sandbox\Stroika\DevRoot\Library\Sources\Stroika\Foundation\DataExchange\XML\Providers\Xerces.cpp(1048): error C2385: ambiguous access of 'delete'
1481>C:\Sandbox\Stroika\DevRoot\Library\Sources\Stroika\Foundation\DataExchange\XML\Providers\Xerces.cpp(1048): note: could be the 'delete' in base 'Stroika::Foundation::Memory::BlockAllocationUseHelper<`anonymous namespace'::NodeRep_>'
1491>C:\Sandbox\Stroika\DevRoot\Library\Sources\Stroika\Foundation\DataExchange\XML\Providers\Xerces.cpp(1048): note: or could be the 'delete' in base 'Stroika:
150 */
151 template <typename DERIVED, Common::ClassNotFinal BASE_REP, bool andTrueCheck = true>
153 template <typename... ARGS>
155 : BASE_REP{forward<ARGS> (args)...}
156 {
157 }
158 static void* operator new (size_t n)
159 {
160 if constexpr (andTrueCheck) {
162 }
163 else {
164 return BASE_REP::operator new (n);
165 }
166 }
167 static void* operator new (size_t n, int a, const char* b, int c)
168 {
169 if constexpr (andTrueCheck) {
170 return BlockAllocationUseHelper<DERIVED>::operator new (n, a, b, c);
171 }
172 else {
173 return BASE_REP::operator new (n, a, b, c);
174 }
175 }
176 static void operator delete (void* p)
177 {
178 if constexpr (andTrueCheck) {
180 }
181 else {
182 return BASE_REP::operator delete (p);
183 }
184 }
185 static void operator delete (void* p, int a, const char* b, int c)
186 {
187 if constexpr (andTrueCheck) {
189 }
190 else {
191 return BASE_REP::operator delete (p, a, b, c);
192 }
193 }
194 };
195
196 /**
197 * \brief for type T, either use BlockAllocator<T>, or std::allocator
198 *
199 * \note If using this, allocate shared_ptr<T> with Memory::MakeSharedPtr.
200 */
201 template <typename T, bool andTrueCheck = true>
203 conditional_t<qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocator<T>, std::allocator<T>>;
204
205 /**
206 * \brief ManuallyBlockAllocated<T> is a simple wrapper on BlockAllocator<T>. If qStroika_Foundation_Memory_PreferBlockAllocation defined, this will use block allocation for a given type - at a given call, else regular free-store.
207 *
208 * This is in sharp contrast to struct T : UseBlockAllocationIfAppropriate<T> {};
209 * If you use UseBlockAllocationIfAppropriate<> - the block allocation strategy happens automatically for all new creations of objects of that type.
210 *
211 * Using ManuallyBlockAllocated, only the particular places ManuallyBlockAllocated<T>::New ()/Delete are used will participate in block allocations, and other uses
212 * of T wont be block allocated. Note that means you MUST BE VERY CAREFUL with this and assure all objects allocated this way are deleted this way, and vice versa, and
213 * don't mix with regular free-store.
214 */
215 template <typename T>
217 public:
218 /**
219 */
220 template <typename... ARGS>
221 static T* New (ARGS&&... args);
222
223 public:
224 /**
225 */
226 static void Delete (T* p) noexcept;
227 };
228
229}
230
231/*
232 ********************************************************************************
233 ***************************** Implementation Details ***************************
234 ********************************************************************************
235 */
236#include "BlockAllocated.inl"
237
238#endif /*_Stroika_Foundation_Memory_BlockAllocated_h_*/
auto MakeSharedPtr(ARGS_TYPE &&... args) -> shared_ptr< T >
same as make_shared, but if type T has block allocation, then use block allocation for the 'shared pa...
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocator< T >, std::allocator< T > > BlockAllocatorOrStdAllocatorAsAppropriate
for type T, either use BlockAllocator<T>, or std::allocator
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
ManuallyBlockAllocated<T> is a simple wrapper on BlockAllocator<T>. If qStroika_Foundation_Memory_Pre...