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