staticlib_io  1.2.11
 All Classes Namespaces Files Functions Variables
array_sink.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017, alex at staticlibs.net
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * File: array_sink.hpp
19  * Author: alex
20  *
21  * Created on June 11, 2017, 10:51 PM
22  */
23 
24 #ifndef STATICLIB_IO_ARRAY_SINK_HPP
25 #define STATICLIB_IO_ARRAY_SINK_HPP
26 
27 #include <cstdlib>
28 #include <cstring>
29 #include <utility>
30 
31 #include "staticlib/config.hpp"
32 #include "staticlib/support.hpp"
33 
35 #include "staticlib/io/span.hpp"
36 
37 namespace staticlib {
38 namespace io {
39 
40 namespace detail_array_sink {
41 
42 inline char* default_alloc(int size_bytes) {
43  if (size_bytes <= 0) {
44  return nullptr;
45  }
46  return reinterpret_cast<char*> (std::malloc(static_cast<size_t> (size_bytes)));
47 };
48 
49 inline void default_free(char* buffer) {
50  std::free(buffer);
51 }
52 
53 } // namespace
54 
58 template<typename AllocFun, typename FreeFun>
59 class array_sink {
60 
64  AllocFun alloc_fun;
65 
69  FreeFun free_fun;
70 
74  float grow_coef;
75 
79  char* buf;
83  size_t capacity;
87  size_t bufsize = 0;
88 
89 public:
90 
98  array_sink(AllocFun alloc_fun, FreeFun free_fun,
99  size_t initial_capacity, float grow_coef = 1.5):
100  alloc_fun(std::move(alloc_fun)),
101  free_fun(std::move(free_fun)),
102  grow_coef(grow_coef),
103  buf(alloc_fun(static_cast<int>(initial_capacity + 1))),
104  capacity(initial_capacity) {
105  if (nullptr == buf) {
106  throw io_exception(TRACEMSG(
107  "Alloc error for capacity: [" + sl::support::to_string(capacity) + "]"));
108  }
109  }
110 
116  array_sink(const array_sink&) = delete;
117 
124  array_sink& operator=(const array_sink&) = delete;
125 
131  array_sink(array_sink&& other) STATICLIB_NOEXCEPT :
132  alloc_fun(std::move(other.alloc_fun)),
133  free_fun(std::move(other.free_fun)),
134  grow_coef(other.grow_coef),
135  buf(other.buf),
136  capacity(other.capacity),
137  bufsize(other.bufsize) {
138  other.buf = nullptr;
139  other.capacity = 0;
140  other.bufsize = 0;
141  }
142 
149  array_sink& operator=(array_sink&& other) STATICLIB_NOEXCEPT {
150  alloc_fun(std::move(other.alloc_fun));
151  free_fun(std::move(other.free_fun));
152  grow_coef = other.grow_coef;
153  buf = other.buf;
154  capacity = other.capacity;
155  other.capacity = 0;
156  bufsize = other.bufsize;
157  other.bufsize = 0;
158  return *this;
159  }
160 
164  ~array_sink() STATICLIB_NOEXCEPT {
165  if (nullptr != buf) {
166  free_fun(buf);
167  }
168  }
169 
176  std::streamsize write(span<const char> span) {
177  while (bufsize + span.size() > capacity) {
178  capacity = static_cast<size_t>(static_cast<float>(capacity) * grow_coef);
179  char* nbuf = alloc_fun(static_cast<int>(capacity + 1));
180  if (nullptr == nbuf) throw io_exception(TRACEMSG(
181  "Alloc error for capacity: [" + sl::support::to_string(capacity) + "]"));
182  std::memcpy(nbuf, buf, bufsize);
183  free_fun(buf);
184  buf = nbuf;
185  }
186  std::memcpy(buf + bufsize, span.data(), span.size());
187  bufsize += span.size();
188  return span.size_signed();
189  }
190 
196  std::streamsize flush() {
197  /* no-op */
198  return 0;
199  }
200 
210  if (nullptr != buf) {
211  buf[bufsize] = '\0';
212  auto res = make_span(buf, bufsize);
213  buf = nullptr;
214  bufsize = 0;
215  capacity = 0;
216  return res;
217  }
218  throw io_exception(TRACEMSG("Cannot release invalid empty 'array_sink'"));
219  }
220 
226  char* data() {
227  return buf;
228  }
229 
235  const char* data() const {
236  return buf;
237  }
238 
244  size_t size() const {
245  return bufsize;
246  }
247 
248 };
249 
250 
260 template <typename AllocFun, typename FreeFun>
261 array_sink<AllocFun, FreeFun> make_array_sink(AllocFun alloc_fun, FreeFun free_fun,
262  size_t initial_capacity = 15) {
263  return array_sink<AllocFun, FreeFun>(std::move(alloc_fun), std::move(free_fun), initial_capacity);
264 }
265 
273 inline array_sink<char*(*)(int), void(*)(char*)> make_array_sink(size_t initial_capacity = 15) {
275 }
276 
277 } // namespace
278 }
279 
280 #endif /* STATICLIB_IO_ARRAY_SINK_HPP */
281