1 
2 // vim:sw=2:ai
3 
4 /*
5  * Copyright (C) 2010-2011 DeNA Co.,Ltd.. All rights reserved.
6  * Copyright (C) 2011 Kentoku SHIBA
7  * See COPYRIGHT.txt for details.
8  */
9 
10 #ifndef DENA_STRING_BUFFER_HPP
11 #define DENA_STRING_BUFFER_HPP
12 
13 /*
14 #include <stdlib.h>
15 #include <string.h>
16 */
17 
18 #include "util.hpp"
19 #include "allocator.hpp"
20 #include "fatal.hpp"
21 
22 namespace dena {
23 
24 struct string_buffer : private noncopyable {
string_bufferdena::string_buffer25   string_buffer() : buffer(0), begin_offset(0), end_offset(0), alloc_size(0) { }
~string_bufferdena::string_buffer26   ~string_buffer() {
27     real_free();
28   }
real_freedena::string_buffer29   void real_free() {
30     if (alloc_size) {
31       DENA_FREE(buffer);
32       buffer = 0;
33       begin_offset = 0;
34       end_offset = 0;
35       alloc_size = 0;
36     }
37   }
real_sizedena::string_buffer38   size_t real_size() {
39     return alloc_size;
40   }
begindena::string_buffer41   const char *begin() const {
42     return buffer + begin_offset;
43   }
enddena::string_buffer44   const char *end() const {
45     return buffer + end_offset;
46   }
begindena::string_buffer47   char *begin() {
48     return buffer + begin_offset;
49   }
enddena::string_buffer50   char *end() {
51     return buffer + end_offset;
52   }
sizedena::string_buffer53   size_t size() const {
54     return end_offset - begin_offset;
55   }
cleardena::string_buffer56   void clear() {
57     begin_offset = end_offset = 0;
58   }
resizedena::string_buffer59   void resize(size_t len) {
60     if (size() < len) {
61       reserve(len);
62       memset(buffer + end_offset, 0, len - size());
63     }
64     end_offset = begin_offset + len;
65   }
reservedena::string_buffer66   void reserve(size_t len) {
67     if (alloc_size >= begin_offset + len) {
68       return;
69     }
70     size_t asz = alloc_size;
71     while (asz < begin_offset + len) {
72       if (asz == 0) {
73         asz = 16;
74       }
75       const size_t asz_n = asz << 1;
76       if (asz_n < asz) {
77         fatal_abort("string_buffer::resize() overflow");
78       }
79       asz = asz_n;
80     }
81     void *const p = DENA_REALLOC(buffer, asz);
82     if (p == 0) {
83       fatal_abort("string_buffer::resize() realloc");
84     }
85     buffer = static_cast<char *>(p);
86     alloc_size = asz;
87   }
erase_frontdena::string_buffer88   void erase_front(size_t len) {
89     if (len >= size()) {
90       clear();
91     } else {
92       begin_offset += len;
93     }
94   }
make_spacedena::string_buffer95   char *make_space(size_t len) {
96     reserve(size() + len);
97     return buffer + end_offset;
98   }
space_wrotedena::string_buffer99   void space_wrote(size_t len) {
100     len = len < alloc_size - end_offset ? len : alloc_size - end_offset;
101     end_offset += len;
102   }
103   template <size_t N>
append_literaldena::string_buffer104   void append_literal(const char (& str)[N]) {
105     append(str, str + N - 1);
106   }
appenddena::string_buffer107   void append(const char *start, const char *finish) {
108     const size_t len = finish - start;
109     reserve(size() + len);
110     memcpy(buffer + end_offset, start, len);
111     end_offset += len;
112   }
append_2dena::string_buffer113   void append_2(const char *s1, const char *f1, const char *s2,
114     const char *f2) {
115     const size_t l1 = f1 - s1;
116     const size_t l2 = f2 - s2;
117     reserve(end_offset + l1 + l2);
118     memcpy(buffer + end_offset, s1, l1);
119     memcpy(buffer + end_offset + l1, s2, l2);
120     end_offset += l1 + l2;
121   }
swapdena::string_buffer122   void swap(string_buffer& sb) {
123     char *tmp_buffer = buffer;
124     size_t tmp_begin_offset = begin_offset;
125     size_t tmp_end_offset = end_offset;
126     size_t tmp_alloc_size = alloc_size;
127     buffer = sb.buffer;
128     begin_offset = sb.begin_offset;
129     end_offset = sb.end_offset;
130     alloc_size = sb.alloc_size;
131     sb.buffer = tmp_buffer;
132     sb.begin_offset = tmp_begin_offset;
133     sb.end_offset = tmp_end_offset;
134     sb.alloc_size = tmp_alloc_size;
135   }
136  private:
137   char *buffer;
138   size_t begin_offset;
139   size_t end_offset;
140   size_t alloc_size;
141 };
142 
143 };
144 
145 #endif
146 
147