From 7de37e57bcb70f517ceb15cd72de4d3cc71edd9c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Sep 2017 11:29:17 -0500 Subject: [PATCH] more AnyScalar --- common/anyscalar.h | 57 ++++++++++++++++++++++++++++----------- testApp/testanyscalar.cpp | 46 ++++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/common/anyscalar.h b/common/anyscalar.h index b82e051..f818f9f 100644 --- a/common/anyscalar.h +++ b/common/anyscalar.h @@ -17,9 +17,12 @@ namespace detail { -// special mangling for AnyScalar ctor to map from argument type to storage type +// special mangling for AnyScalar ctor to map from argument type to storage type. +// allow construction from constants. template struct any_storage_type { typedef T type; }; +template<> struct any_storage_type { typedef epics::pvData::int32 type; }; +template<> struct any_storage_type { typedef epics::pvData::uint32 type; }; template<> struct any_storage_type { typedef std::string type; }; template<> struct any_storage_type { typedef std::string type; }; @@ -53,12 +56,17 @@ private: typename std::aligned_storage::type blob[1]; } _wrap; #else - union wrap_t { - char blob[sizeof(std::string)]; - double align_f; // assume std::string alignment <= 8 + struct wrap_t { + union blob_t { + char data[sizeof(std::string)]; + double align_f; // assume std::string alignment <= 8 + } blob[1]; } _wrap; #endif + // assumed largest non-string type + typedef double _largest_blob; + template inline T& _as() { return *reinterpret_cast(_wrap.blob); @@ -90,8 +98,8 @@ public: { if(o._stype==epics::pvData::pvString) { new (_wrap.blob) std::string(o._as()); - } else { - memcpy(_wrap.blob, o._wrap.blob, sizeof(_wrap.blob)); + } else if(o._stype!=(ScalarType)-1) { + memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob)); } } @@ -99,10 +107,13 @@ public: AnyScalar(AnyScalar&& o) :_stype(o._stype) { + typedef std::string string; if(o._stype==epics::pvData::pvString) { + new (_wrap.blob) std::string(); _as() = std::move(o._as()); - } else { - memcpy(_wrap.blob, o._wrap.blob, sizeof(_wrap.blob)); + o._as().~string(); + } else if(o._stype!=(ScalarType)-1) { + memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob)); } o._stype = (ScalarType)-1; } @@ -111,7 +122,7 @@ public: ~AnyScalar() { if(_stype==epics::pvData::pvString) { typedef std::string string; - (&_as())->~string(); + _as().~string(); } // other types need no cleanup } @@ -127,7 +138,19 @@ public: return *this; } - inline void swap(AnyScalar& o) { +#if __cplusplus>=201103L + AnyScalar& operator=(AnyScalar&& o) { + if(_stype==epics::pvData::pvString) { + typedef std::string string; + _as().~string(); + } + _stype = (ScalarType)-1; + swap(o); + return *this; + } +#endif + + void swap(AnyScalar& o) { typedef std::string string; switch((unsigned)_stype) { case -1: @@ -143,7 +166,7 @@ public: break; default: // nil <-> non-string - memcpy(_wrap.blob, o._wrap.blob, sizeof(_wrap.blob)); + memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob)); break; } break; @@ -166,7 +189,7 @@ public: _as().~string(); - memcpy(_wrap.blob, o._wrap.blob, sizeof(_wrap.blob)); + memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob)); new (o._wrap.blob) std::string(); temp.swap(o._as()); @@ -178,7 +201,7 @@ public: switch((unsigned)o._stype) { case -1: // non-string <-> nil - memcpy(o._wrap.blob, _wrap.blob, sizeof(_wrap.blob)); + memcpy(o._wrap.blob, _wrap.blob, sizeof(_largest_blob)); break; case epics::pvData::pvString: { // non-string <-> string @@ -187,7 +210,7 @@ public: o._as().~string(); - memcpy(o._wrap.blob, _wrap.blob, sizeof(_wrap.blob)); + memcpy(o._wrap.blob, _wrap.blob, sizeof(_largest_blob)); new (_wrap.blob) std::string(); temp.swap(_as()); @@ -195,7 +218,11 @@ public: break; default: // non-string <-> non-string - std::swap(o._wrap.blob, _wrap.blob); + _largest_blob temp; + memcpy(&temp, _wrap.blob, sizeof(_largest_blob)); + memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob)); + memcpy(o._wrap.blob, &temp, sizeof(_largest_blob)); + // std::swap(o._wrap.blob, _wrap.blob); // gcc <=4.3 doesn't like this break; } break; diff --git a/testApp/testanyscalar.cpp b/testApp/testanyscalar.cpp index f20f67e..2bc14ce 100644 --- a/testApp/testanyscalar.cpp +++ b/testApp/testanyscalar.cpp @@ -166,16 +166,60 @@ void test_swap() } } +void test_move() +{ + testDiag("test_move()"); +#if __cplusplus>=201103L + { + AnyScalar x, y(std::move(x)); + testOk1(x.empty()); + testOk1(y.empty()); + } + { + AnyScalar x(5), y(std::move(x)); + testOk1(x.empty()); + testEqual(y.ref(), 5); + } + { + AnyScalar x("hello"), y(std::move(x)); + testOk1(x.empty()); + testEqual(y.ref(), "hello"); + } + + { + AnyScalar x, y; + y = std::move(x); + testOk1(x.empty()); + testOk1(y.empty()); + } + { + AnyScalar x, y(5); + y = std::move(x); + testOk1(x.empty()); + testOk1(y.empty()); + } + { + AnyScalar x, y("test"); + y = std::move(x); + testOk1(x.empty()); + testOk1(y.empty()); + } +#else + testSkip(12, "No c++11"); +#endif } +} // namespace + MAIN(testanyscalar) { - testPlan(54); + testPlan(66); try { test_empty(); test_ctor(); test_basic(); test_swap(); + test_move(); }catch(std::exception& e){ testAbort("Unexpected exception: %s", e.what()); }