1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29
30 #pragma once
31
32 // appleseed.foundation headers.
33 #include "foundation/math/scalar.h"
34 #include "foundation/platform/types.h"
35
36 // Standard headers.
37 #include <cassert>
38 #include <cstddef>
39 #include <cstring>
40
41 namespace foundation
42 {
43
44 //
45 // Memory-alignment related functions.
46 //
47
48 // Align a given pointer to a given boundary.
49 template <typename T>
50 T align(const T ptr, const size_t alignment);
51
52 // Compute the alignment of a given pointer.
53 template <typename T>
54 size_t alignment(const T ptr, const size_t max_alignment = 256);
55
56 // Return whether a given pointer is aligned on a given boundary.
57 template <typename T>
58 bool is_aligned(const T ptr, const size_t alignment);
59
60 // Allocate memory on a specified alignment boundary.
61 void* aligned_malloc(const size_t size, size_t alignment);
62
63 // Free a block of memory that was allocated with aligned_malloc().
64 void aligned_free(void* aligned_ptr);
65
66
67 //
68 // STL containers related functions.
69 //
70
71 // Ensure that a container has a minimum given size.
72 template <typename Container>
73 void ensure_minimum_size(
74 Container& container,
75 const size_t minimum_size);
76 template <typename Container, typename T>
77 void ensure_minimum_size(
78 Container& container,
79 const size_t minimum_size,
80 const T& value);
81
82 // Clear a container and release the memory.
83 template <typename Container>
84 void clear_release_memory(Container& container);
85
86 // Clear a container but keep memory allocated.
87 template <typename Container>
88 void clear_keep_memory(Container& container);
89
90 // Shrink the capacity of a container to its size.
91 template <typename Container>
92 void shrink_to_fit(Container& container);
93
94
95 //
96 // Utility classes to read/write typed data from/to unstructured memory blocks.
97 //
98
99 class MemoryReader
100 {
101 public:
102 explicit MemoryReader(const void* source);
103
104 const void* read(const size_t size);
105
106 template <typename T>
107 const T& read();
108
109 size_t offset() const;
110
111 MemoryReader& operator+=(const isize_t offset);
112 MemoryReader& operator-=(const isize_t offset);
113
114 private:
115 const uint8* const m_base;
116 const uint8* m_ptr;
117 };
118
119 class MemoryWriter
120 {
121 public:
122 explicit MemoryWriter(void* dest);
123
124 void write(const void* src, const size_t size);
125
126 template <typename T>
127 void write(const T& value);
128
129 size_t offset() const;
130
131 private:
132 const uint8* const m_base;
133 uint8* m_ptr;
134 };
135
136
137 //
138 // Memory-alignment related functions implementation.
139 //
140
141 template <typename T>
align(const T ptr,const size_t alignment)142 inline T align(const T ptr, const size_t alignment)
143 {
144 assert(alignment > 0);
145 assert(is_pow2(alignment));
146
147 const size_t a = alignment - 1;
148 const uintptr_t aligned = ((uintptr_t)ptr + a) & ~a;
149
150 return (T)aligned;
151 }
152
153 template <typename T>
alignment(const T ptr,const size_t max_alignment)154 size_t alignment(const T ptr, const size_t max_alignment)
155 {
156 assert(max_alignment > 0);
157 assert(is_pow2(max_alignment));
158
159 const uintptr_t p = (uintptr_t)ptr;
160 size_t a = 1;
161
162 while (a < max_alignment && (p & a) == 0)
163 a <<= 1;
164
165 return a;
166 }
167
168 template <typename T>
is_aligned(const T ptr,const size_t alignment)169 inline bool is_aligned(const T ptr, const size_t alignment)
170 {
171 assert(alignment > 0);
172 assert(is_pow2(alignment));
173
174 const uintptr_t p = (uintptr_t)ptr;
175 return (p & (alignment - 1)) == 0;
176 }
177
178
179 //
180 // STL containers related functions implementation.
181 //
182
183 template <typename Container>
ensure_minimum_size(Container & container,const size_t minimum_size)184 inline void ensure_minimum_size(
185 Container& container,
186 const size_t minimum_size)
187 {
188 if (container.size() < minimum_size)
189 container.resize(minimum_size);
190 }
191
192 template <typename Container, typename T>
ensure_minimum_size(Container & container,const size_t minimum_size,const T & value)193 inline void ensure_minimum_size(
194 Container& container,
195 const size_t minimum_size,
196 const T& value)
197 {
198 if (container.size() < minimum_size)
199 container.resize(minimum_size, value);
200 }
201
202 template <typename Container>
clear_release_memory(Container & container)203 inline void clear_release_memory(Container& container)
204 {
205 Container(container.get_allocator()).swap(container);
206
207 assert(container.empty());
208 }
209
210 template <typename Container>
clear_keep_memory(Container & container)211 inline void clear_keep_memory(Container& container)
212 {
213 #ifndef NDEBUG
214 const size_t old_capacity = container.capacity();
215 #endif
216
217 container.erase(container.begin(), container.end());
218
219 assert(container.capacity() == old_capacity);
220 }
221
222 template <typename Container>
shrink_to_fit(Container & container)223 inline void shrink_to_fit(Container& container)
224 {
225 Container(container).swap(container);
226 }
227
228
229 //
230 // MemoryReader class implementation.
231 //
232
MemoryReader(const void * source)233 inline MemoryReader::MemoryReader(const void* source)
234 : m_base(reinterpret_cast<const uint8*>(source))
235 , m_ptr(reinterpret_cast<const uint8*>(source))
236 {
237 }
238
read(const size_t size)239 inline const void* MemoryReader::read(const size_t size)
240 {
241 const void* result = m_ptr;
242 m_ptr += size;
243 return result;
244 }
245
246 template <typename T>
read()247 inline const T& MemoryReader::read()
248 {
249 return *reinterpret_cast<const T*>(read(sizeof(T)));
250 }
251
offset()252 inline size_t MemoryReader::offset() const
253 {
254 return m_ptr - m_base;
255 }
256
257 inline MemoryReader& MemoryReader::operator+=(const isize_t offset)
258 {
259 m_ptr += offset;
260 return *this;
261 }
262
263 inline MemoryReader& MemoryReader::operator-=(const isize_t offset)
264 {
265 m_ptr -= offset;
266 return *this;
267 }
268
269
270 //
271 // MemoryWriter class implementation.
272 //
273
MemoryWriter(void * dest)274 inline MemoryWriter::MemoryWriter(void* dest)
275 : m_base(reinterpret_cast<uint8*>(dest))
276 , m_ptr(reinterpret_cast<uint8*>(dest))
277 {
278 }
279
write(const void * src,const size_t size)280 inline void MemoryWriter::write(const void* src, const size_t size)
281 {
282 std::memcpy(m_ptr, src, size);
283 m_ptr += size;
284 }
285
286 template <typename T>
write(const T & value)287 inline void MemoryWriter::write(const T& value)
288 {
289 write(&value, sizeof(T));
290 }
291
offset()292 inline size_t MemoryWriter::offset() const
293 {
294 return m_ptr - m_base;
295 }
296
297 } // namespace foundation
298