Coverage Report

Created: 2024-09-08 06:23

/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