source: branches/help/CORE/arb_strbuf.cxx

Last change on this file was 18319, checked in by westram, 5 years ago
  • fix whitespace.
File size: 6.2 KB
Line 
1// ============================================================= //
2//                                                               //
3//   File      : arb_strbuf.cxx                                  //
4//   Purpose   : "unlimited" output buffer                       //
5//                                                               //
6//   Institute of Microbiology (Technical University Munich)     //
7//   http://www.arb-home.de/                                     //
8//                                                               //
9// ============================================================= //
10
11#include "arb_strbuf.h"
12
13void GBS_strstruct::vnprintf(size_t maxlen, const char *templat, va_list& parg) {
14    ensure_mem(maxlen+1);
15
16    char *buffer = data+pos;
17    int   printed;
18
19#ifdef LINUX
20    printed = vsnprintf(buffer, maxlen+1, templat, parg);
21#else
22    printed = vsprintf(buffer, templat, parg);
23#endif
24
25    assert_or_exit(printed >= 0 && (size_t)printed <= maxlen);
26    inc_pos(printed);
27}
28
29void GBS_strstruct::nprintf(size_t maxlen, const char *templat, ...) {
30    va_list parg;
31    va_start(parg, templat);
32    vnprintf(maxlen, templat, parg);
33}
34
35// old interface
36
37static GBS_strstruct last_used;
38
39GBS_strstruct *GBS_stropen(long init_size) {
40    /*! create a new memory file
41     * @param init_size  estimated used size
42     */
43
44    GBS_strstruct *strstr = new GBS_strstruct;
45
46    arb_assert(init_size>0);
47
48    if (last_used.get_buffer_size() >= (size_t)init_size) {
49        strstr->reassign_mem(last_used);
50
51        static short oversized_counter = 0;
52
53        if ((size_t)init_size*10 < strstr->get_buffer_size()) oversized_counter++;
54        else oversized_counter = 0;
55
56        if (oversized_counter>10) {                 // was oversized more than 10 times -> allocate smaller block
57            size_t dummy;
58            free(strstr->release_mem(dummy));
59            strstr->alloc_mem(init_size);
60        }
61    }
62    else {
63        strstr->alloc_mem(init_size);
64    }
65
66    return strstr;
67}
68
69char *GBS_strclose(GBS_strstruct *strstr) {
70    // returns a char* copy of the memory file
71    char *str = strstr->get_copy();
72    GBS_strforget(strstr);
73    return str;
74}
75
76void GBS_strforget(GBS_strstruct *strstr) {
77    size_t last_bsize = last_used.get_buffer_size();
78    size_t curr_bsize = strstr->get_buffer_size();
79
80    if (last_bsize < curr_bsize) { // last_used is smaller -> keep this
81        last_used.reassign_mem(*strstr);
82    }
83    delete strstr;
84}
85
86char *GBS_mempntr(GBS_strstruct *strstr) {
87    // returns the memory file (with write access)
88    return (char*)strstr->get_data();
89}
90
91long GBS_memoffset(GBS_strstruct *strstr) {
92    // returns the offset into the memory file
93    return strstr->get_position();
94}
95
96void GBS_str_cut_tail(GBS_strstruct *strstr, size_t byte_count) {
97    // Removes byte_count characters at the tail of a memfile
98    strstr->cut_tail(byte_count);
99}
100
101void GBS_strncat(GBS_strstruct *strstr, const char *ptr, size_t len) {
102    /* append some bytes string to strstruct
103     * (caution : copies zero byte and mem behind if used with wrong len!)
104     */
105    strstr->ncat(ptr, len);
106}
107
108void GBS_strcat(GBS_strstruct *strstr, const char *ptr) {
109    // append string to strstruct
110    strstr->cat(ptr);
111}
112
113void GBS_strnprintf(GBS_strstruct *strstr, long maxlen, const char *templat, ...) {
114    va_list parg;
115    va_start(parg, templat);
116    strstr->vnprintf(maxlen+2, templat, parg);
117}
118
119void GBS_chrcat(GBS_strstruct *strstr, char ch) {
120    strstr->put(ch);
121}
122
123void GBS_chrncat(GBS_strstruct *strstr, char ch, size_t n) {
124    strstr->nput(ch, n);
125}
126
127void GBS_intcat(GBS_strstruct *strstr, long val) {
128    char buffer[100];
129    long len = sprintf(buffer, "%li", val);
130    GBS_strncat(strstr, buffer, len);
131}
132
133void GBS_floatcat(GBS_strstruct *strstr, double val) {
134    char buffer[100];
135    long len = sprintf(buffer, "%f", val);
136    GBS_strncat(strstr, buffer, len);
137}
138
139// --------------------------------------------------------------------------------
140
141#ifdef UNIT_TESTS
142#ifndef TEST_UNIT_H
143#include <test_unit.h>
144#endif
145
146void TEST_GBS_strstruct() {
147    { GBS_strstruct buf; buf.put ('c');    TEST_EXPECT_EQUAL(buf.get_data(), "c");   }
148    { GBS_strstruct buf; buf.cat ("abc");  TEST_EXPECT_EQUAL(buf.get_data(), "abc"); }
149    { GBS_strstruct buf; buf.nput('x', 0); TEST_EXPECT_EQUAL(buf.get_data(), "");    }
150
151    { GBS_strstruct buf; buf.ncat("abc", 0); TEST_EXPECT_EQUAL(buf.get_data(), ""); }
152    { GBS_strstruct buf; buf.cat ("");       TEST_EXPECT_EQUAL(buf.get_data(), "");  }
153
154    { GBS_strstruct buf; TEST_EXPECT_EQUAL(buf.get_data(), ""); }
155}
156
157#define EXPECT_CONTENT(content) TEST_EXPECT_EQUAL(GBS_mempntr(strstr), content)
158
159void TEST_GBS_strstruct_old_interface() {
160    // test the old, out-dated interface to GBS_strstruct (comes from pre-OO-times).
161
162    {
163        GBS_strstruct *strstr = GBS_stropen(1000); EXPECT_CONTENT("");
164
165        GBS_chrncat(strstr, 'b', 3);        EXPECT_CONTENT("bbb");
166        GBS_intcat(strstr, 17);             EXPECT_CONTENT("bbb17");
167        GBS_chrcat(strstr, '_');            EXPECT_CONTENT("bbb17_");
168        GBS_floatcat(strstr, 3.5);          EXPECT_CONTENT("bbb17_3.500000");
169
170        TEST_EXPECT_EQUAL(GBS_memoffset(strstr), 14);
171        GBS_str_cut_tail(strstr, 13);       EXPECT_CONTENT("b");
172        GBS_strcat(strstr, "utter");        EXPECT_CONTENT("butter");
173        GBS_strncat(strstr, "flying", 3);   EXPECT_CONTENT("butterfly");
174
175        GBS_strnprintf(strstr, 200, "%c%s", ' ', "flutters");
176        EXPECT_CONTENT("butterfly flutters");
177
178        GBS_strforget(strstr);
179    }
180    {
181        // re-alloc smaller
182        GBS_strstruct *strstr = GBS_stropen(500); EXPECT_CONTENT("");
183        GBS_strforget(strstr);
184    }
185
186    // trigger downsize of oversized block
187    for (int i = 0; i<12; ++i) {
188        GBS_strstruct *strstr = GBS_stropen(10);
189        GBS_strforget(strstr);
190    }
191
192    {
193        GBS_strstruct *strstr     = GBS_stropen(10);
194        size_t         oldbufsize = strstr->get_buffer_size();
195        GBS_chrncat(strstr, 'x', 20);               // trigger reallocation of buffer
196
197        TEST_EXPECT_DIFFERENT(oldbufsize, strstr->get_buffer_size()); // did we reallocate?
198        EXPECT_CONTENT("xxxxxxxxxxxxxxxxxxxx");
199        GBS_strforget(strstr);
200    }
201}
202
203#endif // UNIT_TESTS
204
205// --------------------------------------------------------------------------------
206
Note: See TracBrowser for help on using the repository browser.