Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

BREAKING CHG! Major FB::variant refactor, minor behavior change

- FB::variant no longer accepts any type implicitely, only types that it
  "supports"
- To create an FB::variant with an "unsupported" type, construct it
  with FB::variant(value, true); (note the , true boolean parameter)
- To assign an "unsupported" type to an existing FB::variant , use
  the overloaded FB::variant::assign function which takes a bool
  parameter: var.assign(value, true);
- All FB::JSAPI derived types are "supported" when wrapped in
  a boost::shared_ptr, even custom ones
- The only "supported" stl container types are
  FB::VariantMap and FB::VariantList
- convert_cast can be used to convert to any
  FB::JSAPI-derived type wrapped in
  a boost::shared_ptr
- It is now possible to add support for automatic
  conversion of user-supplied types,
  both for implicit conversion to a variant and
  explicit conversion from a variant; however,
  this could take some practice to get working
  right =]
  • Loading branch information...
commit 1af4e1445fda203ca3ee7f1d39634bbd7e0a7d07 1 parent ff17a45
@taxilian taxilian authored
View
17 examples/FBTestPlugin/FBTestPluginAPI.cpp
@@ -19,6 +19,7 @@ Copyright 2009 PacketPass Inc, Georg Fritzsche,
#include "variant_list.h"
#include "FBTestPlugin.h"
#include "SimpleMathAPI.h"
+#include "ThreadRunnerAPI.h"
#include "SimpleStreams.h"
#include "FBTestPluginAPI.h"
@@ -69,7 +70,7 @@ FBTestPluginAPI::FBTestPluginAPI(boost::shared_ptr<FBTestPlugin> plugin, FB::Bro
registerEvent("onfired");
- m_simpleMath = FB::JSAPIPtr(new SimpleMathAPI(m_host));
+ m_simpleMath = boost::make_shared<SimpleMathAPI>(m_host);
}
FBTestPluginAPI::~FBTestPluginAPI()
@@ -253,7 +254,7 @@ FB::VariantMap FBTestPluginAPI::getUserData()
return map;
}
-FB::JSAPIPtr FBTestPluginAPI::get_simpleMath()
+boost::shared_ptr<SimpleMathAPI> FBTestPluginAPI::get_simpleMath()
{
return m_simpleMath;
}
@@ -292,12 +293,12 @@ long FBTestPluginAPI::countArrayLength(const FB::JSObjectPtr &jso)
long len = array.size();// array->GetProperty("length").convert_cast<long>();
return len;
}
-long FBTestPluginAPI::addWithSimpleMath(const FB::JSObjectPtr& jso, long a, long b)
+long FBTestPluginAPI::addWithSimpleMath(const boost::shared_ptr<SimpleMathAPI>& math, long a, long b)
{
- boost::shared_ptr<SimpleMathAPI> math = FB::get_jsapi<SimpleMathAPI>(jso);
- if (!math) {
- throw FB::invalid_arguments("expected SimpleMath object");
- }
-
return math->add(a, b);
}
+
+boost::shared_ptr<ThreadRunnerAPI> FBTestPluginAPI::createThreadRunner()
+{
+ return boost::make_shared<ThreadRunnerAPI>(m_host);
+}
View
15 examples/FBTestPlugin/FBTestPluginAPI.h
@@ -14,13 +14,15 @@ Copyright 2009 PacketPass Inc, Georg Fritzsche,
\**********************************************************/
#include <string>
+#include <boost/shared_ptr.hpp>
#include <sstream>
#include "JSAPIAuto.h"
#include "BrowserHost.h"
#include <boost/weak_ptr.hpp>
-#include "ThreadRunnerAPI.h"
class FBTestPlugin;
+class SimpleMathAPI;
+class ThreadRunnerAPI;
class FBTestPluginAPI : public FB::JSAPIAuto
{
@@ -30,7 +32,7 @@ class FBTestPluginAPI : public FB::JSAPIAuto
boost::shared_ptr<FBTestPlugin> getPlugin();
- FB::JSAPIPtr createThreadRunner() { return FB::JSAPIPtr(new ThreadRunnerAPI(m_host)); }
+ boost::shared_ptr<ThreadRunnerAPI> createThreadRunner();
std::wstring say(const std::wstring& val);
// Read/Write property testString
@@ -40,11 +42,8 @@ class FBTestPluginAPI : public FB::JSAPIAuto
// Read-only property someInt
long get_someInt();
- FB::JSAPIPtr get_simpleMath();
+ boost::shared_ptr<SimpleMathAPI> get_simpleMath();
- FB::JSAPIPtr getTestObj();
- std::string useTestObj(const FB::JSObjectPtr& obj);
-
FB::variant echo(const FB::variant& a);
std::string asString(const FB::variant& a);
@@ -75,11 +74,11 @@ class FBTestPluginAPI : public FB::JSAPIAuto
std::string get_pluginPath();
void eval(std::string str);
- long addWithSimpleMath(const FB::JSObjectPtr& jso, long a, long b);
+ long addWithSimpleMath(const boost::shared_ptr<SimpleMathAPI>& jso, long a, long b);
private:
FB::BrowserHostPtr m_host;
- FB::JSAPIPtr m_simpleMath;
+ boost::shared_ptr<SimpleMathAPI> m_simpleMath;
boost::weak_ptr<FBTestPlugin> m_pluginWeak;
std::string m_testString;
View
4 src/ActiveXCore/JSAPI_IDispatchEx.h
@@ -297,8 +297,8 @@ namespace FB { namespace ActiveX {
bool JSAPI_IDispatchEx<T,IDISP,piid>::callSetEventListener(const std::vector<FB::variant> &args, bool add)
{
if (args.size() < 2 || args.size() > 3
- || args[0].get_type() != typeid(std::string)
- || args[1].get_type() != typeid(FB::JSObjectPtr)) {
+ || !args[0].can_be_type<std::string>()
+ || !args[1].can_be_type<FB::JSObjectPtr>()) {
throw FB::invalid_arguments();
}
View
4 src/ScriptingCore/CMakeLists.txt
@@ -47,9 +47,7 @@ SOURCE_GROUP(Util FILES ${UTILTYPES})
file (GLOB TYPES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
APITypes.*
- variant.*
- variant_list.*
- variant_map.*
+ variant*
TypeIDMap.*
utf8*
URI*
View
2  src/ScriptingCore/CrossThreadCall.cpp
@@ -28,7 +28,7 @@ void CrossThreadCall::syncCallbackFunctor(void *userData)
}
catch(const FB::script_error& e)
{
- call->m_result = new FB::script_error(e.what());
+ call->m_result = variant(new FB::script_error(e.what()), true);
}
call->m_returned = true;
call->m_cond.notify_one();
View
1  src/ScriptingCore/DOM/Document.cpp
@@ -12,6 +12,7 @@ License: Dual license model; choose one of two:
Copyright 2009 PacketPass, Inc and the Firebreath development team
\**********************************************************/
+#include "variant.h"
#include "variant_list.h"
#include "Window.h"
View
3  src/ScriptingCore/JSAPI.h
@@ -567,4 +567,7 @@ namespace FB
const FB::JSAPIPtr ref;
};
};
+
+// There are important conversion routines that require JSObject and JSAPI to both be loaded
+#include "JSObject.h"
#endif
View
2  src/ScriptingCore/JSAPIAuto.cpp
@@ -336,7 +336,7 @@ bool FB::JSAPIAuto::isReserved( const std::string& propertyName ) const
FB::variant FB::JSAPIAuto::getAttribute( const std::string& name )
{
if (m_attributes.find(name) != m_attributes.end()) {
- return m_attributes[name];
+ return m_attributes[name].value;
}
return FB::FBVoid();
}
View
2  src/ScriptingCore/JSEvent.cpp
@@ -25,7 +25,7 @@ FB::VariantMap FB::CreateEvent( const FB::JSAPIPtr& api, const std::string& name
event["bubbles"] = false;
event["cancelable"] = false; // Events in firebreath are async; not cancelable
event["namespaceURI"] = name;
- event["timeStamp"] = FB::FBDateString();
+ //event["timeStamp"] = FB::FBDateString();
// Add the custom members
event.insert(members.begin(), members.end());
View
142 src/ScriptingCore/JSObject.h
@@ -127,8 +127,7 @@ namespace FB
template<class Cont>
void JSObject::GetArrayValues(const FB::JSObjectPtr& src, Cont& dst)
{
- try
- {
+ try {
FB::variant tmp = src->GetProperty("length");
long length = tmp.convert_cast<long>();
std::back_insert_iterator<Cont> inserter(dst);
@@ -137,9 +136,7 @@ namespace FB
tmp = src->GetProperty(i);
*inserter++ = tmp.convert_cast<typename Cont::value_type>();
}
- }
- catch(const FB::script_error& e)
- {
+ } catch(const FB::script_error& e) {
throw e;
}
}
@@ -152,71 +149,116 @@ namespace FB
typedef std::pair<KeyType, MappedType> PairType;
typedef std::vector<std::string> StringVec;
- try
- {
+ try {
StringVec fields;
src->getMemberNames(fields);
std::insert_iterator<Dict> inserter(dst, dst.begin());
- for(StringVec::iterator it = fields.begin(); it != fields.end(); it++)
- {
+ for(StringVec::iterator it = fields.begin(); it != fields.end(); it++) {
FB::variant tmp = src->GetProperty(*it);
*inserter++ = PairType(*it, tmp.convert_cast<MappedType>());
}
- }
- catch (const FB::script_error& e)
- {
+ } catch (const FB::script_error& e) {
throw e;
}
}
- // TODO: this doesn't belong here
- template<class Cont>
- typename FB::meta::enable_for_non_assoc_containers<Cont, const Cont>::type
- variant::convert_cast() const
- {
- typedef FB::JSObjectPtr JsObject;
-
- // if the held data is of type Cont just return it
+ namespace variant_detail { namespace conversion {
+ // Convert in
+ template <class T>
+ typename boost::enable_if<
+ boost::mpl::and_<
+ boost::is_base_of<FB::JSAPI, T>,
+ boost::mpl::not_<boost::is_base_of<FB::JSObject, T> > >
+ ,variant>::type
+ make_variant(const boost::shared_ptr<T>& ptr) {
+ return variant(FB::JSAPIPtr(ptr), true);
+ }
+ template <class T>
+ typename boost::enable_if<boost::is_base_of<FB::JSObject, T>,variant>::type
+ make_variant(const boost::shared_ptr<T>& ptr) {
+ return variant(FB::JSObjectPtr(ptr), true);
+ }
- if(get_type() == typeid(Cont))
- return convert_cast_impl<Cont>();
+ // Convert out
+ template<class T>
+ typename boost::enable_if<boost::is_base_of<FB::JSAPI, T>, boost::shared_ptr<T> >::type
+ convert_variant(const variant& var, variant_detail::conversion::type_spec< boost::shared_ptr<T> >)
+ {
+ FB::JSAPIPtr ptr;
+ // First of all, to succeed it *must* be a JSAPI object!
+ if (var.get_type() == typeid(FB::JSObjectPtr)) {
+ ptr = var.cast<FB::JSObjectPtr>();
+ } else {
+ ptr = var.cast<FB::JSAPIPtr>();
+ }
- // if the help data is not a JavaScript object throw
+ FB::JSObjectPtr jso = FB::ptr_cast<FB::JSObject>(ptr);
+ if (jso) {
+ FB::JSAPIPtr inner = jso->getJSAPI();
+ if (inner) {
+ boost::shared_ptr<T> tmp = FB::ptr_cast<T>(inner);
+ if (tmp) {
+ // Whew! We pulled the JSAPI object out of a JSObject and found what we were
+ // looking for; we always return the inner-most object. Keep that in mind!
+ return tmp;
+ }
+ // If there is an inner object, but it isn't the one we want, fall through
+ }
+ }
+ boost::shared_ptr<T> ret = FB::ptr_cast<T>(ptr);
+ if (ret)
+ return ret;
+ else
+ throw FB::bad_variant_cast(var.get_type(), typeid(T));
+ }
- if(!(get_type() == typeid(JsObject)))
- throw bad_variant_cast(get_type(), typeid(JsObject));
-
- // if it is a JavaScript object try to treat it as an array
+ template<class Cont>
+ typename FB::meta::enable_for_non_assoc_containers<Cont, const Cont>::type
+ convert_variant(const variant& var, variant_detail::conversion::type_spec<Cont>)
+ {
+ typedef FB::JSObjectPtr JsObject;
+
+ // if the held data is of type Cont just return it
- Cont cont;
- FB::JSObject::GetArrayValues(cast<JsObject>(), cont);
- return cont;
- }
+ if(var.is_of_type<Cont>())
+ return var.cast<Cont>();
- // TODO: this doesn't belong here
- template<class Dict>
- typename FB::meta::enable_for_pair_assoc_containers<Dict, const Dict>::type
- variant::convert_cast() const
- {
- typedef FB::JSObjectPtr JsObject;
-
- // if the held data is of type Dict just return it
+ // if the help data is not a JavaScript object throw
+
+ if(!var.can_be_type<JsObject>())
+ throw bad_variant_cast(var.get_type(), typeid(JsObject));
+
+ // if it is a JavaScript object try to treat it as an array
- if(get_type() == typeid(Dict))
- return convert_cast_impl<Dict>();
+ Cont cont;
+ FB::JSObject::GetArrayValues(var.convert_cast<JsObject>(), cont);
+ return cont;
+ }
- // if the help data is not a JavaScript object throw
+ template<class Dict>
+ typename FB::meta::enable_for_pair_assoc_containers<Dict, const Dict>::type
+ convert_variant(const variant& var, variant_detail::conversion::type_spec<Dict>)
+ {
+ typedef FB::JSObjectPtr JsObject;
+
+ // if the held data is of type Dict just return it
- if(!(get_type() == typeid(JsObject)))
- throw bad_variant_cast(get_type(), typeid(JsObject));
-
- // if it is a JavaScript object try to treat it as an array
+ if(var.is_of_type<Dict>())
+ return var.cast<Dict>();
- Dict dict;
- FB::JSObject::GetObjectValues(cast<JsObject>(), dict);
- return dict;
- }
+ // if the help data is not a JavaScript object throw
+
+ if(!var.can_be_type<JsObject>())
+ throw bad_variant_cast(var.get_type(), typeid(JsObject));
+
+ // if it is a JavaScript object try to treat it as an array
+
+ Dict dict;
+ FB::JSObject::GetObjectValues(var.convert_cast<JsObject>(), dict);
+ return dict;
+ }
+ } }
// TODO: this doesn't belong here
View
40 src/ScriptingCore/variant.cpp
@@ -0,0 +1,40 @@
+/**********************************************************\
+Original Author: Richard Bateman (taxilian)
+
+Created: Dec 30, 2011
+License: Dual license model; choose one of two:
+ New BSD License
+ http://www.opensource.org/licenses/bsd-license.php
+ - or -
+ GNU Lesser General Public License, version 2.1
+ http://www.gnu.org/licenses/lgpl-2.1.html
+
+Copyright 2010 Richard Bateman, Firebreath development team
+\**********************************************************/
+
+#include "variant.h"
+
+using FB::variant;
+
+variant FB::variant_detail::conversion::make_variant(const char* x) {
+ return variant(std::string(x), true);
+}
+variant FB::variant_detail::conversion::make_variant(const wchar_t* x) {
+ return variant(std::wstring(x), true);
+}
+///////////////////////////////////////////////////
+// variant convert_cast helpers
+//
+// These functions are called to process any
+// values assigned to the variant. For example,
+// all const char* parameters are converted to
+// std::string
+///////////////////////////////////////////////////
+
+const void FB::variant_detail::conversion::convert_variant(const FB::variant&, const FB::variant_detail::conversion::type_spec<void>&) {
+ return;
+}
+
+const FB::variant& FB::variant_detail::conversion::convert_variant(const FB::variant& var, const FB::variant_detail::conversion::type_spec<FB::variant>&) {
+ return var;
+}
View
323 src/ScriptingCore/variant.h
@@ -26,12 +26,17 @@
#include <sstream>
#include <string>
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/type_traits/is_floating_point.hpp>
+#include <boost/type_traits/is_arithmetic.hpp>
+#include <boost/mpl/or.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/lexical_cast.hpp>
#include "APITypes.h"
#include "Util/meta_util.h"
#include "utf8_tools.h"
+#include "variant_conversions.h"
//#include "JSObject.h"
@@ -41,22 +46,22 @@
#endif
#define FB_BEGIN_CONVERT_MAP(_type_) \
- const std::type_info *type(&get_type()); \
+ const std::type_info *type(&var.get_type()); \
if (*type == typeid(_type_)) { \
- return cast< _type_ >(); \
+ return var.cast< _type_ >(); \
} else
-#define FB_END_CONVERT_MAP(_type_) { throw bad_variant_cast(get_type(), typeid(_type_)); }
+#define FB_END_CONVERT_MAP(_type_) { throw bad_variant_cast(var.get_type(), typeid(_type_)); }
#define FB_END_CONVERT_MAP_NO_THROW(_type_) {}
#define FB_CONVERT_ENTRY_SIMPLE(_type_, _srctype_) \
if ( *type == typeid( _srctype_ ) ) { \
- return static_cast< _type_ >( cast< _srctype_ >() );\
+ return static_cast< _type_ >( var.cast< _srctype_ >() );\
} else
#define FB_CONVERT_ENTRY_COMPLEX_BEGIN(_srctype_, _var_) \
if (*type == typeid(_srctype_)) { \
- _srctype_ _var_ = cast<_srctype_>();
+ _srctype_ _var_ = var.cast<_srctype_>();
#define FB_CONVERT_ENTRY_COMPLEX_END() \
} else
@@ -64,21 +69,21 @@
#define FB_CONVERT_ENTRY_NUMERIC(_type_, _srctype_) \
if (*type == typeid(_srctype_)) { \
try { \
- return boost::numeric_cast<_type_>(cast<_srctype_>());\
+ return boost::numeric_cast<_type_>(var.cast<_srctype_>());\
} catch (const boost::numeric::bad_numeric_cast& ) { \
- throw bad_variant_cast(get_type(), typeid(_type_)); \
+ throw bad_variant_cast(var.get_type(), typeid(_type_)); \
} \
} else
#define FB_CONVERT_ENTRY_FROM_STRING(_type_, _srctype_) \
if (*type == typeid(_srctype_)) { \
typedef _srctype_::value_type char_type; \
- std::basic_istringstream<char_type> iss(cast<_srctype_>()); \
+ std::basic_istringstream<char_type> iss(var.cast<_srctype_>()); \
_type_ to; \
if (iss >> to) { \
return to; \
} else { \
- throw bad_variant_cast(get_type(), typeid(_type_)); \
+ throw bad_variant_cast(var.get_type(), typeid(_type_)); \
} \
} else
@@ -86,10 +91,10 @@
if (*type == typeid(_srctype_)) { \
typedef _type_::value_type char_type; \
std::basic_ostringstream<char_type> oss; \
- if (oss << cast<_srctype_>()) { \
+ if (oss << var.cast<_srctype_>()) { \
return oss.str(); \
} else { \
- throw bad_variant_cast(get_type(), typeid(_type_)); \
+ throw bad_variant_cast(var.get_type(), typeid(_type_)); \
} \
} else
@@ -224,6 +229,11 @@ namespace FB
};
} // namespace variant_detail
+ class variant;
+
+ template <class T>
+ variant make_variant(T t);
+
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @class variant
///
@@ -264,37 +274,14 @@ namespace FB
/// @param x The value
////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename T>
- variant(const T& x) {
- table = variant_detail::get_table<T>::get();
- if (sizeof(T) <= sizeof(void*)) {
- new(&object) T(x);
- }
- else {
- object = new T(x);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- /// @fn variant::variant(const wchar_t *x)
- ///
- /// @brief Constructor with a wide string.
- ///
- /// @param x The string value
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- variant(const wchar_t *x) {
+ variant(const T& x, bool) {
table = variant_detail::get_table<variant_detail::empty>::get();
object = NULL;
- assign(x);
+ assign(x, true);
}
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- /// @fn variant::variant(const char *x)
- ///
- /// @brief Constructor with a string.
- ///
- /// @param x The string value
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- variant(const char *x) {
+ template <typename T>
+ variant(const T& x) {
table = variant_detail::get_table<variant_detail::empty>::get();
object = NULL;
assign(x);
@@ -353,30 +340,24 @@ namespace FB
return *this;
}
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- /// @fn variant& variant::assign(const char *x)
- ///
- /// @brief Assigns a string value as a std::string from a const char*
- ///
- /// @param x The string value
- ///
- /// @return *this
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- variant& assign(const char *x) {
- return assign(std::string(x));
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- /// @fn variant& variant::assign(const wchar_t *x)
- ///
- /// @brief Assigns a wide string value as a std::wstring from a const wchar_t*
- ///
- /// @param x The string value
- ///
- /// @return *this
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- variant& assign(const wchar_t *x) {
- return assign(std::wstring(x));
+ template<class T>
+ variant& assign(const T x) {
+ *this = make_variant(x);
+ // If you get an error that there are no overloads that could convert all the argument
+ // types for this line, you are trying to use a type that is not known to FireBreath.
+ // First, make sure you really want to use this type! If you aren't doing this on
+ // purpose, double check your type, because it's wrong!
+ //
+ // Alternately, if you mean to do this there are two options:
+ // 1. You can create a variant or call .assign on a variant with a second bool
+ // parameter, like so:
+ // FB::variant tmp((void*)0x12, true); // Forces creation with unknown type
+ // tmp.assign((int*)0x32, true); // Forces assignment of unknown type
+ //
+ // 2. You could either create your own assignment function by either overriding
+ // FB::make_variant or FB::variant_detail::conversion::make_variant.
+ //
+ return *this;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -389,7 +370,7 @@ namespace FB
/// @return *this
////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename T>
- variant& assign(const T& x)
+ variant& assign(const T& x, bool)
{
// are we copying between the same type?
variant_detail::fxn_ptr_table* x_table = variant_detail::get_table<T>::get();
@@ -483,6 +464,34 @@ namespace FB
/// @return true if of type, false if not.
////////////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
+ bool can_be_type() const {
+ if (get_type() == typeid(T))
+ return true;
+ try {
+ // See if it can be that type by converting
+ convert_cast<T>();
+ return true;
+ } catch (...) {
+ return false;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ /// @fn template<typename T> bool variant::is_of_type() const
+ ///
+ /// @brief Query if this object is of a particular type.
+ ///
+ /// Example:
+ /// @code
+ /// if (value.is_of_type<int>())
+ /// {
+ /// // Do something
+ /// }
+ /// @endcode
+ ///
+ /// @return true if of type, false if not.
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ template<typename T>
bool is_of_type() const {
return (get_type() == typeid(T));
}
@@ -526,24 +535,8 @@ namespace FB
///
/// @return converted value of the specified type
////////////////////////////////////////////////////////////////////////////////////////////////////
- template<typename T>
- typename FB::meta::disable_for_containers_and_numbers<T, const T>::type
- convert_cast() const
- {
- return convert_cast_impl<T>();
- }
-
- template<class T>
- typename FB::meta::enable_for_numbers<T, T>::type
- convert_cast() const;
-
- template<class Cont>
- typename FB::meta::enable_for_non_assoc_containers<Cont, const Cont>::type
- convert_cast() const;
-
- template<class Dict>
- typename FB::meta::enable_for_pair_assoc_containers<Dict, const Dict>::type
- convert_cast() const;
+ template<typename T>
+ const T convert_cast() const;
////////////////////////////////////////////////////////////////////////////////////////////////////
/// @fn bool variant::empty() const
@@ -577,21 +570,6 @@ namespace FB
object = NULL;
}
- // boost::any-like casting
- template<typename T>
- inline T* variant_cast()
- {
- if (get_type() != typeid(T)) {
- throw bad_variant_cast(get_type(), typeid(T));
- }
- if (sizeof(T) <= sizeof(void*)) {
- return reinterpret_cast<T*>(&object);
- }
- else {
- return reinterpret_cast<T*>(object);
- }
- }
-
private:
template<typename T>
const T convert_cast_impl() const {
@@ -603,54 +581,9 @@ namespace FB
void* object;
};
- // boost::any-like casting
- template<typename T>
- inline T* variant_cast(variant* v) {
- return v->variant_cast<T>();
- }
-
- template<typename T>
- inline T const* variant_cast(variant const* v) {
- return variant_cast<T>(const_cast<variant*>(v));
- }
-
- template<typename T>
- inline T const& variant_cast(variant const& v){
- return *variant_cast<T>(const_cast<variant*>(&v));
- }
-
- template<> inline const void variant::convert_cast_impl<void>() const {
- return;
- }
-
- template<> inline const variant variant::convert_cast_impl<variant>() const {
- return *this;
- }
-
- template<class T>
- inline typename FB::meta::enable_for_numbers<T, T>::type
- variant::convert_cast() const {
- FB_BEGIN_CONVERT_MAP(T)
- FB_CONVERT_ENTRY_NUMERIC(T, char)
- FB_CONVERT_ENTRY_NUMERIC(T, unsigned char)
- FB_CONVERT_ENTRY_NUMERIC(T, short)
- FB_CONVERT_ENTRY_NUMERIC(T, unsigned short)
- FB_CONVERT_ENTRY_NUMERIC(T, int)
- FB_CONVERT_ENTRY_NUMERIC(T, unsigned int)
- FB_CONVERT_ENTRY_NUMERIC(T, long)
- FB_CONVERT_ENTRY_NUMERIC(T, unsigned long)
- FB_CONVERT_ENTRY_NUMERIC(T, float)
- FB_CONVERT_ENTRY_NUMERIC(T, double)
- FB_CONVERT_ENTRY_COMPLEX_BEGIN(bool, bval);
- // we handle bool here specifically because the numeric_cast produces warnings
- return static_cast<T>(bval ? 1 : 0);
- FB_CONVERT_ENTRY_COMPLEX_END();
- FB_CONVERT_ENTRY_FROM_STRING(T, std::string)
- FB_CONVERT_ENTRY_FROM_STRING(T, std::wstring)
- FB_END_CONVERT_MAP(T)
- }
-
- template<> inline const std::string variant::convert_cast_impl<std::string>() const {
+ template <>
+ inline const std::string variant::convert_cast<std::string>() const {
+ variant var = *this;
FB_BEGIN_CONVERT_MAP(std::string);
FB_CONVERT_ENTRY_TO_STRING(double);
FB_CONVERT_ENTRY_TO_STRING(float);
@@ -673,7 +606,9 @@ namespace FB
FB_END_CONVERT_MAP(std::string);
}
- template<> inline const std::wstring variant::convert_cast_impl<std::wstring>() const {
+ template<>
+ inline const std::wstring variant::convert_cast<std::wstring>() const {
+ variant var = *this;
FB_BEGIN_CONVERT_MAP(std::wstring);
FB_CONVERT_ENTRY_TO_WSTRING(double);
FB_CONVERT_ENTRY_TO_WSTRING(float);
@@ -694,7 +629,9 @@ namespace FB
FB_END_CONVERT_MAP(std::wstring);
}
- template<> inline const bool variant::convert_cast_impl<bool>() const {
+ template<>
+ inline const bool variant::convert_cast<bool>() const {
+ variant var = *this;
FB_BEGIN_CONVERT_MAP(bool);
FB_CONVERT_ENTRY_COMPLEX_BEGIN(std::string, str);
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
@@ -706,7 +643,99 @@ namespace FB
FB_CONVERT_ENTRY_COMPLEX_END();
FB_END_CONVERT_MAP_NO_THROW(short);
- return convert_cast_impl<long>();
+ return convert_cast<long>();
+ }
+
+ namespace variant_detail {
+ namespace conversion {
+ ///////////////////////////////////////////////////
+ // variant assign conversion functions
+ //
+ // These functions are called to process any
+ // values assigned to the variant. For example,
+ // all const char* parameters are converted to
+ // std::string
+ ///////////////////////////////////////////////////
+ template <class T>
+ typename boost::enable_if<
+ boost::mpl::or_<
+ boost::mpl::or_<
+ boost::mpl::or_<
+ boost::is_same<std::vector<variant>, T>,
+ boost::is_same<std::map<std::string, variant>, T>
+ >,
+ boost::mpl::or_<
+ boost::is_same<std::wstring, T>,
+ boost::is_same<std::string, T>
+ >
+ >,
+ boost::mpl::or_<
+ boost::is_same<variant_detail::empty, T>,
+ boost::is_same<variant_detail::null, T>
+ >
+ >, variant>::type
+ make_variant(const T& t) {
+ return variant(t, true);
+ }
+
+ template <class T>
+ typename boost::enable_if<boost::is_arithmetic<T>, variant>::type
+ make_variant(const T t) {
+ return variant(t, true);
+ }
+
+ variant make_variant(const char* x);
+ variant make_variant(const wchar_t* x);
+ ///////////////////////////////////////////////////
+ // variant convert_cast helpers
+ //
+ // These functions are called to process any
+ // values assigned to the variant. For example,
+ // all const char* parameters are converted to
+ // std::string
+ ///////////////////////////////////////////////////
+
+ const void convert_variant(const variant&, const variant_detail::conversion::type_spec<void>&);
+ const variant& convert_variant(const variant& var, const variant_detail::conversion::type_spec<variant>&);
+
+ template<typename T>
+ typename FB::meta::enable_for_numbers<T, T>::type
+ convert_variant(const variant& var, const variant_detail::conversion::type_spec<T>&) {
+ FB_BEGIN_CONVERT_MAP(T)
+ FB_CONVERT_ENTRY_NUMERIC(T, char)
+ FB_CONVERT_ENTRY_NUMERIC(T, unsigned char)
+ FB_CONVERT_ENTRY_NUMERIC(T, short)
+ FB_CONVERT_ENTRY_NUMERIC(T, unsigned short)
+ FB_CONVERT_ENTRY_NUMERIC(T, int)
+ FB_CONVERT_ENTRY_NUMERIC(T, unsigned int)
+ FB_CONVERT_ENTRY_NUMERIC(T, long)
+ FB_CONVERT_ENTRY_NUMERIC(T, unsigned long)
+ FB_CONVERT_ENTRY_NUMERIC(T, long long)
+ FB_CONVERT_ENTRY_NUMERIC(T, unsigned long long)
+ FB_CONVERT_ENTRY_NUMERIC(T, float)
+ FB_CONVERT_ENTRY_NUMERIC(T, double)
+ FB_CONVERT_ENTRY_COMPLEX_BEGIN(bool, bval);
+ // we handle bool here specifically because the numeric_cast produces warnings
+ return static_cast<T>(bval ? 1 : 0);
+ FB_CONVERT_ENTRY_COMPLEX_END();
+ FB_CONVERT_ENTRY_FROM_STRING(T, std::string)
+ FB_CONVERT_ENTRY_FROM_STRING(T, std::wstring)
+ FB_END_CONVERT_MAP(T)
+ }
+ }
+ }
+ template<typename T>
+ const T variant::convert_cast() const
+ {
+ return variant_detail::conversion::convert_variant(*this, variant_detail::conversion::type_spec<T>());
+ }
+ template <class T>
+ variant make_variant(T t)
+ {
+ // If you got an error on this line, you are trying to assign an unsupported type to
+ // FB::variant! If you're certain you want to do this then you should use the constructor
+ // or assign method that takes a bool. e.g.: variant tmp(myWeirdType, true);
+ return variant_detail::conversion::make_variant(t);
}
}
View
52 src/ScriptingCore/variant_conversions.h
@@ -0,0 +1,52 @@
+/**********************************************************\
+ Original Author: Richard Bateman
+
+ Created: Dec 30, 2010
+ License: Dual license model; choose one of two:
+ New BSD License
+ http://www.opensource.org/licenses/bsd-license.php
+ - or -
+ GNU Lesser General Public License, version 2.1
+ http://www.gnu.org/licenses/lgpl-2.1.html
+
+ Copyright 2009 Richard Bateman, Firebreath development team
+\**********************************************************/
+
+#include <boost/shared_ptr.hpp>
+
+namespace FB {
+ class variant;
+ class JSAPI;
+ class JSObject;
+ namespace variant_detail {
+ namespace conversion {
+ template <class T>
+ struct type_spec
+ {};
+
+ template <class T>
+ typename boost::enable_if<
+ boost::mpl::and_<
+ boost::is_base_of<FB::JSAPI, T>,
+ boost::mpl::not_<boost::is_base_of<FB::JSObject, T> > >
+ ,variant>::type
+ make_variant(const boost::shared_ptr<T>& ptr);
+
+ template <class T>
+ typename boost::enable_if<boost::is_base_of<FB::JSObject, T>,variant>::type
+ make_variant(const boost::shared_ptr<T>& ptr);
+
+ template<class T>
+ typename boost::enable_if<boost::is_base_of<FB::JSAPI, T>, boost::shared_ptr<T> >::type
+ convert_variant(const variant& var, variant_detail::conversion::type_spec< boost::shared_ptr<T> >);
+
+ template<class Cont>
+ typename FB::meta::enable_for_non_assoc_containers<Cont, const Cont>::type
+ convert_variant(const variant& var, type_spec<Cont>);
+
+ template<class Dict>
+ typename FB::meta::enable_for_pair_assoc_containers<Dict, const Dict>::type
+ convert_variant(const variant& var, type_spec<Dict>);
+ }
+ }
+}
View
5 tests/ScriptingCoreTest/CMakeLists.txt
@@ -46,11 +46,6 @@ set (SOURCES
add_executable(${PROJNAME} ${SOURCES})
-add_dependencies(${PROJNAME}
- ScriptingCore
- UnitTest++
- )
-
target_link_libraries (${PROJNAME}
ScriptingCore
UnitTest++
View
5 tests/ScriptingCoreTest/jsapiauto_test.h
@@ -150,7 +150,7 @@ TEST(JSAPIAuto_Methods)
{
// Test variant parameter type
const std::string method("getType");
- CHECK(test->HasMethod(method));
+ CHECK(test->HasMethod(method));
FB::variant ret = test->Invoke(method, FB::variant_list_of((long)12));
CHECK(ret.cast<std::string>() == typeid(long).name());
@@ -161,7 +161,8 @@ TEST(JSAPIAuto_Methods)
ret = test->Invoke(method, FB::variant_list_of((bool)true));
CHECK(ret.cast<std::string>() == typeid(bool).name());
- ret = test->Invoke(method, FB::variant_list_of((void *)0x12));
+ // Test explicit assignment
+ ret = test->Invoke(method, FB::variant_list_of(FB::variant((void *)0x12, true)));
CHECK(ret.cast<std::string>() == typeid(void*).name());
}
Please sign in to comment.
Something went wrong with that request. Please try again.