Graphite Version 3
An experimental 3D geometry processing program
Loading...
Searching...
No Matches
memory.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40#ifndef GEOGRAM_BASIC_MEMORY
41#define GEOGRAM_BASIC_MEMORY
42
47#include <vector>
48#include <new>
49#include <string.h>
50#include <stdlib.h>
51
52#ifdef GEO_OS_WINDOWS
53
54#include <windows.h>
55#ifdef min
56#undef min
57#endif
58#ifdef max
59#undef max
60#endif
61
62#else
63
64#include <unistd.h>
65
66#endif
67
68// Stack size depending on OS:
69// Linux: 10 Mb
70// Windows: 1 Mb
71// Mac OSX: 512 Kb
72// GEO_HAS_BIG_STACK is defined under Linux
73// and lets some of the functions that
74// manipulate exact precision numbers
75// allocate temporaries on the stack.
76
77#ifdef GEO_OS_LINUX
78#define GEO_HAS_BIG_STACK
79#endif
80
86namespace GEO {
87
91 namespace Memory {
93 typedef unsigned char byte;
94
96 typedef unsigned char word8;
97
99 typedef unsigned short word16;
100
102 typedef unsigned int word32;
103
105 typedef byte* pointer;
106
108 typedef const byte* const_pointer;
109
111 typedef void (*function_pointer)();
112
120 inline void clear(void* addr, size_t size) {
121 ::memset(addr, 0, size);
122 }
123
133 inline void copy(void* to, const void* from, size_t size) {
134 ::memcpy(to, from, size);
135 }
136
147 template <class FPTR=function_pointer>
149 // I know this is ugly, but I did not find a simpler warning-free
150 // way that is portable between all compilers.
151 pointer result = nullptr;
152 ::memcpy(&result, &fptr, sizeof(pointer));
153 return result;
154 }
155
166 template <class FPTR = function_pointer>
168 // I know this is ugly, but I did not find a simpler warning-free
169 // way that is portable between all compilers.
170 FPTR result = nullptr;
171 ::memcpy(&result, &ptr, sizeof(pointer));
172 return result;
173 }
174
185 template <class FPTR = function_pointer>
186 inline FPTR generic_pointer_to_function_pointer(void* ptr) {
187 // I know this is ugly, but I did not find a simpler warning-free
188 // way that is portable between all compilers.
189 FPTR result = nullptr;
190 ::memcpy(&result, &ptr, sizeof(pointer));
191 return result;
192 }
193
194
201 template <class T> inline T& pointer_as_reference(void* ptr) {
202 // This is the recommended way of converting between pointers
203 // of different types. Casting the pointer directly is undefined
204 // behavior. Note: the call to memcpy() is eliminated by the
205 // compiler (that generates the same thing as when casting the
206 // pointer).
207 T* T_ptr;
208 ::memcpy(&T_ptr, &ptr, sizeof(pointer));
209 return *T_ptr;
210 }
211
218 template <class T> inline const T& pointer_as_reference(
219 const void* ptr
220 ) {
221 // This is the recommended way of converting between pointers
222 // of different types. Casting the pointer directly is undefined
223 // behavior. Note: the call to memcpy() is eliminated by the
224 // compiler (that generates the same thing as when casting the
225 // pointer).
226 const T* T_ptr;
227 ::memcpy(&T_ptr, &ptr, sizeof(pointer));
228 return *T_ptr;
229 }
230
231
240#define GEO_MEMORY_ALIGNMENT 64
241
252 template <int DIM>
258 static const size_t value = 1;
259 };
260
265 template <>
266 struct PointAlignment<2> {
267 static const size_t value = 16;
268 };
269
274 template <>
275 struct PointAlignment<3> {
276 static const size_t value = 8;
277 };
278
283 template <>
284 struct PointAlignment<4> {
285 static const size_t value = 32;
286 };
287
292 template <>
293 struct PointAlignment<6> {
294 static const size_t value = 16;
295 };
296
301 template <>
302 struct PointAlignment<8> {
303 static const size_t value = 64;
304 };
305
314#define geo_dim_alignment(dim) GEO::Memory::PointAlignment<dim>::value
315
325 inline void* aligned_malloc(
326 size_t size, size_t alignment = GEO_MEMORY_ALIGNMENT
327 ) {
328#if defined(GEO_OS_ANDROID)
329 // Alignment not supported under Android.
330 geo_argused(alignment);
331 return malloc(size);
332#elif defined(GEO_COMPILER_INTEL)
333 return _mm_malloc(size, alignment);
334#elif defined(GEO_COMPILER_GCC) || defined(GEO_COMPILER_CLANG)
335 void* result;
336 return posix_memalign(&result, alignment, size) == 0
337 ? result : nullptr;
338#elif defined(GEO_COMPILER_MSVC)
339 return _aligned_malloc(size, alignment);
340#else
341 geo_argused(alignment);
342 return malloc(size);
343#endif
344 }
345
353 inline void aligned_free(void* p) {
354#if defined(GEO_OS_ANDROID)
355 // Alignment not supported under Android.
356 free(p);
357#elif defined(GEO_COMPILER_INTEL)
358 _mm_free(p);
359#elif defined(GEO_COMPILER_GCC_FAMILY)
360 free(p);
361#elif defined(GEO_COMPILER_MSVC)
362 _aligned_free(p);
363#else
364 free(p);
365#endif
366 }
367
381#if defined(GEO_OS_ANDROID)
382#define geo_decl_aligned(var) var
383#elif defined(GEO_COMPILER_INTEL)
384#define geo_decl_aligned(var) __declspec(aligned(GEO_MEMORY_ALIGNMENT)) var
385#elif defined(GEO_COMPILER_GCC_FAMILY)
386#define geo_decl_aligned(var) var __attribute__((aligned(GEO_MEMORY_ALIGNMENT)))
387#elif defined(GEO_COMPILER_MSVC)
388#define geo_decl_aligned(var) __declspec(align(GEO_MEMORY_ALIGNMENT)) var
389#elif defined(GEO_COMPILER_EMSCRIPTEN)
390#define geo_decl_aligned(var) var
391#endif
392
409#if defined(GEO_OS_ANDROID)
410#define geo_assume_aligned(var, alignment)
411#elif defined(GEO_COMPILER_INTEL)
412#define geo_assume_aligned(var, alignment) \
413 __assume_aligned(var, alignment)
414#elif defined(GEO_COMPILER_CLANG)
415#define geo_assume_aligned(var, alignment)
416 // GCC __builtin_assume_aligned is not yet supported by clang-3.3
417#elif defined(GEO_COMPILER_GCC)
418#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
419#define geo_assume_aligned(var, alignment) \
420 *(void**) (&var) = __builtin_assume_aligned(var, alignment)
421 // the GCC way of specifying that a pointer is aligned returns
422 // the aligned pointer (I can't figure out why). It needs to be
423 // affected otherwise it is not taken into account (verified by
424 // looking at the output of gcc -S)
425#else
426#define geo_assume_aligned(var, alignment)
427#endif
428#elif defined(GEO_COMPILER_MSVC)
429#define geo_assume_aligned(var, alignment)
430 // TODO: I do not know how to do that with MSVC
431#elif defined(GEO_COMPILER_EMSCRIPTEN)
432#define geo_assume_aligned(var, alignment)
433#elif defined(GEO_COMPILER_MINGW)
434#define geo_assume_aligned(var, alignment)
435#endif
436
447#if defined(GEO_COMPILER_INTEL)
448#define geo_restrict __restrict
449#elif defined(GEO_COMPILER_GCC_FAMILY)
450#define geo_restrict __restrict__
451#elif defined(GEO_COMPILER_MSVC)
452#define geo_restrict __restrict
453#elif defined(GEO_COMPILER_EMSCRIPTEN)
454#define geo_restrict
455#endif
456
464 inline bool is_aligned(
465 void* p, size_t alignment = GEO_MEMORY_ALIGNMENT
466 ) {
467 return (reinterpret_cast<size_t>(p) & (alignment - 1)) == 0;
468 }
469
473 inline void* align(void* p) {
474 size_t offset = (
476 (reinterpret_cast<size_t>(p) & (GEO_MEMORY_ALIGNMENT - 1))
477 ) & (GEO_MEMORY_ALIGNMENT - 1);
478 return reinterpret_cast<char*>(p) + offset;
479 }
480
490#define geo_aligned_alloca(size) \
491 GEO::Memory::align(alloca(size + GEO_MEMORY_ALIGNMENT - 1))
492
500 template <class T, int ALIGN = GEO_MEMORY_ALIGNMENT>
502 public:
504 typedef T value_type;
505
507 typedef T* pointer;
508
510 typedef T& reference;
511
513 typedef const T* const_pointer;
514
516 typedef const T& const_reference;
517
519 typedef ::std::size_t size_type;
520
522 typedef ::std::ptrdiff_t difference_type;
523
525 static constexpr int ALIGNMENT = ALIGN;
526
531 template <class U>
536
537 /* \brief default constructor */
538 constexpr aligned_allocator() noexcept = default;
539
540 /* \brief conversion copy constructor */
541 template <class U, int A2> constexpr aligned_allocator(
542 const aligned_allocator<U, A2>&
543 ) noexcept {
544 }
545
552 return &x;
553 }
554
561 return &x;
562 }
563
582 size_type nb_elt, const void* hint = nullptr
583 ) {
584 nb_elt = std::max(nb_elt,size_type(1));
585 geo_argused(hint);
586 while(true) {
587 pointer result = static_cast<pointer>(
588 aligned_malloc(sizeof(T) * nb_elt, ALIGNMENT)
589 );
590 if(result != nullptr) {
591 return result;
592 }
593 // under Linux, a process requesting more mem than available
594 // is killed (and there is nothing we can capture). Under
595 // other OSes, the standard mechanism to let the runtime
596 // know is as follows:
597 // see: https://stackoverflow.com/questions/7194127/
598 // how-should-i-write-iso-c-standard-conformant-custom-
599 // new-and-delete-operators
600 // (if there is a handler, call it repeatedly until
601 // allocation succeeds, else throw a bad_alloc exception)
602 std::new_handler handler = std::get_new_handler();
603 if(handler != nullptr) {
604 (*handler)();
605 } else {
606 throw std::bad_alloc();
607 }
608 }
609 }
610
622 void deallocate(pointer p, size_type nb_elt) {
623 geo_argused(nb_elt);
624 aligned_free(p);
625 }
626
634 ::std::allocator<char> a;
635 return std::allocator_traits<decltype(a)>::max_size(a) /
636 sizeof(T);
637 }
638
652 new (static_cast<void*>(p))value_type(val);
653 }
654
663 void destroy(pointer p) {
664 geo_argused(p); // else MSVC complains
665 p->~value_type();
666 }
667 };
668
673 template <typename T1, int A1, typename T2, int A2>
674 inline bool operator== (
676 ) {
677 return true;
678 }
679
684 template <typename T1, int A1, typename T2, int A2>
685 inline bool operator!= (
687 ) {
688 return false;
689 }
690 }
691
692 /************************************************************************/
693
702 template <class T>
703 class vector : public ::std::vector<T, Memory::aligned_allocator<T> > {
708
712 typedef ::std::vector<T, Memory::aligned_allocator<T> > baseclass;
713
714
715
716 public:
721 baseclass() {
722 }
723
730 explicit vector(index_t size) :
731 baseclass(size) {
732 }
733
741 explicit vector(index_t size, const T& val) :
742 baseclass(size, val) {
743 }
744
749 index_t size() const {
750 // casts baseclass::size() from size_t (64 bits)
751 // to index_t (32 bits), because all
752 // indices in Vorpaline are supposed to fit in 32 bits (index_t).
753 // TODO: geo_debug_assert(baseclass::size() < max index_t)
754 return index_t(baseclass::size());
755 }
756
763 geo_debug_assert(i < size());
764 return baseclass::operator[] (i);
765 }
766
773 const T& operator[] (index_t i) const {
774 geo_debug_assert(i < size());
775 return baseclass::operator[] (i);
776 }
777
784 geo_debug_assert(i >= 0 && index_t(i) < size());
785 return baseclass::operator[] (index_t(i));
786 }
787
794 const T& operator[] (signed_index_t i) const {
795 geo_debug_assert(i >= 0 && index_t(i) < size());
796 return baseclass::operator[] (index_t(i));
797 }
798
799
800#ifdef GARGANTUA // If compiled with 64 bits index_t
801
807 T& operator[] (int i) {
808 geo_debug_assert(i >= 0 && index_t(i) < size());
809 return baseclass::operator[] (index_t(i));
810 }
811
818 const T& operator[] (int i) const {
819 geo_debug_assert(i >= 0 && index_t(i) < size());
820 return baseclass::operator[] (index_t(i));
821 }
822
828 T& operator[] (unsigned int i) {
830 return baseclass::operator[] (index_t(i));
831 }
832
839 const T& operator[] (unsigned int i) const {
841 return baseclass::operator[] (index_t(i));
842 }
843#endif
844
849 T* data() {
850 T* result = baseclass::data();
851 // Tell the compiler that the pointer is aligned, to enable AVX
852 // vectorization, can be useful when using vector<double>
853 // with blas-like operations. I hope the hint will propagate to
854 // the caller (not sure...)
855 geo_assume_aligned(result, allocator::ALIGNMENT);
856 return result;
857 }
858
863 const T* data() const {
864 const T* result = baseclass::data();
865 // Tell the compiler that the pointer is aligned, to enable AVX
866 // vectorization, can be useful when using vector<double>
867 // with blas-like operations. I hope the hint will propagate to
868 // the caller (not sure...)
869 geo_assume_aligned(result, allocator::ALIGNMENT);
870 return result;
871 }
872
873
880 vector<T> other;
881 this->swap(other);
882 }
883 };
884
891 template <>
892 class vector<bool> : public ::std::vector<bool> {
893 typedef ::std::vector<bool> baseclass;
894
895 public:
898 baseclass() {
899 }
900
902 explicit vector(index_t size) :
903 baseclass(size) {
904 }
905
907 explicit vector(index_t size, bool val) :
908 baseclass(size, val) {
909 }
910
912 index_t size() const {
913 // casts baseclass::size() from size_t (64 bits)
914 // to index_t (32 bits), because all
915 // indices in Vorpaline are supposed to fit in 32 bits (index_t).
916 // TODO: geo_debug_assert(baseclass::size() < max index_t)
917 return index_t(baseclass::size());
918 }
919
920 // TODO: operator[] with bounds checking (more complicated
921 // than just returning bool&, check implementation in STL).
922 };
923}
924
925#endif
A function to suppress unused parameters compilation warnings.
Assertion checking mechanism.
#define geo_debug_assert(x)
Verifies that a condition is met.
Definition assert.h:196
An allocator that performs aligned memory allocations.
Definition memory.h:501
size_type max_size() const
Gets the maximum size possible to allocate.
Definition memory.h:633
T * pointer
Pointer to element.
Definition memory.h:507
const T & const_reference
Reference to constant element.
Definition memory.h:516
void destroy(pointer p)
Destroys an object.
Definition memory.h:663
const T * const_pointer
Pointer to constant element.
Definition memory.h:513
pointer address(reference x)
Gets the address of an object.
Definition memory.h:551
pointer allocate(size_type nb_elt, const void *hint=nullptr)
Allocates a block of storage.
Definition memory.h:581
T value_type
Element type.
Definition memory.h:504
static constexpr int ALIGNMENT
Alignment in bytes.
Definition memory.h:525
const_pointer address(const_reference x)
Gets the address of a object.
Definition memory.h:560
T & reference
Reference to element.
Definition memory.h:510
void construct(pointer p, const_reference val)
Constructs an object.
Definition memory.h:651
::std::size_t size_type
Quantities of elements.
Definition memory.h:519
void deallocate(pointer p, size_type nb_elt)
Releases a block of storage.
Definition memory.h:622
::std::ptrdiff_t difference_type
Difference between two pointers.
Definition memory.h:522
index_t size() const
Gets the number of elements.
Definition memory.h:912
vector(index_t size)
Creates a pre-allocated vector.
Definition memory.h:902
vector(index_t size, bool val)
Creates a pre-initialized vector.
Definition memory.h:907
vector()
Creates an empty vector.
Definition memory.h:897
Vector with aligned memory allocation.
Definition memory.h:703
void clear_and_deallocate()
Resizes this vector to zero and deallocated all the memory.
Definition memory.h:879
vector()
Creates an empty vector.
Definition memory.h:720
const T * data() const
Gets a pointer to the array of elements.
Definition memory.h:863
vector(index_t size, const T &val)
Creates a pre-initialized vector.
Definition memory.h:741
vector(index_t size)
Creates a pre-allocated vector.
Definition memory.h:730
T * data()
Gets a pointer to the array of elements.
Definition memory.h:849
T & operator[](index_t i)
Gets a vector element.
Definition memory.h:762
index_t size() const
Gets the number of elements.
Definition memory.h:749
Common include file, providing basic definitions. Should be included before anything else by all head...
#define GEO_MEMORY_ALIGNMENT
Default memory alignment for efficient vector operations.
Definition memory.h:240
void * aligned_malloc(size_t size, size_t alignment=GEO_MEMORY_ALIGNMENT)
Allocates aligned memory.
Definition memory.h:325
unsigned short word16
Unsigned 16 bits integer.
Definition memory.h:99
T & pointer_as_reference(void *ptr)
Converts a pointer to a reference.
Definition memory.h:201
unsigned char byte
Unsigned byte type.
Definition memory.h:93
void(* function_pointer)()
Generic function pointer.
Definition memory.h:111
void * align(void *p)
Returns the smallest aligned memory address from p.
Definition memory.h:473
void aligned_free(void *p)
Deallocates aligned memory.
Definition memory.h:353
unsigned int word32
Unsigned 32 bits integer.
Definition memory.h:102
byte * pointer
Pointer to unsigned byte(s)
Definition memory.h:105
unsigned char word8
Unsigned 8 bits integer.
Definition memory.h:96
void clear(void *addr, size_t size)
Clears a memory block.
Definition memory.h:120
FPTR generic_pointer_to_function_pointer(pointer ptr)
Converts a generic pointer to a function pointer.
Definition memory.h:167
const byte * const_pointer
Const pointer to unsigned byte(s)
Definition memory.h:108
bool is_aligned(void *p, size_t alignment=GEO_MEMORY_ALIGNMENT)
Checks whether a pointer is aligned.
Definition memory.h:464
bool operator!=(const aligned_allocator< T1, A1 > &, const aligned_allocator< T2, A2 > &)
Tests whether two aligned_allocators are different.
Definition memory.h:685
pointer function_pointer_to_generic_pointer(FPTR fptr)
Converts a function pointer to a generic pointer.
Definition memory.h:148
bool operator==(const aligned_allocator< T1, A1 > &, const aligned_allocator< T2, A2 > &)
Tests whether two aligned_allocators are equal.
Definition memory.h:674
void copy(void *to, const void *from, size_t size)
Copies a memory block.
Definition memory.h:133
Global Vorpaline namespace.
void geo_argused(const T &)
Suppresses compiler warnings about unused parameters.
Definition argused.h:60
geo_signed_index_t signed_index_t
The type for storing and manipulating indices differences.
Definition numeric.h:354
geo_index_t index_t
The type for storing and manipulating indices.
Definition numeric.h:340
Types and functions for numbers manipulation.
Functions for string manipulation.
Defines the memory alignment of points in a vector.
Definition memory.h:253
static const size_t value
Alignment value in bytes.
Definition memory.h:258
Defines the same allocator for other types.
Definition memory.h:532
aligned_allocator< U, ALIGN > other
Definition memory.h:534