/* Mantra - http://www.neuromancy.net/mantra * (c) 2007-2009 - The Neuromancy Society * * This code is released under the Artistic License 2.0. If you have not * received a copy of the license with this source code, you may find * this license at: * http://www.opensource.org/licenses/artistic-license-2.0.php * * $Id: dynarg.h 619 2010-03-12 00:42:11Z prez $ */ #ifndef MANTRA_TRACE_DYNARG_H #define MANTRA_TRACE_DYNARG_H 1 #ifdef ENABLE_MANTRA_TRACE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_NO_IS_ABSTRACT # include #else # include # include #endif namespace mantra { namespace trace { #define DECLARE_ARG(x) \ explicit dynamic_arg(x &in); \ explicit dynamic_arg(const x &in); #define DECLARE_TPL_ARG(x,y) \ template \ explicit dynamic_arg(y &in); \ template \ explicit dynamic_arg(const y &in); class dynamic_arg { public: dynamic_arg() {} // We need an explicit copy constructor so we don't use the templates below. explicit dynamic_arg(dynamic_arg &in); explicit dynamic_arg(const dynamic_arg &in); // All types ... template dynamic_arg(T &in); template dynamic_arg(const T &in); // Specializations for 'char', mainly because its used so often. explicit dynamic_arg(char *in); explicit dynamic_arg(const char *in); // And specializations for string and format ... DECLARE_TPL_ARG(3, std::basic_string) DECLARE_TPL_ARG(3, boost::basic_format) // In this case we want the actual pointer to show ... DECLARE_TPL_ARG(1, std::auto_ptr) DECLARE_TPL_ARG(1, mantra::auto_ptr) DECLARE_TPL_ARG(1, boost::shared_ptr) DECLARE_TPL_ARG(1, boost::scoped_ptr) DECLARE_TPL_ARG(1, boost::intrusive_ptr) DECLARE_TPL_ARG(1, boost::function) // Its nice to see both arguments. // Maybe one day I'll do boost::tuple too. DECLARE_TPL_ARG(2, std::pair) DECLARE_TPL_ARG(1, boost::optional) // Only have specializations for containers where size() is O(1) DECLARE_TPL_ARG(2, std::vector) DECLARE_TPL_ARG(2, std::deque) DECLARE_TPL_ARG(3, std::set) DECLARE_TPL_ARG(4, std::map) DECLARE_TPL_ARG(3, std::multiset) DECLARE_TPL_ARG(4, std::multimap) const std::string &type() const; const std::string &arg() const; private: std::string type_; std::string arg_; template void assign1(const char *type, const T &value); template void assign1(const char *type, const T &value, boost::mpl::bool_); template void assign1(const char *type, const T &value, boost::mpl::bool_); template void assign2(const char *type, const T *value); template void assign(T &in, boost::mpl::bool_); template void assign(T &in, boost::mpl::bool_); template void assign(T *in, boost::mpl::bool_); }; #undef DECLARE_ARG #undef DECLARE_TPL_ARG // --------------------------------------------------------------------------- // Inline Functions // --------------------------------------------------------------------------- inline dynamic_arg::dynamic_arg(dynamic_arg &in) : type_(in.type_), arg_(in.arg_) { } inline dynamic_arg::dynamic_arg(const dynamic_arg &in) : type_(in.type_), arg_(in.arg_) { } template inline void dynamic_arg::assign1(const char *type, const T &value) { assign1(type, value, boost::mpl::bool_::value>()); } template inline void dynamic_arg::assign1(const char *type, const T &value, boost::mpl::bool_) { // This should only be called for enums. Some compilers kick // out a warning about choosing int over unsigned int, etc. // This function just ensures int is not an ambiguous choice, // and passes it through. assign1(type, static_cast(value), boost::mpl::bool_()); } template inline void dynamic_arg::assign1(const char *type, const T &value, boost::mpl::bool_) { type_ = type; std::ostringstream tmp; tmp.flags(tmp.flags() | std::ios_base::boolalpha); tmp << value; arg_ = tmp.str(); } template inline void dynamic_arg::assign2(const char *type, const T *value) { type_ = type; std::ostringstream tmp; tmp.flags(tmp.flags() | std::ios_base::boolalpha); tmp << "0x" << std::setw(sizeof(long int)*2) << std::setfill('0') << std::hex << reinterpret_cast(value); arg_ = tmp.str(); } template inline void dynamic_arg::assign(T &in, boost::mpl::bool_) { assign1(type_id().name(), in); } template inline void dynamic_arg::assign(T &in, boost::mpl::bool_) { assign2(type_id().name(), &in); } template inline void dynamic_arg::assign(T *in, boost::mpl::bool_) { assign2(type_id().name(), in); } template inline dynamic_arg::dynamic_arg(T &in) { #ifdef BOOST_NO_IS_ABSTRACT assign(in, boost::mpl::bool_, boost::is_enum >::value>()); #else assign(in, boost::mpl::bool_ >, boost::has_left_shift_op >::value>()); #endif } template inline dynamic_arg::dynamic_arg(const T &in) { #ifdef BOOST_NO_IS_ABSTRACT assign(in, boost::mpl::bool_, boost::is_enum >::value>()); #else assign(in, boost::mpl::bool_ >, boost::has_left_shift_op >::value>()); #endif } inline dynamic_arg::dynamic_arg(char *in) { assign1(static_cast("char *"), in ? in : ""); } inline dynamic_arg::dynamic_arg(const char *in) { assign1(static_cast("const char *"), in ? in : ""); } #define DEFINE_ARG_PTR(x) \ template \ inline dynamic_arg::dynamic_arg(x &in) \ { assign2(type_id >().name(), in.get()); } \ template \ inline dynamic_arg::dynamic_arg(const x &in) \ { assign2(type_id >().name(), in.get()); } #define DEFINE_ARG_SIZE(x,y) \ template \ inline dynamic_arg::dynamic_arg(y &in) \ { assign1(type_id >().name(), in.size()); } \ template \ inline dynamic_arg::dynamic_arg(const y &in) \ { assign1(type_id >().name(), in.size()); } template inline dynamic_arg::dynamic_arg(std::basic_string &in) { assign1(type_id >().name(), convert_string(in)); } template inline dynamic_arg::dynamic_arg(const std::basic_string &in) { assign1(type_id >().name(), convert_string(in)); } template inline dynamic_arg::dynamic_arg(boost::basic_format &in) { assign1(type_id >().name(), convert_string(in.str())); } template inline dynamic_arg::dynamic_arg(const boost::basic_format &in) { assign1(type_id >().name(), convert_string(in.str())); } template inline dynamic_arg::dynamic_arg(boost::function &in) { assign2(type_id >().name(), &in); } template inline dynamic_arg::dynamic_arg(const boost::function &in) { assign2(type_id >().name(), &in); } template inline dynamic_arg::dynamic_arg(boost::optional &in) { if (in) { dynamic_arg tmp(in.get()); type_ = "boost::optional<" + tmp.type() + ">"; arg_ = tmp.arg(); } else assign2(type_id >().name(), (T *) NULL); } template inline dynamic_arg::dynamic_arg(const boost::optional &in) { if (in) { dynamic_arg tmp(in.get()); type_ = "const boost::optional<" + tmp.type() + ">"; arg_ = tmp.arg(); } else assign2(type_id >().name(), (T *) NULL); } template inline dynamic_arg::dynamic_arg(std::pair &in) { dynamic_arg tmp1(in.first), tmp2(in.second); type_ = "std::pair<" + tmp1.type() + ", " + tmp2.type() + ">"; arg_ = "(" + tmp1.arg() + ", " + tmp2.arg() + ")"; } template inline dynamic_arg::dynamic_arg(const std::pair &in) { dynamic_arg tmp1(in.first), tmp2(in.second); type_ = "const std::pair<" + tmp1.type() + ", " + tmp2.type() + ">"; arg_ = "(" + tmp1.arg() + ", " + tmp2.arg() + ")"; } DEFINE_ARG_PTR(std::auto_ptr) DEFINE_ARG_PTR(mantra::auto_ptr) DEFINE_ARG_PTR(boost::shared_ptr) DEFINE_ARG_PTR(boost::scoped_ptr) DEFINE_ARG_PTR(boost::intrusive_ptr) DEFINE_ARG_SIZE(2, std::vector); DEFINE_ARG_SIZE(2, std::deque); DEFINE_ARG_SIZE(3, std::set); DEFINE_ARG_SIZE(4, std::map); DEFINE_ARG_SIZE(3, std::multiset); DEFINE_ARG_SIZE(4, std::multimap); #undef DEFINE_ARG_PTR #undef DEFINE_ARG_SIZE inline const std::string &dynamic_arg::type() const { return type_; } inline const std::string &dynamic_arg::arg() const { return arg_; } } } // namespace mantra::trace #endif // ENABLE_MANTRA_TRACE #endif // MANTRA_TRACE_DYNARG_H