[vlc-commits] npapi: utils: Introduce a storage policy to be able to wrap NPVariant pointers
Hugo Beauzée-Luyssen
git at videolan.org
Tue Mar 31 10:51:57 CEST 2015
npapi-vlc | branch: cleanup | Hugo Beauzée-Luyssen <hugo at beauzee.fr> | 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);
}
}
More information about the vlc-commits
mailing list