Commit 21cabf32 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

npapi: utils: Introduce a storage policy to be able to wrap NPVariant pointers

parent 4e8989e3
......@@ -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);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment