Coverage Report

Created: 2025-08-26 06:57

/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
192k
  bool will_overflow(size_t sz) const {
31
192k
    return offsetof(Node,data) + sz > chunk_size;
32
192k
  }
33
192k
  void check_size(size_t sz) {
34
192k
    assert(!will_overflow(sz));
35
192k
  }
36
37
  ObjStack(const ObjStack &);
38
  void operator=(const ObjStack &);
39
40
612k
  void align_bottom(size_t align) {
41
612k
    size_t a = (size_t)bottom % align;
42
612k
    if (a != 0) bottom += align - a;
43
612k
  }
44
614k
  void align_top(size_t align) {
45
614k
    top -= (size_t)top % align;
46
614k
  }
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.17M
  void * alloc_bottom(size_t size)  {
64
3.17M
    byte * tmp = bottom;
65
3.17M
    bottom += size;
66
3.17M
    if (bottom > top) {check_size(size); new_chunk(); tmp = bottom; bottom += size;}
67
3.17M
    return tmp;
68
3.17M
  }
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
23.6M
  void * alloc_top(size_t size) {
88
23.6M
    top -= size;
89
23.6M
    if (top < bottom) {check_size(size); new_chunk(); top -= size;}
90
23.6M
    return top;
91
23.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
1.81k
  {loop:
96
1.81k
    top -= size;
97
1.81k
    align_top(align);
98
1.81k
    if (top < bottom) {check_size(size); new_chunk(); goto loop;}
99
1.81k
    return top;
100
1.81k
  }
101
13.2M
  char * dup_top(ParmString str) {
102
13.2M
    return (char *)memcpy(alloc_top(str.size() + 1), 
103
13.2M
                          str.str(), str.size() + 1);
104
13.2M
  }
105
106
  // By default objects are allocated from the top since that is slightly
107
  // more efficient
108
10.4M
  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
13.2M
  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
36.6k
  void * temp_ptr() {
118
36.6k
    if (temp_end) return bottom;
119
0
    else return 0;
120
36.6k
  }
121
0
  unsigned temp_size() {
122
0
    return temp_end - bottom;
123
0
  }
124
1.36M
  void * alloc_temp(size_t size) {
125
1.36M
    temp_end = bottom + size;
126
1.36M
    if (temp_end > top) {
127
2.13k
      check_size(size);
128
2.13k
      new_chunk();
129
2.13k
      temp_end = bottom + size;
130
2.13k
    }
131
1.36M
    return bottom;
132
1.36M
  }
133
  // returns a pointer to the new beginning of the temp memory
134
756k
  void * resize_temp(size_t size) {
135
756k
    if (temp_end == 0)
136
0
      return alloc_temp(size);
137
756k
    if (bottom + size <= top) {
138
756k
      temp_end = bottom + size;
139
756k
    } 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
756k
    return bottom;
148
756k
  }
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
145k
  void * grow_temp(size_t s) {
153
145k
    if (temp_end == 0)
154
36.6k
      return alloc_temp(s);
155
108k
    unsigned old_size = temp_end - bottom;
156
108k
    unsigned size = old_size + s;
157
108k
    if (bottom + size <= top) {
158
108k
      temp_end = bottom + size;
159
108k
    } else {
160
59
      size_t s = temp_end - bottom;
161
59
      byte * p = bottom;
162
59
      check_size(size);
163
59
      new_chunk();
164
59
      memcpy(bottom, p, s);
165
59
      temp_end = bottom + size;
166
59
    }
167
108k
    return bottom + old_size;
168
145k
  }
169
17.5M
  void abort_temp() {
170
17.5M
    temp_end = 0;}
171
792k
  void commit_temp() {
172
792k
    bottom = temp_end;
173
792k
    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