mirror of https://github.com/SeanOMik/libki.git
pclass: Implement Value casting
This commit is contained in:
parent
24d3c0f146
commit
38f69d722c
|
@ -231,7 +231,7 @@ namespace pclass
|
|||
|
||||
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
||||
// so we need to copy the value in.
|
||||
prop.m_value = *object;
|
||||
prop.m_value = *dynamic_cast<ValueT *>(object);
|
||||
delete object;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,12 +1,71 @@
|
|||
#pragma once
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <typeinfo>
|
||||
#include <sstream>
|
||||
#include "ki/util/exception.h"
|
||||
|
||||
namespace ki
|
||||
{
|
||||
namespace pclass
|
||||
{
|
||||
class Value;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename SrcT>
|
||||
struct value_caster_helper;
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
struct value_caster_base
|
||||
{
|
||||
virtual ~value_caster_base() {}
|
||||
virtual Value cast(const type_info &dst_type, Value &v) const = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Provides a nice way for specialized casters to throw with a
|
||||
* consistent error when casting is not possible.
|
||||
*/
|
||||
Value bad_cast(const type_info &src_type, const type_info &dst_type) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
struct value_caster
|
||||
{
|
||||
// Allow Value to call the default constructor and make
|
||||
friend Value;
|
||||
|
||||
/**
|
||||
* @tparam DstT The cast destination type.
|
||||
* @param[in] value The Value that is being casted to the destination type.
|
||||
* @returns A Value with a reference that has been casted to the destination type.
|
||||
*/
|
||||
template <typename DstT>
|
||||
Value cast(Value &value) const;
|
||||
|
||||
private:
|
||||
value_caster_base *m_caster;
|
||||
|
||||
explicit value_caster(value_caster_base *caster = nullptr)
|
||||
{
|
||||
m_caster = caster;
|
||||
}
|
||||
|
||||
/**
|
||||
* @tparam SrcT
|
||||
*/
|
||||
template <typename SrcT>
|
||||
static value_caster make()
|
||||
{
|
||||
return value_caster(new value_caster_helper<SrcT>());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around a void pointer that ensures type safety.
|
||||
*/
|
||||
|
@ -18,6 +77,7 @@ namespace pclass
|
|||
{
|
||||
m_value_ptr = static_cast<void *>(&value);
|
||||
m_type_hash = typeid(value).hash_code();
|
||||
m_caster = detail::value_caster::make<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -25,11 +85,13 @@ namespace pclass
|
|||
{
|
||||
m_value_ptr = const_cast<void *>(static_cast<const void *>(&value));
|
||||
m_type_hash = typeid(value).hash_code();
|
||||
m_caster = detail::value_caster::make<T>();
|
||||
}
|
||||
|
||||
Value(Value &&o) noexcept
|
||||
: m_value_ptr(std::move(m_value_ptr))
|
||||
: m_value_ptr(std::move(o.m_value_ptr))
|
||||
, m_type_hash(std::move(o.m_type_hash))
|
||||
, m_caster(std::move(o.m_caster))
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -48,9 +110,9 @@ namespace pclass
|
|||
template <typename T>
|
||||
const T &get() const
|
||||
{
|
||||
// Make sure that this is allowed
|
||||
// Do we need to attempt casting?
|
||||
if (!is<T>())
|
||||
throw std::runtime_error("Type mismatch in Value::get<T>() call.");
|
||||
return m_caster.cast<T>(*this).get<T>();
|
||||
return *static_cast<T *>(m_value_ptr);
|
||||
}
|
||||
|
||||
|
@ -60,15 +122,46 @@ namespace pclass
|
|||
template <typename T>
|
||||
T &get()
|
||||
{
|
||||
// Make sure that this is allowed
|
||||
// Do we need to attempt casting?
|
||||
if (!is<T>())
|
||||
throw std::runtime_error("Type mismatch in Value::get<T>() call.");
|
||||
return m_caster.cast<T>(*this).get<T>();
|
||||
return *static_cast<T *>(m_value_ptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void *m_value_ptr;
|
||||
std::size_t m_type_hash;
|
||||
detail::value_caster m_caster;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline Value value_caster_base::bad_cast(
|
||||
const type_info& src_type, const type_info& dst_type) const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "Cannot cast Value from " << src_type.name()
|
||||
<< " to " << dst_type.name() << ".";
|
||||
throw runtime_error(oss.str());
|
||||
}
|
||||
|
||||
template <typename DstT>
|
||||
Value value_caster::cast(Value& value) const
|
||||
{
|
||||
return m_caster->cast(typeid(DstT), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Documentation
|
||||
*/
|
||||
template <typename SrcT>
|
||||
struct value_caster_helper : value_caster_base
|
||||
{
|
||||
Value cast(const type_info &dst_type, Value& value) const override
|
||||
{
|
||||
return bad_cast(typeid(SrcT), dst_type);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ namespace pclass
|
|||
|
||||
// ValueT does derive from PropertyClass, and we have an instance of ValueT,
|
||||
// so we can cast down to a PropertyClass pointer.
|
||||
return dynamic_cast<PropertyClass *>(&prop.at(index));
|
||||
return dynamic_cast<const PropertyClass *>(&prop.at(index));
|
||||
}
|
||||
|
||||
static void set_object(VectorProperty<ValueT> &prop, PropertyClass *object, const int index)
|
||||
|
@ -208,7 +208,7 @@ namespace pclass
|
|||
|
||||
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
||||
// so we need to copy the value in.
|
||||
prop.at(index) = dynamic_cast<ValueT>(*object);
|
||||
prop.at(index) = *dynamic_cast<ValueT *>(object);
|
||||
delete object;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue