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.
Files changed (40) hide show
  1. pvxslibs/__init__.py +0 -0
  2. pvxslibs/dbd/pvxsIoc.dbd +8 -0
  3. pvxslibs/include/pvxs/client.h +1094 -0
  4. pvxslibs/include/pvxs/data.h +948 -0
  5. pvxslibs/include/pvxs/iochooks.h +170 -0
  6. pvxslibs/include/pvxs/log.h +148 -0
  7. pvxslibs/include/pvxs/netcommon.h +82 -0
  8. pvxslibs/include/pvxs/nt.h +208 -0
  9. pvxslibs/include/pvxs/server.h +238 -0
  10. pvxslibs/include/pvxs/sharedArray.h +748 -0
  11. pvxslibs/include/pvxs/sharedpv.h +121 -0
  12. pvxslibs/include/pvxs/source.h +290 -0
  13. pvxslibs/include/pvxs/srvcommon.h +148 -0
  14. pvxslibs/include/pvxs/unittest.h +327 -0
  15. pvxslibs/include/pvxs/util.h +354 -0
  16. pvxslibs/include/pvxs/version.h +97 -0
  17. pvxslibs/include/pvxs/versionNum.h +6 -0
  18. pvxslibs/ioc.py +10 -0
  19. pvxslibs/lib/__init__.py +0 -0
  20. pvxslibs/lib/event_core_dsoinfo.py +14 -0
  21. pvxslibs/lib/event_pthread_dsoinfo.py +14 -0
  22. pvxslibs/lib/libevent_core.so +0 -0
  23. pvxslibs/lib/libevent_core.so.2.2.0 +0 -0
  24. pvxslibs/lib/libevent_pthread.so +0 -0
  25. pvxslibs/lib/libevent_pthread.so.2.2.0 +0 -0
  26. pvxslibs/lib/libpvxs.so +0 -0
  27. pvxslibs/lib/libpvxs.so.1.5 +0 -0
  28. pvxslibs/lib/libpvxsIoc.so +0 -0
  29. pvxslibs/lib/libpvxsIoc.so.1.5 +0 -0
  30. pvxslibs/lib/pvxsIoc_dsoinfo.py +14 -0
  31. pvxslibs/lib/pvxs_dsoinfo.py +14 -0
  32. pvxslibs/path.py +12 -0
  33. pvxslibs/test/__init__.py +0 -0
  34. pvxslibs/test/test_load.py +30 -0
  35. pvxslibs/version.py +32 -0
  36. pvxslibs-1.5.0.dist-info/METADATA +44 -0
  37. pvxslibs-1.5.0.dist-info/RECORD +40 -0
  38. pvxslibs-1.5.0.dist-info/WHEEL +5 -0
  39. pvxslibs-1.5.0.dist-info/licenses/LICENSE +26 -0
  40. 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