1//
2// MessagePack for C++ simple buffer implementation
3//
4// Copyright (C) 2008-2013 FURUHASHI Sadayuki and KONDO Takatoshi
5//
6//    Distributed under the Boost Software License, Version 1.0.
7//    (See accompanying file LICENSE_1_0.txt or copy at
8//    http://www.boost.org/LICENSE_1_0.txt)
9//
10#ifndef MSGPACK_SBUFFER_HPP
11#define MSGPACK_SBUFFER_HPP
12
13#include "msgpack/versioning.hpp"
14
15#include <stdexcept>
16
17#ifndef MSGPACK_SBUFFER_INIT_SIZE
18#define MSGPACK_SBUFFER_INIT_SIZE 8192
19#endif
20
21namespace msgpack {
22
23/// @cond
24MSGPACK_API_VERSION_NAMESPACE(v1) {
25/// @endcond
26
27class sbuffer {
28public:
29    sbuffer(size_t initsz = MSGPACK_SBUFFER_INIT_SIZE):m_size(0), m_alloc(initsz)
30    {
31        if(initsz == 0) {
32            m_data = nullptr;
33        } else {
34            m_data = (char*)::malloc(initsz);
35            if(!m_data) {
36                throw std::bad_alloc();
37            }
38        }
39    }
40
41    ~sbuffer()
42    {
43        ::free(m_data);
44    }
45
46#if !defined(MSGPACK_USE_CPP03)
47    sbuffer(const sbuffer&) = delete;
48    sbuffer& operator=(const sbuffer&) = delete;
49
50    sbuffer(sbuffer&& other) :
51        m_size(other.m_size), m_data(other.m_data), m_alloc(other.m_alloc)
52    {
53        other.m_size = other.m_alloc = 0;
54        other.m_data = nullptr;
55    }
56
57    sbuffer& operator=(sbuffer&& other)
58    {
59        ::free(m_data);
60
61        m_size = other.m_size;
62        m_alloc = other.m_alloc;
63        m_data = other.m_data;
64
65        other.m_size = other.m_alloc = 0;
66        other.m_data = nullptr;
67
68        return *this;
69    }
70#endif // !defined(MSGPACK_USE_CPP03)
71
72    void write(const char* buf, size_t len)
73    {
74        if(m_alloc - m_size < len) {
75            expand_buffer(len);
76        }
77        std::memcpy(m_data + m_size, buf, len);
78        m_size += len;
79    }
80
81    char* data()
82    {
83        return m_data;
84    }
85
86    const char* data() const
87    {
88        return m_data;
89    }
90
91    size_t size() const
92    {
93        return m_size;
94    }
95
96    char* release()
97    {
98        char* tmp = m_data;
99        m_size = 0;
100        m_data = nullptr;
101        m_alloc = 0;
102        return tmp;
103    }
104
105    void clear()
106    {
107        m_size = 0;
108    }
109
110private:
111    void expand_buffer(size_t len)
112    {
113        size_t nsize = (m_alloc > 0) ?
114                m_alloc * 2 : MSGPACK_SBUFFER_INIT_SIZE;
115
116        while(nsize < m_size + len) {
117            size_t tmp_nsize = nsize * 2;
118            if (tmp_nsize <= nsize) {
119                nsize = m_size + len;
120                break;
121            }
122            nsize = tmp_nsize;
123        }
124
125        void* tmp = ::realloc(m_data, nsize);
126        if(!tmp) {
127            throw std::bad_alloc();
128        }
129
130        m_data = static_cast<char*>(tmp);
131        m_alloc = nsize;
132    }
133
134#if defined(MSGPACK_USE_CPP03)
135private:
136    sbuffer(const sbuffer&);
137    sbuffer& operator=(const sbuffer&);
138#endif  // defined(MSGPACK_USE_CPP03)
139
140private:
141    size_t m_size;
142    char* m_data;
143    size_t m_alloc;
144};
145
146/// @cond
147}  // MSGPACK_API_VERSION_NAMESPACE(v1)
148/// @endcond
149
150}  // namespace msgpack
151
152#endif /* msgpack/sbuffer.hpp */
153