1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 14 янв. 2019 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef INCLUDE_CORE_3D_ALLOCATOR3D_H_
23 #define INCLUDE_CORE_3D_ALLOCATOR3D_H_
24 
25 #include <core/types.h>
26 
27 namespace lsp
28 {
29     /**
30      * Fixed-pointer allocator, allocates data grouped into partitions or 'chunks'
31      * to avoid huge memory fragmentation
32      */
33     class BasicAllocator3D
34     {
35         protected:
36             size_t      nChunks;        // Number of chunks in vChunks array
37             size_t      nShift;         // Chunk identifier shift
38             size_t      nMask;          // Chunk item mask
39             size_t      nSizeOf;        // Size of record (in bytes)
40             size_t      nAllocated;     // Number of allocated items
41             uint8_t   **vChunks;        // List of all chunks
42             uint8_t    *pCurr;          // Current chunk
43             size_t      nLeft;          // Number of left items
44 
45         protected:
46             uint8_t    *get_chunk(size_t id);
47             void       *do_alloc();
48             void        do_clear();
49             ssize_t     do_ialloc(void **p);
50             void       *do_get(size_t idx);
51             void        do_destroy();
52             size_t      do_alloc_n(void **ptr, size_t n);
53             void        do_swap(BasicAllocator3D *alloc);
54             bool        do_validate(const void *ptr) const;
55             ssize_t     calc_index_of(const void *ptr) const;
56 
57         public:
58             explicit BasicAllocator3D(size_t sz_of, size_t c_size);
59             ~BasicAllocator3D();
60     };
61 
62     template <class T>
63         class Allocator3D: public BasicAllocator3D
64         {
65             public:
66                 /**
67                  * Constructor
68                  * @param csize chunk size, will be rounded to be power of 2
69                  */
Allocator3D(size_t csize)70                 explicit Allocator3D(size_t csize): BasicAllocator3D(sizeof(T), csize) {}
71 
72             public:
73                 /**
74                  * Allocate single item
75                  * @return pointer to allocated single item or NULL
76                  */
alloc()77                 inline T *alloc() { return reinterpret_cast<T *>(do_alloc()); }
78 
79                 /**
80                  * Allocate single item
81                  * @return pointer to allocated single item or negative error status
82                  */
ialloc(T ** dst)83                 inline ssize_t ialloc(T **dst) { return do_ialloc(reinterpret_cast<void **>(dst)); }
84 
85                 /**
86                  * Allocate single item and initialize with value
87                  * @param src value to initialize
88                  * @return pointer to allocated item or NULL
89                  */
alloc(const T * src)90                 inline T *alloc(const T *src)
91                 {
92                     T *res = reinterpret_cast<T *>(do_alloc());
93                     if (res != NULL)
94                         *res = *src;
95                     return res;
96                 }
97 
98                 /**
99                  * Allocate single item
100                  * @return pointer to allocated single item or NULL
101                  */
ialloc(T ** dst,const T * src)102                 inline ssize_t ialloc(T **dst, const T *src) {
103                     size_t res = do_ialloc(reinterpret_cast<void **>(dst));
104                     if (*dst != NULL)
105                         **dst = *src;
106                     return res;
107                 }
108 
109                 /**
110                  * Allocate single item and initialize with value
111                  * @param src value to initialize
112                  * @return pointer to allocated item or NULL
113                  */
alloc(const T & src)114                 inline T *alloc(const T &src)
115                 {
116                     T *res = reinterpret_cast<T *>(do_alloc());
117                     if (res != NULL)
118                         *res = src;
119                     return res;
120                 }
121 
122                 /**
123                  * Allocate single item
124                  * @return pointer to allocated single item or NULL
125                  */
ialloc(T ** dst,const T & src)126                 inline ssize_t ialloc(T **dst, const T &src) {
127                     size_t res = do_ialloc(reinterpret_cast<void **>(dst));
128                     if (*dst != NULL)
129                         **dst = src;
130                     return res;
131                 }
132 
133                 /**
134                  * Allocate set of items
135                  * @param retval pointer to store pointers to allocated elements
136                  * @param n number of elements to allocate
137                  * @return actual number of allocated items
138                  */
alloc_n(T ** retval,size_t n)139                 inline size_t alloc_n(T **retval, size_t n) { return do_alloc_n(reinterpret_cast<void **>(retval), n); }
140 
141                 /**
142                  * Get number of allocated items
143                  * @return number of allocated items
144                  */
size()145                 inline size_t size() const { return nAllocated; }
146 
147                 /**
148                  * Get number of elements per one chunk
149                  * @return number of elements per one chunk
150                  */
chunk_size()151                 inline size_t chunk_size() const { return 1 << nShift; }
152 
153                 /**
154                  * Get number of allocated chunks
155                  * @return number of allocated chunks
156                  */
chunks()157                 inline size_t chunks() const { return nChunks; }
158 
159                 /**
160                  * Get chunk pointer
161                  * @param id chunk identifier
162                  * @return chunk pointer
163                  */
chunk(size_t id)164                 inline T *chunk(size_t id) { return (id < nChunks) ? reinterpret_cast<T *>(vChunks[id]) : NULL; }
165 
166                 /**
167                  * Get element at specified index
168                  * @param idx element at specified index
169                  * @return element at specified index or NULL if index is invalid
170                  */
get(size_t idx)171                 inline T *get(size_t idx) { return reinterpret_cast<T *>(do_get(idx)); }
172 
173                 /**
174                  * Get element at specified index
175                  * @param idx element at specified index
176                  * @return element at specified index or NULL if index is invalid
177                  */
178                 inline T * operator[] (size_t idx) { return do_get(idx); }
179 
180                 /**
181                  * Swap internal contents with another allocator
182                  * @param src allocator to perform swapping
183                  */
swap(Allocator3D<T> * src)184                 inline void swap(Allocator3D<T> *src) { do_swap(src); };
185 
186                 /** Drop all allocated data
187                  *
188                  */
destroy()189                 inline void destroy() { do_destroy(); };
190 
191                 /** Drop all allocated data (similar to destroy)
192                  *
193                  */
flush()194                 inline void flush() { do_destroy(); };
195 
196                 /** Drop all allocated data (currently similar to destroy)
197                  *
198                  */
clear()199                 inline void clear() { do_clear(); };
200 
201                 /**
202                  * Ensure that the specified pointer is right pointer, NULL pointers
203                  * also return positive result
204                  * @param ptr pointer
205                  * @return true if pointer is right and belongs to this allocator
206                  */
validate(const void * ptr)207                 inline bool validate(const void *ptr) const { return do_validate(ptr); };
208 
209                 /**
210                  * Get index of the item in allocator
211                  * @param ptr pointer to the item
212                  * @return index of the item or negative value on error
213                  */
index_of(const void * ptr)214                 inline ssize_t index_of(const void *ptr) const { return calc_index_of(ptr); }
215         };
216 }
217 
218 #endif /* INCLUDE_CORE_3D_ALLOCATOR3D_H_ */
219