From 078e0ea69f9f2104a63e5148b2eb48d300a07d3e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 19 Mar 2020 16:39:15 -0700 Subject: [PATCH] sharedArray formatting with size limit. --- src/datafmt.cpp | 2 +- src/pvxs/sharedArray.h | 102 ++++++++++++++++++++++------------------- src/util.cpp | 95 +++++++++++++++++++------------------- test/testshared.cpp | 4 +- test/testtype.cpp | 4 +- test/testxcode.cpp | 6 +-- 6 files changed, 113 insertions(+), 100 deletions(-) diff --git a/src/datafmt.cpp b/src/datafmt.cpp index f5ea84d..229de02 100644 --- a/src/datafmt.cpp +++ b/src/datafmt.cpp @@ -184,7 +184,7 @@ struct FmtTree { if(!fmt._showValue) { strm<<"\n"; } else if(varr.original_type()!=ArrayType::Value) { - strm<<" = "<(); strm<<" [\n"; diff --git a/src/pvxs/sharedArray.h b/src/pvxs/sharedArray.h index 7e86de8..2573758 100644 --- a/src/pvxs/sharedArray.h +++ b/src/pvxs/sharedArray.h @@ -82,7 +82,7 @@ protected: template friend struct sa_base; std::shared_ptr _data; - size_t _size; + size_t _count; public: // shared_array() @@ -95,60 +95,61 @@ public: // shared_array(shared_ptr, T*, size_t) //! empty - constexpr sa_base() :_size(0u) {} + constexpr sa_base() :_count(0u) {} // copyable sa_base(const sa_base&) = default; // movable inline sa_base(sa_base&& o) noexcept - :_data(std::move(o._data)), _size(o._size) + :_data(std::move(o._data)), _count(o._count) { - o._size = 0; + o._count = 0; } sa_base& operator=(const sa_base&) =default; inline sa_base& operator=(sa_base&& o) noexcept { _data = std::move(o._data); - _size = o._size; - o._size = 0; + _count = o._count; + o._count = 0; return *this; } // use existing alloc with delete[] template sa_base(A* a, size_t len) - :_data(a, sa_default_delete()),_size(len) + :_data(a, sa_default_delete()),_count(len) {} // use existing alloc w/ custom deletor template sa_base(E* a, B b, size_t len) - :_data(a, b),_size(len) + :_data(a, b),_count(len) {} // build around existing shared_ptr sa_base(const std::shared_ptr& a, size_t len) - :_data(a),_size(len) + :_data(a),_count(len) {} // alias existing shared_ptr template sa_base(const std::shared_ptr& a, E* b, size_t len) - :_data(a, b),_size(len) + :_data(a, b),_count(len) {} void clear() noexcept { _data.reset(); - _size = 0; + _count = 0; } void swap(sa_base& o) noexcept { std::swap(_data, o._data); - std::swap(_size, o._data); + std::swap(_count, o._data); } - inline size_t size() const { return _size; } - inline bool empty() const noexcept { return _size==0; } + //! Number of elements + inline size_t size() const { return _count; } + inline bool empty() const noexcept { return _count==0; } inline bool unique() const noexcept { return !_data || _data.use_count()<=1; } @@ -157,6 +158,23 @@ public: const std::shared_ptr& dataPtr() const { return _data; } }; +class Limiter { + const void* _base; + size_t _count; + size_t _limit=0u; + ArrayType _type; + friend + std::ostream& operator<<(std::ostream& strm, const Limiter& lim); +public: + Limiter(const void* base, size_t count, ArrayType type) + :_base(base), _count(count), _type(type) + {} + Limiter& limit(size_t l) { _limit = l; return *this; } +}; + +PVXS_API +std::ostream& operator<<(std::ostream& strm, const Limiter&); + } // namespace detail /** std::vector-like contigious array of items passed by reference. @@ -229,7 +247,7 @@ public: shared_array(size_t c, V e) :base_t(new _E_non_const[c], c) { - std::fill_n((_E_non_const*)this->_data.get(), this->_size, e); + std::fill_n((_E_non_const*)this->_data.get(), this->_count, e); } //! use existing alloc with delete[] @@ -260,7 +278,7 @@ public: //! Extend size. Implies make_unique() void resize(size_t i) { - if(!this->unique() || i!=this->_size) { + if(!this->unique() || i!=this->_count) { shared_array o(i); std::copy_n(this->begin(), std::min(this->size(), i), o.begin()); this->swap(o); @@ -281,7 +299,7 @@ private: */ inline E* base_ptr() const { #if defined(_MSC_VER) && _MSC_VER<=1600 - return this->_size ? this->_data.get() : (E*)(this-1); + return this->_count ? this->_data.get() : (E*)(this-1); #else return this->_data.get(); #endif @@ -294,7 +312,7 @@ public: inline const_iterator cbegin() const noexcept{return begin();} //! end iteration - inline iterator end() const noexcept{return this->base_ptr()+this->_size;} + inline iterator end() const noexcept{return this->base_ptr()+this->_count;} inline const_iterator cend() const noexcept{return end();} inline reverse_iterator rbegin() const noexcept{return reverse_iterator(end());} @@ -315,7 +333,7 @@ public: //! @throws std::out_of_range if empty() || i>=size(). reference at(size_t i) const { - if(i>this->_size) + if(i > this->_count) throw std::out_of_range("Index out of bounds"); return (*this)[i]; } @@ -330,7 +348,7 @@ public: throw std::logic_error("Can't freeze non-unique shared_array"); // alias w/ implied cast to const. - shared_array::type> ret(this->_data, this->_data.get(), this->_size); + shared_array::type> ret(this->_data, this->_data.get(), this->_count); // c++20 provides a move()-able alternative to the aliasing constructor. // until this stops being the future, we consume the src ref. and @@ -343,16 +361,20 @@ public: template{} && (std::is_const{} == std::is_const{}), int>::type =0> shared_array castTo() const { - auto alen = this->_size*sizeof(E)/sizeof(TO); - return shared_array(this->_data, static_cast(this->_data.get()), alen); + return shared_array(this->_data, static_cast(this->_data.get()), this->_count); } //! static_cast() to void, preserving const-ness template{} && (std::is_const{} == std::is_const{}), int>::type =0> shared_array castTo() const { - auto alen = this->_size*sizeof(E); - return shared_array(this->_data, this->_data.get(), alen); // implied cast to void* + return shared_array(this->_data, this->_data.get(), this->_count); // implied cast to void* + } + + detail::Limiter format() const { + return Limiter(this->_data.get(), + this->_count, + detail::CaptureCode::type>::code); } }; @@ -455,7 +477,7 @@ public: throw std::logic_error("Can't freeze non-unique shared_array"); // alias w/ implied cast to const. - shared_array::type> ret(this->_data, this->_data.get(), this->_size, this->_type); + shared_array::type> ret(this->_data, this->_data.get(), this->_count, this->_type); // c++20 provides a move()-able alternative to the aliasing constructor. // until this stops being the future, we consume the src ref. and @@ -468,8 +490,7 @@ public: template{} && (std::is_const{} == std::is_const{}), int>::type =0> shared_array castTo() const { - auto alen = this->_size/sizeof(TO); - return shared_array(this->_data, static_cast(this->_data.get()), alen); + return shared_array(this->_data, static_cast(this->_data.get()), this->_count); } // static_cast() to void, preserving const-ness @@ -480,6 +501,12 @@ public: // aka. simple copy return *this; } + + detail::Limiter format() const { + return detail::Limiter(this->_data.get(), + this->_count, + this->_type); + } }; // non-const -> const @@ -500,29 +527,12 @@ shared_array_static_cast(const shared_array& src) return src.template castTo(); } -template{}, int>::type =0> +template std::ostream& operator<<(std::ostream& strm, const shared_array& arr) { - strm<<'{'<10) { - strm<<"..."; - break; - } - strm<& arr); - -PVXS_API -std::ostream& operator<<(std::ostream& strm, const shared_array& arr); - } // namespace pvxs #endif // PVXS_SHAREDVECTOR_H diff --git a/src/util.cpp b/src/util.cpp index ef9a236..5140b1f 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -73,54 +73,57 @@ std::ostream& operator<<(std::ostream& strm, ArrayType code) return strm; } -std::ostream& operator<<(std::ostream& strm, const shared_array& arr) -{ - switch(arr.original_type()) { - case ArrayType::Null: strm<<"[null]"; break; -#define CASE(CODE, Type) case ArrayType::CODE: strm<(); break - CASE(Bool, bool); - CASE(UInt8, uint8_t); - CASE(UInt16, uint16_t); - CASE(UInt32, uint32_t); - CASE(UInt64, uint64_t); - CASE(Int8, int8_t); - CASE(Int16, int16_t); - CASE(Int32, int32_t); - CASE(Int64, int64_t); - CASE(Float32, float); - CASE(Float64, double); - CASE(String, std::string); - CASE(Value, Value); -#undef CASE - } - return strm; -} - -std::ostream& operator<<(std::ostream& strm, const shared_array& arr) -{ - switch(arr.original_type()) { - case ArrayType::Null: strm<<"[null]"; break; -#define CASE(CODE, Type) case ArrayType::CODE: strm<(); break - CASE(Bool, bool); - CASE(UInt8, uint8_t); - CASE(UInt16, uint16_t); - CASE(UInt32, uint32_t); - CASE(UInt64, uint64_t); - CASE(Int8, int8_t); - CASE(Int16, int16_t); - CASE(Int32, int32_t); - CASE(Int64, int64_t); - CASE(Float32, float); - CASE(Float64, double); - CASE(String, std::string); - CASE(Value, Value); -#undef CASE - } - return strm; -} - namespace detail { +namespace { +template +void showArr(std::ostream& strm, const void* raw, size_t count, size_t limit) +{ + auto base = reinterpret_cast(raw); + + if(limit==0) + limit=size_t(-1); + + strm<<"{"<limit) { + strm<<"..."; + break; + } + strm<(strm, lim._base, lim._count, lim._limit); break + CASE(Bool, bool); + CASE(UInt8, uint8_t); + CASE(UInt16, uint16_t); + CASE(UInt32, uint32_t); + CASE(UInt64, uint64_t); + CASE(Int8, int8_t); + CASE(Int16, int16_t); + CASE(Int32, int32_t); + CASE(Int64, int64_t); + CASE(Float32, float); + CASE(Float64, double); + CASE(String, std::string); +#undef CASE + case ArrayType::Null: + strm<<"{\?}[]"; + break; + default: + strm<<"[\?\?\?]"; + } + return strm; +} + Escaper::Escaper(const char* v) :val(v) ,count(v ? strlen(v) : 0) diff --git a/test/testshared.cpp b/test/testshared.cpp index d9ac648..f8fc20b 100644 --- a/test/testshared.cpp +++ b/test/testshared.cpp @@ -85,7 +85,7 @@ void testVoid() testOk1(!X.unique()); testOk1(!Y.unique()); testEq(X.size(), 2u); - testEq(Y.size(), 8u); + testEq(Y.size(), 2u); testEq(Y.original_type(), ArrayType::UInt32); // never const uint32_t testThrows([&Y]() { @@ -99,7 +99,7 @@ void testVoid() testOk1(Y.unique()); testOk1(Z.unique()); testEq(Y.size(), 0u); - testEq(Z.size(), 8u); + testEq(Z.size(), 2u); } void testFreeze() diff --git a/test/testtype.cpp b/test/testtype.cpp index 862ce73..31797cf 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -386,7 +386,7 @@ void testFormat() " int32_t ahalf = 2468\n" " }\n" " ]\n" - " struct[] more = [null]\n" + " struct[] more = {\?}[]\n" " } array\n" "}\n" ); @@ -417,7 +417,7 @@ void testFormat() "array.choice[1] null\n" "array.choice[2] union\n" "array.choice[2]->two.ahalf int32_t = 2468\n" - "array.more struct[] = [null]\n" + "array.more struct[] = {\?}[]\n" ); } diff --git a/test/testxcode.cpp b/test/testxcode.cpp index b5cc110..6824040 100644 --- a/test/testxcode.cpp +++ b/test/testxcode.cpp @@ -331,7 +331,7 @@ void testDeserialize2() }); testOk1(!val["value"].isMarked()); testOk1(!!val["arbitrary.sarr"].isMarked()); - testEq(val["arbitrary.sarr"].as>().size(), 3u*sizeof(Value)); + testEq(val["arbitrary.sarr"].as>().size(), 3u); testEq(val["arbitrary.sarr[0].value"].as(), 0xdeadbeef); testEq(val["arbitrary.sarr[1]"]["value"].as(), 0x1badfaceu); testEq(val["arbitrary.sarr[2].value"].type(), TypeCode::Null); @@ -358,7 +358,7 @@ void testDeserialize2() }); testOk1(!val["value"].isMarked()); testOk1(!!val["achoice"].isMarked()); - testEq(val["achoice"].as>().size(), 3u*sizeof(Value)); + testEq(val["achoice"].as>().size(), 3u); testEq(val["achoice[0]"].as(), "theX"); testEq(val["achoice[1]"].as(), "theY"); testEq(val["achoice[2]"].type(), TypeCode::Null); @@ -397,7 +397,7 @@ void testDeserialize2() }); testOk1(!val["value"].isMarked()); testOk1(!!val["anya"].isMarked()); - testEq(val["anya"].as>().size(), 3u*sizeof(Value)); + testEq(val["anya"].as>().size(), 3u); testEq(val["anya[0]"].as(), 0x7bu); testEq(val["anya[1].q"].as(), "theq"); testEq(val["anya[2]"].type(), TypeCode::Null);