diff options
author | Determinant <[email protected]> | 2018-07-12 17:39:48 -0400 |
---|---|---|
committer | Determinant <[email protected]> | 2018-07-12 17:39:48 -0400 |
commit | 33faa8e355dc47a126790f1ea3e52d1813aedc69 (patch) | |
tree | 151c047fd4b8b8a10be2ca45931c482ceb79b451 | |
parent | a0ea3b5fb7eaedb9b6789657bed998585bb98b77 (diff) |
support array type in smart pointers
-rw-r--r-- | include/salticidae/ref.h | 341 | ||||
-rw-r--r-- | include/salticidae/stream.h | 79 | ||||
-rw-r--r-- | include/salticidae/type.h | 7 |
3 files changed, 341 insertions, 86 deletions
diff --git a/include/salticidae/ref.h b/include/salticidae/ref.h index c2dcdd3..a1c5dc7 100644 --- a/include/salticidae/ref.h +++ b/include/salticidae/ref.h @@ -31,45 +31,102 @@ namespace salticidae { template<typename T> -class BoxObj { - T *obj; +struct default_delete { + constexpr default_delete() = default; + void operator()(T *ptr) const { + static_assert(!std::is_void<T>::value, + "can't delete pointer to incomplete type"); + static_assert(sizeof(T) > 0, + "can't delete pointer to incomplete type"); + delete ptr; + } +}; - void release() { - if (obj) delete obj; +template<typename T> +struct default_delete<T[]> { + constexpr default_delete() = default; + void operator()(T *ptr) const { + static_assert(sizeof(T) > 0, + "can't delete pointer to incomplete type"); + delete [] ptr; } +}; + +template<typename T, typename D> +class BoxObj; + +template<typename T, typename D> +class _BoxObj { + protected: + using ptr_type = T *; + ptr_type obj; + constexpr _BoxObj(ptr_type obj): obj(obj) {} public: - template<typename T__, typename T_> - friend BoxObj<T__> static_pointer_cast(const BoxObj<T_> &other); - operator T*() const { return obj; } - T *operator->() const { return obj; } - BoxObj(): obj(nullptr) {} - BoxObj(T *obj): obj(obj) {} - BoxObj &operator=(const BoxObj &other) = delete; - BoxObj &operator=(BoxObj &&other) { - release(); - obj = other.obj; + + constexpr _BoxObj(): obj(nullptr) {} + _BoxObj(const _BoxObj &other) = delete; + _BoxObj(_BoxObj &&other): obj(other.obj) { other.obj = nullptr; - return *this; } - BoxObj(const BoxObj &other) = delete; - BoxObj(BoxObj &&other): obj(other.obj) { - other.obj = nullptr; + + ~_BoxObj() { + if (obj) D()(obj); } - template<typename T_> - BoxObj(BoxObj<T_> &&other): obj(other.obj) { - other.obj = nullptr; + void swap(_BoxObj &other) { + std::swap(obj, other.obj); } - ~BoxObj() { release(); } + _BoxObj &operator=(const _BoxObj &other) = delete; + _BoxObj &operator=(_BoxObj &&other) { + if (this != &other) + { + _BoxObj tmp(std::move(other)); + tmp.swap(*this); + } + return *this; + } + + operator T*() const { return obj; } +}; + +template<typename T, typename D = default_delete<T>> +class BoxObj: public _BoxObj<T, D> { + using base_t = _BoxObj<T, D>; + template<typename T__, typename D__, typename T_, typename D_> + friend BoxObj<T__, D__> static_pointer_cast(BoxObj<T_, D_> &&other); + + public: + BoxObj() = default; + BoxObj(T *obj): base_t(obj) {} + template<typename T_, typename = + typename std::enable_if<!std::is_array<T_>::value>::value> + BoxObj(BoxObj<T_> &&other): base_t(other) {} + + T *operator->() const { return base_t::obj; } +}; + +template<typename T, typename D> +class BoxObj<T[], D>: public _BoxObj<T, D> { + using base_t = _BoxObj<T, D>; + template<typename T__, typename D__, typename T_, typename D_> + friend BoxObj<T__, D__> static_pointer_cast(BoxObj<T_, D_> &&other); + + public: + BoxObj() = default; + BoxObj(T obj[]): base_t(obj) {} + template<typename T_> + BoxObj(BoxObj<T_[]> &&other): base_t(std::move(other)) {} + + T &operator[](size_t idx) { return base_t::obj[idx]; } }; -template<typename T, typename T_> -BoxObj<T> static_pointer_cast(BoxObj<T_> &&other) { - BoxObj<T> box{}; - box.obj = static_cast<T *>(other.obj); +template<typename T, typename D = default_delete<T>, typename T_, typename D_> +BoxObj<T, D> static_pointer_cast(BoxObj<T_, D_> &&other) { + BoxObj<T, D> box{}; + box.obj = static_cast<typename BoxObj<T, D>::ptr_type>(other.obj); return std::move(box); } @@ -118,96 +175,147 @@ struct _ARCCtl { ~_ARCCtl() {} }; -template<typename T, typename R> class RcObjBase; +template<typename T, typename R, typename D> class RcObjBase; template<typename T, typename R> -class WeakObjBase { +class _WeakObjBase { T *obj; R *ctl; - void release() { if (ctl) ctl->release_weak(); } + + template<typename D> using ROB = RcObjBase<T, R, D>; + friend class ROB; + friend std::hash<_WeakObjBase<T, R>>; + public: - friend RcObjBase<T, R>; - friend std::hash<WeakObjBase<T, R>>; - WeakObjBase(): ctl(nullptr) {} - WeakObjBase &operator=(const WeakObjBase &other) { - release(); - obj = other.obj; - if ((ctl = other.ctl)) - ctl->add_weak(); + _WeakObjBase(): ctl(nullptr) {} + + void swap(_WeakObjBase &other) { + std::swap(obj, other.obj); + std::swap(ctl, other.ctl); + } + + _WeakObjBase &operator=(const _WeakObjBase &other) { + if (this != &other) + { + _WeakObjBase tmp(other); + tmp.swap(*this); + } return *this; } - WeakObjBase(const WeakObjBase &other): + _WeakObjBase &operator=(_WeakObjBase &&other) { + if (this != &other) + { + _WeakObjBase tmp(std::move(other)); + tmp.swap(*this); + } + return *this; + } + + _WeakObjBase(const _WeakObjBase &other): obj(other.obj), ctl(other.ctl) { if (ctl) ctl->add_weak(); } - WeakObjBase(WeakObjBase &&other): + _WeakObjBase(_WeakObjBase &&other): obj(other.obj), ctl(other.ctl) { other.ctl = nullptr; } - WeakObjBase(const RcObjBase<T, R> &other); + template<typename D> + _WeakObjBase(const RcObjBase<T, R, D> &other); - ~WeakObjBase() { release(); } + ~_WeakObjBase() { if (ctl) ctl->release_weak(); } }; + template<typename T, typename R> -class RcObjBase { - T *obj; - R *ctl; - void release() { - if (ctl && ctl->release_ref()) - delete obj; - } +class WeakObjBase: public _WeakObjBase<T, R> { + public: + WeakObjBase() = default; + WeakObjBase(const WeakObjBase &other) = default; + WeakObjBase(WeakObjBase &&other) = default; + template<typename D> + WeakObjBase(const RcObjBase<T, R, D> &other); +}; + +template<typename T, typename R> +class WeakObjBase<T[], R>: public _WeakObjBase<T, R> { public: + WeakObjBase() = default; + WeakObjBase(const WeakObjBase &other) = default; + WeakObjBase(WeakObjBase &&other) = default; + template<typename D> + WeakObjBase(const RcObjBase<T[], R, D> &other); +}; + + +template<typename T, typename R, typename D> +class _RcObjBase { + protected: + using ptr_type = T *; + ptr_type obj; + R *ctl; + friend WeakObjBase<T, R>; - friend std::hash<RcObjBase<T, R>>; - template<typename T__, typename T_, typename R_> - friend RcObjBase<T__, R_> static_pointer_cast(const RcObjBase<T_, R_> &other); - template<typename T__, typename T_, typename R_> - friend RcObjBase<T__, R_> static_pointer_cast(RcObjBase<T_, R_> &&other); - template<typename T_, typename R_> friend class RcObjBase; + friend std::hash<_RcObjBase<T, R, D>>; + template<typename T_, typename R_, typename D_> + friend class _RcObjBase; + public: operator T*() const { return obj; } - T *operator->() const { return obj; } - RcObjBase(): obj(nullptr), ctl(nullptr) {} - RcObjBase(T *obj): obj(obj), ctl(new R()) {} - RcObjBase(BoxObj<T> &&box_ref): obj(box_ref.obj), ctl(new R()) { + _RcObjBase(): obj(nullptr), ctl(nullptr) {} + _RcObjBase(ptr_type obj): obj(obj), ctl(new R()) {} + _RcObjBase(BoxObj<T> &&box_ref): obj(box_ref.obj), ctl(new R()) { box_ref.obj = nullptr; } - RcObjBase &operator=(const RcObjBase &other) { - release(); - obj = other.obj; - if ((ctl = other.ctl)) - ctl->add_ref(); + void swap(_RcObjBase &other) { + std::swap(obj, other.obj); + std::swap(ctl, other.ctl); + } + + _RcObjBase &operator=(const _RcObjBase &other) { + if (this != &other) + { + _RcObjBase tmp(other); + tmp.swap(*this); + } return *this; } - RcObjBase(const RcObjBase &other): + _RcObjBase &operator=(_RcObjBase &&other) { + if (this != &other) + { + _RcObjBase tmp(std::move(other)); + tmp.swap(*this); + } + return *this; + } + + _RcObjBase(const _RcObjBase &other): obj(other.obj), ctl(other.ctl) { if (ctl) ctl->add_ref(); } - template<typename T_> - RcObjBase(const RcObjBase<T_, R> &other): + template<typename T_, typename D_> + _RcObjBase(const _RcObjBase<T_, R, D_> &other): obj(other.obj), ctl(other.ctl) { if (ctl) ctl->add_ref(); } - RcObjBase(RcObjBase &&other): + _RcObjBase(_RcObjBase &&other): obj(other.obj), ctl(other.ctl) { other.ctl = nullptr; } - template<typename T_> - RcObjBase(RcObjBase<T_, R> &&other): + template<typename T_, typename D_> + _RcObjBase(_RcObjBase<T_, R, D_> &&other): obj(other.obj), ctl(other.ctl) { other.ctl = nullptr; } - RcObjBase(const WeakObjBase<T, R> &other) { + _RcObjBase(const WeakObjBase<T, R> &other) { if (other.ctl && other.ctl->ref_cnt) { obj = other.obj; @@ -221,36 +329,101 @@ class RcObjBase { } } - ~RcObjBase() { release(); } + ~_RcObjBase() { + if (ctl && ctl->release_ref()) + D()(obj); + } size_t get_cnt() const { return ctl ? ctl->get_cnt() : 0; } }; -template<typename T, typename T_, typename R> -RcObjBase<T, R> static_pointer_cast(const RcObjBase<T_, R> &other) { - RcObjBase<T, R> rc{}; - rc.obj = static_cast<T *>(other.obj); +template<typename T, typename R, typename D = default_delete<T>> +class RcObjBase: public _RcObjBase<T, R, D> { + using base_t = _RcObjBase<T, R, D>; + template<typename T__, typename D__, typename T_, typename R_, typename D_> + friend RcObjBase<T__, R_, D__> static_pointer_cast(const RcObjBase<T_, R_, D_> &other); + template<typename T__, typename D__, typename T_, typename R_, typename D_> + friend RcObjBase<T__, R_, D__> static_pointer_cast(RcObjBase<T_, R_, D_> &&other); + + public: + T *operator->() const { return base_t::obj; } + RcObjBase() = default; + RcObjBase(T *obj): base_t(obj) {} + RcObjBase(BoxObj<T> &&box_ref): base_t(std::move(box_ref)) {} + + template<typename T_, typename D_, + typename = typename std::enable_if<!std::is_array<T_>::value>::value> + RcObjBase(const RcObjBase<T_, R, D_> &other): base_t(other) {} + + template<typename T_, typename D_, + typename = typename std::enable_if<!std::is_array<T_>::value>::value> + RcObjBase(RcObjBase<T_, R, D_> &&other): base_t(std::move(other)) {} + + RcObjBase(const WeakObjBase<T, R> &other): base_t(other) {} + + + RcObjBase(const RcObjBase &other) = default; + RcObjBase(RcObjBase &&other) = default; + RcObjBase &operator=(const RcObjBase &) = default; + RcObjBase &operator=(RcObjBase &&) = default; +}; + +template<typename T, typename R, typename D> +class RcObjBase<T[], R, D>: public _RcObjBase<T, R, D> { + using base_t = _RcObjBase<T, R, D>; + template<typename T__, typename D__, typename T_, typename R_, typename D_> + friend RcObjBase<T__, R_, D__> static_pointer_cast(const RcObjBase<T_, R_, D_> &other); + template<typename T__, typename D__, typename T_, typename R_, typename D_> + friend RcObjBase<T__, R_, D__> static_pointer_cast(RcObjBase<T_, R_, D_> &&other); + + public: + T &operator[](size_t idx) { return base_t::obj; } + RcObjBase() = default; + RcObjBase(T obj[]): base_t(obj) {} + RcObjBase(BoxObj<T[]> &&box_ref): base_t(std::move(box_ref)) {} + + template<typename T_, typename D_> + RcObjBase(const RcObjBase<T_[], R, D_> &other): base_t(other) {} + + template<typename T_, typename D_> + RcObjBase(RcObjBase<T_[], R, D_> &&other): base_t(std::move(other)) {} + + RcObjBase(const WeakObjBase<T[], R> &other): base_t(other) {} + + RcObjBase(const RcObjBase &other) = default; + RcObjBase(RcObjBase &&other) = default; + RcObjBase &operator=(const RcObjBase &) = default; + RcObjBase &operator=(RcObjBase &&) = default; +}; + + +template<typename T, typename D = default_delete<T>, + typename T_, typename R_, typename D_> +RcObjBase<T, R_, D> static_pointer_cast(const RcObjBase<T_, R_, D_> &other) { + RcObjBase<T, R_, D> rc{}; + rc.obj = static_cast<typename RcObjBase<T, R_, D>::ptr_type>(other.obj); if ((rc.ctl = other.ctl)) rc.ctl->add_ref(); return std::move(rc); } -template<typename T, typename T_, typename R> -RcObjBase<T, R> static_pointer_cast(RcObjBase<T_, R> &&other) { - RcObjBase<T, R> rc{}; - rc.obj = static_cast<T *>(other.obj); +template<typename T, typename D = default_delete<T>, + typename T_, typename R_, typename D_> +RcObjBase<T, R_, D> static_pointer_cast(RcObjBase<T_, R_, D_> &&other) { + RcObjBase<T, R_, D> rc{}; + rc.obj = static_cast<typename RcObjBase<T, R_, D>::ptr_type>(other.obj); rc.ctl = other.ctl; other.ctl = nullptr; return std::move(rc); } template<typename T, typename R> -inline WeakObjBase<T, R>::WeakObjBase(const RcObjBase<T, R> &other): +template<typename D> +inline _WeakObjBase<T, R>::_WeakObjBase(const RcObjBase<T, R, D> &other): obj(other.obj), ctl(other.ctl) { if (ctl) ctl->add_weak(); } - template<typename T> using RcObj = RcObjBase<T, _RCCtl>; template<typename T> using WeakObj = WeakObjBase<T, _RCCtl>; @@ -260,9 +433,9 @@ template<typename T> using AweakObj = WeakObjBase<T, _ARCCtl>; } namespace std { - template<typename T, typename R> - struct hash<salticidae::RcObjBase<T, R>> { - size_t operator()(const salticidae::RcObjBase<T, R> &k) const { + template<typename T, typename R, typename D> + struct hash<salticidae::RcObjBase<T, R, D>> { + size_t operator()(const salticidae::RcObjBase<T, R, D> &k) const { return (size_t)k.obj; } }; diff --git a/include/salticidae/stream.h b/include/salticidae/stream.h index ffffbe2..9e4791c 100644 --- a/include/salticidae/stream.h +++ b/include/salticidae/stream.h @@ -26,6 +26,7 @@ #define _SALTICIDAE_STREAM_H #include "salticidae/type.h" +#include "salticidae/ref.h" #include "salticidae/crypto.h" namespace salticidae { @@ -258,6 +259,84 @@ class Blob { } }; +template<typename T = uint64_t> +class Bits { + using _impl_type = T; + static const size_t bit_per_datum = sizeof(_impl_type) * 8; + BoxObj<_impl_type[]> data; + size_t nbits; + size_t ndata; + + public: + + Bits(): data(nullptr) {} + Bits(const bytearray_t &arr) { + load(&*arr.begin(), arr.size()); + } + + Bits(const uint8_t *arr, size_t len) { load(arr, len); } + Bits(size_t nbits): nbits(nbits) { + ndata = (nbits + bit_per_datum - 1) / bit_per_datum; + data = new _impl_type[ndata]; + } + + ~Bits() {} + + void load(const uint8_t *arr, size_t len) { + nbits = len * 8; + ndata = (len + sizeof(_impl_type) - 1) / + sizeof(_impl_type); + data = new _impl_type[ndata]; + + uint8_t *end = arr + len; + for (_impl_type *ptr = data; ptr < data + ndata;) + { + _impl_type x = 0; + for (unsigned j = 0, k = 0; j < sizeof(_impl_type); j++, k += 8) + if (arr < end) x |= *(arr++) << k; + *(ptr++) = x; + } + } + + bool is_null() const { return data == nullptr; } + + size_t cheap_hash() const { return *data; } + + void serialize(DataStream &s) const { + s << htole(nbits); + if (data) + { + for (const _impl_type *ptr = data; ptr < data + ndata; ptr++) + s << htole(*ptr); + } + else + { + for (const _impl_type *ptr = data; ptr < data + ndata; ptr++) + s << htole((_impl_type)0); + } + } + + void unserialize(DataStream &s) { + _impl_type x; + s >> x; + nbits = letoh(x); + ndata = (nbits + bit_per_datum - 1) / bit_per_datum; + data = new _impl_type[ndata]; + for (_impl_type *ptr = data; ptr < data + ndata; ptr++) + { + s >> x; + *ptr = letoh(x); + } + } + + operator bytearray_t () const & { + DataStream s; + s << *this; + return std::move(s); + } +}; + + const size_t ENT_HASH_LENGTH = 256 / 8; uint256_t DataStream::get_hash() const { diff --git a/include/salticidae/type.h b/include/salticidae/type.h index edf38a6..d5834a5 100644 --- a/include/salticidae/type.h +++ b/include/salticidae/type.h @@ -54,13 +54,16 @@ template<> inline uint16_t letoh<uint16_t>(uint16_t x) { return le16toh(x); } template<> inline uint32_t letoh<uint32_t>(uint32_t x) { return le32toh(x); } template<> inline uint64_t letoh<uint64_t>(uint64_t x) { return le64toh(x); } +template<typename... > +using void_t = void; + template <typename T, typename = void> struct is_ranged : std::false_type {}; template <typename T> struct is_ranged<T, - std::void_t<decltype(std::declval<T>().begin()), - decltype(std::declval<T>().end())>> : std::true_type {}; + void_t<decltype(std::declval<T>().begin()), + decltype(std::declval<T>().end())>> : std::true_type {}; } |