d98ff61cbf2369ad9b87c6fe7934eff0c2780f93
[platform/upstream/aspell.git] / common / objstack.hpp
1
2 #ifndef ACOMMON_OBJSTACK__HPP
3 #define ACOMMON_OBJSTACK__HPP
4
5 #include "parm_string.hpp"
6 #include <stdlib.h>
7 #include <assert.h>
8
9 namespace acommon {
10
11 class ObjStack
12 {
13   typedef unsigned char byte;
14   struct Node
15   {
16     Node * next;
17     byte data[1]; // hack for data[]
18   };
19   size_t chunk_size;
20   size_t min_align;
21   Node * first;
22   Node * first_free;
23   Node * reserve;
24   byte * top;
25   byte * bottom;
26   byte * temp_end;
27   void setup_chunk();
28   void new_chunk();
29
30   ObjStack(const ObjStack &);
31   void operator=(const ObjStack &);
32
33   void align_bottom(size_t align) {
34     size_t a = (size_t)bottom % align;
35     if (a != 0) bottom += align - a;
36   }
37   void align_top(size_t align) {
38     top -= (size_t)top % align;
39   }
40 public:
41   // The alignment here is the guaranteed alignment that memory in
42   // new chunks will be aligned to.   It does NOT guarantee that
43   // every object is aligned as such unless all objects inserted
44   // are a multiple of align.
45   ObjStack(size_t chunk_s = 1024, size_t align = sizeof(void *));
46   ~ObjStack();
47
48   size_t calc_size();
49
50   void reset();
51   void trim();
52   
53   // This alloc_bottom does NOT check alignment.  However, if you always
54   // insert objects with a multiple of min_align than it will always
55   // me aligned as such.
56   void * alloc_bottom(size_t size)  {
57     byte * tmp = bottom;
58     bottom += size;
59     if (bottom > top) {new_chunk(); tmp = bottom; bottom += size;}
60     return tmp;
61   }
62   // This alloc_bottom will insure that the object is aligned based on the
63   // alignment given.
64   void * alloc_bottom(size_t size, size_t align) 
65   {loop:
66     align_bottom(align);
67     byte * tmp = bottom;
68     bottom += size;
69     if (bottom > top) {new_chunk(); goto loop;}
70     return tmp;
71   }
72   char * dup_bottom(ParmString str) {
73     return (char *)memcpy(alloc_bottom(str.size() + 1), 
74                           str.str(), str.size() + 1);
75   }
76
77   // This alloc_bottom does NOT check alignment.  However, if you
78   // always insert objects with a multiple of min_align than it will
79   // always be aligned as such.
80   void * alloc_top(size_t size) {
81     top -= size;
82     if (top < bottom) {new_chunk(); top -= size;}
83     return top;
84   }
85   // This alloc_top will insure that the object is aligned based on
86   // the alignment given.
87   void * alloc_top(size_t size, size_t align) 
88   {loop:
89     top -= size;
90     align_top(align);
91     if (top < bottom) {new_chunk(); goto loop;}
92     return top;
93   }
94   char * dup_top(ParmString str) {
95     return (char *)memcpy(alloc_top(str.size() + 1), 
96                           str.str(), str.size() + 1);
97   }
98
99   // By default objects are allocated from the top since that is sligtly
100   // more efficient
101   void * alloc(size_t size) {return alloc_top(size);}
102   void * alloc(size_t size, size_t align) {return alloc_top(size,align);}
103   char * dup(ParmString str) {return dup_top(str);}
104
105   // alloc_temp allocates an object from the bottom which can be
106   // resized untill it is commited.  If the resizing will involve
107   // moving the object than the data will be copied in the same way
108   // realloc does.  Any previously allocated objects are aborted when
109   // alloc_temp is called.
110   void * temp_ptr() {
111     if (temp_end) return bottom;
112     else return 0;
113   }
114   unsigned temp_size() {
115     return temp_end - bottom;
116   }
117   void * alloc_temp(size_t size) {
118     temp_end = bottom + size;
119     if (temp_end > top) {
120       new_chunk();
121       temp_end = bottom + size;
122     }
123     return bottom;
124   }
125   // returns a pointer the the new beginning of the temp memory
126   void * resize_temp(size_t size) {
127     if (temp_end == 0)
128       return alloc_temp(size);
129     if (bottom + size <= top) {
130       temp_end = bottom + size;
131     } else {
132       size_t s = temp_end - bottom;
133       byte * p = bottom;
134       new_chunk();
135       memcpy(bottom, p, s);
136       temp_end = bottom + size;
137     }
138     return bottom;
139   }
140   // returns a pointer to the beginning of the new memory (in
141   // otherwords the END of the temp memory BEFORE the call to grow
142   // temp) NOT the beginning if the temp memory
143   void * grow_temp(size_t s) {
144     if (temp_end == 0)
145       return alloc_temp(s);
146     unsigned old_size = temp_end - bottom;
147     unsigned size = old_size + s;
148     if (bottom + size <= top) {
149       temp_end = bottom + size;
150     } else {
151       size_t s = temp_end - bottom;
152       byte * p = bottom;
153       new_chunk();
154       memcpy(bottom, p, s);
155       temp_end = bottom + size;
156     }
157     return bottom + old_size;
158   }
159   void abort_temp() {
160     temp_end = 0;}
161   void commit_temp() {
162     bottom = temp_end;
163     temp_end = 0;}
164
165 };
166
167 typedef ObjStack StringBuffer;
168
169 }
170
171 #endif