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