/*============================================================================= Library: CppMicroServices Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. Extracted from Boost 1.46.1 and adapted for CppMicroServices. Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =========================================================================*/ #ifndef CPPMICROSERVICES_ANY_H #define CPPMICROSERVICES_ANY_H #include "cppmicroservices/FrameworkConfig.h" #include #include #include #include #include #include #include #include /** \defgroup gr_any Any \brief The Any class and related functions. */ namespace cppmicroservices { class Any; US_Framework_EXPORT std::ostream& any_value_to_string(std::ostream& os, const Any& any); US_Framework_EXPORT std::ostream& any_value_to_json(std::ostream& os, const Any& val); US_Framework_EXPORT std::ostream& any_value_to_json(std::ostream& os, const std::string& val); US_Framework_EXPORT std::ostream& any_value_to_json(std::ostream& os, bool val); template ValueType* any_cast(Any* operand); template std::ostream& any_value_to_string(std::ostream& os, const T& val) { os << val; return os; } template std::ostream& any_value_to_json(std::ostream& os, const T& val) { return os << val; } /** * \internal */ template std::ostream& container_to_string(std::ostream& os, Iterator i1, Iterator i2) { os << "["; const Iterator begin = i1; for (; i1 != i2; ++i1) { if (i1 == begin) { any_value_to_string(os, *i1); } else { os << ","; any_value_to_string(os, *i1); } } os << "]"; return os; } /** * \internal */ template std::ostream& container_to_json(std::ostream& os, Iterator i1, Iterator i2) { os << "["; const Iterator begin = i1; for (; i1 != i2; ++i1) { if (i1 == begin) { any_value_to_json(os, *i1); } else { os << ","; any_value_to_json(os, *i1); } } os << "]"; return os; } template std::ostream& any_value_to_string(std::ostream& os, const std::vector& vec) { return container_to_string(os, vec.begin(), vec.end()); } template std::ostream& any_value_to_json(std::ostream& os, const std::vector& vec) { return container_to_json(os, vec.begin(), vec.end()); } template std::ostream& any_value_to_string(std::ostream& os, const std::list& l) { return container_to_string(os, l.begin(), l.end()); } template std::ostream& any_value_to_json(std::ostream& os, const std::list& l) { return container_to_json(os, l.begin(), l.end()); } template std::ostream& any_value_to_string(std::ostream& os, const std::set& s) { return container_to_string(os, s.begin(), s.end()); } template std::ostream& any_value_to_json(std::ostream& os, const std::set& s) { return container_to_json(os, s.begin(), s.end()); } template std::ostream& any_value_to_string(std::ostream& os, const std::map& m); template std::ostream& any_value_to_string(std::ostream& os, const std::map& m); template std::ostream& any_value_to_json(std::ostream& os, const std::map& m); template std::ostream& any_value_to_json(std::ostream& os, const std::map& m); /** * \ingroup gr_any * * An Any class represents a general type and is capable of storing any type, supporting type-safe extraction * of the internally stored data. * * Code taken from the Boost 1.46.1 library. Original copyright by Kevlin Henney. Modified for CppMicroServices. */ class US_Framework_EXPORT Any { public: /** * Creates an empty any type. */ Any() {} /** * Creates an Any which stores the init parameter inside. * * \param value The content of the Any * * Example: * \code * Any a(13); * Any a(string("12345")); * \endcode */ template Any(const ValueType& value) : _content(new Holder(value)) {} /** * Copy constructor, works with empty Anys and initialized Any values. * * \param other The Any to copy */ Any(const Any& other) : _content(other._content ? other._content->Clone() : 0) {} /** * Move constructor. * * @param other The Any to move */ Any(Any&& other) : _content(std::move(other._content)) {} /** * Swaps the content of the two Anys. * * \param rhs The Any to swap this Any with. */ Any& Swap(Any& rhs) { std::swap(_content, rhs._content); return *this; } /** * Compares this Any with another value. * If the internal type of this any and of \c val do not * match, the comparison always returns false. * * \param val The value to compare to. * \returns \c true if this Any contains value \c val, \c false otherwise. */ template bool operator==(const ValueType& val) const { if (Type() != typeid(ValueType)) return false; return *any_cast(this) == val; } /** * Compares this Any with another value for inequality. * * This is the same as * \code * !this->operator==(val) * \endcode * * \param val The value to compare to. * \returns \c true if this Any does not contain value \c val, \c false otherwise. */ template bool operator!=(const ValueType& val) const { return !operator==(val); } /** * Assignment operator for all types != Any. * * \param rhs The value which should be assigned to this Any. * * Example: * \code * Any a = 13; * Any a = string("12345"); * \endcode */ template Any& operator=(const ValueType& rhs) { Any(rhs).Swap(*this); return *this; } /** * Assignment operator for Any. * * \param rhs The Any which should be assigned to this Any. */ Any& operator=(const Any& rhs) { Any(rhs).Swap(*this); return *this; } /** * Move assignment operator for Any. * * \param rhs The Any which should be moved into this Any. * \return A reference to this Any. */ Any& operator=(Any&& rhs) { _content = std::move(rhs._content); return *this; } /** * returns true if the Any is empty */ bool Empty() const { return !_content; } /** * Returns a string representation for the content if it is not empty. * * Custom types should either provide a std::ostream& operator<<(std::ostream& os, const CustomType& ct) * function or specialize the any_value_to_string template function for meaningful output. * * \throws std::logic_error if the Any is empty. */ std::string ToString() const; /** * Returns a string representation for the content. If the Any is * empty, an empty string is returned. * * Custom types should either provide a std::ostream& operator<<(std::ostream& os, const CustomType& ct) * function or specialize the any_value_to_string template function for meaningful output. */ std::string ToStringNoExcept() const; /** * Returns a JSON representation for the content. * * Custom types should specialize the any_value_to_json template function for meaningful output. */ std::string ToJSON() const { return Empty() ? "null" : _content->ToJSON(); } /** * Returns the type information of the stored content. * If the Any is empty typeid(void) is returned. * It is suggested to always query an Any for its type info before trying to extract * data via an any_cast/ref_any_cast. */ const std::type_info& Type() const { return _content ? _content->Type() : typeid(void); } private: class Placeholder { public: virtual ~Placeholder() {} virtual std::string ToString() const = 0; virtual std::string ToJSON() const = 0; virtual const std::type_info& Type() const = 0; virtual std::unique_ptr Clone() const = 0; }; template class Holder : public Placeholder { public: Holder(const ValueType& value) : _held(value) {} virtual std::string ToString() const { std::stringstream ss; any_value_to_string(ss, _held); return ss.str(); } virtual std::string ToJSON() const { std::stringstream ss; any_value_to_json(ss, _held); return ss.str(); } virtual const std::type_info& Type() const { return typeid(ValueType); } virtual std::unique_ptr Clone() const { return std::unique_ptr(new Holder(_held)); } ValueType _held; private: // intentionally left unimplemented Holder& operator=(const Holder&); }; private: template friend ValueType* any_cast(Any*); template friend ValueType* unsafe_any_cast(Any*); std::unique_ptr _content; }; /** * \ingroup gr_any * * The BadAnyCastException class is thrown in case * of casting an Any instance */ class BadAnyCastException : public std::bad_cast { public: BadAnyCastException(const std::string& msg = "") : std::bad_cast() , _msg(msg) {} ~BadAnyCastException() throw() {} virtual const char* what() const throw() { if (_msg.empty()) return "cppmicroservices::BadAnyCastException: " "failed conversion using cppmicroservices::any_cast"; else return _msg.c_str(); } private: std::string _msg; }; namespace detail { /** * * A utility function used to throw a BadAnyCastException object * containing an exception message containing the source and target type names. * * \param funcName The throwing function's name. * \param anyTypeName A string representing the Any object's underlying type. * \throws cppmicroservices::BadAnyCastException */ US_Framework_EXPORT void ThrowBadAnyCastException(const std::string& funcName, const std::type_info& source, const std::type_info& target); } /** * \ingroup gr_any * * any_cast operator used to extract the ValueType from an Any*. Will return a pointer * to the stored value. * * Example Usage: * \code * MyType* pTmp = any_cast(pAny) * \endcode * Will return nullptr if the cast fails, i.e. types don't match. */ template ValueType* any_cast(Any* operand) { return operand && operand->Type() == typeid(ValueType) ? &static_cast*>(operand->_content.get()) ->_held : nullptr; } /** * \ingroup gr_any * * any_cast operator used to extract a const ValueType pointer from an const Any*. Will return a const pointer * to the stored value. * * Example Usage: * \code * const MyType* pTmp = any_cast(pAny) * \endcode * Will return nullptr if the cast fails, i.e. types don't match. */ template const ValueType* any_cast(const Any* operand) { return any_cast(const_cast(operand)); } /** * \ingroup gr_any * * any_cast operator used to extract a copy of the ValueType from an const Any&. * * Example Usage: * \code * MyType tmp = any_cast(anAny) * \endcode * * \throws BadAnyCastException if the cast fails. * * Dont use an any_cast in combination with references, i.e. MyType& tmp = ... or const MyType& = ... * Some compilers will accept this code although a copy is returned. Use the ref_any_cast in * these cases. */ template ValueType any_cast(const Any& operand) { ValueType* result = any_cast(const_cast(&operand)); if (!result) { detail::ThrowBadAnyCastException( std::string("any_cast"), operand.Type(), typeid(ValueType)); } return *result; } /** * \ingroup gr_any * * any_cast operator used to extract a copy of the ValueType from an Any&. * * Example Usage: * \code * MyType tmp = any_cast(anAny) * \endcode * * \throws BadAnyCastException if the cast fails. * * Dont use an any_cast in combination with references, i.e. MyType& tmp = ... or const MyType& tmp = ... * Some compilers will accept this code although a copy is returned. Use the ref_any_cast in * these cases. */ template ValueType any_cast(Any& operand) { ValueType* result = any_cast(&operand); if (!result) { detail::ThrowBadAnyCastException( std::string("any_cast"), operand.Type(), typeid(ValueType)); } return *result; } /** * \ingroup gr_any * * ref_any_cast operator used to return a const reference to the internal data. * * Example Usage: * \code * const MyType& tmp = ref_any_cast(anAny); * \endcode * * \throws BadAnyCastException if the cast fails. */ template const ValueType& ref_any_cast(const Any& operand) { ValueType* result = any_cast(const_cast(&operand)); if (!result) { detail::ThrowBadAnyCastException( std::string("ref_any_cast"), operand.Type(), typeid(ValueType)); } return *result; } /** * \ingroup gr_any * * ref_any_cast operator used to return a reference to the internal data. * * Example Usage: * \code * MyType& tmp = ref_any_cast(anAny); * \endcode * * \throws BadAnyCastException if the cast fails. */ template ValueType& ref_any_cast(Any& operand) { ValueType* result = any_cast(&operand); if (!result) { detail::ThrowBadAnyCastException( std::string("ref_any_cast"), operand.Type(), typeid(ValueType)); } return *result; } /** * \internal * * The "unsafe" versions of any_cast are not part of the * public interface and may be removed at any time. They are * required where we know what type is stored in the any and can't * use typeid() comparison, e.g., when our types may travel across * different shared libraries. */ template ValueType* unsafe_any_cast(Any* operand) { return &static_cast*>(operand->_content.get())->_held; } /** * \internal * * The "unsafe" versions of any_cast are not part of the * public interface and may be removed at any time. They are * required where we know what type is stored in the any and can't * use typeid() comparison, e.g., when our types may travel across * different shared libraries. */ template const ValueType* unsafe_any_cast(const Any* operand) { return any_cast(const_cast(operand)); } template std::ostream& any_value_to_string(std::ostream& os, const std::map& m) { os << "{"; typedef typename std::map::const_iterator Iterator; Iterator i1 = m.begin(); const Iterator begin = i1; const Iterator end = m.end(); for (; i1 != end; ++i1) { if (i1 == begin) os << i1->first << " : " << i1->second.ToString(); else os << ", " << i1->first << " : " << i1->second.ToString(); } os << "}"; return os; } template std::ostream& any_value_to_string(std::ostream& os, const std::map& m) { os << "{"; typedef typename std::map::const_iterator Iterator; Iterator i1 = m.begin(); const Iterator begin = i1; const Iterator end = m.end(); for (; i1 != end; ++i1) { if (i1 == begin) os << i1->first << " : " << i1->second; else os << ", " << i1->first << " : " << i1->second; } os << "}"; return os; } template std::ostream& any_value_to_json(std::ostream& os, const std::map& m) { os << "{"; typedef typename std::map::const_iterator Iterator; Iterator i1 = m.begin(); const Iterator begin = i1; const Iterator end = m.end(); for (; i1 != end; ++i1) { if (i1 == begin) os << "\"" << i1->first << "\" : " << i1->second.ToJSON(); else os << ", " << "\"" << i1->first << "\" : " << i1->second.ToJSON(); } os << "}"; return os; } template std::ostream& any_value_to_json(std::ostream& os, const std::map& m) { os << "{"; typedef typename std::map::const_iterator Iterator; Iterator i1 = m.begin(); const Iterator begin = i1; const Iterator end = m.end(); for (; i1 != end; ++i1) { if (i1 == begin) os << "\"" << i1->first << "\" : " << i1->second; else os << ", " << "\"" << i1->first << "\" : " << i1->second; } os << "}"; return os; } } #endif // CPPMICROSERVICES_ANY_H