File: buffer_ref.h

package info (click to toggle)
paho.mqtt.cpp 1.5.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,672 kB
  • sloc: cpp: 13,068; ansic: 113; sh: 55; makefile: 22
file content (310 lines) | stat: -rw-r--r-- 10,908 bytes parent folder | download | duplicates (2)
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/////////////////////////////////////////////////////////////////////////////
/// @file buffer_ref.h
/// Buffer reference type for the Paho MQTT C++ library.
/// @date April 18, 2017
/// @author Frank Pagliughi
/////////////////////////////////////////////////////////////////////////////

/*******************************************************************************
 * Copyright (c) 2017-2024 Frank Pagliughi <fpagliughi@mindspring.com>
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 *
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v20.html
 * and the Eclipse Distribution License is available at
 *   http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *    Frank Pagliughi - initial implementation and documentation
 *******************************************************************************/

#ifndef __mqtt_buffer_ref_h
#define __mqtt_buffer_ref_h

#include <cstring>
#include <iostream>

#include "mqtt/types.h"

namespace mqtt {

/////////////////////////////////////////////////////////////////////////////

/**
 * A reference object for holding immutable data buffers, with cheap copy
 * semantics and lifetime management.
 *
 * Each object of this class contains a reference-counted pointer to an
 * immutable data buffer. Objects can be copied freely and easily, even
 * across threads, since all instances promise not to modify the contents
 * of the buffer.
 *
 * The buffer is immutable but the reference itself acts like a normal
 * variable. It can be reassigned to point to a different buffer.
 *
 * If no value has been assigned to a reference, then it is in a default
 * "null" state. It is not safe to call any member functions on a null
 * reference, other than to check if the object is null or empty.
 * @verbatim
 * string_ref sr;
 * if (!sr)
 *   cout << "null reference" << endl;
 * else
 *   cout.write(sr.data(), sr.size());
 * @endverbatim
 */
template <typename T>
class buffer_ref
{
public:
    /**
     * The underlying type for the buffer.
     * Normally byte-wide data (char or uint8_t) for Paho.
     */
    using value_type = T;
    /**
     * The type for the buffer.
     * We use basic_string for compatibility with string data.
     */
    using blob = std::basic_string<value_type>;
    /**
     *  The pointer we use.
     *  Note that it is a pointer to a _const_ blob.
     */
    using pointer_type = std::shared_ptr<const blob>;

private:
    /** Our data is a shared pointer to a const buffer */
    pointer_type data_;

public:
    /**
     * Default constructor creates a null reference.
     */
    buffer_ref() = default;
    /**
     * Copy constructor only copies a shared pointer.
     * @param buf Another buffer reference.
     */
    buffer_ref(const buffer_ref& buf) = default;
    /**
     * Move constructor only moves a shared pointer.
     * @param buf Another buffer reference.
     */
    buffer_ref(buffer_ref&& buf) = default;
    /**
     * Creates a reference to a new buffer by copying data.
     * @param b A string from which to create a new buffer.
     */
    buffer_ref(const blob& b) : data_{std::make_shared<blob>(b)} {}
    /**
     * Creates a reference to a new buffer by moving a string into the
     * buffer.
     * @param b A string from which to create a new buffer.
     */
    buffer_ref(blob&& b) : data_{std::make_shared<blob>(std::move(b))} {}
    /**
     * Creates a reference to an existing buffer by copying the shared
     * pointer.
     * Note that it is up to the caller to insure that there are no mutable
     * references to the buffer.
     * @param p A shared pointer to a string.
     */
    buffer_ref(const pointer_type& p) : data_(p) {}
    /**
     * Creates a reference to an existing buffer by moving the shared
     * pointer.
     * Note that it is up to the caller to insure that there are no mutable
     * references to the buffer.
     * @param p A shared pointer to a string.
     */
    buffer_ref(pointer_type&& p) : data_(std::move(p)) {}
    /**
     * Creates a reference to a new buffer containing a copy of the data.
     * @param buf The memory to copy
     * @param n The number of bytes to copy.
     */
    buffer_ref(const value_type* buf, size_t n) : data_{std::make_shared<blob>(buf, n)} {}
    /**
     * Creates a reference to a new buffer containing a copy of the
     * NUL-terminated char array.
     * @param buf A NUL-terminated char array (C string).
     */
    buffer_ref(const char* buf)
        : buffer_ref(reinterpret_cast<const value_type*>(buf), std::strlen(buf)) {
        static_assert(
            sizeof(char) == sizeof(T), "can only use C arr with char or byte buffers"
        );
    }

    /**
     * Copy the reference to the buffer.
     * @param rhs Another buffer
     * @return A reference to this object
     */
    buffer_ref& operator=(const buffer_ref& rhs) = default;
    /**
     * Move a reference to a buffer.
     * @param rhs The other reference to move.
     * @return A reference to this object.
     */
    buffer_ref& operator=(buffer_ref&& rhs) = default;
    /**
     * Copy a string into this object, creating a new buffer.
     * Modifies the reference for this object, pointing it to a
     * newly-created buffer. Other references to the old object remain
     * unchanges, so this follows copy-on-write semantics.
     * @param b A new blob/string to copy.
     * @return A reference to this object.
     */
    buffer_ref& operator=(const blob& b) {
        data_.reset(new blob(b));
        return *this;
    }
    /**
     * Move a string into this object, creating a new buffer.
     * Modifies the reference for this object, pointing it to a
     * newly-created buffer. Other references to the old object remain
     * unchanges, so this follows copy-on-write semantics.
     * @param b A new blob/string to move.
     * @return A reference to this object.
     */
    buffer_ref& operator=(blob&& b) {
        data_.reset(new blob(std::move(b)));
        return *this;
    }
    /**
     * Copy a NUL-terminated C char array into a new buffer
     * @param cstr A NUL-terminated C string.
     * @return A reference to this object
     */
    buffer_ref& operator=(const char* cstr) {
        static_assert(
            sizeof(char) == sizeof(T), "can only use C arr with char or byte buffers"
        );
        data_.reset(new blob(reinterpret_cast<const value_type*>(cstr), strlen(cstr)));
        return *this;
    }
    /**
     * Copy another type of buffer reference to this one.
     * This can copy a buffer of different types, provided that the size of
     * the data elements are the same. This is typically used to convert
     * from char to byte, where the data is the same, but the interpretation
     * is different. Note that this copies the underlying buffer.
     * @param rhs A reference to a different type of buffer.
     * @return A reference to this object.
     */
    template <typename OT>
    buffer_ref& operator=(const buffer_ref<OT>& rhs) {
        static_assert(
            sizeof(OT) == sizeof(T), "Can only assign buffers if values the same size"
        );
        data_.reset(new blob(reinterpret_cast<const value_type*>(rhs.data()), rhs.size()));
        return *this;
    }
    /**
     * Clears the reference to nil.
     */
    void reset() { data_.reset(); }
    /**
     * Determines if the reference is valid.
     * If the reference is invalid then it is not safe to call @em any
     * member functions other than @ref is_null() and @ref empty()
     * @return @em true if referring to a valid buffer, @em false if the
     *  	   reference (pointer) is null.
     */
    explicit operator bool() const { return bool(data_); }
    /**
     * Determines if the reference is invalid.
     * If the reference is invalid then it is not safe to call @em any
     * member functions other than @ref is_null() and @ref empty()
     * @return @em true if the reference is null, @em false if it is
     *  	   referring to a valid buffer,
     */
    bool is_null() const { return !data_; }
    /**
     * Determines if the buffer is empty.
     * @return @em true if the buffer is empty or the reference is null,
     *  	   @em false if the buffer contains data.
     */
    bool empty() const { return !data_ || data_->empty(); }
    /**
     * Gets a const pointer to the data buffer.
     * @return A pointer to the data buffer.
     */
    const value_type* data() const { return data_->data(); }
    /**
     * Gets the size of the data buffer.
     * @return The size of the data buffer.
     */
    size_t size() const { return data_->size(); }
    /**
     * Gets the size of the data buffer.
     * @return The size of the data buffer.
     */
    size_t length() const { return data_->length(); }
    /**
     * Gets the data buffer as a string.
     * @return The data buffer as a string.
     */
    const blob& str() const { return *data_; }
    /**
     * Gets the data buffer as a string.
     * @return The data buffer as a string.
     */
    const blob& to_string() const { return str(); }
    /**
     * Gets the data buffer as NUL-terminated C string.
     * Note that the reference must be set to call this function.
     * @return The data buffer as a string.
     */
    const char* c_str() const { return data_->c_str(); }
    /**
     * Gets a shared pointer to the (const) data buffer.
     * @return A shared pointer to the (const) data buffer.
     */
    const pointer_type& ptr() const { return data_; }
    /**
     * Gets elemental access to the data buffer (read only)
     * @param i The index into the buffer.
     * @return The value at the specified index.
     */
    const value_type& operator[](size_t i) const { return (*data_)[i]; }
};

/**
 * Stream inserter for a buffer reference.
 * This does a binary write of the data in the buffer.
 * @param os The output stream.
 * @param buf The buffer reference to write.
 * @return A reference to the output stream.
 */
template <typename T>
std::ostream& operator<<(std::ostream& os, const buffer_ref<T>& buf) {
    if (!buf.empty())
        os.write(buf.data(), buf.size());
    return os;
}

/////////////////////////////////////////////////////////////////////////////

/**
 * A reference to a text buffer.
 */
using string_ref = buffer_ref<char>;

/**
 * A reference to a binary buffer.
 * Note that we're using char for the underlying data type to allow
 * efficient moves to and from std::string's. Using a separate type
 * indicates that the data may be arbitrary binary.
 */
using binary_ref = buffer_ref<char>;

/////////////////////////////////////////////////////////////////////////////
}  // namespace mqtt

#endif  // __mqtt_buffer_ref_h