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,
|
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
||||||
// so we need to copy the value in.
|
// so we need to copy the value in.
|
||||||
prop.m_value = *object;
|
prop.m_value = *dynamic_cast<ValueT *>(object);
|
||||||
delete object;
|
delete object;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,71 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <stdexcept>
|
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
#include <sstream>
|
||||||
|
#include "ki/util/exception.h"
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
namespace pclass
|
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.
|
* A wrapper around a void pointer that ensures type safety.
|
||||||
*/
|
*/
|
||||||
|
@ -18,6 +77,7 @@ namespace pclass
|
||||||
{
|
{
|
||||||
m_value_ptr = static_cast<void *>(&value);
|
m_value_ptr = static_cast<void *>(&value);
|
||||||
m_type_hash = typeid(value).hash_code();
|
m_type_hash = typeid(value).hash_code();
|
||||||
|
m_caster = detail::value_caster::make<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -25,11 +85,13 @@ namespace pclass
|
||||||
{
|
{
|
||||||
m_value_ptr = const_cast<void *>(static_cast<const void *>(&value));
|
m_value_ptr = const_cast<void *>(static_cast<const void *>(&value));
|
||||||
m_type_hash = typeid(value).hash_code();
|
m_type_hash = typeid(value).hash_code();
|
||||||
|
m_caster = detail::value_caster::make<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Value(Value &&o) noexcept
|
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_type_hash(std::move(o.m_type_hash))
|
||||||
|
, m_caster(std::move(o.m_caster))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,9 +110,9 @@ namespace pclass
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T &get() const
|
const T &get() const
|
||||||
{
|
{
|
||||||
// Make sure that this is allowed
|
// Do we need to attempt casting?
|
||||||
if (!is<T>())
|
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);
|
return *static_cast<T *>(m_value_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,15 +122,46 @@ namespace pclass
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T &get()
|
T &get()
|
||||||
{
|
{
|
||||||
// Make sure that this is allowed
|
// Do we need to attempt casting?
|
||||||
if (!is<T>())
|
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);
|
return *static_cast<T *>(m_value_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void *m_value_ptr;
|
void *m_value_ptr;
|
||||||
std::size_t m_type_hash;
|
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,
|
// ValueT does derive from PropertyClass, and we have an instance of ValueT,
|
||||||
// so we can cast down to a PropertyClass pointer.
|
// 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)
|
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,
|
// ValueT does derive from PropertyClass, but we don't store a pointer,
|
||||||
// so we need to copy the value in.
|
// so we need to copy the value in.
|
||||||
prop.at(index) = dynamic_cast<ValueT>(*object);
|
prop.at(index) = *dynamic_cast<ValueT *>(object);
|
||||||
delete object;
|
delete object;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue