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