1 | /* stringpool.h - Coterminal String Pools. |
---|
2 | Copyright (c) 2008, Robert D. Cameron. |
---|
3 | Licensed to the public under the Open Software License 3.0. |
---|
4 | Licensed to International Characters, Inc., under the Academic |
---|
5 | Free License 3.0. |
---|
6 | |
---|
7 | A storage pool for strings all of which remain allocated |
---|
8 | until the pool is destroyed. |
---|
9 | */ |
---|
10 | #ifndef STRINGPOOL_H |
---|
11 | #define STRINGPOOL_H |
---|
12 | |
---|
13 | template <int BasePoolSize, int ExpansionPercent> |
---|
14 | class StringPool { |
---|
15 | public: |
---|
16 | StringPool(); |
---|
17 | ~StringPool(); |
---|
18 | char * Insert(const char * full_string, int lgth); |
---|
19 | /* The following methods provide for incremental construction of strings |
---|
20 | each constructed by a sequence of calls of the form: |
---|
21 | OpenString(); AppendSegment(...)+; CloseString(). */ |
---|
22 | void OpenString(); |
---|
23 | void AppendSegment(char * segment, int segment_lgth); |
---|
24 | char * CloseString(); /* Return the pointer to the constructed string. */ |
---|
25 | private: |
---|
26 | /* The initial buffer is allocated as part of the StringPool object. |
---|
27 | For stack allocated StringPools that do not exceed the initial |
---|
28 | BasePoolSize, this completely eliminates the overhead and memory |
---|
29 | fragmentation associated with calls to new and delete. */ |
---|
30 | struct buffer_node { |
---|
31 | buffer_node * more_buffers; |
---|
32 | size_t buffer_size; |
---|
33 | char buffer[BasePoolSize]; |
---|
34 | }; |
---|
35 | buffer_node node1; |
---|
36 | buffer_node * current_node; |
---|
37 | size_t total_size; |
---|
38 | char * insertion_ptr; |
---|
39 | size_t space_avail; |
---|
40 | char * opened_string_ptr; |
---|
41 | |
---|
42 | void ExtendPool(); /* Adds a new buffer to the pool. */ |
---|
43 | }; |
---|
44 | |
---|
45 | template <int BasePoolSize, int ExpansionPercent> |
---|
46 | StringPool<BasePoolSize, ExpansionPercent>::StringPool() { |
---|
47 | node1.more_buffers = NULL; |
---|
48 | node1.buffer_size = BasePoolSize; |
---|
49 | total_size = node1.buffer_size; |
---|
50 | insertion_ptr = (char *) &(node1.buffer); |
---|
51 | space_avail = node1.buffer_size; |
---|
52 | opened_string_ptr = NULL; /* not open */ |
---|
53 | current_node = &node1; |
---|
54 | } |
---|
55 | |
---|
56 | template <int BasePoolSize, int ExpansionPercent> |
---|
57 | StringPool<BasePoolSize, ExpansionPercent>::~StringPool() { |
---|
58 | while (current_node != &node1) { |
---|
59 | buffer_node * allocated_node = current_node; |
---|
60 | current_node = allocated_node->more_buffers; |
---|
61 | free(allocated_node); |
---|
62 | } |
---|
63 | } |
---|
64 | |
---|
65 | template <int BasePoolSize, int ExpansionPercent> |
---|
66 | void StringPool<BasePoolSize, ExpansionPercent>::ExtendPool() { |
---|
67 | size_t new_buffer_size = (size_t) ((total_size * ExpansionPercent)/100); |
---|
68 | buffer_node * new_node = (buffer_node *) malloc(sizeof(buffer_node) + new_buffer_size - BasePoolSize); |
---|
69 | if (new_node == NULL) { |
---|
70 | fprintf(stderr, "Allocation failure in StringPool<BasePoolSize, ExpansionPercent>::ExtendPool\n"); |
---|
71 | exit(-1); |
---|
72 | } |
---|
73 | new_node->more_buffers = current_node; |
---|
74 | new_node->buffer_size = new_buffer_size; |
---|
75 | total_size += new_buffer_size; |
---|
76 | current_node = new_node; |
---|
77 | if (opened_string_ptr != NULL) { |
---|
78 | size_t open_string_prefix_size = (size_t) insertion_ptr - (size_t) opened_string_ptr; |
---|
79 | memcpy(new_node->buffer, opened_string_ptr, open_string_prefix_size); |
---|
80 | insertion_ptr = &(new_node->buffer[open_string_prefix_size]); |
---|
81 | opened_string_ptr = new_node->buffer; |
---|
82 | space_avail = new_buffer_size - open_string_prefix_size; |
---|
83 | } |
---|
84 | else { |
---|
85 | insertion_ptr = new_node->buffer; |
---|
86 | space_avail = new_buffer_size; |
---|
87 | } |
---|
88 | #ifdef DEBUG |
---|
89 | printf("ExtendPool() called: space_avail = %i\n", space_avail); |
---|
90 | #endif |
---|
91 | } |
---|
92 | |
---|
93 | template <int BasePoolSize, int ExpansionPercent> |
---|
94 | char * StringPool<BasePoolSize, ExpansionPercent>::Insert(const char * s, int lgth) { |
---|
95 | int total_lgth = lgth + 1; |
---|
96 | while (total_lgth > space_avail) ExtendPool(); |
---|
97 | memcpy(insertion_ptr, s, lgth); |
---|
98 | char * this_string_ptr = insertion_ptr; |
---|
99 | insertion_ptr[lgth] = '\0'; |
---|
100 | insertion_ptr += total_lgth; |
---|
101 | space_avail -= total_lgth; |
---|
102 | #ifdef DEBUG |
---|
103 | printf("Insert(%s, %i)\n", this_string_ptr, lgth); |
---|
104 | #endif |
---|
105 | return this_string_ptr; |
---|
106 | } |
---|
107 | |
---|
108 | template <int BasePoolSize, int ExpansionPercent> |
---|
109 | void StringPool<BasePoolSize, ExpansionPercent>::OpenString() { |
---|
110 | opened_string_ptr = insertion_ptr; |
---|
111 | } |
---|
112 | |
---|
113 | template <int BasePoolSize, int ExpansionPercent> |
---|
114 | void StringPool<BasePoolSize, ExpansionPercent>::AppendSegment(char * segment, int segment_lgth) { |
---|
115 | /* Make sure that there is length for this segment plus null byte. */ |
---|
116 | while (segment_lgth + 1 > space_avail) ExtendPool(); |
---|
117 | memcpy(insertion_ptr, segment, segment_lgth); |
---|
118 | insertion_ptr += segment_lgth; |
---|
119 | space_avail -= segment_lgth; |
---|
120 | } |
---|
121 | |
---|
122 | template <int BasePoolSize, int ExpansionPercent> |
---|
123 | char * StringPool<BasePoolSize, ExpansionPercent>::CloseString() { |
---|
124 | insertion_ptr[0] = '\0'; |
---|
125 | insertion_ptr++; |
---|
126 | space_avail--; |
---|
127 | char * this_string_ptr = opened_string_ptr; |
---|
128 | opened_string_ptr = NULL; |
---|
129 | return this_string_ptr; |
---|
130 | } |
---|
131 | #endif |
---|