pvxslibs 1.5.0__cp310-cp310-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pvxslibs/__init__.py +0 -0
- pvxslibs/dbd/pvxsIoc.dbd +8 -0
- pvxslibs/include/pvxs/client.h +1094 -0
- pvxslibs/include/pvxs/data.h +948 -0
- pvxslibs/include/pvxs/iochooks.h +170 -0
- pvxslibs/include/pvxs/log.h +148 -0
- pvxslibs/include/pvxs/netcommon.h +82 -0
- pvxslibs/include/pvxs/nt.h +208 -0
- pvxslibs/include/pvxs/server.h +238 -0
- pvxslibs/include/pvxs/sharedArray.h +748 -0
- pvxslibs/include/pvxs/sharedpv.h +121 -0
- pvxslibs/include/pvxs/source.h +290 -0
- pvxslibs/include/pvxs/srvcommon.h +148 -0
- pvxslibs/include/pvxs/unittest.h +327 -0
- pvxslibs/include/pvxs/util.h +354 -0
- pvxslibs/include/pvxs/version.h +97 -0
- pvxslibs/include/pvxs/versionNum.h +6 -0
- pvxslibs/ioc.py +10 -0
- pvxslibs/lib/__init__.py +0 -0
- pvxslibs/lib/event_core_dsoinfo.py +14 -0
- pvxslibs/lib/event_pthread_dsoinfo.py +14 -0
- pvxslibs/lib/libevent_core.so +0 -0
- pvxslibs/lib/libevent_core.so.2.2.0 +0 -0
- pvxslibs/lib/libevent_pthread.so +0 -0
- pvxslibs/lib/libevent_pthread.so.2.2.0 +0 -0
- pvxslibs/lib/libpvxs.so +0 -0
- pvxslibs/lib/libpvxs.so.1.5 +0 -0
- pvxslibs/lib/libpvxsIoc.so +0 -0
- pvxslibs/lib/libpvxsIoc.so.1.5 +0 -0
- pvxslibs/lib/pvxsIoc_dsoinfo.py +14 -0
- pvxslibs/lib/pvxs_dsoinfo.py +14 -0
- pvxslibs/path.py +12 -0
- pvxslibs/test/__init__.py +0 -0
- pvxslibs/test/test_load.py +30 -0
- pvxslibs/version.py +32 -0
- pvxslibs-1.5.0.dist-info/METADATA +44 -0
- pvxslibs-1.5.0.dist-info/RECORD +40 -0
- pvxslibs-1.5.0.dist-info/WHEEL +5 -0
- pvxslibs-1.5.0.dist-info/licenses/LICENSE +26 -0
- pvxslibs-1.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright - See the COPYRIGHT that is included with this distribution.
|
|
3
|
+
* pvxs is distributed subject to a Software License Agreement found
|
|
4
|
+
* in file LICENSE that is included with this distribution.
|
|
5
|
+
*/
|
|
6
|
+
#ifndef PVXS_SHAREDVECTOR_H
|
|
7
|
+
#define PVXS_SHAREDVECTOR_H
|
|
8
|
+
|
|
9
|
+
#include <cstddef>
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <memory>
|
|
12
|
+
#include <type_traits>
|
|
13
|
+
#include <algorithm>
|
|
14
|
+
#include <iosfwd>
|
|
15
|
+
#include <iterator>
|
|
16
|
+
|
|
17
|
+
#include <pvxs/version.h>
|
|
18
|
+
|
|
19
|
+
namespace pvxs {
|
|
20
|
+
|
|
21
|
+
class Value;
|
|
22
|
+
|
|
23
|
+
template<typename E, class Enable = void> class shared_array;
|
|
24
|
+
|
|
25
|
+
//! Identify real array type in void specializations of shared_array.
|
|
26
|
+
//! @see shared_array::original_type()
|
|
27
|
+
enum class ArrayType : uint8_t {
|
|
28
|
+
Null = 0xff, //!< Untyped
|
|
29
|
+
Bool = 0x08, //!< bool
|
|
30
|
+
Int8 = 0x28, //!< int8_t
|
|
31
|
+
Int16 = 0x29, //!< int16_t
|
|
32
|
+
Int32 = 0x2a, //!< int32_t
|
|
33
|
+
Int64 = 0x2b, //!< int64_t
|
|
34
|
+
UInt8 = 0x2c, //!< uint8_t
|
|
35
|
+
UInt16= 0x2d, //!< uint16_t
|
|
36
|
+
UInt32= 0x2e, //!< uint32_t
|
|
37
|
+
UInt64= 0x2f, //!< uint64_t
|
|
38
|
+
Float32=0x4a, //!< float
|
|
39
|
+
Float64=0x4b, //!< double
|
|
40
|
+
String= 0x68, //!< std::string
|
|
41
|
+
Value = 0x88, //!< Value
|
|
42
|
+
// also used for 0x89 and 0x8a
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
PVXS_API
|
|
46
|
+
std::ostream& operator<<(std::ostream& strm, ArrayType code);
|
|
47
|
+
|
|
48
|
+
//! Return storage size (aka. sizeof() ) for array element type
|
|
49
|
+
//! @throws std::logic_error for invalid types.
|
|
50
|
+
PVXS_API
|
|
51
|
+
size_t elementSize(ArrayType type);
|
|
52
|
+
|
|
53
|
+
//! Return a void array usable for the given storage type
|
|
54
|
+
PVXS_API
|
|
55
|
+
shared_array<void> allocArray(ArrayType type, size_t count);
|
|
56
|
+
|
|
57
|
+
namespace detail {
|
|
58
|
+
template<typename T>
|
|
59
|
+
struct CaptureCode;
|
|
60
|
+
|
|
61
|
+
#define CASE(TYPE, CODE) \
|
|
62
|
+
template<> struct CaptureCode<TYPE> { static constexpr ArrayType code{ArrayType::CODE}; }
|
|
63
|
+
CASE(bool, Bool);
|
|
64
|
+
CASE(int8_t, Int8);
|
|
65
|
+
CASE(int16_t, Int16);
|
|
66
|
+
CASE(int32_t, Int32);
|
|
67
|
+
CASE(int64_t, Int64);
|
|
68
|
+
CASE(uint8_t, UInt8);
|
|
69
|
+
CASE(uint16_t, UInt16);
|
|
70
|
+
CASE(uint32_t, UInt32);
|
|
71
|
+
CASE(uint64_t, UInt64);
|
|
72
|
+
CASE(float, Float32);
|
|
73
|
+
CASE(double, Float64);
|
|
74
|
+
CASE(std::string, String);
|
|
75
|
+
CASE(Value, Value);
|
|
76
|
+
#undef CASE
|
|
77
|
+
|
|
78
|
+
template<typename T>
|
|
79
|
+
using CaptureBase = CaptureCode<typename std::remove_cv<T>::type>;
|
|
80
|
+
|
|
81
|
+
template<typename T, typename Enable=void>
|
|
82
|
+
struct sizeofx {
|
|
83
|
+
static inline size_t op() { return sizeof(T); }
|
|
84
|
+
};
|
|
85
|
+
template<typename T>
|
|
86
|
+
struct sizeofx<T, typename std::enable_if<std::is_void<T>::value>::type> {
|
|
87
|
+
static inline size_t op() { return 1u; } // treat void* as pointer to bytes
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
template<typename E>
|
|
91
|
+
struct sa_default_delete {
|
|
92
|
+
void operator()(E* e) const { delete[] e; }
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
template<typename E>
|
|
96
|
+
struct sa_base {
|
|
97
|
+
protected:
|
|
98
|
+
template<typename E1> friend struct sa_base;
|
|
99
|
+
|
|
100
|
+
std::shared_ptr<E> _data;
|
|
101
|
+
size_t _count;
|
|
102
|
+
public:
|
|
103
|
+
|
|
104
|
+
// shared_array()
|
|
105
|
+
// shared_array(const shared_array&)
|
|
106
|
+
// shared_array(shared_array&&)
|
|
107
|
+
// shared_array(size_t, T)
|
|
108
|
+
// shared_array(T*, size_t)
|
|
109
|
+
// shared_array(T*, d, size_t)
|
|
110
|
+
// shared_array(shared_ptr<T>, size_t)
|
|
111
|
+
// shared_array(shared_ptr<T>, T*, size_t)
|
|
112
|
+
|
|
113
|
+
//! empty
|
|
114
|
+
constexpr sa_base() :_count(0u) {}
|
|
115
|
+
|
|
116
|
+
// copyable
|
|
117
|
+
sa_base(const sa_base&) = default;
|
|
118
|
+
// movable
|
|
119
|
+
inline sa_base(sa_base&& o) noexcept
|
|
120
|
+
:_data(std::move(o._data)), _count(o._count)
|
|
121
|
+
{
|
|
122
|
+
o._count = 0;
|
|
123
|
+
}
|
|
124
|
+
sa_base& operator=(const sa_base&) =default;
|
|
125
|
+
inline sa_base& operator=(sa_base&& o) noexcept
|
|
126
|
+
{
|
|
127
|
+
_data = std::move(o._data);
|
|
128
|
+
_count = o._count;
|
|
129
|
+
o._count = 0;
|
|
130
|
+
return *this;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// use existing alloc with delete[]
|
|
134
|
+
template<typename A>
|
|
135
|
+
sa_base(A* a, size_t len)
|
|
136
|
+
:_data(a, sa_default_delete<E>()),_count(len)
|
|
137
|
+
{}
|
|
138
|
+
|
|
139
|
+
// use existing alloc w/ custom deletor
|
|
140
|
+
template<typename B>
|
|
141
|
+
sa_base(E* a, B b, size_t len)
|
|
142
|
+
:_data(a, b),_count(len)
|
|
143
|
+
{}
|
|
144
|
+
|
|
145
|
+
// build around existing shared_ptr
|
|
146
|
+
sa_base(const std::shared_ptr<E>& a, size_t len)
|
|
147
|
+
:_data(a),_count(len)
|
|
148
|
+
{}
|
|
149
|
+
|
|
150
|
+
// alias existing shared_ptr
|
|
151
|
+
template<typename A>
|
|
152
|
+
sa_base(const std::shared_ptr<A>& a, E* b, size_t len)
|
|
153
|
+
:_data(a, b),_count(len)
|
|
154
|
+
{}
|
|
155
|
+
|
|
156
|
+
void clear() noexcept {
|
|
157
|
+
_data.reset();
|
|
158
|
+
_count = 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
void swap(sa_base& o) noexcept {
|
|
162
|
+
std::swap(_data, o._data);
|
|
163
|
+
std::swap(_count, o._count);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
//! Number of elements
|
|
167
|
+
inline size_t size() const { return _count; }
|
|
168
|
+
inline bool empty() const noexcept { return _count==0; }
|
|
169
|
+
|
|
170
|
+
inline bool unique() const noexcept { return !_data || _data.use_count()<=1; }
|
|
171
|
+
|
|
172
|
+
E* data() const noexcept { return _data.get(); }
|
|
173
|
+
|
|
174
|
+
const std::shared_ptr<E>& dataPtr() const { return _data; }
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
//! Provide options when rendering with std::ostream.
|
|
178
|
+
class Limiter {
|
|
179
|
+
const void* _base;
|
|
180
|
+
size_t _count;
|
|
181
|
+
size_t _limit=0u;
|
|
182
|
+
ArrayType _type;
|
|
183
|
+
friend
|
|
184
|
+
PVXS_API
|
|
185
|
+
std::ostream& operator<<(std::ostream& strm, const Limiter& lim);
|
|
186
|
+
public:
|
|
187
|
+
Limiter(const void* base, size_t count, ArrayType type)
|
|
188
|
+
:_base(base), _count(count), _type(type)
|
|
189
|
+
{}
|
|
190
|
+
//! Maximum number of array elements to print.
|
|
191
|
+
//! "..." is printed in place of any further elements.
|
|
192
|
+
Limiter& limit(size_t l) { _limit = l; return *this; }
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
PVXS_API
|
|
196
|
+
std::ostream& operator<<(std::ostream& strm, const Limiter&);
|
|
197
|
+
|
|
198
|
+
PVXS_API
|
|
199
|
+
void _throw_bad_cast(ArrayType from, ArrayType to);
|
|
200
|
+
|
|
201
|
+
PVXS_API
|
|
202
|
+
void convertArr(ArrayType dtype, void *dbase,
|
|
203
|
+
ArrayType stype, const void *sbase,
|
|
204
|
+
size_t count);
|
|
205
|
+
|
|
206
|
+
PVXS_API
|
|
207
|
+
shared_array<void> copyAs(ArrayType dtype, ArrayType stype, const void *sbase, size_t count);
|
|
208
|
+
|
|
209
|
+
} // namespace detail
|
|
210
|
+
|
|
211
|
+
/** std::vector-like contiguous array of items passed by reference.
|
|
212
|
+
*
|
|
213
|
+
* shared_array comes in const and non-const, as well as void and non-void variants.
|
|
214
|
+
*
|
|
215
|
+
* A non-const array is allocated and filled, then last non-const reference is exchanged for new const reference.
|
|
216
|
+
* This const reference can then be safely shared between various threads.
|
|
217
|
+
*
|
|
218
|
+
* @code
|
|
219
|
+
* shared_array<uint32_t> arr({1, 2, 3});
|
|
220
|
+
* assert(arr.size()==3);
|
|
221
|
+
* shared_ptr<const uint32_t> constarr(arr.freeze());
|
|
222
|
+
* assert(arr.size()==0);
|
|
223
|
+
* assert(constarr.size()==3);
|
|
224
|
+
* @endcode
|
|
225
|
+
*
|
|
226
|
+
* The void / non-void variants allow arrays to be moved without explicit typing.
|
|
227
|
+
* However, the void variant preserves the original ArrayType.
|
|
228
|
+
*
|
|
229
|
+
* @code
|
|
230
|
+
* shared_array<uint32_t> arr({1, 2, 3});
|
|
231
|
+
* assert(arr.size()==3);
|
|
232
|
+
* shared_array<void> voidarr(arr.castTo<void>());
|
|
233
|
+
* assert(arr.size()==0);
|
|
234
|
+
* assert(voidarr.size()==3); // void size() in elements
|
|
235
|
+
* @endcode
|
|
236
|
+
*/
|
|
237
|
+
template<typename E, class Enable>
|
|
238
|
+
class shared_array : public detail::sa_base<E> {
|
|
239
|
+
static_assert (!std::is_void<E>::value, "non-void specialization");
|
|
240
|
+
|
|
241
|
+
template<typename E1, class Enable1> friend class shared_array;
|
|
242
|
+
|
|
243
|
+
typedef detail::sa_base<E> base_t;
|
|
244
|
+
typedef typename std::remove_const<E>::type _E_non_const;
|
|
245
|
+
public:
|
|
246
|
+
typedef E value_type;
|
|
247
|
+
typedef E& reference;
|
|
248
|
+
typedef typename std::add_const<E>::type& const_reference;
|
|
249
|
+
typedef E* pointer;
|
|
250
|
+
typedef typename std::add_const<E>::type* const_pointer;
|
|
251
|
+
typedef E* iterator;
|
|
252
|
+
typedef std::reverse_iterator<iterator> reverse_iterator;
|
|
253
|
+
typedef typename std::add_const<E>::type* const_iterator;
|
|
254
|
+
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
255
|
+
typedef std::ptrdiff_t difference_type;
|
|
256
|
+
typedef size_t size_type;
|
|
257
|
+
|
|
258
|
+
typedef E element_type;
|
|
259
|
+
|
|
260
|
+
constexpr shared_array() noexcept :base_t() {}
|
|
261
|
+
|
|
262
|
+
//! allocate new array and populate from initializer list
|
|
263
|
+
template<typename A>
|
|
264
|
+
shared_array(std::initializer_list<A> L)
|
|
265
|
+
:base_t(new _E_non_const[L.size()], L.size())
|
|
266
|
+
{
|
|
267
|
+
auto raw = const_cast<_E_non_const*>(this->data());
|
|
268
|
+
std::copy(L.begin(), L.end(), raw);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
//! Construct a copy of another a sequence.
|
|
272
|
+
//! Requires random access iterators.
|
|
273
|
+
template<typename Iter, typename std::iterator_traits<Iter>::difference_type=0>
|
|
274
|
+
shared_array(Iter begin, Iter end)
|
|
275
|
+
:shared_array(std::distance(begin, end))
|
|
276
|
+
{
|
|
277
|
+
std::copy(begin, end, const_cast<_E_non_const*>(this->begin()));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
//! @brief Allocate (with new[]) a new vector of size c
|
|
281
|
+
explicit shared_array(size_t c)
|
|
282
|
+
:base_t(new _E_non_const[c], c)
|
|
283
|
+
{}
|
|
284
|
+
|
|
285
|
+
//! @brief Allocate (with new[]) a new vector of size c and fill with value e
|
|
286
|
+
template<typename V>
|
|
287
|
+
shared_array(size_t c, V e)
|
|
288
|
+
:base_t(new _E_non_const[c], c)
|
|
289
|
+
{
|
|
290
|
+
std::fill_n((_E_non_const*)this->_data.get(), this->_count, e);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
//! use existing alloc with delete[]
|
|
294
|
+
shared_array(E* a, size_t len)
|
|
295
|
+
:base_t(a, len)
|
|
296
|
+
{}
|
|
297
|
+
|
|
298
|
+
//! use existing alloc w/ custom deletor
|
|
299
|
+
template<typename B>
|
|
300
|
+
shared_array(E* a, B b, size_t len)
|
|
301
|
+
:base_t(a, b, len)
|
|
302
|
+
{}
|
|
303
|
+
|
|
304
|
+
//! build around existing shared_ptr
|
|
305
|
+
shared_array(const std::shared_ptr<E>& a, size_t len)
|
|
306
|
+
:base_t(a, len)
|
|
307
|
+
{}
|
|
308
|
+
|
|
309
|
+
//! alias existing shared_array
|
|
310
|
+
template<typename A>
|
|
311
|
+
shared_array(const std::shared_ptr<A>& a, E* b, size_t len)
|
|
312
|
+
:base_t(a, b, len)
|
|
313
|
+
{}
|
|
314
|
+
|
|
315
|
+
#ifdef _DOXYGEN_
|
|
316
|
+
// documentation for sa_base method since this is an implementation detail
|
|
317
|
+
|
|
318
|
+
//! Number of elements
|
|
319
|
+
size_t size() const;
|
|
320
|
+
//! size()==0
|
|
321
|
+
bool empty() const;
|
|
322
|
+
//! True if this instance is the only (strong) reference
|
|
323
|
+
bool unique() const;
|
|
324
|
+
//! Reset size()==0
|
|
325
|
+
void clear();
|
|
326
|
+
//! Exchange contents with other
|
|
327
|
+
void swap(shared_array& o);
|
|
328
|
+
//! Access to raw pointer.
|
|
329
|
+
//! May be nullptr if size()==0
|
|
330
|
+
E* data() const noexcept;
|
|
331
|
+
#endif
|
|
332
|
+
|
|
333
|
+
size_t max_size() const noexcept {return ((size_t)-1)/sizeof(E);}
|
|
334
|
+
|
|
335
|
+
inline void reserve(size_t i) {}
|
|
336
|
+
|
|
337
|
+
//! Extend size. Implies make_unique().
|
|
338
|
+
//! @post unique()==true
|
|
339
|
+
void resize(size_t i) {
|
|
340
|
+
if(!this->unique() || i!=this->_count) {
|
|
341
|
+
shared_array o(i);
|
|
342
|
+
std::copy_n(this->begin(), std::min(this->size(), i), o.begin());
|
|
343
|
+
this->swap(o);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
//! Ensure exclusive ownership of array data by making a copy if necessary.
|
|
348
|
+
//! @post unique()==true
|
|
349
|
+
inline void make_unique() {
|
|
350
|
+
this->resize(this->size());
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private:
|
|
354
|
+
/* Hack alert.
|
|
355
|
+
* For reasons of simplicity and efficiency, we want to use raw pointers for iteration.
|
|
356
|
+
* However, shared_ptr::get() isn't defined when !_data, although practically it gives NULL.
|
|
357
|
+
* Unfortunately, many of the MSVC (<= VS 2010) STL methods assert() that iterators are never NULL.
|
|
358
|
+
* So we fudge here by abusing 'this' so that our iterators are always !NULL.
|
|
359
|
+
*/
|
|
360
|
+
inline E* base_ptr() const {
|
|
361
|
+
#if defined(_MSC_VER) && _MSC_VER<=1600
|
|
362
|
+
return this->_count ? this->_data.get() : (E*)(this-1);
|
|
363
|
+
#else
|
|
364
|
+
return this->_data.get();
|
|
365
|
+
#endif
|
|
366
|
+
}
|
|
367
|
+
public:
|
|
368
|
+
// STL iterators
|
|
369
|
+
|
|
370
|
+
//! begin iteration
|
|
371
|
+
inline iterator begin() const noexcept{return this->base_ptr();}
|
|
372
|
+
inline const_iterator cbegin() const noexcept{return begin();}
|
|
373
|
+
|
|
374
|
+
//! end iteration
|
|
375
|
+
inline iterator end() const noexcept{return this->base_ptr()+this->_count;}
|
|
376
|
+
inline const_iterator cend() const noexcept{return end();}
|
|
377
|
+
|
|
378
|
+
inline reverse_iterator rbegin() const noexcept{return reverse_iterator(end());}
|
|
379
|
+
inline const_reverse_iterator crbegin() const noexcept{return rbegin();}
|
|
380
|
+
|
|
381
|
+
inline reverse_iterator rend() const noexcept{return reverse_iterator(begin());}
|
|
382
|
+
inline const_reverse_iterator crend() const noexcept{return rend();}
|
|
383
|
+
|
|
384
|
+
inline reference front() const noexcept{return (*this)[0];}
|
|
385
|
+
inline reference back() const noexcept{return (*this)[this->_count-1];}
|
|
386
|
+
|
|
387
|
+
//! @brief Member access
|
|
388
|
+
//! Use sa.data() instead of &sa[0]
|
|
389
|
+
//! @pre !empty() && i<size()
|
|
390
|
+
inline reference operator[](size_t i) const noexcept {return this->_data.get()[i];}
|
|
391
|
+
|
|
392
|
+
//! @brief Member access
|
|
393
|
+
//! @throws std::out_of_range if empty() || i>=size().
|
|
394
|
+
reference at(size_t i) const
|
|
395
|
+
{
|
|
396
|
+
if(i > this->_count)
|
|
397
|
+
throw std::out_of_range("Index out of bounds");
|
|
398
|
+
return (*this)[i];
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
//! Cast to const, consuming this
|
|
402
|
+
//! @pre unique()==true
|
|
403
|
+
//! @post empty()==true
|
|
404
|
+
//! @throws std::logic_error if !unique()
|
|
405
|
+
shared_array<typename std::add_const<E>::type>
|
|
406
|
+
freeze() {
|
|
407
|
+
if(!this->unique())
|
|
408
|
+
throw std::logic_error("Can't freeze non-unique shared_array");
|
|
409
|
+
|
|
410
|
+
// alias w/ implied cast to const.
|
|
411
|
+
shared_array<typename std::add_const<E>::type> ret(this->_data, this->_data.get(), this->_count);
|
|
412
|
+
|
|
413
|
+
// c++20 provides a move()-able alternative to the aliasing constructor.
|
|
414
|
+
// until this stops being the future, we consume the src ref. and
|
|
415
|
+
// inc. + dec. the ref counter...
|
|
416
|
+
this->clear();
|
|
417
|
+
return ret;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/** Return non-const (maybe) copy. consuming this
|
|
421
|
+
* @post empty()==true
|
|
422
|
+
* @since 1.1.2
|
|
423
|
+
*
|
|
424
|
+
* If unique(), transforms this reference into the returned const reference.
|
|
425
|
+
* If not unique(), returns a copy and clears this reference.
|
|
426
|
+
* In either case, the returned reference will be unique().
|
|
427
|
+
*/
|
|
428
|
+
shared_array<typename std::remove_const<E>::type>
|
|
429
|
+
thaw() {
|
|
430
|
+
if(this->unique()) { // only reference, avoid copy
|
|
431
|
+
shared_array<typename std::remove_const<E>::type> ret(this->_data, (typename std::remove_const<E>::type*)this->_data.get(), this->_count);
|
|
432
|
+
|
|
433
|
+
this->clear();
|
|
434
|
+
return ret;
|
|
435
|
+
|
|
436
|
+
} else { // other references, copy
|
|
437
|
+
shared_array<typename std::remove_const<E>::type> ret(this->_data.get(),
|
|
438
|
+
this->_data.get() + this->_count);
|
|
439
|
+
this->clear();
|
|
440
|
+
return ret;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
#if _DOXYGEN_
|
|
445
|
+
/** Cast to/from void, preserving const-ness.
|
|
446
|
+
*
|
|
447
|
+
* A "safe" version of static_cast<>()
|
|
448
|
+
*
|
|
449
|
+
* Allowed casts depend upon two aspects of type parameter E.
|
|
450
|
+
*
|
|
451
|
+
* Whether the base type is void or non-void.
|
|
452
|
+
* And whether or not the const qualifier is present.
|
|
453
|
+
*
|
|
454
|
+
* Type E may always be cast to itself.
|
|
455
|
+
*
|
|
456
|
+
* Casts must preserve const-ness.
|
|
457
|
+
* Either both of E and TO, or neither, must be const qualified.
|
|
458
|
+
*
|
|
459
|
+
* At most one of E or TO may have different non-void base type.
|
|
460
|
+
*
|
|
461
|
+
* @throws std::logic_error on void -> non-void cast when requested type and the original_type() do not match.
|
|
462
|
+
*/
|
|
463
|
+
template<typename TO>
|
|
464
|
+
shared_array<TO>
|
|
465
|
+
castTo() const;
|
|
466
|
+
|
|
467
|
+
/** Cast with fallback to copy. Preserves const-ness
|
|
468
|
+
*
|
|
469
|
+
* Return either a reference or a copy of this array.
|
|
470
|
+
* A copy will be made if the requested type and the original_type() do not match.
|
|
471
|
+
* Otherwise functions like castTo().
|
|
472
|
+
*/
|
|
473
|
+
template<typename TO>
|
|
474
|
+
shared_array<TO>
|
|
475
|
+
convertTo() const;
|
|
476
|
+
#endif
|
|
477
|
+
|
|
478
|
+
template<typename TO, typename std::enable_if<std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
479
|
+
shared_array<TO>
|
|
480
|
+
castTo() const {
|
|
481
|
+
return shared_array<TO>(this->_data, this->_data.get(), this->_count); // implied cast to void*
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
template<typename TO, typename std::enable_if<std::is_same<TO, E>::value, int>::type =0>
|
|
485
|
+
shared_array<TO>
|
|
486
|
+
castTo() const {
|
|
487
|
+
return *this;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// static_cast<TO>() to non-void, preserving const-ness
|
|
491
|
+
template<typename TO, typename std::enable_if<!std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
492
|
+
shared_array<TO>
|
|
493
|
+
castToUnsafe() const {
|
|
494
|
+
return shared_array<TO>(this->_data, static_cast<TO*>(this->_data.get()), this->_count);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// static_cast<TO>() to void, preserving const-ness
|
|
498
|
+
template<typename TO, typename std::enable_if<std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
499
|
+
shared_array<TO>
|
|
500
|
+
castToUnsafe() const {
|
|
501
|
+
return shared_array<TO>(this->_data, this->_data.get(), this->_count); // implied cast to void*
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
template<typename TO, typename std::enable_if<!std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
505
|
+
shared_array<TO>
|
|
506
|
+
convertTo() const {
|
|
507
|
+
shared_array<TO> ret(this->_count);
|
|
508
|
+
detail::convertArr(detail::CaptureBase<TO>::code, (void*)ret._data.get(),
|
|
509
|
+
detail::CaptureBase<E>::code, this->_data.get(),
|
|
510
|
+
this->_count);
|
|
511
|
+
return ret;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/** Provide options when rendering with std::ostream.
|
|
515
|
+
*
|
|
516
|
+
* @code
|
|
517
|
+
* shared_array<int32_t> arr({1,2,3,4});
|
|
518
|
+
* // print entire array
|
|
519
|
+
* // {4}[1,2,3,4]
|
|
520
|
+
* std::cout<<arr;
|
|
521
|
+
* // print at most 3 elements
|
|
522
|
+
* // {4}[1,2,3,...]
|
|
523
|
+
* std::cout<<arr.format().limit(3);
|
|
524
|
+
* @endcode
|
|
525
|
+
*/
|
|
526
|
+
detail::Limiter format() const {
|
|
527
|
+
return detail::Limiter(this->_data.get(),
|
|
528
|
+
this->_count,
|
|
529
|
+
detail::CaptureBase<E>::code);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
#ifdef _DOXYGEN_
|
|
533
|
+
//! return type of underlying array. (void only)
|
|
534
|
+
inline ArrayType original_type() const;
|
|
535
|
+
#endif
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
template<typename E>
|
|
540
|
+
class shared_array<E, typename std::enable_if<std::is_void<E>::value>::type >
|
|
541
|
+
: public detail::sa_base<E>
|
|
542
|
+
{
|
|
543
|
+
static_assert (std::is_void<E>::value, "void specialization");
|
|
544
|
+
|
|
545
|
+
template<typename E1, class Enable1> friend class shared_array;
|
|
546
|
+
|
|
547
|
+
typedef detail::sa_base<E> base_t;
|
|
548
|
+
typedef typename std::remove_const<E>::type _E_non_const;
|
|
549
|
+
|
|
550
|
+
ArrayType _type;
|
|
551
|
+
public:
|
|
552
|
+
typedef E value_type;
|
|
553
|
+
typedef E* pointer;
|
|
554
|
+
typedef std::ptrdiff_t difference_type;
|
|
555
|
+
typedef size_t size_type;
|
|
556
|
+
|
|
557
|
+
//! empty array, untyped
|
|
558
|
+
constexpr shared_array() noexcept :base_t(), _type(ArrayType::Null) {}
|
|
559
|
+
//! empty array, typed
|
|
560
|
+
constexpr explicit shared_array(ArrayType code) noexcept :base_t(), _type(code) {}
|
|
561
|
+
//! copy
|
|
562
|
+
shared_array(const shared_array& o) = default;
|
|
563
|
+
//! move
|
|
564
|
+
inline shared_array(shared_array&& o) noexcept
|
|
565
|
+
:base_t(std::move(o))
|
|
566
|
+
,_type(o._type)
|
|
567
|
+
{
|
|
568
|
+
o._type = ArrayType::Null;
|
|
569
|
+
}
|
|
570
|
+
//! assign
|
|
571
|
+
shared_array& operator=(const shared_array&) =default;
|
|
572
|
+
//! move
|
|
573
|
+
inline shared_array& operator=(shared_array&& o) noexcept
|
|
574
|
+
{
|
|
575
|
+
base_t::operator=(std::move(o));
|
|
576
|
+
_type = o._type;
|
|
577
|
+
o._type = ArrayType::Null;
|
|
578
|
+
return *this;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
//! use existing alloc with delete[]
|
|
582
|
+
shared_array(E* a, size_t len, ArrayType type)
|
|
583
|
+
:base_t(a, len)
|
|
584
|
+
,_type(type)
|
|
585
|
+
{}
|
|
586
|
+
|
|
587
|
+
//! use existing alloc w/ custom deletor
|
|
588
|
+
template<typename B>
|
|
589
|
+
shared_array(E* a, B b, size_t len, ArrayType type)
|
|
590
|
+
:base_t(a, b, len)
|
|
591
|
+
,_type(type)
|
|
592
|
+
{}
|
|
593
|
+
|
|
594
|
+
//! build around existing shared_ptr and length
|
|
595
|
+
shared_array(const std::shared_ptr<E>& a, size_t len, ArrayType type)
|
|
596
|
+
:base_t(a, len)
|
|
597
|
+
,_type(type)
|
|
598
|
+
{}
|
|
599
|
+
|
|
600
|
+
//! alias existing shared_ptr and length
|
|
601
|
+
template<typename A>
|
|
602
|
+
shared_array(const std::shared_ptr<A>& a, E* b, size_t len)
|
|
603
|
+
:base_t(a, b, len)
|
|
604
|
+
,_type(detail::CaptureBase<A>::code)
|
|
605
|
+
{}
|
|
606
|
+
|
|
607
|
+
private:
|
|
608
|
+
template<typename A>
|
|
609
|
+
shared_array(const std::shared_ptr<A>& a, E* b, size_t len, ArrayType code)
|
|
610
|
+
:base_t(a, b, len)
|
|
611
|
+
,_type(code)
|
|
612
|
+
{}
|
|
613
|
+
public:
|
|
614
|
+
|
|
615
|
+
//! clear data and become untyped
|
|
616
|
+
void clear() noexcept {
|
|
617
|
+
base_t::clear();
|
|
618
|
+
_type = ArrayType::Null;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
//! exchange
|
|
622
|
+
void swap(shared_array& o) noexcept {
|
|
623
|
+
base_t::swap(o);
|
|
624
|
+
std::swap(_type, o._type);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
size_t max_size() const noexcept{return (size_t)-1;}
|
|
628
|
+
|
|
629
|
+
inline ArrayType original_type() const { return _type; }
|
|
630
|
+
|
|
631
|
+
shared_array<typename std::add_const<E>::type>
|
|
632
|
+
freeze() {
|
|
633
|
+
if(!this->unique())
|
|
634
|
+
throw std::logic_error("Can't freeze non-unique shared_array");
|
|
635
|
+
|
|
636
|
+
// alias w/ implied cast to const.
|
|
637
|
+
shared_array<typename std::add_const<E>::type> ret(this->_data, this->_data.get(), this->_count, this->_type);
|
|
638
|
+
|
|
639
|
+
// c++20 provides a move()-able alternative to the aliasing constructor.
|
|
640
|
+
// until this stops being the future, we consume the src ref. and
|
|
641
|
+
// inc. + dec. the ref counter...
|
|
642
|
+
this->clear();
|
|
643
|
+
return ret;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
shared_array<typename std::remove_const<E>::type>
|
|
647
|
+
thaw() {
|
|
648
|
+
if(this->unique()) { // only reference, avoid copy
|
|
649
|
+
shared_array<typename std::remove_const<E>::type> ret(this->_data, (typename std::remove_const<E>::type*)this->_data.get(), this->_count, this->_type);
|
|
650
|
+
|
|
651
|
+
this->clear();
|
|
652
|
+
return ret;
|
|
653
|
+
|
|
654
|
+
} else { // other references, copy
|
|
655
|
+
auto copy(allocArray(this->_type, this->_count));
|
|
656
|
+
detail::convertArr(this->_type, copy._data.get(), this->_type, this->_data.get(), this->_count);
|
|
657
|
+
this->clear();
|
|
658
|
+
return copy.template castTo<typename std::remove_const<E>::type>();
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// static_cast<TO>() to non-void, preserving const-ness
|
|
663
|
+
template<typename TO, typename std::enable_if<!std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
664
|
+
shared_array<TO>
|
|
665
|
+
castTo() const {
|
|
666
|
+
if(this->_data && _type!=detail::CaptureBase<TO>::code) {
|
|
667
|
+
detail::_throw_bad_cast(_type, detail::CaptureBase<TO>::code);
|
|
668
|
+
}
|
|
669
|
+
return shared_array<TO>(this->_data, static_cast<TO*>(this->_data.get()), this->_count);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
template<typename TO, typename std::enable_if<std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
673
|
+
shared_array<TO>
|
|
674
|
+
castTo() const {
|
|
675
|
+
return *this;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// static_cast<TO>() to non-void, preserving const-ness
|
|
679
|
+
template<typename TO, typename std::enable_if<!std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
680
|
+
shared_array<TO>
|
|
681
|
+
castToUnsafe() const {
|
|
682
|
+
return shared_array<TO>(this->_data, static_cast<TO*>(this->_data.get()), this->_count);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// static_cast<TO>() to void, preserving const-ness
|
|
686
|
+
template<typename TO, typename std::enable_if<std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
687
|
+
shared_array<TO>
|
|
688
|
+
castToUnsafe() const {
|
|
689
|
+
// in reality this is either void -> void, or const void -> const void
|
|
690
|
+
// aka. simple copy
|
|
691
|
+
return *this;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
template<typename TO, typename std::enable_if<!std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
695
|
+
shared_array<TO>
|
|
696
|
+
convertTo() const {
|
|
697
|
+
if(detail::CaptureBase<TO>::code==_type) {
|
|
698
|
+
return castTo<TO>();
|
|
699
|
+
} else {
|
|
700
|
+
shared_array<TO> ret(this->_count);
|
|
701
|
+
detail::convertArr(detail::CaptureBase<TO>::code, (void*)ret._data.get(),
|
|
702
|
+
_type, this->_data.get(),
|
|
703
|
+
this->_count);
|
|
704
|
+
return ret;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
template<typename TO, typename std::enable_if<std::is_void<TO>::value && (std::is_const<E>::value == std::is_const<TO>::value), int>::type =0>
|
|
709
|
+
shared_array<TO>
|
|
710
|
+
convertTo() const {
|
|
711
|
+
return castTo<TO>();
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
//! Provide options when rendering with std::ostream.
|
|
715
|
+
detail::Limiter format() const {
|
|
716
|
+
return detail::Limiter(this->_data.get(),
|
|
717
|
+
this->_count,
|
|
718
|
+
this->_type);
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
// non-const -> const
|
|
723
|
+
template <typename SRC>
|
|
724
|
+
static inline
|
|
725
|
+
shared_array<typename std::add_const<typename SRC::value_type>::type>
|
|
726
|
+
freeze(SRC&& src)
|
|
727
|
+
{
|
|
728
|
+
return src.freeze();
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// change type, while keeping same const
|
|
732
|
+
template<typename TO, typename FROM>
|
|
733
|
+
static inline
|
|
734
|
+
shared_array<TO>
|
|
735
|
+
shared_array_static_cast(const shared_array<FROM>& src)
|
|
736
|
+
{
|
|
737
|
+
return src.template castTo<TO>();
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
template<typename E>
|
|
741
|
+
std::ostream& operator<<(std::ostream& strm, const shared_array<E>& arr)
|
|
742
|
+
{
|
|
743
|
+
return strm<<arr.format();
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
} // namespace pvxs
|
|
747
|
+
|
|
748
|
+
#endif // PVXS_SHAREDVECTOR_H
|