summaryrefslogtreecommitdiffstats
path: root/ext/protozero/include/protozero/buffer_fixed.hpp
blob: b2e6d1d270ba00b18579df8417731220da8ed1d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#ifndef PROTOZERO_BUFFER_FIXED_HPP
#define PROTOZERO_BUFFER_FIXED_HPP

/*****************************************************************************

protozero - Minimalistic protocol buffer decoder and encoder in C++.

This file is from https://github.com/mapbox/protozero where you can find more
documentation.

*****************************************************************************/

/**
 * @file buffer_fixed.hpp
 *
 * @brief Contains the fixed_size_buffer_adaptor class.
 */

#include "buffer_tmpl.hpp"
#include "config.hpp"

#include <algorithm>
#include <cstddef>
#include <iterator>
#include <stdexcept>

namespace protozero {

/**
 * This class can be used instead of std::string if you want to create a
 * vector tile in a fixed-size buffer. Any operation that needs more space
 * than is available will fail with a std::length_error exception.
 */
class fixed_size_buffer_adaptor {

    char* m_data;
    std::size_t m_capacity;
    std::size_t m_size = 0;

public:

    /// @cond usual container typedefs not documented

    using size_type = std::size_t;

    using value_type = char;
    using reference = value_type&;
    using const_reference = const value_type&;
    using pointer = value_type*;
    using const_pointer = const value_type*;

    using iterator = pointer;
    using const_iterator = const_pointer;

    /// @endcond

    /**
     * Constructor.
     *
     * @param data Pointer to some memory allocated for the buffer.
     * @param capacity Number of bytes available.
     */
    fixed_size_buffer_adaptor(char* data, std::size_t capacity) noexcept :
        m_data(data),
        m_capacity(capacity) {
    }

    /**
     * Constructor.
     *
     * @param container Some container class supporting the member functions
     *        data() and size().
     */
    template <typename T>
    explicit fixed_size_buffer_adaptor(T& container) :
        m_data(container.data()),
        m_capacity(container.size()) {
    }

    /// Returns a pointer to the data in the buffer.
    const char* data() const noexcept {
        return m_data;
    }

    /// Returns a pointer to the data in the buffer.
    char* data() noexcept {
        return m_data;
    }

    /// The capacity this buffer was created with.
    std::size_t capacity() const noexcept {
        return m_capacity;
    }

    /// The number of bytes used in the buffer. Always <= capacity().
    std::size_t size() const noexcept {
        return m_size;
    }

    /// Return iterator to beginning of data.
    char* begin() noexcept {
        return m_data;
    }

    /// Return iterator to beginning of data.
    const char* begin() const noexcept {
        return m_data;
    }

    /// Return iterator to beginning of data.
    const char* cbegin() const noexcept {
        return m_data;
    }

    /// Return iterator to end of data.
    char* end() noexcept {
        return m_data + m_size;
    }

    /// Return iterator to end of data.
    const char* end() const noexcept {
        return m_data + m_size;
    }

    /// Return iterator to end of data.
    const char* cend() const noexcept {
        return m_data + m_size;
    }

/// @cond INTERNAL

    // Do not rely on anything beyond this point

    void append(const char* data, std::size_t count) {
        if (m_size + count > m_capacity) {
            throw std::length_error{"fixed size data store exhausted"};
        }
        std::copy_n(data, count, m_data + m_size);
        m_size += count;
    }

    void append_zeros(std::size_t count) {
        if (m_size + count > m_capacity) {
            throw std::length_error{"fixed size data store exhausted"};
        }
        std::fill_n(m_data + m_size, count, '\0');
        m_size += count;
    }

    void resize(std::size_t size) {
        protozero_assert(size < m_size);
        if (size > m_capacity) {
            throw std::length_error{"fixed size data store exhausted"};
        }
        m_size = size;
    }

    void erase_range(std::size_t from, std::size_t to) {
        protozero_assert(from <= m_size);
        protozero_assert(to <= m_size);
        protozero_assert(from < to);
        std::copy(m_data + to, m_data + m_size, m_data + from);
        m_size -= (to - from);
    }

    char* at_pos(std::size_t pos) {
        protozero_assert(pos <= m_size);
        return m_data + pos;
    }

    void push_back(char ch) {
        if (m_size >= m_capacity) {
            throw std::length_error{"fixed size data store exhausted"};
        }
        m_data[m_size++] = ch;
    }
/// @endcond

}; // class fixed_size_buffer_adaptor

/// @cond INTERNAL
template <>
struct buffer_customization<fixed_size_buffer_adaptor> {

    static std::size_t size(const fixed_size_buffer_adaptor* buffer) noexcept {
        return buffer->size();
    }

    static void append(fixed_size_buffer_adaptor* buffer, const char* data, std::size_t count) {
        buffer->append(data, count);
    }

    static void append_zeros(fixed_size_buffer_adaptor* buffer, std::size_t count) {
        buffer->append_zeros(count);
    }

    static void resize(fixed_size_buffer_adaptor* buffer, std::size_t size) {
        buffer->resize(size);
    }

    static void reserve_additional(fixed_size_buffer_adaptor* /*buffer*/, std::size_t /*size*/) {
        /* nothing to be done for fixed-size buffers */
    }

    static void erase_range(fixed_size_buffer_adaptor* buffer, std::size_t from, std::size_t to) {
        buffer->erase_range(from, to);
    }

    static char* at_pos(fixed_size_buffer_adaptor* buffer, std::size_t pos) {
        return buffer->at_pos(pos);
    }

    static void push_back(fixed_size_buffer_adaptor* buffer, char ch) {
        buffer->push_back(ch);
    }

};
/// @endcond

} // namespace protozero

#endif // PROTOZERO_BUFFER_FIXED_HPP