Skip to content

Commit

Permalink
added new interfaces in variant and variant_array_view
Browse files Browse the repository at this point in the history
Now it possible to extrace a wrapped value inside a variant:
template<typename T>
const T& variant::get_wrapped_value() const;

template<typename T>
variant variant::extract_wrapped_value() const;

return a value in an array wrapped inside a std::reference_wrapper
variant variant_array_view::get_value_as_ref(std::size_t index_1) const;

This change makes it a lot easier when working with multiple dimensional arrays.
No more index hassle

Unit Tests will follow
  • Loading branch information
acki-m committed Nov 28, 2016
1 parent fa42023 commit 7e651ec
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 47 deletions.
62 changes: 19 additions & 43 deletions src/examples/json_serialization/json_serialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,35 +104,27 @@ void write_atomic_types_to_json(const type& t, const variant& var, PrettyWriter<

/////////////////////////////////////////////////////////////////////////////////////////

static void write_array(const variant_array_view& a,
const std::vector<std::size_t>& size_indices,
std::vector<std::size_t>& indices, PrettyWriter<StringBuffer>& writer)
static void write_array(const variant_array_view& a, PrettyWriter<StringBuffer>& writer)
{
writer.StartArray();
for (int i = 0; i < a.get_size_variadic(size_indices); i++)
for (int i = 0; i < a.get_size(); ++i)
{
if (!size_indices.empty())
indices[size_indices.size()] = i;
else
indices[0] = i;

if (size_indices.size() + 1 < a.get_rank())
variant var = a.get_value_as_ref(i);
if (var.is_array())
{
std::vector<std::size_t> new_size_indices = size_indices;
new_size_indices.push_back(i);
write_array(a, new_size_indices, indices, writer);
write_array(var.create_array_view(), writer);
}
else
{
variant value = a.get_value_variadic(indices);
type value_type = value.get_type();
variant wrapped_var = var.extract_wrapped_value();
type value_type = wrapped_var.get_type();
if (value_type.is_arithmetic() || value_type == type::get<std::string>() || value_type.is_enumeration())
{
write_atomic_types_to_json(value_type, value, writer);
write_atomic_types_to_json(value_type, wrapped_var, writer);
}
else // object
{
to_json_recursively(value, writer);
to_json_recursively(wrapped_var, writer);
}
}
}
Expand All @@ -141,15 +133,6 @@ static void write_array(const variant_array_view& a,

/////////////////////////////////////////////////////////////////////////////////////////

static void write_array(const variant_array_view& a, PrettyWriter<StringBuffer>& writer)
{
std::vector<std::size_t> indices(a.get_rank(), 0);
std::vector<std::size_t> size_indices;
write_array(a, size_indices, indices, writer);
}

/////////////////////////////////////////////////////////////////////////////////////////

void to_json_recursively(const instance& obj2, PrettyWriter<StringBuffer>& writer)
{
writer.StartObject();
Expand Down Expand Up @@ -238,34 +221,29 @@ variant extract_basic_types(Value& json_value)

/////////////////////////////////////////////////////////////////////////////////////////

void write_array_recursively(variant_array_view& var_array, Value& json_array_value,
const std::vector<std::size_t>& size_indices,
std::vector<std::size_t>& indices)
void write_array_recursively(variant_array_view& var_array, Value& json_array_value)
{
var_array.set_size_variadic(json_array_value.Size(), size_indices);
const auto rank = size_indices.size();
const type array_type = var_array.get_rank_type(rank + 1);
var_array.set_size(json_array_value.Size());
for (SizeType i = 0; i < json_array_value.Size(); ++i)
{
auto& json_index_value = json_array_value[i];
indices[rank] = i;
if (json_index_value.IsArray())
{
std::vector<std::size_t> new_size_indices = size_indices;
new_size_indices.push_back(i);
write_array_recursively(var_array, json_index_value, new_size_indices, indices);
write_array_recursively(var_array.get_value_as_ref(i).create_array_view(), json_index_value);
}
else if (json_index_value.IsObject())
{
variant var_tmp = var_array.get_value_variadic(indices);
fromjson_recursively(var_tmp, json_index_value);
var_array.set_value_variadic(indices, var_tmp);
variant var_tmp = var_array.get_value_as_ref(i);
variant wrapped_var = var_tmp.extract_wrapped_value();
fromjson_recursively(wrapped_var, json_index_value);
var_array.set_value(i, wrapped_var);
}
else
{
const type array_type = var_array.get_rank_type(i);
variant extracted_value = extract_basic_types(json_index_value);
if (extracted_value.convert(array_type))
var_array.set_value_variadic(indices, extracted_value);
var_array.set_value(i, extracted_value);
}
}
}
Expand All @@ -292,9 +270,7 @@ void fromjson_recursively(instance obj2, Value& json_object)
{
variant var = prop.get_value(obj);
auto array_view = var.create_array_view();
std::vector<std::size_t> indices(array_view.get_rank(), 0);
std::vector<std::size_t> size_indices;
write_array_recursively(array_view, json_value, size_indices, indices);
write_array_recursively(array_view, json_value);

prop.set_value(obj, var);
break;
Expand Down
4 changes: 3 additions & 1 deletion src/examples/json_serialization/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
#include <string>
#include <vector>
#include <array>

#include <iostream>

#include <rttr/registration>

#include "json_serialize.h"

using namespace rttr;
Expand Down Expand Up @@ -142,6 +143,7 @@ int main(int argc, char** argv)
std::cout << "\n############################################\n" << std::endl;

std::cout << "Circle c_2:\n" << io::to_json(c_2) << std::endl;

return 0;
}

4 changes: 4 additions & 0 deletions src/rttr/detail/array/array_accessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ struct array_accessor

/////////////////////////////////////////////////////////////////////////////////////////

static variant get_value_as_ref(Array_Type& array, std::size_t index_1);

/////////////////////////////////////////////////////////////////////////////////////////

template<typename... Indices>
static bool set_value(const Array_Type&, argument&, Indices... indices);
static bool set_value(const Array_Type&, argument&, const std::vector<std::size_t>&);
Expand Down
26 changes: 25 additions & 1 deletion src/rttr/detail/array/array_accessor_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ template<typename Return_Type, typename Array_Type>
struct get_value_from_array_impl<Return_Type, Array_Type, std::true_type>
{
template<typename... Indices>
static const Return_Type& get_value(const Array_Type& array, std::size_t index, Indices... args)
static Return_Type& get_value(const Array_Type& array, std::size_t index, Indices... args)
{
using sub_type = typename array_mapper<Array_Type>::sub_type;
using arg_count_valid = typename std::integral_constant<bool, sizeof...(Indices) != 0>::type;
Expand Down Expand Up @@ -341,6 +341,13 @@ struct array_accessor_impl<Array_Type, std::true_type>

/////////////////////////////////////////////////////////////////////////////////////////

static variant get_value_as_ref(Array_Type& obj, std::size_t index_1)
{
return variant(std::ref(array_mapper<Array_Type>::get_value(obj, index_1)));
}

/////////////////////////////////////////////////////////////////////////////////////////

template<typename... Indices>
static bool set_value(Array_Type& obj, argument& arg, Indices... indices)
{
Expand Down Expand Up @@ -402,6 +409,13 @@ struct array_accessor_impl<Array_Type, std::false_type>

/////////////////////////////////////////////////////////////////////////////////////////

static variant get_value_as_ref(Array_Type& obj, std::size_t index_1)
{
return variant();
}

/////////////////////////////////////////////////////////////////////////////////////////

template<typename... Indices>
static bool set_value(Array_Type& obj, argument& arg, Indices... indices)
{
Expand Down Expand Up @@ -696,6 +710,16 @@ variant array_accessor<Array_Type>::get_value(const Array_Type& array, const std
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

template<typename Array_Type>
variant array_accessor<Array_Type>::get_value_as_ref(Array_Type& array, std::size_t index)
{
using is_rank_in_range = typename std::integral_constant<bool, (1 <= rank<Array_Type>::value) >::type;
return array_accessor_impl<Array_Type, is_rank_in_range>::get_value_as_ref(array, index);
}

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

template<typename Array_Type>
template<typename... Indices>
bool array_accessor<Array_Type>::set_value(const Array_Type&, argument&, Indices... indices) { return false; }
Expand Down
7 changes: 7 additions & 0 deletions src/rttr/detail/array/array_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ class array_wrapper : public array_wrapper_base

/////////////////////////////////////////////////////////////////////////////////////////

variant get_value_as_ref(std::size_t index_1) const
{
return array_accessor<Array_Type>::get_value_as_ref(*m_address_data, index_1);
}

/////////////////////////////////////////////////////////////////////////////////////////

bool insert_value(std::size_t index_1, argument& arg)
{
return array_accessor<Array_Type>::insert_value(*m_address_data, arg, index_1);
Expand Down
2 changes: 2 additions & 0 deletions src/rttr/detail/array/array_wrapper_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class RTTR_API array_wrapper_base
virtual variant get_value(std::size_t index_1, std::size_t index_2, std::size_t index_3) const { return variant(); }
virtual variant get_value_variadic(const std::vector<std::size_t>& index_list) const { return variant(); }

virtual variant get_value_as_ref(std::size_t index_1) const { return variant(); }

virtual bool insert_value(std::size_t index_1, argument& arg) { return false; }
virtual bool insert_value(std::size_t index_1, std::size_t index_2, argument& arg) { return false; }
virtual bool insert_value(std::size_t index_1, std::size_t index_2, std::size_t index_3, argument& arg) { return false; }
Expand Down
31 changes: 30 additions & 1 deletion src/rttr/detail/variant/variant_data_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ enum class variant_policy_operation : uint8_t
DESTROY,
CLONE,
SWAP,
EXTRACT_WRAPPED_VALUE,
GET_VALUE,
GET_TYPE,
GET_PTR,
Expand Down Expand Up @@ -176,6 +177,24 @@ static RTTR_INLINE is_nullptr(T& to)
return false;
}

/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

template<typename T, typename Tp = wrapper_mapper_t<T>>
enable_if_t<std::is_copy_constructible<Tp>::value &&
is_wrapper<T>::value, variant> get_wrapped_value(T& value)
{
using raw_wrapper_type = remove_cv_t<remove_reference_t<T>>;
return variant(wrapper_mapper<raw_wrapper_type>::get(value));
}

template<typename T, typename Tp = wrapper_mapper_t<T>>
enable_if_t<!std::is_copy_constructible<Tp>::value ||
!is_wrapper<T>::value, variant> get_wrapped_value(T& value)
{
return variant();
}

/////////////////////////////////////////////////////////////////////////////////////////

/*!
Expand Down Expand Up @@ -207,6 +226,11 @@ struct variant_data_base_policy
Tp::swap(const_cast<T&>(Tp::get_value(src_data)), arg.get_value<variant_data>());
break;
}
case variant_policy_operation::EXTRACT_WRAPPED_VALUE:
{
arg.get_value<variant>() = get_wrapped_value(Tp::get_value(src_data));
break;
}
case variant_policy_operation::GET_VALUE:
{
arg.get_value<const void*>() = &Tp::get_value(src_data);
Expand Down Expand Up @@ -244,7 +268,7 @@ struct variant_data_base_policy
}
case variant_policy_operation::IS_ARRAY:
{
return ::rttr::detail::is_array<typename raw_type<T>::type>::value;
return can_create_array_container<T>::value;
}
case variant_policy_operation::TO_ARRAY:
{
Expand Down Expand Up @@ -662,6 +686,7 @@ struct RTTR_API variant_data_policy_void
case variant_policy_operation::DESTROY:
case variant_policy_operation::CLONE:
case variant_policy_operation::SWAP:
case variant_policy_operation::EXTRACT_WRAPPED_VALUE:
{
break;
}
Expand Down Expand Up @@ -794,6 +819,10 @@ struct RTTR_API variant_data_policy_nullptr_t
swap(get_value(src_data), arg.get_value<variant_data>());
break;
}
case variant_policy_operation::EXTRACT_WRAPPED_VALUE:
{
break;
}
case variant_policy_operation::GET_VALUE:
{
arg.get_value<const void*>() = &get_value(src_data);
Expand Down
11 changes: 11 additions & 0 deletions src/rttr/detail/variant/variant_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ RTTR_INLINE const T& variant::get_value() const

/////////////////////////////////////////////////////////////////////////////////////////

template<typename T>
RTTR_INLINE const T& variant::get_wrapped_value() const
{
detail::data_address_container result{detail::get_invalid_type(), detail::get_invalid_type(), nullptr, nullptr};
m_policy(detail::variant_policy_operation::GET_ADDRESS_CONTAINER, m_data, result);
using nonRef = detail::remove_cv_t<T>;
return *reinterpret_cast<const nonRef*>(result.m_data_address_wrapped_type);
}

/////////////////////////////////////////////////////////////////////////////////////////

RTTR_INLINE void* variant::get_ptr() const
{
void* value;
Expand Down
9 changes: 9 additions & 0 deletions src/rttr/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ type variant::get_type() const

/////////////////////////////////////////////////////////////////////////////////////////

variant variant::extract_wrapped_value() const
{
variant var;
m_policy(detail::variant_policy_operation::EXTRACT_WRAPPED_VALUE, m_data, var);
return var;
}

/////////////////////////////////////////////////////////////////////////////////////////

variant_array_view variant::create_array_view() const
{
variant_array_view result;
Expand Down
45 changes: 45 additions & 0 deletions src/rttr/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,51 @@ class RTTR_API variant
template<typename T>
const T& get_value() const;

/*!
* \brief Returns a reference to the contained wrapped value as type \p T.
*
* \code{.cpp}
* int value = 23;
* variant var = std::ref(value);
*
* if (var.get_type().get_wrapped_type() == type::get<int>()) // yields to true
* const int& ref_value = var.get_wrapped_value<int>(); // extracts the value by reference
* \endcode
*
* \remark Only call this method when it is possible to return the containing value as the given type \p T.
* Use therefore the method \ref rttr::type::get_wrapped_type() "get_wrapped_type()".
* Otherwise the call leads to undefined behaviour.
*
* \see rttr::type::get_wrapped_type()
*
* \return A reference to the stored wrapped value.
*/
template<typename T>
const T& get_wrapped_value() const;

/*!
* \brief Extracts the wrapped value and copies its content into a new variant.
*
* \code{.cpp}
* int value1 = 23;
* variant var1 = std::ref(value1);
*
* if (var1.get_type().get_wrapped_type() == type::get<int>()) // yields to true
* {
* variant var2 = var1.extract_wrapped_value(); // value will be copied into "var2"
* var2.get_type() == type::get<int>(); // yields to true
* const int& value2 = var2.get_value<int>();
* std::cout << value2 << std::endl; // prints "23"
* }
* \endcode
*
* \remark Calling this method works only for wrapped types which are copiable.
* When you work with custom types, which are not copyable, the variant will be \ref is_valid "invalid"
*
* \return A variant with the wrapped value.
*/
variant extract_wrapped_value() const;

/*!
* \brief Returns `true` if the contained value can be converted to the given type \p T.
* Otherwise `false`.
Expand Down
7 changes: 7 additions & 0 deletions src/rttr/variant_array_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,13 @@ variant variant_array_view::get_value_variadic(const std::vector<std::size_t>& i

/////////////////////////////////////////////////////////////////////////////////////////

variant variant_array_view::get_value_as_ref(std::size_t index_1) const
{
return m_array_wrapper->get_value_as_ref(index_1);
}

/////////////////////////////////////////////////////////////////////////////////////////

bool variant_array_view::insert_value(std::size_t index_1, argument arg)
{
return m_array_wrapper->insert_value(index_1, arg);
Expand Down
Loading

0 comments on commit 7e651ec

Please sign in to comment.