Geogram Version 1.9.8
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
671 template <class T2, int A2> operator aligned_allocator<T2, A2>() {
673 }
674 };
675
680 template <typename T1, int A1, typename T2, int A2>
681 inline bool operator== (
683 ) {
684 return true;
685 }
686
691 template <typename T1, int A1, typename T2, int A2>
692 inline bool operator!= (
694 ) {
695 return false;
696 }
697 }
698
699 /************************************************************************/
700
709 template <class T>
710 class vector : public ::std::vector<T, Memory::aligned_allocator<T> > {
715
719 typedef ::std::vector<T, Memory::aligned_allocator<T> > baseclass;
720
721
722
723 public:
728 baseclass() {
729 }
730
737 explicit vector(index_t size) :
738 baseclass(size) {
739 }
740
748 explicit vector(index_t size, const T& val) :
749 baseclass(size, val) {
750 }
751
756 index_t size() const {
757 // casts baseclass::size() from size_t (64 bits)
758 // to index_t (32 bits), because all
759 // indices in Vorpaline are supposed to fit in 32 bits (index_t).
760 // TODO: geo_debug_assert(baseclass::size() < max index_t)
761 return index_t(baseclass::size());
762 }
763
770 geo_debug_assert(i < size());
771 return baseclass::operator[] (i);
772 }
773
780 const T& operator[] (index_t i) const {
781 geo_debug_assert(i < size());
782 return baseclass::operator[] (i);
783 }
784
791 geo_debug_assert(i >= 0 && index_t(i) < size());
792 return baseclass::operator[] (index_t(i));
793 }
794
801 const T& operator[] (signed_index_t i) const {
802 geo_debug_assert(i >= 0 && index_t(i) < size());
803 return baseclass::operator[] (index_t(i));
804 }
805
806
807#ifdef GARGANTUA // If compiled with 64 bits index_t
808
814 T& operator[] (int i) {
815 geo_debug_assert(i >= 0 && index_t(i) < size());
816 return baseclass::operator[] (index_t(i));
817 }
818
825 const T& operator[] (int i) const {
826 geo_debug_assert(i >= 0 && index_t(i) < size());
827 return baseclass::operator[] (index_t(i));
828 }
829
835 T& operator[] (unsigned int i) {
837 return baseclass::operator[] (index_t(i));
838 }
839
846 const T& operator[] (unsigned int i) const {
848 return baseclass::operator[] (index_t(i));
849 }
850#endif
851
856 T* data() {
857 T* result = baseclass::data();
858 // Tell the compiler that the pointer is aligned, to enable AVX
859 // vectorization, can be useful when using vector<double>
860 // with blas-like operations. I hope the hint will propagate to
861 // the caller (not sure...)
863 return result;
864 }
865
870 const T* data() const {
871 const T* result = baseclass::data();
872 // Tell the compiler that the pointer is aligned, to enable AVX
873 // vectorization, can be useful when using vector<double>
874 // with blas-like operations. I hope the hint will propagate to
875 // the caller (not sure...)
877 return result;
878 }
879
880
887 vector<T> other;
888 this->swap(other);
889 }
890 };
891
898 template <>
899 class vector<bool> : public ::std::vector<bool> {
900 typedef ::std::vector<bool> baseclass;
901
902 public:
905 baseclass() {
906 }
907
909 explicit vector(index_t size) :
910 baseclass(size) {
911 }
912
914 explicit vector(index_t size, bool val) :
915 baseclass(size, val) {
916 }
917
919 index_t size() const {
920 // casts baseclass::size() from size_t (64 bits)
921 // to index_t (32 bits), because all
922 // indices in Vorpaline are supposed to fit in 32 bits (index_t).
923 // TODO: geo_debug_assert(baseclass::size() < max index_t)
924 return index_t(baseclass::size());
925 }
926
927 // TODO: operator[] with bounds checking (more complicated
928 // than just returning bool&, check implementation in STL).
929 };
930}
931
932#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:919
vector(index_t size)
Creates a pre-allocated vector.
Definition memory.h:909
vector(index_t size, bool val)
Creates a pre-initialized vector.
Definition memory.h:914
vector()
Creates an empty vector.
Definition memory.h:904
Vector with aligned memory allocation.
Definition memory.h:710
void clear_and_deallocate()
Resizes this vector to zero and deallocated all the memory.
Definition memory.h:886
vector()
Creates an empty vector.
Definition memory.h:727
const T * data() const
Gets a pointer to the array of elements.
Definition memory.h:870
vector(index_t size, const T &val)
Creates a pre-initialized vector.
Definition memory.h:748
vector(index_t size)
Creates a pre-allocated vector.
Definition memory.h:737
T * data()
Gets a pointer to the array of elements.
Definition memory.h:856
T & operator[](index_t i)
Gets a vector element.
Definition memory.h:769
index_t size() const
Gets the number of elements.
Definition memory.h:756
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:692
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:681
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:343
geo_index_t index_t
The type for storing and manipulating indices.
Definition numeric.h:329
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