1 #ifndef GUM_TEST_LEARNING_ALLOC_H
2 #define GUM_TEST_LEARNING_ALLOC_H
3 
4 #include <vector>
5 #include <utility>
6 #include <new>
7 #include <memory>
8 #include <string>
9 #include <iostream>
10 #include <sstream>
11 
12 namespace gum_tests {
13 
14   class DebugPoolAlloc {
15   public:
DebugPoolAlloc(const std::size_t size)16     DebugPoolAlloc ( const std::size_t size )
17       :  _mempool_ ( new int[size / sizeof(int) + 1 ] )
18       ,  _size_ ( size / sizeof(int) + 1 ) {
19       //std::cout << "create a new pool alloc " <<  _mempool_ << std::endl;
20     }
21 
22     DebugPoolAlloc ( const DebugPoolAlloc& ) = delete;
23     DebugPoolAlloc ( DebugPoolAlloc&& ) = delete;
24 
~DebugPoolAlloc()25     ~DebugPoolAlloc () {
26       delete[]  _mempool_;
27     }
28 
29     DebugPoolAlloc& operator= ( const DebugPoolAlloc& ) = delete;
30     DebugPoolAlloc& operator= ( DebugPoolAlloc&& ) = delete;
31 
allocate(const std::size_t nb_bytes)32     int* allocate ( const std::size_t nb_bytes ) {
33       std::size_t nb_int = nb_bytes / sizeof(int);
34       if ( nb_bytes % sizeof(int) ) ++nb_int;
35       if (  _current_index_ + nb_int >  _size_ )
36         throw std::bad_alloc ();
37       int* alloc_pointer =  _mempool_ +  _current_index_;
38        _allocations_.push_back (  _current_index_ );
39        _current_index_ += nb_int;
40 
41       //std::cout << "LearningAlloc allocated: " << alloc_pointer
42       //          << "  of size : " << nb_bytes
43       //          << "  mempool = " <<  _mempool_ << std::endl;
44 
45       return alloc_pointer;
46     }
47 
deallocate(int * pointer)48     void deallocate ( int* pointer ) {
49       const std::size_t index = pointer -  _mempool_;
50       for ( auto iter =  _allocations_.rbegin();
51             iter !=  _allocations_.rend(); ++iter ) {
52         if ( *iter == index ) {
53           if ( iter ==  _allocations_.rbegin() )
54              _current_index_ = index;
55            _allocations_.erase ( (iter+1).base() );
56           return;
57         }
58       }
59 
60       //std::cout << "LearningAlloc cannot find address: " << pointer
61       //          << "  in mempool " <<  _mempool_ << std::endl;
62       throw std::bad_alloc ();
63     }
64 
allocatedSize()65     std::size_t allocatedSize () {
66       return  _allocations_.size ();
67     }
68 
toString()69     std::string toString () const {
70       bool deja = false;
71       std::stringstream str;
72       str << "allocator " <<  _mempool_ << " = { ";
73       for ( auto index :  _allocations_ ) {
74         if ( deja ) str << ", ";
75         else deja = true;
76         str << (  _mempool_ + index );
77       }
78       str << " }";
79       return str.str ();
80     }
81 
82 
83   private:
84     // the pool of memory used
85     int * _mempool_;
86 
87     // the size of the pool
88     const std::size_t  _size_;
89 
90     std::size_t  _current_index_ { 0 };
91 
92     // the set of allocation performed as a set sorted of [begin,end)
93     std::vector<std::size_t>  _allocations_;
94 
95   };
96 
97 
98   template <typename T>
99   class LearningAlloc {
100   public:
101     using value_type = T;
102 
103     template <typename _Tp1>
104     struct rebind {
105       typedef LearningAlloc<_Tp1> other;
106     };
107 
108     LearningAlloc ( const std::size_t size = 1000 )
_mempool_(new DebugPoolAlloc (size))109       :  _mempool_ ( new DebugPoolAlloc ( size ) ) {}
110 
LearningAlloc(const LearningAlloc<T> & from)111     LearningAlloc ( const LearningAlloc<T>& from )
112       :  _mempool_ ( from. _mempool_ ) {}
113 
114     template <typename U>
LearningAlloc(const LearningAlloc<U> & from)115     LearningAlloc( const LearningAlloc<U>& from )
116       :  _mempool_ ( from. _mempool_ ) {}
117 
LearningAlloc(LearningAlloc<T> && from)118     LearningAlloc ( LearningAlloc<T>&& from )
119       :  _mempool_ ( from. _mempool_ ) {}
120 
~LearningAlloc()121     ~LearningAlloc () {}
122 
123     LearningAlloc<T>& operator= ( const LearningAlloc<T>& from ) {
124       if ( this != &from ) {
125          _mempool_ = from. _mempool_;
126       }
127       return *this;
128     }
129 
130     LearningAlloc<T>& operator= ( LearningAlloc<T>&& from ) {
131       if ( this != &from ) {
132          _mempool_ = from. _mempool_;
133       }
134       return *this;
135     }
136 
137     template <typename U>
138     bool operator== ( const LearningAlloc<U>& other ) const {
139       return  _mempool_.get() == other. _mempool_.get();
140     }
141 
142     template <typename U>
143     bool operator!= ( const LearningAlloc<U>& other ) const {
144       return ! operator== ( other );
145     }
146 
147 
allocate(std::size_t num)148     T* allocate( std::size_t num ) {
149       return reinterpret_cast<T*>(  _mempool_->allocate ( num * sizeof( T ) ) );
150     }
151 
deallocate(T * p,std::size_t num)152     void deallocate( T* p, std::size_t num ) {
153        _mempool_->deallocate ( reinterpret_cast<int*> ( p ) );
154     }
155 
156     template <typename... Args>
construct(T * p,Args &&...args)157     void construct( T* p, Args&&... args ) {
158       ::new ( (void*) p ) T( std::forward<Args>( args )... );
159     }
160 
destroy(T * p)161     void destroy( T* p ) { p->~T(); }
162 
allocatedSize()163     std::size_t allocatedSize () {
164       return  _mempool_->allocatedSize ();
165     }
166 
toString()167     std::string toString () const {
168       return  _mempool_->toString ();
169     }
170 
171   private:
172     std::shared_ptr<DebugPoolAlloc>  _mempool_;
173 
174     template <typename U>
175     friend class LearningAlloc;
176 
177   };
178 
179 } /* namespace gum_tests */
180 
181 #endif /* GUM_TEST_LEARNING_ALLOC_H */
182