Geogram Version 1.10.0-rc
A programming library of geometric algorithms
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 <string.h>
49#include <stdlib.h>
50
51#ifdef GEO_OS_WINDOWS
52
53#include <windows.h>
54#ifdef min
55#undef min
56#endif
57#ifdef max
58#undef max
59#endif
60
61#else
62
63#include <unistd.h>
64
65#endif
66
67// Stack size depending on OS:
68// Linux: 10 Mb
69// Windows: 1 Mb
70// Mac OSX: 512 Kb
71// GEO_HAS_BIG_STACK is defined under Linux
72// and lets some of the functions that
73// manipulate exact precision numbers
74// allocate temporaries on the stack.
75
76#ifdef GEO_OS_LINUX
77#define GEO_HAS_BIG_STACK
78#endif
79
85namespace GEO {
86
90 namespace Memory {
92 typedef unsigned char byte;
93
95 typedef unsigned char word8;
96
98 typedef unsigned short word16;
99
101 typedef unsigned int word32;
102
104 typedef byte* pointer;
105
107 typedef const byte* const_pointer;
108
110 typedef void (*function_pointer)();
111
119 inline void clear(void* addr, size_t size) {
120 ::memset(addr, 0, size);
121 }
122
132 inline void copy(void* to, const void* from, size_t size) {
133 ::memcpy(to, from, size);
134 }
135
146 template <class FPTR=function_pointer>
148 // I know this is ugly, but I did not find a simpler warning-free
149 // way that is portable between all compilers.
150 pointer result = nullptr;
151 ::memcpy(&result, &fptr, sizeof(pointer));
152 return result;
153 }
154
165 template <class FPTR = function_pointer>
167 // I know this is ugly, but I did not find a simpler warning-free
168 // way that is portable between all compilers.
169 FPTR result = nullptr;
170 ::memcpy(&result, &ptr, sizeof(pointer));
171 return result;
172 }
173
184 template <class FPTR = function_pointer>
185 inline FPTR generic_pointer_to_function_pointer(void* ptr) {
186 // I know this is ugly, but I did not find a simpler warning-free
187 // way that is portable between all compilers.
188 FPTR result = nullptr;
189 ::memcpy(&result, &ptr, sizeof(pointer));
190 return result;
191 }
192
193
200 template <class T> inline T& pointer_as_reference(void* ptr) {
201 // This is the recommended way of converting between pointers
202 // of different types. Casting the pointer directly is undefined
203 // behavior. Note: the call to memcpy() is eliminated by the
204 // compiler (that generates the same thing as when casting the
205 // pointer).
206 T* T_ptr;
207 ::memcpy(&T_ptr, &ptr, sizeof(pointer));
208 return *T_ptr;
209 }
210
217 template <class T> inline const T& pointer_as_reference(
218 const void* ptr
219 ) {
220 // This is the recommended way of converting between pointers
221 // of different types. Casting the pointer directly is undefined
222 // behavior. Note: the call to memcpy() is eliminated by the
223 // compiler (that generates the same thing as when casting the
224 // pointer).
225 const T* T_ptr;
226 ::memcpy(&T_ptr, &ptr, sizeof(pointer));
227 return *T_ptr;
228 }
229
230
239#define GEO_MEMORY_ALIGNMENT 64
240
251 template <int DIM>
257 static const size_t value = 1;
258 };
259
264 template <>
265 struct PointAlignment<2> {
266 static const size_t value = 16;
267 };
268
273 template <>
274 struct PointAlignment<3> {
275 static const size_t value = 8;
276 };
277
282 template <>
283 struct PointAlignment<4> {
284 static const size_t value = 32;
285 };
286
291 template <>
292 struct PointAlignment<6> {
293 static const size_t value = 16;
294 };
295
300 template <>
301 struct PointAlignment<8> {
302 static const size_t value = 64;
303 };
304
313#define geo_dim_alignment(dim) GEO::Memory::PointAlignment<dim>::value
314
324 inline void* aligned_malloc(
325 size_t size, size_t alignment = GEO_MEMORY_ALIGNMENT
326 ) {
327#if defined(GEO_OS_ANDROID)
328 // Alignment not supported under Android.
329 geo_argused(alignment);
330 return malloc(size);
331#elif defined(GEO_COMPILER_INTEL)
332 return _mm_malloc(size, alignment);
333#elif defined(GEO_COMPILER_GCC) || defined(GEO_COMPILER_CLANG)
334 void* result;
335 return posix_memalign(&result, alignment, size) == 0
336 ? result : nullptr;
337#elif defined(GEO_COMPILER_MSVC)
338 return _aligned_malloc(size, alignment);
339#else
340 geo_argused(alignment);
341 return malloc(size);
342#endif
343 }
344
352 inline void aligned_free(void* p) {
353#if defined(GEO_OS_ANDROID)
354 // Alignment not supported under Android.
355 free(p);
356#elif defined(GEO_COMPILER_INTEL)
357 _mm_free(p);
358#elif defined(GEO_COMPILER_GCC_FAMILY)
359 free(p);
360#elif defined(GEO_COMPILER_MSVC)
361 _aligned_free(p);
362#else
363 free(p);
364#endif
365 }
366
380#if defined(GEO_OS_ANDROID)
381#define geo_decl_aligned(var) var
382#elif defined(GEO_COMPILER_INTEL)
383#define geo_decl_aligned(var) __declspec(aligned(GEO_MEMORY_ALIGNMENT)) var
384#elif defined(GEO_COMPILER_GCC_FAMILY)
385#define geo_decl_aligned(var) var __attribute__((aligned(GEO_MEMORY_ALIGNMENT)))
386#elif defined(GEO_COMPILER_MSVC)
387#define geo_decl_aligned(var) __declspec(align(GEO_MEMORY_ALIGNMENT)) var
388#elif defined(GEO_COMPILER_EMSCRIPTEN)
389#define geo_decl_aligned(var) var
390#endif
391
408#if defined(GEO_OS_ANDROID)
409#define geo_assume_aligned(var, alignment)
410#elif defined(GEO_COMPILER_INTEL)
411#define geo_assume_aligned(var, alignment) \
412 __assume_aligned(var, alignment)
413#elif defined(GEO_COMPILER_CLANG)
414#define geo_assume_aligned(var, alignment)
415 // GCC __builtin_assume_aligned is not yet supported by clang-3.3
416#elif defined(GEO_COMPILER_GCC)
417#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
418#define geo_assume_aligned(var, alignment) \
419 *(void**) (&var) = __builtin_assume_aligned(var, alignment)
420 // the GCC way of specifying that a pointer is aligned returns
421 // the aligned pointer (I can't figure out why). It needs to be
422 // affected otherwise it is not taken into account (verified by
423 // looking at the output of gcc -S)
424#else
425#define geo_assume_aligned(var, alignment)
426#endif
427#elif defined(GEO_COMPILER_MSVC)
428#define geo_assume_aligned(var, alignment)
429 // TODO: I do not know how to do that with MSVC
430#elif defined(GEO_COMPILER_EMSCRIPTEN)
431#define geo_assume_aligned(var, alignment)
432#elif defined(GEO_COMPILER_MINGW)
433#define geo_assume_aligned(var, alignment)
434#endif
435
446#if defined(GEO_COMPILER_INTEL)
447#define geo_restrict __restrict
448#elif defined(GEO_COMPILER_GCC_FAMILY)
449#define geo_restrict __restrict__
450#elif defined(GEO_COMPILER_MSVC)
451#define geo_restrict __restrict
452#elif defined(GEO_COMPILER_EMSCRIPTEN)
453#define geo_restrict
454#endif
455
463 inline bool is_aligned(
464 void* p, size_t alignment = GEO_MEMORY_ALIGNMENT
465 ) {
466 return (reinterpret_cast<size_t>(p) & (alignment - 1)) == 0;
467 }
468
472 inline void* align(void* p) {
473 size_t offset = (
475 (reinterpret_cast<size_t>(p) & (GEO_MEMORY_ALIGNMENT - 1))
476 ) & (GEO_MEMORY_ALIGNMENT - 1);
477 return reinterpret_cast<char*>(p) + offset;
478 }
479
489#define geo_aligned_alloca(size) \
490 GEO::Memory::align(alloca(size + GEO_MEMORY_ALIGNMENT - 1))
491
499 template <class T, int ALIGN = GEO_MEMORY_ALIGNMENT>
501 public:
503 typedef T value_type;
504
506 typedef T* pointer;
507
509 typedef T& reference;
510
512 typedef const T* const_pointer;
513
515 typedef const T& const_reference;
516
518 typedef ::std::size_t size_type;
519
521 typedef ::std::ptrdiff_t difference_type;
522
524 static constexpr int ALIGNMENT = ALIGN;
525
530 template <class U>
535
536 /* \brief default constructor */
537 constexpr aligned_allocator() noexcept = default;
538
539 /* \brief conversion copy constructor */
540 template <class U, int A2> constexpr aligned_allocator(
541 const aligned_allocator<U, A2>&
542 ) noexcept {
543 }
544
551 return &x;
552 }
553
560 return &x;
561 }
562
581 size_type nb_elt, const void* hint = nullptr
582 ) {
583 nb_elt = std::max(nb_elt,size_type(1));
584 geo_argused(hint);
585 while(true) {
586 pointer result = static_cast<pointer>(
587 aligned_malloc(sizeof(T) * nb_elt, ALIGNMENT)
588 );
589 if(result != nullptr) {
590 return result;
591 }
592 // under Linux, a process requesting more mem than available
593 // is killed (and there is nothing we can capture). Under
594 // other OSes, the standard mechanism to let the runtime
595 // know is as follows:
596 // see: https://stackoverflow.com/questions/7194127/
597 // how-should-i-write-iso-c-standard-conformant-custom-
598 // new-and-delete-operators
599 // (if there is a handler, call it repeatedly until
600 // allocation succeeds, else throw a bad_alloc exception)
601 std::new_handler handler = std::get_new_handler();
602 if(handler != nullptr) {
603 (*handler)();
604 } else {
605 throw std::bad_alloc();
606 }
607 }
608 }
609
621 void deallocate(pointer p, size_type nb_elt) {
622 geo_argused(nb_elt);
623 aligned_free(p);
624 }
625
633 ::std::allocator<char> a;
634 return std::allocator_traits<decltype(a)>::max_size(a) /
635 sizeof(T);
636 }
637
651 new (static_cast<void*>(p))value_type(val);
652 }
653
662 void destroy(pointer p) {
663 geo_argused(p); // else MSVC complains
664 p->~value_type();
665 }
666 };
667
672 template <typename T1, int A1, typename T2, int A2>
673 inline bool operator== (
675 ) {
676 return true;
677 }
678
683 template <typename T1, int A1, typename T2, int A2>
684 inline bool operator!= (
686 ) {
687 return false;
688 }
689 }
690
691 /************************************************************************/
692
701 template <class T>
702 class vector : public ::std::vector<T, Memory::aligned_allocator<T> > {
707
711 typedef ::std::vector<T, Memory::aligned_allocator<T> > baseclass;
712
713
714
715 public:
720 baseclass() {
721 }
722
729 explicit vector(index_t size) :
730 baseclass(size) {
731 }
732
740 explicit vector(index_t size, const T& val) :
741 baseclass(size, val) {
742 }
743
748 index_t size() const {
749 // casts baseclass::size() from size_t (64 bits)
750 // to index_t (32 bits), because all
751 // indices in Vorpaline are supposed to fit in 32 bits (index_t).
752 // TODO: geo_debug_assert(baseclass::size() < max index_t)
753 return index_t(baseclass::size());
754 }
755
762 geo_debug_assert(i < size());
763 return baseclass::operator[] (i);
764 }
765
772 const T& operator[] (index_t i) const {
773 geo_debug_assert(i < size());
774 return baseclass::operator[] (i);
775 }
776
783 geo_debug_assert(i >= 0 && index_t(i) < size());
784 return baseclass::operator[] (index_t(i));
785 }
786
793 const T& operator[] (signed_index_t i) const {
794 geo_debug_assert(i >= 0 && index_t(i) < size());
795 return baseclass::operator[] (index_t(i));
796 }
797
798
799#ifdef GARGANTUA // If compiled with 64 bits index_t
800
806 T& operator[] (int i) {
807 geo_debug_assert(i >= 0 && index_t(i) < size());
808 return baseclass::operator[] (index_t(i));
809 }
810
817 const T& operator[] (int i) const {
818 geo_debug_assert(i >= 0 && index_t(i) < size());
819 return baseclass::operator[] (index_t(i));
820 }
821
827 T& operator[] (unsigned int i) {
829 return baseclass::operator[] (index_t(i));
830 }
831
838 const T& operator[] (unsigned int i) const {
840 return baseclass::operator[] (index_t(i));
841 }
842#endif
843
848 T* data() {
849 T* result = baseclass::data();
850 // Tell the compiler that the pointer is aligned, to enable AVX
851 // vectorization, can be useful when using vector<double>
852 // with blas-like operations. I hope the hint will propagate to
853 // the caller (not sure...)
855 return result;
856 }
857
862 const T* data() const {
863 const T* result = baseclass::data();
864 // Tell the compiler that the pointer is aligned, to enable AVX
865 // vectorization, can be useful when using vector<double>
866 // with blas-like operations. I hope the hint will propagate to
867 // the caller (not sure...)
869 return result;
870 }
871
872
879 vector<T> other;
880 this->swap(other);
881 }
882 };
883
890 template <>
891 class vector<bool> : public ::std::vector<bool> {
892 typedef ::std::vector<bool> baseclass;
893
894 public:
897 baseclass() {
898 }
899
901 explicit vector(index_t size) :
902 baseclass(size) {
903 }
904
906 explicit vector(index_t size, bool val) :
907 baseclass(size, val) {
908 }
909
911 index_t size() const {
912 // casts baseclass::size() from size_t (64 bits)
913 // to index_t (32 bits), because all
914 // indices in Vorpaline are supposed to fit in 32 bits (index_t).
915 // TODO: geo_debug_assert(baseclass::size() < max index_t)
916 return index_t(baseclass::size());
917 }
918
919 // TODO: operator[] with bounds checking (more complicated
920 // than just returning bool&, check implementation in STL).
921 };
922}
923
924#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:500
size_type max_size() const
Gets the maximum size possible to allocate.
Definition memory.h:632
T * pointer
Pointer to element.
Definition memory.h:506
const T & const_reference
Reference to constant element.
Definition memory.h:515
void destroy(pointer p)
Destroys an object.
Definition memory.h:662
const T * const_pointer
Pointer to constant element.
Definition memory.h:512
pointer address(reference x)
Gets the address of an object.
Definition memory.h:550
pointer allocate(size_type nb_elt, const void *hint=nullptr)
Allocates a block of storage.
Definition memory.h:580
T value_type
Element type.
Definition memory.h:503
static constexpr int ALIGNMENT
Alignment in bytes.
Definition memory.h:524
const_pointer address(const_reference x)
Gets the address of a object.
Definition memory.h:559
T & reference
Reference to element.
Definition memory.h:509
void construct(pointer p, const_reference val)
Constructs an object.
Definition memory.h:650
::std::size_t size_type
Quantities of elements.
Definition memory.h:518
void deallocate(pointer p, size_type nb_elt)
Releases a block of storage.
Definition memory.h:621
::std::ptrdiff_t difference_type
Difference between two pointers.
Definition memory.h:521
index_t size() const
Gets the number of elements.
Definition memory.h:911
vector(index_t size)
Creates a pre-allocated vector.
Definition memory.h:901
vector(index_t size, bool val)
Creates a pre-initialized vector.
Definition memory.h:906
vector()
Creates an empty vector.
Definition memory.h:896
Vector with aligned memory allocation.
Definition memory.h:702
void clear_and_deallocate()
Resizes this vector to zero and deallocated all the memory.
Definition memory.h:878
vector()
Creates an empty vector.
Definition memory.h:719
const T * data() const
Gets a pointer to the array of elements.
Definition memory.h:862
vector(index_t size, const T &val)
Creates a pre-initialized vector.
Definition memory.h:740
vector(index_t size)
Creates a pre-allocated vector.
Definition memory.h:729
T * data()
Gets a pointer to the array of elements.
Definition memory.h:848
T & operator[](index_t i)
Gets a vector element.
Definition memory.h:761
index_t size() const
Gets the number of elements.
Definition memory.h:748
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:239
#define geo_assume_aligned(var, alignment)
Informs the compiler that a given pointer is memory-aligned.
Definition memory.h:418
void * aligned_malloc(size_t size, size_t alignment=GEO_MEMORY_ALIGNMENT)
Allocates aligned memory.
Definition memory.h:324
unsigned short word16
Unsigned 16 bits integer.
Definition memory.h:98
T & pointer_as_reference(void *ptr)
Converts a pointer to a reference.
Definition memory.h:200
unsigned char byte
Unsigned byte type.
Definition memory.h:92
void(* function_pointer)()
Generic function pointer.
Definition memory.h:110
void * align(void *p)
Returns the smallest aligned memory address from p.
Definition memory.h:472
void aligned_free(void *p)
Deallocates aligned memory.
Definition memory.h:352
unsigned int word32
Unsigned 32 bits integer.
Definition memory.h:101
byte * pointer
Pointer to unsigned byte(s)
Definition memory.h:104
unsigned char word8
Unsigned 8 bits integer.
Definition memory.h:95
void clear(void *addr, size_t size)
Clears a memory block.
Definition memory.h:119
FPTR generic_pointer_to_function_pointer(pointer ptr)
Converts a generic pointer to a function pointer.
Definition memory.h:166
const byte * const_pointer
Const pointer to unsigned byte(s)
Definition memory.h:107
bool is_aligned(void *p, size_t alignment=GEO_MEMORY_ALIGNMENT)
Checks whether a pointer is aligned.
Definition memory.h:463
bool operator!=(const aligned_allocator< T1, A1 > &, const aligned_allocator< T2, A2 > &)
Tests whether two aligned_allocators are different.
Definition memory.h:684
pointer function_pointer_to_generic_pointer(FPTR fptr)
Converts a function pointer to a generic pointer.
Definition memory.h:147
bool operator==(const aligned_allocator< T1, A1 > &, const aligned_allocator< T2, A2 > &)
Tests whether two aligned_allocators are equal.
Definition memory.h:673
void copy(void *to, const void *from, size_t size)
Copies a memory block.
Definition memory.h:132
Global Vorpaline namespace.
Definition basic.h:55
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:344
geo_index_t index_t
The type for storing and manipulating indices.
Definition numeric.h:330
Types and functions for numbers manipulation.
Functions for string manipulation.
Defines the memory alignment of points in a vector.
Definition memory.h:252
static const size_t value
Alignment value in bytes.
Definition memory.h:257
Defines the same allocator for other types.
Definition memory.h:531
aligned_allocator< U, ALIGN > other
Definition memory.h:533