1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 #include "platform.h"
7 #include <vector>
8 #include <set>
9 
10 namespace embree
11 {
12 #define ALIGNED_STRUCT_(align)                                           \
13   void* operator new(size_t size) { return alignedMalloc(size,align); } \
14   void operator delete(void* ptr) { alignedFree(ptr); }                 \
15   void* operator new[](size_t size) { return alignedMalloc(size,align); } \
16   void operator delete[](void* ptr) { alignedFree(ptr); }
17 
18 #define ALIGNED_CLASS_(align)                                           \
19  public:                                                               \
20     ALIGNED_STRUCT_(align)                                              \
21  private:
22 
23   /*! aligned allocation */
24   void* alignedMalloc(size_t size, size_t align);
25   void alignedFree(void* ptr);
26 
27   /*! allocator that performs aligned allocations */
28   template<typename T, size_t alignment>
29     struct aligned_allocator
30     {
31       typedef T value_type;
32       typedef T* pointer;
33       typedef const T* const_pointer;
34       typedef T& reference;
35       typedef const T& const_reference;
36       typedef std::size_t size_type;
37       typedef std::ptrdiff_t difference_type;
38 
allocatealigned_allocator39       __forceinline pointer allocate( size_type n ) {
40         return (pointer) alignedMalloc(n*sizeof(value_type),alignment);
41       }
42 
deallocatealigned_allocator43       __forceinline void deallocate( pointer p, size_type n ) {
44         return alignedFree(p);
45       }
46 
constructaligned_allocator47       __forceinline void construct( pointer p, const_reference val ) {
48         new (p) T(val);
49       }
50 
destroyaligned_allocator51       __forceinline void destroy( pointer p ) {
52         p->~T();
53       }
54     };
55 
56   /*! allocates pages directly from OS */
57   bool win_enable_selockmemoryprivilege(bool verbose);
58   bool os_init(bool hugepages, bool verbose);
59   void* os_malloc (size_t bytes, bool& hugepages);
60   size_t os_shrink (void* ptr, size_t bytesNew, size_t bytesOld, bool hugepages);
61   void  os_free   (void* ptr, size_t bytes, bool hugepages);
62   void  os_advise (void* ptr, size_t bytes);
63 
64   /*! allocator that performs OS allocations */
65   template<typename T>
66     struct os_allocator
67     {
68       typedef T value_type;
69       typedef T* pointer;
70       typedef const T* const_pointer;
71       typedef T& reference;
72       typedef const T& const_reference;
73       typedef std::size_t size_type;
74       typedef std::ptrdiff_t difference_type;
75 
os_allocatoros_allocator76       __forceinline os_allocator ()
77         : hugepages(false) {}
78 
allocateos_allocator79       __forceinline pointer allocate( size_type n ) {
80         return (pointer) os_malloc(n*sizeof(value_type),hugepages);
81       }
82 
deallocateos_allocator83       __forceinline void deallocate( pointer p, size_type n ) {
84         return os_free(p,n*sizeof(value_type),hugepages);
85       }
86 
constructos_allocator87       __forceinline void construct( pointer p, const_reference val ) {
88         new (p) T(val);
89       }
90 
destroyos_allocator91       __forceinline void destroy( pointer p ) {
92         p->~T();
93       }
94 
95       bool hugepages;
96     };
97 
98   /*! allocator for IDs */
99   template<typename T, size_t max_id>
100     struct IDPool
101     {
102       typedef T value_type;
103 
IDPoolIDPool104       IDPool ()
105       : nextID(0) {}
106 
allocateIDPool107       T allocate()
108       {
109         /* return ID from list */
110         if (!IDs.empty())
111         {
112           T id = *IDs.begin();
113           IDs.erase(IDs.begin());
114           return id;
115         }
116 
117         /* allocate new ID */
118         else
119         {
120           if (size_t(nextID)+1 > max_id)
121             return -1;
122 
123           return nextID++;
124         }
125       }
126 
127       /* adds an ID provided by the user */
addIDPool128       bool add(T id)
129       {
130         if (id > max_id)
131           return false;
132 
133         /* check if ID should be in IDs set */
134         if (id < nextID) {
135           auto p = IDs.find(id);
136           if (p == IDs.end()) return false;
137           IDs.erase(p);
138           return true;
139         }
140 
141         /* otherwise increase ID set */
142         else
143         {
144           for (T i=nextID; i<id; i++) {
145             IDs.insert(i);
146           }
147           nextID = id+1;
148           return true;
149         }
150       }
151 
deallocateIDPool152       void deallocate( T id )
153       {
154         assert(id < nextID);
155         MAYBE_UNUSED auto done = IDs.insert(id).second;
156         assert(done);
157       }
158 
159     private:
160       std::set<T> IDs;   //!< stores deallocated IDs to be reused
161       T nextID;          //!< next ID to use when IDs vector is empty
162     };
163 }
164 
165