initial commit
[camargo/libcamargoutils.git] / include / camargoutils / buffer.h
1 #ifndef BUFFER_HPP_INCLUDED
2 #define BUFFER_HPP_INCLUDED
3
4 //
5 //  buffer.hpp
6 //
7 //  Copyright (c) 2011 Boris Kolpackov
8 //
9 //  Distributed under the Boost Software License, Version 1.0. (See
10 //  accompanying file LICENSE_1_0.txt or copy at
11 //  http://www.boost.org/LICENSE_1_0.txt)
12 //
13 //  Simple memory buffer abstraction. Version 1.0.0.
14 //
15
16 #include <cstddef>   // std::size_t
17 #include <cstring>   // std::memcpy, std::memcmp, std::memset, std::memchr
18 #include <stdexcept> // std::out_of_range, std::invalid_argument
19
20 namespace camargo {
21
22 class buffer
23 {
24 public:
25   typedef std::size_t size_type;
26
27   static const size_type npos = static_cast<size_type> (-1);
28
29   ~buffer ();
30
31   explicit buffer (size_type size = 0);
32   buffer (size_type size, size_type capacity);
33   buffer (const void* data, size_type size);
34   buffer (const void* data, size_type size, size_type capacity);
35   buffer (void* data, size_type size, size_type capacity,
36           bool assume_ownership);
37
38   buffer (const buffer&);
39   buffer& operator= (const buffer&);
40
41   void swap (buffer&);
42   char* detach ();
43
44   void assign (const void* data, size_type size);
45   void assign (void* data, size_type size, size_type capacity,
46                bool assume_ownership);
47   void append (const buffer&);
48   void append (const void* data, size_type size);
49   void fill (char value = 0);
50
51   size_type size () const;
52   bool size (size_type);
53   size_type capacity () const;
54   bool capacity (size_type);
55   bool empty () const;
56   void clear ();
57
58   char* data ();
59   const char* data () const;
60
61   char& operator[] (size_type);
62   char operator[] (size_type) const;
63   char& at (size_type);
64   char at (size_type) const;
65
66   size_type find (char, size_type pos = 0) const;
67   size_type rfind (char, size_type pos = npos) const;
68
69 private:
70   char* data_;
71   size_type size_;
72   size_type capacity_;
73   bool free_;
74 };
75
76 bool operator== (const buffer&, const buffer&);
77 bool operator!= (const buffer&, const buffer&);
78
79 //
80 // Implementation.
81 //
82 inline buffer::~buffer ()
83 {
84   if (free_)
85     delete[] data_;
86 }
87
88 inline buffer::buffer (size_type s)
89     : free_ (true)
90 {
91   data_ = (s != 0 ? new char[s] : 0);
92   size_ = capacity_ = s;
93 }
94
95 inline buffer::buffer (size_type s, size_type c)
96     : free_ (true)
97 {
98   if (s > c)
99     throw std::invalid_argument ("size greater than capacity");
100
101   data_ = (c != 0 ? new char[c] : 0);
102   size_ = s;
103   capacity_ = c;
104 }
105
106 inline buffer::buffer (const void* d, size_type s)
107     : free_ (true)
108 {
109   if (s != 0)
110   {
111     data_ = new char[s];
112     std::memcpy (data_, d, s);
113   }
114   else
115     data_ = 0;
116
117   size_ = capacity_ = s;
118 }
119
120 inline buffer::buffer (const void* d, size_type s, size_type c)
121     : free_ (true)
122 {
123   if (s > c)
124     throw std::invalid_argument ("size greater than capacity");
125
126   if (c != 0)
127   {
128     data_ = new char[c];
129
130     if (s != 0)
131       std::memcpy (data_, d, s);
132   }
133   else
134     data_ = 0;
135
136   size_ = s;
137   capacity_ = c;
138 }
139
140 inline buffer::buffer (void* d, size_type s, size_type c, bool own)
141     : data_ (static_cast<char*> (d)), size_ (s), capacity_ (c), free_ (own)
142 {
143   if (s > c)
144     throw std::invalid_argument ("size greater than capacity");
145 }
146
147 inline buffer::buffer (const buffer& x)
148     : free_ (true)
149 {
150   if (x.capacity_ != 0)
151   {
152     data_ = new char[x.capacity_];
153
154     if (x.size_ != 0)
155       std::memcpy (data_, x.data_, x.size_);
156   }
157   else
158     data_ = 0;
159
160   size_ = x.size_;
161   capacity_ = x.capacity_;
162 }
163
164 inline buffer& buffer::operator= (const buffer& x)
165 {
166   if (&x != this)
167   {
168     if (x.size_ > capacity_)
169     {
170       if (free_)
171         delete[] data_;
172
173       data_ = new char[x.capacity_];
174       capacity_ = x.capacity_;
175       free_ = true;
176     }
177
178     if (x.size_ != 0)
179       std::memcpy (data_, x.data_, x.size_);
180
181     size_ = x.size_;
182   }
183
184   return *this;
185 }
186
187 inline void buffer::swap (buffer& x)
188 {
189   char* d (x.data_);
190   size_type s (x.size_);
191   size_type c (x.capacity_);
192   bool f (x.free_);
193
194   x.data_ = data_;
195   x.size_ = size_;
196   x.capacity_ = capacity_;
197   x.free_ = free_;
198
199   data_ = d;
200   size_ = s;
201   capacity_ = c;
202   free_ = f;
203 }
204
205 inline char* buffer::detach ()
206 {
207   char* r (data_);
208
209   data_ = 0;
210   size_ = 0;
211   capacity_ = 0;
212
213   return r;
214 }
215
216 inline void buffer::assign (const void* d, size_type s)
217 {
218   if (s > capacity_)
219   {
220     if (free_)
221       delete[] data_;
222
223     data_ = new char[s];
224     capacity_ = s;
225     free_ = true;
226   }
227
228   if (s != 0)
229     std::memcpy (data_, d, s);
230
231   size_ = s;
232 }
233
234 inline void buffer::assign (void* d, size_type s, size_type c, bool own)
235 {
236   if (free_)
237     delete[] data_;
238
239   data_ = static_cast<char*> (d);
240   size_ = s;
241   capacity_ = c;
242   free_ = own;
243 }
244
245 inline void buffer::append (const buffer& b)
246 {
247   append (b.data (), b.size ());
248 }
249
250 inline void buffer::append (const void* d, size_type s)
251 {
252   if (s != 0)
253   {
254     size_type ns (size_ + s);
255
256     if (capacity_ < ns)
257       capacity (ns);
258
259     std::memcpy (data_ + size_, d, s);
260     size_ = ns;
261   }
262 }
263
264 inline void buffer::fill (char v)
265 {
266   if (size_ > 0)
267     std::memset (data_, v, size_);
268 }
269
270 inline buffer::size_type buffer::size () const
271 {
272   return size_;
273 }
274
275 inline bool buffer::size (size_type s)
276 {
277   bool r (false);
278
279   if (capacity_ < s)
280     r = capacity (s);
281
282   size_ = s;
283   return r;
284 }
285
286 inline buffer::size_type buffer::capacity () const
287 {
288   return capacity_;
289 }
290
291 inline bool buffer::capacity (size_type c)
292 {
293   // Ignore capacity decrease requests.
294   //
295   if (capacity_ >= c)
296     return false;
297
298   char* d (new char[c]);
299
300   if (size_ != 0)
301     std::memcpy (d, data_, size_);
302
303   if (free_)
304     delete[] data_;
305
306   data_ = d;
307   capacity_ = c;
308   free_ = true;
309
310   return true;
311 }
312
313 inline bool buffer::empty () const
314 {
315   return size_ == 0;
316 }
317
318 inline void buffer::clear ()
319 {
320   size_ = 0;
321 }
322
323 inline char* buffer::data ()
324 {
325   return data_;
326 }
327
328 inline const char* buffer::data () const
329 {
330   return data_;
331 }
332
333 inline char& buffer::operator[] (size_type i)
334 {
335   return data_[i];
336 }
337
338 inline char buffer::operator[] (size_type i) const
339 {
340   return data_[i];
341 }
342
343 inline char& buffer::at (size_type i)
344 {
345   if (i >= size_)
346     throw std::out_of_range ("index out of range");
347
348   return data_[i];
349 }
350
351 inline char buffer::at (size_type i) const
352 {
353   if (i >= size_)
354     throw std::out_of_range ("index out of range");
355
356   return data_[i];
357 }
358
359 inline buffer::size_type buffer::find (char v, size_type pos) const
360 {
361   if (size_ == 0 || pos >= size_)
362     return npos;
363
364   char* p (static_cast<char*> (std::memchr (data_ + pos, v, size_ - pos)));
365   return p != 0 ? static_cast<size_type> (p - data_) : npos;
366 }
367
368 inline buffer::size_type buffer::rfind (char v, size_type pos) const
369 {
370   // memrchr() is not standard.
371   //
372   if (size_ != 0)
373   {
374     size_type n (size_);
375
376     if (--n > pos)
377       n = pos;
378
379     for (++n; n-- != 0; )
380       if (data_[n] == v)
381         return n;
382   }
383
384   return npos;
385 }
386
387 inline bool operator== (const buffer& a, const buffer& b)
388 {
389   return a.size () == b.size () &&
390     std::memcmp (a.data (), b.data (), a.size ()) == 0;
391 }
392
393 inline bool operator!= (const buffer& a, const buffer& b)
394 {
395   return !(a == b);
396 }
397
398 } // namespace camargo
399
400 #endif // BUFFER_HPP_INCLUDED
401