root/trunk/whisperlib/common/base/free_list.h

Revision 7, 6.8 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Catalin Popescu
31
32 #ifndef __COMMON_BASE_FREE_LIST_H__
33 #define __COMMON_BASE_FREE_LIST_H__
34
35 #define _XOPEN_SOURCE 600
36 #include <stdlib.h>
37
38 #include <vector>
39 #include <whisperlib/common/base/types.h>
40 #include <whisperlib/common/sync/mutex.h>
41 #include <whisperlib/common/base/errno.h>
42
43 namespace util {
44
45 template <typename T>
46 class FreeList {
47  public:
48   explicit FreeList(size_t max_size)
49     : max_size_(max_size) {
50   }
51   virtual ~FreeList() {
52     while ( !free_list_.empty() ) {
53       T* const p = free_list_.back();
54       free_list_.pop_back();
55       delete p;
56     }
57   }
58   virtual T* New() {
59     if ( !free_list_.empty() ) {
60       T* const p = free_list_.back();
61       free_list_.pop_back();
62       return p;
63     } else {
64       return new T;
65     }
66   }
67   virtual bool Dispose(T* p) {
68     if ( free_list_.size() < max_size_ ) {
69       free_list_.push_back(p);
70       return false;
71     }
72     delete p;
73     return true;
74   }
75   size_t max_size() const {
76     return max_size_;
77   }
78  private:
79   const size_t max_size_;
80   vector<T*> free_list_;
81 };
82
83 template <typename T>
84 class ThreadSafeFreeList : public FreeList<T> {
85  public:
86   explicit ThreadSafeFreeList(size_t max_size)
87     : FreeList<T>(max_size) {
88   }
89   virtual T* New() {
90     synch::MutexLocker ml(&mutex_);
91     return FreeList<T>::New();
92   }
93   virtual bool Dispose(T* p) {
94     synch::MutexLocker ml(&mutex_);
95     return FreeList<T>::Dispose(p);
96   }
97  private:
98   synch::Mutex mutex_;
99 };
100
101 //////////////////////////////////////////////////////////////////////
102
103 template <typename T>
104 class FreeArrayList {
105  public:
106   FreeArrayList(size_t size, size_t max_size)
107     : size_(size),
108       max_size_(max_size) {
109   }
110   virtual ~FreeArrayList() {
111     while ( !free_list_.empty() ) {
112       T* const p = free_list_.back();
113       free_list_.pop_back();
114       delete [] p;
115     }
116   }
117   virtual T* New() {
118     if ( !free_list_.empty() ) {
119       T* const p = free_list_.back();
120       free_list_.pop_back();
121       return p;
122     } else {
123       return new T[size_];
124     }
125   }
126   virtual bool Dispose(T* p) {
127     if ( free_list_.size() < max_size_ ) {
128       free_list_.push_back(p);
129       return false;
130     }
131     delete [] p;
132     return true;
133   }
134   size_t size() const {
135     return size_;
136   }
137  protected:
138   const size_t size_;
139   const size_t max_size_;
140   vector<T*> free_list_;
141 };
142
143 template <typename T>
144 class ThreadSafeFreeArrayList : public FreeArrayList<T> {
145  public:
146   ThreadSafeFreeArrayList(size_t size, size_t max_size)
147     : FreeArrayList<T>(size, max_size) {
148   }
149   virtual T* New() {
150     synch::MutexLocker ml(&mutex_);
151     return FreeArrayList<T>::New();
152   }
153   virtual bool Dispose(T* p) {
154     synch::MutexLocker ml(&mutex_);
155     return FreeArrayList<T>::Dispose(p);
156   }
157  private:
158   synch::Mutex mutex_;
159 };
160
161 //////////////////////////////////////////////////////////////////////
162
163
164 // ATTENTION : here the size is in blocks !!
165 class MemAlignedFreeArrayList : public FreeArrayList<char> {
166  public:
167   MemAlignedFreeArrayList(size_t size_in_blocks,
168                           size_t alignment,
169                           size_t max_size,
170                           bool alloc_initially = false)
171     : FreeArrayList<char>(size_in_blocks, max_size),
172       alignment_(alignment),
173       alloc_initially_(false) {
174     if ( alloc_initially ) {
175       vector<char*> p;
176       for ( size_t i = 0; i < max_size; ++i ) {
177         p.push_back(NewInternal());
178         CHECK(p.back() != NULL);
179       }
180       for ( size_t i = 0; i < p.size(); ++i ) {
181         DisposeInternal(p[i]);
182       }
183       alloc_initially_ = true;
184     }
185   }
186   virtual ~MemAlignedFreeArrayList() {
187     while ( !free_list_.empty() ) {
188       char* const p = free_list_.back();
189       free_list_.pop_back();
190       free(p);
191     }
192   }
193   virtual char* New() {
194     return NewInternal();
195   }
196   virtual bool Dispose(char* p) {
197     return DisposeInternal(p);
198   }
199   size_t alignment() const {
200     return alignment_;
201   }
202  private:
203   char* NewInternal() {
204     if ( !free_list_.empty() ) {
205       char* const p = free_list_.back();
206       free_list_.pop_back();
207       return p;
208     } else if ( alloc_initially_ ) {
209       LOG_ERROR << " Freepool exhausted";
210       return NULL;
211     } else {
212       void* ret = NULL;
213       const int err = posix_memalign(&ret,
214                                      alignment_,
215                                      size_ * alignment_);
216       if ( err ) {
217         LOG_ERROR << " Error in posix_memalign: " << errno
218                   << " : " << GetSystemErrorDescription(errno);
219         return NULL;
220       }
221       return reinterpret_cast<char*>(ret);
222     }
223   }
224   bool DisposeInternal(char* p) {
225     if ( free_list_.size() < max_size_ ) {
226       free_list_.push_back(p);
227       return false;
228     }
229     CHECK(!alloc_initially_);
230     free(p);
231     return true;
232   }
233  private:
234   const size_t alignment_;
235   bool alloc_initially_;
236 };
237
238 class ThreadSafeMemAlignedFreeArrayList : public MemAlignedFreeArrayList {
239  public:
240   ThreadSafeMemAlignedFreeArrayList(size_t size,
241                                     size_t alignment,
242                                     size_t max_size)
243     : MemAlignedFreeArrayList(size, alignment, max_size) {
244   }
245   virtual char* New() {
246     synch::MutexLocker ml(&mutex_);
247     return MemAlignedFreeArrayList::New();
248   }
249   virtual bool Dispose(char* p) {
250     synch::MutexLocker ml(&mutex_);
251     return MemAlignedFreeArrayList::Dispose(p);
252   }
253  private:
254   synch::Mutex mutex_;
255 };
256 }
257
258 #endif  // __COMMON_BASE_FREE_LIST_H__
Note: See TracBrowser for help on using the browser.