Created
July 19, 2016 08:35
-
-
Save OXPHOS/406213621fc9983478336bd2459c769c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016, Shogun-Toolbox e.V. <shogun-team@shogun-toolbox.org> | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the following disclaimer. | |
* | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* 3. Neither the name of the copyright holder nor the names of its | |
* contributors may be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
* | |
* Written (W) 2016 Sergey Lisitsyn | |
* Written (W) 2016 Sanuj Sharma | |
*/ | |
#ifndef _ANY_H_ | |
#define _ANY_H_ | |
#include <shogun/io/SGIO.h> | |
#include <string.h> | |
#include <stdexcept> | |
#include <typeinfo> | |
#include <cxxabi.h> | |
namespace shogun | |
{ | |
namespace serial | |
{ | |
enum EnumContainerType | |
{ | |
CT_UNDEFINED, | |
CT_PRIMITIVE, | |
CT_SGVECTOR, | |
CT_SGMATRIX | |
}; | |
enum EnumPrimitiveType | |
{ | |
PT_UNDEFINED, | |
PT_INT_32, | |
PT_FLOAT_64, | |
PT_SGVECTOR_INT_32, | |
PT_SGVECTOR_FLOAT_64 | |
}; | |
template<typename T> | |
struct Type2Enum | |
{ | |
static constexpr EnumContainerType e_containertype = CT_UNDEFINED; | |
static constexpr EnumPrimitiveType e_primitivetype = PT_UNDEFINED; | |
}; | |
template<> | |
struct Type2Enum<int32_t> | |
{ | |
static constexpr EnumContainerType e_containertype = CT_PRIMITIVE; | |
static constexpr EnumPrimitiveType e_primitivetype = PT_INT_32; | |
}; | |
template<> | |
struct Type2Enum<float64_t> | |
{ | |
static constexpr EnumContainerType e_containertype = CT_PRIMITIVE; | |
static constexpr EnumPrimitiveType e_primitivetype = PT_FLOAT_64; | |
}; | |
template<> | |
struct Type2Enum<SGVector<int32_t> > | |
{ | |
static constexpr EnumContainerType e_containertype = CT_SGVECTOR; | |
static constexpr EnumPrimitiveType e_primitivetype = PT_INT_32; | |
}; | |
template<> | |
struct Type2Enum<SGVector<float64_t> > | |
{ | |
static constexpr EnumContainerType e_containertype = CT_SGVECTOR; | |
static constexpr EnumPrimitiveType e_primitivetype = PT_FLOAT_64; | |
}; | |
template <enum EnumPrimitiveType> | |
struct Enum2PType | |
{ | |
typedef void Type; | |
}; | |
template <enum EnumContainerType, enum EnumPrimitiveType> | |
struct Enum2Type | |
{ | |
typedef void Type; | |
}; | |
template<> | |
struct Enum2PType<EnumPrimitiveType::PT_INT_32> | |
{ | |
typedef int32_t Type; | |
}; | |
template<> | |
struct Enum2PType<EnumPrimitiveType::PT_FLOAT_64> | |
{ | |
typedef float64_t Type; | |
}; | |
template<enum EnumPrimitiveType EPType> | |
struct Enum2Type<EnumContainerType::CT_PRIMITIVE, EPType> | |
{ | |
using Type = typename Enum2PType<EPType>::Type; | |
}; | |
template<enum EnumPrimitiveType EPType> | |
struct Enum2Type<EnumContainerType::CT_SGVECTOR, EPType> | |
{ | |
using Type = SGVector<typename Enum2PType<EPType>::Type>; | |
}; | |
template<enum EnumPrimitiveType EPType> | |
struct Enum2Type<EnumContainerType::CT_SGMATRIX, EPType> | |
{ | |
using Type = SGMatrix<typename Enum2PType<EPType>::Type>; | |
}; | |
struct DataType | |
{ | |
EnumContainerType e_containertype; | |
EnumPrimitiveType e_primitivetype; | |
template<typename T> | |
void set() | |
{ | |
e_containertype = Type2Enum<T>::e_containertype; | |
e_primitivetype = Type2Enum<T>::e_primitivetype; | |
} | |
}; | |
} | |
/** Converts compiler-dependent name of class to | |
* something human readable. | |
* @return human readable name of class | |
*/ | |
template <typename T> | |
std::string demangledType() | |
{ | |
size_t length; | |
int status; | |
char* demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, &length, &status); | |
std::string demangled_string(demangled); | |
free(demangled); | |
return demangled_string; | |
} | |
/** @brief An interface for a policy to store a value. | |
* Value can be any data like primitive data-types, shogun objects, etc. | |
* Policy defines how to handle this data. It works with a | |
* provided memory region and is able to set value, clear it | |
* and return the type-name as string. | |
*/ | |
class BaseAnyPolicy | |
{ | |
public: | |
/** Puts provided value pointed by v (untyped to be generic) to storage. | |
* @param storage pointer to a pointer to storage | |
* @param v pointer to value | |
*/ | |
virtual void set(void** storage, const void* v) const = 0; | |
/** Clears storage. | |
* @param storage pointer to a pointer to storage | |
*/ | |
virtual void clear(void** storage) const = 0; | |
/** Returns type-name as string. | |
* @return name of type class | |
*/ | |
virtual std::string type() const = 0; | |
/** Compares type. | |
* @param ti type information | |
* @return true if type matches | |
*/ | |
virtual bool matches(const std::type_info& ti) const = 0; | |
/** Compares two storages. | |
* @param storage pointer to a pointer to storage | |
* @param other_storage pointer to a pointer to another storage | |
* @return true if both storages have same value | |
*/ | |
virtual bool equals(void** storage, void** other_storage) const = 0; | |
}; | |
/** @brief This is one concrete implementation of policy that | |
* uses void pointers to store values. | |
*/ | |
template <typename T> | |
class PointerValueAnyPolicy : public BaseAnyPolicy | |
{ | |
public: | |
/** Puts provided value pointed by v (untyped to be generic) to storage. | |
* @param storage pointer to a pointer to storage | |
* @param v pointer to value | |
*/ | |
virtual void set(void** storage, const void* v) const | |
{ | |
*(storage) = new T(*reinterpret_cast<T const*>(v)); | |
} | |
/** Clears storage. | |
* @param storage pointer to a pointer to storage | |
*/ | |
virtual void clear(void** storage) const | |
{ | |
delete reinterpret_cast<T*>(*storage); | |
} | |
/** Returns type-name as string. | |
* @return name of type class | |
*/ | |
virtual std::string type() const | |
{ | |
return demangledType<T>(); | |
} | |
/** Compares type. | |
* @param ti type information | |
* @return true if type matches | |
*/ | |
virtual bool matches(const std::type_info& ti) const | |
{ | |
return typeid(T) == ti; | |
} | |
/** Compares two storages. | |
* @param storage pointer to a pointer to storage | |
* @param other_storage pointer to a pointer to another storage | |
* @return true if both storages have same value | |
*/ | |
bool equals(void** storage, void** other_storage) const | |
{ | |
int typed_storage = *(reinterpret_cast<int*>(*storage)); | |
int typed_other_storage = *(reinterpret_cast<int*>(*other_storage)); | |
return typed_storage == typed_other_storage; | |
} | |
}; | |
/** @brief Allows to store objects of arbitrary types | |
* by using a BaseAnyPolicy and provides a type agnostic API. | |
* See its usage in CSGObject::Self, CSGObject::set(), CSGObject::get() | |
* and CSGObject::has(). | |
* . | |
*/ | |
class Any | |
{ | |
public: | |
/** Used to denote an empty Any object */ | |
struct Empty; | |
/** Constructor */ | |
Any() : policy(select_policy<Empty>()), storage(nullptr) | |
{ | |
} | |
/** Constructor to copy value */ | |
template <typename T> | |
explicit Any(const T& v) : policy(select_policy<T>()), storage(nullptr) | |
{ | |
policy->set(&storage, &v); | |
m_datatype = m_datatype.set<T>(); | |
} | |
/** Copy constructor */ | |
Any(const Any& other) : policy(other.policy), storage(nullptr) | |
{ | |
policy->set(&storage, other.storage); | |
m_datatype = other.m_datatype; | |
} | |
/** Assignment operator | |
* @param other another Any object | |
* @return Any object | |
*/ | |
Any& operator=(const Any& other) | |
{ | |
policy->clear(&storage); | |
policy = other.policy; | |
policy->set(&storage, other.storage); | |
m_datatype = other.m_datatype; | |
return *(this); | |
} | |
/** Equality operator | |
* @param lhs Any object on left hand side | |
* @param rhs Any object on right hand side | |
* @return true if both are equal | |
*/ | |
friend inline bool operator==(const Any& lhs, const Any& rhs); | |
/** Inequality operator | |
* @param lhs Any object on left hand side | |
* @param rhs Any object on right hand side | |
* @return false if both are equal | |
*/ | |
friend inline bool operator!=(const Any& lhs, const Any& rhs); | |
/** Destructor */ | |
~Any() | |
{ | |
policy->clear(&storage); | |
} | |
template<class Archive> | |
void cereal_save(Archive& ar) const | |
{ | |
typedef serial::Enum2Type<m_datatype.e_containertype, m_datatype.e_primitivetype>::Type primitivetype; | |
ar(*(reinterpret_cast<primitivetype*>(storage))); | |
/* | |
switch (m_datatype.e_primitivetype) { | |
case serial::EnumPrimitiveType::PT_INT_32: | |
typedef int32_t primitivetype; break; | |
case serial::EnumPrimitiveType::PT_FLOAT_64: | |
typedef float64_t primitivetype; break; | |
case serial::EnumPrimitiveType::PT_UNDEFINED: | |
SG_SERROR("Type error: undefined data type cannot be serialized.\n"); | |
break; | |
} | |
typedef m_datatype.get()::Type primitivetype; | |
//typedef serial::Enum2Type<m_datatype.e_primitivetype>::Type primitivetype; | |
switch (m_datatype.e_containertype) { | |
case serial::EnumContainerType::CT_PRIMITIVE: | |
ar(*(reinterpret_cast<primitivetype*>(storage))); break; | |
case serial::EnumContainerType::CT_SGVECTOR: | |
ar(*(reinterpret_cast<SGVector<primitivetype>*>(storage))); break; | |
case serial::EnumContainerType::CT_SGMATRIX: | |
ar(*(reinterpret_cast<SGMatrix<primitivetype>*>(storage))); break; | |
case serial::EnumContainerType::CT_UNDEFINED: | |
SG_SERROR("Type error: undefined container type cannot be serialized.\n"); | |
break; | |
} | |
*/ | |
} | |
/** Casts hidden value to provided type, fails otherwise. | |
* @return type-casted value | |
*/ | |
template <typename T> | |
T& as() const | |
{ | |
if (same_type<T>()) | |
{ | |
return *(reinterpret_cast<T*>(storage)); | |
} | |
else | |
{ | |
throw std::logic_error("Bad cast to " + demangledType<T>() + | |
" but the type is " + policy->type()); | |
} | |
} | |
/** @return true if type is same. */ | |
template <typename T> | |
inline bool same_type() const | |
{ | |
return (policy == select_policy<T>()) || same_type_fallback<T>(); | |
} | |
/** @return true if type-id is same. */ | |
template <typename T> | |
bool same_type_fallback() const | |
{ | |
return policy->matches(typeid(T)); | |
} | |
/** @return true if Any object is empty. */ | |
bool empty() const | |
{ | |
return same_type<Empty>(); | |
} | |
private: | |
template <typename T> | |
static BaseAnyPolicy* select_policy() | |
{ | |
typedef PointerValueAnyPolicy<T> Policy; | |
static Policy policy; | |
return &policy; | |
} | |
BaseAnyPolicy* policy; | |
void* storage; | |
serial::DataType m_datatype; | |
}; | |
inline bool operator==(const Any& lhs, const Any& rhs) | |
{ | |
void* lhs_storage = lhs.storage; | |
void* rhs_storage = rhs.storage; | |
return lhs.policy == rhs.policy and | |
lhs.policy->equals(&lhs_storage, &rhs_storage); | |
} | |
inline bool operator!=(const Any& lhs, const Any& rhs) | |
{ | |
return !(lhs == rhs); | |
} | |
/** Used to denote an empty Any object */ | |
struct Any::Empty | |
{ | |
/** Equality operator */ | |
bool operator==(const Empty& other) const | |
{ | |
return true; | |
} | |
}; | |
/** Erases value type i.e. converts it to Any | |
* For input object of any type, it returns an Any object | |
* which stores the input object's raw value. It saves the type | |
* information internally to be recalled later by using recall_type(). | |
* | |
* @param v value | |
* @return Any object with the input value | |
*/ | |
template <typename T> | |
inline Any erase_type(const T& v) | |
{ | |
return Any(v); | |
} | |
/** Tries to recall Any type, fails when type is wrong. | |
* Any stores type information of an object internally in a BaseAnyPolicy. | |
* This function returns type-casted value if the internal type information | |
* matches with the provided typename, otherwise throws std::logic_error. | |
* | |
* @param any object of Any | |
* @return type-casted value | |
*/ | |
template <typename T> | |
inline T recall_type(const Any& any) | |
{ | |
return any.as<T>(); | |
} | |
} | |
#endif //_ANY_H_ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment