File: objstack.hpp

package info (click to toggle)
aspell 0.60.8-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 15,008 kB
  • sloc: cpp: 24,356; sh: 12,325; perl: 1,921; ansic: 1,661; makefile: 829; sed: 16
file content (184 lines) | stat: -rw-r--r-- 4,994 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

#ifndef ACOMMON_OBJSTACK__HPP
#define ACOMMON_OBJSTACK__HPP

#include "parm_string.hpp"
#include <stdlib.h>
#include <assert.h>
#include <stddef.h>

namespace acommon {

class ObjStack
{
  typedef unsigned char byte;
  struct Node
  {
    Node * next;
    byte data[1]; // hack for data[]
  };
  size_t chunk_size;
  size_t min_align;
  Node * first;
  Node * first_free;
  Node * reserve;
  byte * top;
  byte * bottom;
  byte * temp_end;
  void setup_chunk();
  void new_chunk();
  bool will_overflow(size_t sz) const {
    return offsetof(Node,data) + sz > chunk_size;
  }
  void check_size(size_t sz) {
    assert(!will_overflow(sz));
  }

  ObjStack(const ObjStack &);
  void operator=(const ObjStack &);

  void align_bottom(size_t align) {
    size_t a = (size_t)bottom % align;
    if (a != 0) bottom += align - a;
  }
  void align_top(size_t align) {
    top -= (size_t)top % align;
  }
public:
  // The alignment here is the guaranteed alignment that memory in
  // new chunks will be aligned to.   It does NOT guarantee that
  // every object is aligned as such unless all objects inserted
  // are a multiple of align.
  ObjStack(size_t chunk_s = 1024, size_t align = sizeof(void *));
  ~ObjStack();

  size_t calc_size();

  void reset();
  void trim();
  
  // This alloc_bottom does NOT check alignment.  However, if you always
  // insert objects with a multiple of min_align than it will always
  // me aligned as such.
  void * alloc_bottom(size_t size)  {
    byte * tmp = bottom;
    bottom += size;
    if (bottom > top) {check_size(size); new_chunk(); tmp = bottom; bottom += size;}
    return tmp;
  }
  // This alloc_bottom will insure that the object is aligned based on the
  // alignment given.
  void * alloc_bottom(size_t size, size_t align) 
  {loop:
    align_bottom(align);
    byte * tmp = bottom;
    bottom += size;
    if (bottom > top) {check_size(size); new_chunk(); goto loop;}
    return tmp;
  }
  char * dup_bottom(ParmString str) {
    return (char *)memcpy(alloc_bottom(str.size() + 1), 
                          str.str(), str.size() + 1);
  }

  // This alloc_bottom does NOT check alignment.  However, if you
  // always insert objects with a multiple of min_align than it will
  // always be aligned as such.
  void * alloc_top(size_t size) {
    top -= size;
    if (top < bottom) {check_size(size); new_chunk(); top -= size;}
    return top;
  }
  // This alloc_top will insure that the object is aligned based on
  // the alignment given.
  void * alloc_top(size_t size, size_t align) 
  {loop:
    top -= size;
    align_top(align);
    if (top < bottom) {check_size(size); new_chunk(); goto loop;}
    return top;
  }
  char * dup_top(ParmString str) {
    return (char *)memcpy(alloc_top(str.size() + 1), 
                          str.str(), str.size() + 1);
  }

  // By default objects are allocated from the top since that is sligtly
  // more efficient
  void * alloc(size_t size) {return alloc_top(size);}
  void * alloc(size_t size, size_t align) {return alloc_top(size,align);}
  char * dup(ParmString str) {return dup_top(str);}

  // alloc_temp allocates an object from the bottom which can be
  // resized until it is committed.  If the resizing will involve
  // moving the object than the data will be copied in the same way
  // realloc does.  Any previously allocated objects are aborted when
  // alloc_temp is called.
  void * temp_ptr() {
    if (temp_end) return bottom;
    else return 0;
  }
  unsigned temp_size() {
    return temp_end - bottom;
  }
  void * alloc_temp(size_t size) {
    temp_end = bottom + size;
    if (temp_end > top) {
      check_size(size);
      new_chunk();
      temp_end = bottom + size;
    }
    return bottom;
  }
  // returns a pointer the the new beginning of the temp memory
  void * resize_temp(size_t size) {
    if (temp_end == 0)
      return alloc_temp(size);
    if (bottom + size <= top) {
      temp_end = bottom + size;
    } else {
      size_t s = temp_end - bottom;
      byte * p = bottom;
      check_size(size);
      new_chunk();
      memcpy(bottom, p, s);
      temp_end = bottom + size;
    }
    return bottom;
  }
  // returns a pointer to the beginning of the new memory (in
  // otherwords the END of the temp memory BEFORE the call to grow
  // temp) NOT the beginning if the temp memory
  void * grow_temp(size_t s) {
    if (temp_end == 0)
      return alloc_temp(s);
    unsigned old_size = temp_end - bottom;
    unsigned size = old_size + s;
    if (bottom + size <= top) {
      temp_end = bottom + size;
    } else {
      size_t s = temp_end - bottom;
      byte * p = bottom;
      check_size(size);
      new_chunk();
      memcpy(bottom, p, s);
      temp_end = bottom + size;
    }
    return bottom + old_size;
  }
  void abort_temp() {
    temp_end = 0;}
  void commit_temp() {
    bottom = temp_end;
    temp_end = 0;}

  typedef Node Memory;
  Memory * freeze();
  static void dealloc(Memory *);
};

typedef ObjStack StringBuffer;

}

#endif