npapi-vlc | branch: cleanup | Hugo Beauzée-Luyssen <[email protected]> | Fri Mar 27 17:48:16 2015 +0100| [21cabf32ccfa017ea3631d508893ac43dc77fd9a] | committer: Hugo Beauzée-Luyssen
npapi: utils: Introduce a storage policy to be able to wrap NPVariant pointers > http://git.videolan.org/gitweb.cgi/npapi-vlc.git/?a=commit;h=21cabf32ccfa017ea3631d508893ac43dc77fd9a --- npapi/utils.hpp | 225 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 178 insertions(+), 47 deletions(-) diff --git a/npapi/utils.hpp b/npapi/utils.hpp index 5298ee1..e4cb76e 100644 --- a/npapi/utils.hpp +++ b/npapi/utils.hpp @@ -44,7 +44,7 @@ namespace details template <typename T> using PointerLess = typename std::remove_pointer<T>::type; - // Remove the const & volatile + // Remove const and volatile template <typename T> using Decayed = typename std::remove_cv<PointerLess<T>>::type; } @@ -272,6 +272,11 @@ struct traits<NPString> static void from( NPString s, NPVariant& v ) { + if ( s.UTF8Characters == nullptr ) + { + NULL_TO_NPVARIANT( v ); + return; + } auto raw = strdup( s.UTF8Characters ); STRINGZ_TO_NPVARIANT( raw, v ); } @@ -290,8 +295,13 @@ struct traits<NPUTF8*> return to_tmp_string( v ); } - static void from( const char* str, NPVariant& v ) + static void from( const NPUTF8* str, NPVariant& v ) { + if ( str == nullptr ) + { + NULL_TO_NPVARIANT( v ); + return; + } auto copy = strdup( str ); STRINGZ_TO_NPVARIANT( copy, v ); } @@ -317,38 +327,157 @@ struct traits<std::string> } }; -// This needs to be the exact size of a NPVariant -// That means no smart pointer, no virtual function, just -// good old functions to wrap a type. -class Variant +namespace details { -public: - Variant() - : m_variant{} +namespace policy +{ +struct Embeded +{ + using VariantType = NPVariant; + + Embeded() + { + memset( &v, 0, sizeof( v ) ); + } + + Embeded( const Embeded& ) = default; + + // Allow btiwise copy, assuming that the called has handled releasing + // previously held resources + Embeded& operator=( const Embeded& ) = default; + + Embeded( Embeded&& e ) + { + v = e.v; + memset( &e.v, 0, sizeof( e.v ) ); + } + + Embeded( const NPVariant& npv ) { - memset( &m_variant, 0, sizeof( m_variant ) ); + memcpy( &v, &npv, sizeof( npv ) ); } - Variant( const NPVariant& v ) + Embeded& operator=( const NPVariant& npv ) + { + memcpy( &v, &npv, sizeof( npv ) ); + return *this; + } + + ~Embeded() + { + NPN_ReleaseVariantValue( &v ); + } + + NPVariant* ptr() + { + return &v; + } + + const NPVariant* ptr() const + { + return &v; + } + + NPVariant& ref() + { + return v; + } + + const NPVariant& ref() const + { + return v; + } + + NPVariant v; +}; + +/// +/// \brief This storage policy is meant to wrap an output variant. +/// This means we don't have to release the content upon destruction, and mostly +/// care about storing a pointer upon construction. +/// +struct Wrapped +{ + using VariantType = NPVariant*; + + Wrapped() = default; + + Wrapped( NPVariant* vt ) + : v( vt ) + { + memset( v, 0, sizeof( *v ) ); + } + + // We don't want to release anything, as NPAPI will use the Wrapped NPVariant + // we are currently writing to. + ~Wrapped() = default; + + Wrapped( const Wrapped& ) = delete; + Wrapped& operator=( const Wrapped& ) = delete; + + Wrapped(Wrapped&& w) + { + *this = std::move( w ); + } + + Wrapped& operator=( Wrapped&& w ) + { + v = w.v; + w.v = nullptr; + return *this; + } + + NPVariant* ptr() + { + return v; + } + + const NPVariant* ptr() const + { + return v; + } + + NPVariant& ref() + { + return *v; + } + + const NPVariant& ref() const + { + return *v; + } + + NPVariant* v; +}; + +} + +template <typename StoragePolicy = details::policy::Embeded> +class Variant +{ +public: + Variant() = default; + // Let the storage policy handle the resources release. + ~Variant() = default; + + //FIXME: This results in a reference to pointer for the Wrapped policy. + // That's an unneeded indirection + Variant( const typename StoragePolicy::VariantType& v ) : m_variant( v ) { - if (is<NPString>() ) - traits<NPString>::from( (NPString)*this, m_variant ); - else if ( is<NPObject>() ) - traits<NPObject>::from( (NPObject*)*this, m_variant ); + retainOrCopy(); } Variant(const Variant& v) + : m_variant( v.m_variant ) { - memset( &m_variant, 0, sizeof( m_variant ) ); - *this = v; + retainOrCopy(); } template <typename T> - Variant(const T& t) + explicit Variant(const T& t) { - memset( &m_variant, 0, sizeof( m_variant ) ); - traits<TraitsType<T>>::from( t, m_variant ); + traits<TraitsType<T>>::from( t, m_variant.ref() ); } Variant& operator=(const Variant& v) @@ -356,35 +485,27 @@ public: if ( &v == this ) return *this; release(); - if (v.is<NPString>()) - { - traits<NPString>::from( (NPString)v, m_variant ); - return *this; - } + m_variant = v.m_variant; - if (v.is<NPObject>()) - NPN_RetainObject( *this ); + retainOrCopy(); + return *this; } - Variant(Variant&& v) - { - m_variant = v.m_variant; - memset( &v.m_variant, 0, sizeof( v.m_variant ) ); - } + Variant(Variant&& v) = default; Variant& operator=(Variant&& v) { release(); - m_variant = v.m_variant; - memset( &v.m_variant, 0, sizeof( v.m_variant ) ); + m_variant = std::move( v.m_variant ); + return *this; } template <typename T> bool is() const { - return traits<TraitsType<T>>::is( m_variant ); + return traits<TraitsType<T>>::is( m_variant.ref() ); } // /!\ Warning /!\ This does not retain the value for strings & objects @@ -393,23 +514,23 @@ public: template <typename T> operator T() const { - assert(traits<TraitsType<T>>::is( m_variant )); - return traits<TraitsType<T>>::to( m_variant ); + assert(traits<TraitsType<T>>::is( m_variant.ref() )); + return traits<TraitsType<T>>::to( m_variant.ref() ); } operator const NPVariant() const { - return m_variant; + return m_variant.ref(); } operator const NPVariant*() const { - return &m_variant; + return m_variant.ptr(); } operator NPVariant*() { - return &m_variant; + return m_variant.ptr(); } template <typename T> @@ -436,20 +557,28 @@ public: return (const T)*this >= rhs; } - ~Variant() + void release() { - release(); + NPN_ReleaseVariantValue( m_variant.ptr() ); } - void release() +private: + void retainOrCopy() { - NPN_ReleaseVariantValue( &m_variant ); + if (is<NPObject>()) + NPN_RetainObject( *this ); + else if (is<NPString>()) + traits<NPString>::from( (NPString)*this, m_variant.ref() ); } private: - NPVariant m_variant; + StoragePolicy m_variant; }; +} + +using Variant = details::Variant<>; + class VariantArray { using VPtr = std::unique_ptr<Variant[]>; @@ -504,14 +633,16 @@ namespace details template <size_t Idx, typename T> void wrap( VariantArray& array, T arg ) { - array[Idx] = Variant(arg); + array[Idx] = Variant<details::policy::Embeded>(arg); } template <size_t Idx, typename T, typename... Args> void wrap( VariantArray& array, T arg, Args&&... args ) { wrap<Idx + 1>( array, std::forward<Args>( args )... ); - array[Idx] = Variant(arg); + // This needs the Variant wrapper to be the exact size of a NPVariant + // For future proofness, we make this explicit: + array[Idx] = Variant<details::policy::Embeded>(arg); } } _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
