<commit_before>#pragma once

#include <utility>
#include <type_traits>
#include <string>

#include "any.hpp"
#include <type_list.hpp>
#include <function_deduction.hpp>
#include <member_variable_deduction.hpp>
#include <void_t.hpp>

namespace shadow
{
// free function signature
typedef any (*free_function_binding_signature)(any*);
// member function signature
typedef any (*member_function_binding_signature)(any&, any*);
// member variable getter
typedef any (*member_variable_get_binding_signature)(const any&);
// member variable setter
typedef void (*member_variable_set_binding_signature)(any&, const any&);
// constructor signature
typedef any (*constructor_binding_signature)(any*);
// conversion signature
typedef any (*conversion_binding_signature)(const any&);
// string serialize signature
typedef std::string (*string_serialization_signature)(const any&);
// string deserialization signature
typedef any (*string_deserialization_signature)(const std::string&);
// address of signature
typedef any (*address_of_signature)(any&);

////////////////////////////////////////////////////////////////////////////////
// generic bind point for free functions
// has the same signature as function pointer free_function_binding_signature
// which can be stored in the free_function_info struct

namespace free_function_detail
{
// necessary to handle void as return type differently when calling underlying
// free function
template <class ReturnType>
struct return_type_specializer
{
    // dispatch: unpacks argument type list and sequence to correctly index into
    // argument array and call get with the right types to retrieve raw values
    // from the anys
    template <class FunctionPointerType,
              FunctionPointerType FunctionPointerValue,
              class... ArgTypes,
              std::size_t... ArgSeq>
    static any
    dispatch(any* argument_array,
             metamusil::t_list::type_list<ArgTypes...>,
             std::index_sequence<ArgSeq...>)
    {
        // necessary to remove reference from types as any only stores
        // unqualified types, ie values only
        return FunctionPointerValue(
            argument_array[ArgSeq]
                .get<typename std::remove_reference_t<ArgTypes>>()...);
    }
};

template <>
struct return_type_specializer<void>
{
    // dispatch: unpacks argument type list and sequence to correctly index into
    // argument array and call get with the right types to retrieve raw values
    // from the anys
    template <class FunctionPointerType,
              FunctionPointerType FunctionPointerValue,
              class... ArgTypes,
              std::size_t... ArgSeq>
    static any
    dispatch(any* argument_array,
             metamusil::t_list::type_list<ArgTypes...>,
             std::index_sequence<ArgSeq...>)
    {
        // necessary to remove reference from types as any only stores
        // unqualified types, ie values only
        FunctionPointerValue(
            argument_array[ArgSeq]
                .get<typename std::remove_reference_t<ArgTypes>>()...);

        // return empty any, ie 'void'
        return any();
    }
};

// the value of the function pointer is stored at runtime in the template
// overload set
// this enables any function to be wrapped into uniform function signature that
// can be stored homogenously at runtime
template <class FunctionPointerType, FunctionPointerType FunctionPointerValue>
any
generic_free_function_bind_point(any* argument_array)
{
    typedef metamusil::deduce_return_type_t<FunctionPointerType> return_type;
    typedef metamusil::deduce_parameter_types_t<FunctionPointerType>
        parameter_types;
    // make integer sequence from type list
    typedef metamusil::t_list::index_sequence_for_t<parameter_types>
        parameter_sequence;

    return return_type_specializer<return_type>::
        template dispatch<FunctionPointerType, FunctionPointerValue>(
            argument_array, parameter_types(), parameter_sequence());
}
} // namespace free_function_detail

namespace member_function_detail
{

template <class ReturnType>
struct return_type_specializer
{
    template <class MemFunPointerType,
              MemFunPointerType MemFunPointerValue,
              class ObjectType,
              class... ParamTypes,
              std::size_t... ParamSequence>
    static any
    dispatch(any& object,
             any* argument_array,
             metamusil::t_list::type_list<ParamTypes...>,
             std::index_sequence<ParamSequence...>)
    {
        return (object.get<ObjectType>().*MemFunPointerValue)(
            argument_array[ParamSequence]
                .get<std::remove_reference_t<ParamTypes>>()...);
    }
};

template <>
struct return_type_specializer<void>
{
    template <class MemFunPointerType,
              MemFunPointerType MemFunPointerValue,
              class ObjectType,
              class... ParamTypes,
              std::size_t... ParamSequence>
    static any
    dispatch(any& object,
             any* argument_array,
             metamusil::t_list::type_list<ParamTypes...>,
             std::index_sequence<ParamSequence...>)
    {
        (object.get<ObjectType>().*MemFunPointerValue)(
            argument_array[ParamSequence]
                .get<std::remove_reference_t<ParamTypes>>()...);

        return any();
    }
};

template <class MemFunPointerType, MemFunPointerType MemFunPointerValue>
any
generic_member_function_bind_point(any& object, any* argument_array)
{
    // deduce return type
    typedef metamusil::deduce_return_type_t<MemFunPointerType> return_type;

    // deduce parameter types
    typedef metamusil::deduce_parameter_types_t<MemFunPointerType>
        parameter_types;

    // make integer sequence from parameter type list
    typedef metamusil::t_list::index_sequence_for_t<parameter_types>
        parameter_sequence;

    // deduce object type
    typedef metamusil::deduce_object_type_t<MemFunPointerType> object_type;

    return return_type_specializer<return_type>::
        template dispatch<MemFunPointerType, MemFunPointerValue, object_type>(
            object, argument_array, parameter_types(), parameter_sequence());
}
} // namespace member_function_detail

namespace member_variable_detail
{

template <class MemVarPointerType,
          MemVarPointerType MemVarPointerValue,
          class ObjectType,
          class MemVarType>
any
get_dispatch(const any& object)
{
    return (object.get<ObjectType>().*MemVarPointerValue);
}

template <class MemVarPointerType,
          MemVarPointerType MemVarPointerValue,
          class ObjectType,
          class MemVarType>
void
set_dispatch(any& object, const any& value)
{
    (object.get<ObjectType>().*MemVarPointerValue) = value.get<MemVarType>();
}

template <class MemVarPointerType, MemVarPointerType MemVarPointerValue>
any
generic_member_variable_get_bind_point(const any& object)
{
    typedef metamusil::deduce_member_variable_object_type_t<MemVarPointerType>
        object_type;
    typedef metamusil::deduce_member_variable_type_t<MemVarPointerType>
        member_variable_type;

    return get_dispatch<MemVarPointerType,
                        MemVarPointerValue,
                        object_type,
                        member_variable_type>(object);
}

template <class MemVarPointerType, MemVarPointerType MemVarPointerValue>
void
generic_member_variable_set_bind_point(any& object, const any& value)
{
    typedef metamusil::deduce_member_variable_object_type_t<MemVarPointerType>
        object_type;
    typedef metamusil::deduce_member_variable_type_t<MemVarPointerType>
        member_variable_type;

    return set_dispatch<MemVarPointerType,
                        MemVarPointerValue,
                        object_type,
                        member_variable_type>(object, value);
}
} // namespace member_variable_detail

namespace constructor_detail
{

// purpose of braced_init_selector is to attempt to use constructor T(...) if
// available, otherwise fall back to braced init list initialization
template <class, class T, class... ParamTypes>
struct braced_init_selector_impl
{
    template <std::size_t... Seq>
    static any
    constructor_dispatch(any* argument_array, std::index_sequence<Seq...>)
    {
        any out = T{argument_array[Seq].get<ParamTypes>()...};
        return out;
    }
};

template <class T, class... ParamTypes>
struct braced_init_selector_impl<
    metamusil::void_t<decltype(T(std::declval<ParamTypes>()...))>,
    T,
    ParamTypes...>
{
    template <std::size_t... Seq>
    static any
    constructor_dispatch(any* argument_array, std::index_sequence<Seq...>)
    {
        any out = T(argument_array[Seq].get<ParamTypes>()...);
        return out;
    }
};

template <class T, class... ParamTypes>
using braced_init_selector = braced_init_selector_impl<void, T, ParamTypes...>;

template <class T, class... ParamTypes>
any
generic_constructor_bind_point(any* argument_array)
{
    typedef std::index_sequence_for<ParamTypes...> param_sequence;

    return braced_init_selector<T, ParamTypes...>::constructor_dispatch(
        argument_array, param_sequence());
}
} // namespace constructor_detail

namespace conversion_detail
{
template <class TargetType, class SourceType, class = void>
struct conversion_specializer;

template <>
struct conversion_specializer<void, void>;

template <class TargetType, class SourceType>
struct conversion_specializer<
    TargetType,
    SourceType,
    std::enable_if_t<std::is_convertible<SourceType, TargetType>::value>>
{
    static any
    dispatch(const any& src)
    {
        TargetType temp = (TargetType)src.get<SourceType>();
        return temp;
    }
};

template <class TargetType, class SourceType>
any
generic_conversion_bind_point(const any& src)
{
    return conversion_specializer<TargetType, SourceType>::dispatch(src);
}
} // namespace conversion_detail

namespace string_serialization_detail
{

template <class T, class = void>
struct string_serialize_type_selector;

template <class T>
struct string_serialize_type_selector<
    T,
    std::enable_if_t<std::is_arithmetic<T>::value>>
{
    static std::string
    dispatch(const any& value)
    {
        return std::to_string(value.get<T>());
    }
};

template <>
struct string_serialize_type_selector<std::string>
{
    static std::string
    dispatch(const any& value)
    {
        return value.get<std::string>();
    }
};

template <>
struct string_serialize_type_selector<char>
{
    static std::string
    dispatch(const any& value)
    {
        std::string out;
        out.push_back(value.get<char>());
        return out;
    }
};

template <>
struct string_serialize_type_selector<void>
{
    static std::string
    dispatch(const any& value)
    {
        return "empty";
    }
};

template <class T>
std::string
generic_string_serialization_bind_point(const any& value)
{
    return string_serialize_type_selector<T>::dispatch(value);
}

template <class T, class = void>
struct string_deserialize_type_selector;

template <class T>
struct string_deserialize_type_selector<
    T,
    std::enable_if_t<std::is_arithmetic<T>::value>>
{
    static any
    dispatch(const std::string& str_value)
    {
        T out = std::stold(str_value);
        return out;
    }
};

template <>
struct string_deserialize_type_selector<char>
{
    static any
    dispatch(const std::string& str_value)
    {
        return str_value[0];
    }
};

template <>
struct string_deserialize_type_selector<std::string>
{
    static any
    dispatch(const std::string& str_value)
    {
        return str_value;
    }
};

template <>
struct string_deserialize_type_selector<int>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoi(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stol(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoll(str_value);
    }
};

template <>
struct string_deserialize_type_selector<unsigned long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoul(str_value);
    }
};

template <>
struct string_deserialize_type_selector<unsigned long long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoull(str_value);
    }
};

template <>
struct string_deserialize_type_selector<float>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stof(str_value);
    }
};

template <>
struct string_deserialize_type_selector<double>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stod(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long double>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stold(str_value);
    }
};

template <>
struct string_deserialize_type_selector<void>
{
    static any
    dispatch(const std::string& str_value)
    {
        return shadow::any();
    }
};

template <class T>
any
generic_string_deserialization_bind_point(const std::string& str_value)
{
    return string_deserialize_type_selector<T>::dispatch(str_value);
}
} // namespace string_serialization_detail

namespace pointer_detail
{
template <class T>
inline any
generic_address_of_bind_point(any& value)
{
    return any(&(value.get<T>()));
}

template <>
inline any
generic_address_of_bind_point<void>(any& value)
{
    return any(nullptr);
}

template <class T>
inline any
generic_dereference_bind_point(any& value)
{
    return any(*(value.get<T*>()));
}

template <>
inline any
generic_dereference_bind_point<void>(any& value)
{
    return any();
}

} // namespace pointer_detail

} // namespace shadow
<commit_msg>Add pointer to function signature dereference_signature. 	modified:   include/reflection_binding.hpp<commit_after>#pragma once

#include <utility>
#include <type_traits>
#include <string>

#include "any.hpp"
#include <type_list.hpp>
#include <function_deduction.hpp>
#include <member_variable_deduction.hpp>
#include <void_t.hpp>

namespace shadow
{
// free function signature
typedef any (*free_function_binding_signature)(any*);
// member function signature
typedef any (*member_function_binding_signature)(any&, any*);
// member variable getter
typedef any (*member_variable_get_binding_signature)(const any&);
// member variable setter
typedef void (*member_variable_set_binding_signature)(any&, const any&);
// constructor signature
typedef any (*constructor_binding_signature)(any*);
// conversion signature
typedef any (*conversion_binding_signature)(const any&);
// string serialize signature
typedef std::string (*string_serialization_signature)(const any&);
// string deserialization signature
typedef any (*string_deserialization_signature)(const std::string&);
// address of signature
typedef any (*address_of_signature)(any&);
// dereference signature
typedef any (*dereference_signature)(any&);

////////////////////////////////////////////////////////////////////////////////
// generic bind point for free functions
// has the same signature as function pointer free_function_binding_signature
// which can be stored in the free_function_info struct

namespace free_function_detail
{
// necessary to handle void as return type differently when calling underlying
// free function
template <class ReturnType>
struct return_type_specializer
{
    // dispatch: unpacks argument type list and sequence to correctly index into
    // argument array and call get with the right types to retrieve raw values
    // from the anys
    template <class FunctionPointerType,
              FunctionPointerType FunctionPointerValue,
              class... ArgTypes,
              std::size_t... ArgSeq>
    static any
    dispatch(any* argument_array,
             metamusil::t_list::type_list<ArgTypes...>,
             std::index_sequence<ArgSeq...>)
    {
        // necessary to remove reference from types as any only stores
        // unqualified types, ie values only
        return FunctionPointerValue(
            argument_array[ArgSeq]
                .get<typename std::remove_reference_t<ArgTypes>>()...);
    }
};

template <>
struct return_type_specializer<void>
{
    // dispatch: unpacks argument type list and sequence to correctly index into
    // argument array and call get with the right types to retrieve raw values
    // from the anys
    template <class FunctionPointerType,
              FunctionPointerType FunctionPointerValue,
              class... ArgTypes,
              std::size_t... ArgSeq>
    static any
    dispatch(any* argument_array,
             metamusil::t_list::type_list<ArgTypes...>,
             std::index_sequence<ArgSeq...>)
    {
        // necessary to remove reference from types as any only stores
        // unqualified types, ie values only
        FunctionPointerValue(
            argument_array[ArgSeq]
                .get<typename std::remove_reference_t<ArgTypes>>()...);

        // return empty any, ie 'void'
        return any();
    }
};

// the value of the function pointer is stored at runtime in the template
// overload set
// this enables any function to be wrapped into uniform function signature that
// can be stored homogenously at runtime
template <class FunctionPointerType, FunctionPointerType FunctionPointerValue>
any
generic_free_function_bind_point(any* argument_array)
{
    typedef metamusil::deduce_return_type_t<FunctionPointerType> return_type;
    typedef metamusil::deduce_parameter_types_t<FunctionPointerType>
        parameter_types;
    // make integer sequence from type list
    typedef metamusil::t_list::index_sequence_for_t<parameter_types>
        parameter_sequence;

    return return_type_specializer<return_type>::
        template dispatch<FunctionPointerType, FunctionPointerValue>(
            argument_array, parameter_types(), parameter_sequence());
}
} // namespace free_function_detail

namespace member_function_detail
{

template <class ReturnType>
struct return_type_specializer
{
    template <class MemFunPointerType,
              MemFunPointerType MemFunPointerValue,
              class ObjectType,
              class... ParamTypes,
              std::size_t... ParamSequence>
    static any
    dispatch(any& object,
             any* argument_array,
             metamusil::t_list::type_list<ParamTypes...>,
             std::index_sequence<ParamSequence...>)
    {
        return (object.get<ObjectType>().*MemFunPointerValue)(
            argument_array[ParamSequence]
                .get<std::remove_reference_t<ParamTypes>>()...);
    }
};

template <>
struct return_type_specializer<void>
{
    template <class MemFunPointerType,
              MemFunPointerType MemFunPointerValue,
              class ObjectType,
              class... ParamTypes,
              std::size_t... ParamSequence>
    static any
    dispatch(any& object,
             any* argument_array,
             metamusil::t_list::type_list<ParamTypes...>,
             std::index_sequence<ParamSequence...>)
    {
        (object.get<ObjectType>().*MemFunPointerValue)(
            argument_array[ParamSequence]
                .get<std::remove_reference_t<ParamTypes>>()...);

        return any();
    }
};

template <class MemFunPointerType, MemFunPointerType MemFunPointerValue>
any
generic_member_function_bind_point(any& object, any* argument_array)
{
    // deduce return type
    typedef metamusil::deduce_return_type_t<MemFunPointerType> return_type;

    // deduce parameter types
    typedef metamusil::deduce_parameter_types_t<MemFunPointerType>
        parameter_types;

    // make integer sequence from parameter type list
    typedef metamusil::t_list::index_sequence_for_t<parameter_types>
        parameter_sequence;

    // deduce object type
    typedef metamusil::deduce_object_type_t<MemFunPointerType> object_type;

    return return_type_specializer<return_type>::
        template dispatch<MemFunPointerType, MemFunPointerValue, object_type>(
            object, argument_array, parameter_types(), parameter_sequence());
}
} // namespace member_function_detail

namespace member_variable_detail
{

template <class MemVarPointerType,
          MemVarPointerType MemVarPointerValue,
          class ObjectType,
          class MemVarType>
any
get_dispatch(const any& object)
{
    return (object.get<ObjectType>().*MemVarPointerValue);
}

template <class MemVarPointerType,
          MemVarPointerType MemVarPointerValue,
          class ObjectType,
          class MemVarType>
void
set_dispatch(any& object, const any& value)
{
    (object.get<ObjectType>().*MemVarPointerValue) = value.get<MemVarType>();
}

template <class MemVarPointerType, MemVarPointerType MemVarPointerValue>
any
generic_member_variable_get_bind_point(const any& object)
{
    typedef metamusil::deduce_member_variable_object_type_t<MemVarPointerType>
        object_type;
    typedef metamusil::deduce_member_variable_type_t<MemVarPointerType>
        member_variable_type;

    return get_dispatch<MemVarPointerType,
                        MemVarPointerValue,
                        object_type,
                        member_variable_type>(object);
}

template <class MemVarPointerType, MemVarPointerType MemVarPointerValue>
void
generic_member_variable_set_bind_point(any& object, const any& value)
{
    typedef metamusil::deduce_member_variable_object_type_t<MemVarPointerType>
        object_type;
    typedef metamusil::deduce_member_variable_type_t<MemVarPointerType>
        member_variable_type;

    return set_dispatch<MemVarPointerType,
                        MemVarPointerValue,
                        object_type,
                        member_variable_type>(object, value);
}
} // namespace member_variable_detail

namespace constructor_detail
{

// purpose of braced_init_selector is to attempt to use constructor T(...) if
// available, otherwise fall back to braced init list initialization
template <class, class T, class... ParamTypes>
struct braced_init_selector_impl
{
    template <std::size_t... Seq>
    static any
    constructor_dispatch(any* argument_array, std::index_sequence<Seq...>)
    {
        any out = T{argument_array[Seq].get<ParamTypes>()...};
        return out;
    }
};

template <class T, class... ParamTypes>
struct braced_init_selector_impl<
    metamusil::void_t<decltype(T(std::declval<ParamTypes>()...))>,
    T,
    ParamTypes...>
{
    template <std::size_t... Seq>
    static any
    constructor_dispatch(any* argument_array, std::index_sequence<Seq...>)
    {
        any out = T(argument_array[Seq].get<ParamTypes>()...);
        return out;
    }
};

template <class T, class... ParamTypes>
using braced_init_selector = braced_init_selector_impl<void, T, ParamTypes...>;

template <class T, class... ParamTypes>
any
generic_constructor_bind_point(any* argument_array)
{
    typedef std::index_sequence_for<ParamTypes...> param_sequence;

    return braced_init_selector<T, ParamTypes...>::constructor_dispatch(
        argument_array, param_sequence());
}
} // namespace constructor_detail

namespace conversion_detail
{
template <class TargetType, class SourceType, class = void>
struct conversion_specializer;

template <>
struct conversion_specializer<void, void>;

template <class TargetType, class SourceType>
struct conversion_specializer<
    TargetType,
    SourceType,
    std::enable_if_t<std::is_convertible<SourceType, TargetType>::value>>
{
    static any
    dispatch(const any& src)
    {
        TargetType temp = (TargetType)src.get<SourceType>();
        return temp;
    }
};

template <class TargetType, class SourceType>
any
generic_conversion_bind_point(const any& src)
{
    return conversion_specializer<TargetType, SourceType>::dispatch(src);
}
} // namespace conversion_detail

namespace string_serialization_detail
{

template <class T, class = void>
struct string_serialize_type_selector;

template <class T>
struct string_serialize_type_selector<
    T,
    std::enable_if_t<std::is_arithmetic<T>::value>>
{
    static std::string
    dispatch(const any& value)
    {
        return std::to_string(value.get<T>());
    }
};

template <>
struct string_serialize_type_selector<std::string>
{
    static std::string
    dispatch(const any& value)
    {
        return value.get<std::string>();
    }
};

template <>
struct string_serialize_type_selector<char>
{
    static std::string
    dispatch(const any& value)
    {
        std::string out;
        out.push_back(value.get<char>());
        return out;
    }
};

template <>
struct string_serialize_type_selector<void>
{
    static std::string
    dispatch(const any& value)
    {
        return "empty";
    }
};

template <class T>
std::string
generic_string_serialization_bind_point(const any& value)
{
    return string_serialize_type_selector<T>::dispatch(value);
}

template <class T, class = void>
struct string_deserialize_type_selector;

template <class T>
struct string_deserialize_type_selector<
    T,
    std::enable_if_t<std::is_arithmetic<T>::value>>
{
    static any
    dispatch(const std::string& str_value)
    {
        T out = std::stold(str_value);
        return out;
    }
};

template <>
struct string_deserialize_type_selector<char>
{
    static any
    dispatch(const std::string& str_value)
    {
        return str_value[0];
    }
};

template <>
struct string_deserialize_type_selector<std::string>
{
    static any
    dispatch(const std::string& str_value)
    {
        return str_value;
    }
};

template <>
struct string_deserialize_type_selector<int>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoi(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stol(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoll(str_value);
    }
};

template <>
struct string_deserialize_type_selector<unsigned long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoul(str_value);
    }
};

template <>
struct string_deserialize_type_selector<unsigned long long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoull(str_value);
    }
};

template <>
struct string_deserialize_type_selector<float>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stof(str_value);
    }
};

template <>
struct string_deserialize_type_selector<double>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stod(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long double>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stold(str_value);
    }
};

template <>
struct string_deserialize_type_selector<void>
{
    static any
    dispatch(const std::string& str_value)
    {
        return shadow::any();
    }
};

template <class T>
any
generic_string_deserialization_bind_point(const std::string& str_value)
{
    return string_deserialize_type_selector<T>::dispatch(str_value);
}
} // namespace string_serialization_detail

namespace pointer_detail
{
template <class T>
inline any
generic_address_of_bind_point(any& value)
{
    return any(&(value.get<T>()));
}

template <>
inline any
generic_address_of_bind_point<void>(any& value)
{
    return any(nullptr);
}

template <class T>
inline any
generic_dereference_bind_point(any& value)
{
    return any(*(value.get<T*>()));
}

template <>
inline any
generic_dereference_bind_point<void>(any& value)
{
    return any();
}

} // namespace pointer_detail

} // namespace shadow
<|endoftext|>


<commit_before>#ifndef REFLECTION_BINDING_HPP
#define REFLECTION_BINDING_HPP

#include <string>
#include <type_traits>
#include <utility>

#include "any.hpp"
#include <function_deduction.hpp>
#include <member_variable_deduction.hpp>
#include <type_list.hpp>
#include <void_t.hpp>

namespace shadow
{
// free function signature
typedef any (*free_function_binding_signature)(any*);
// member function signature
typedef any (*member_function_binding_signature)(any&, any*);
// member variable getter
typedef any (*member_variable_get_binding_signature)(const any&);
// member variable setter
typedef void (*member_variable_set_binding_signature)(any&, const any&);
// constructor signature
typedef any (*constructor_binding_signature)(any*);
// conversion signature
typedef any (*conversion_binding_signature)(const any&);
// string serialize signature
typedef std::string (*string_serialization_signature)(const any&);
// string deserialization signature
typedef any (*string_deserialization_signature)(const std::string&);
// address of signature
typedef any (*address_of_signature)(any&);
// dereference signature
typedef any (*dereference_signature)(any&);

////////////////////////////////////////////////////////////////////////////////
// generic bind point for free functions
// has the same signature as function pointer free_function_binding_signature
// which can be stored in the free_function_info struct

namespace free_function_detail
{
// necessary to handle void as return type differently when calling underlying
// free function
template <class ReturnType>
struct return_type_specializer
{
    // dispatch: unpacks argument type list and sequence to correctly index into
    // argument array and call get with the right types to retrieve raw values
    // from the anys
    template <class FunctionPointerType,
              FunctionPointerType FunctionPointerValue,
              class... ArgTypes,
              std::size_t... ArgSeq>
    static any
    dispatch(any* argument_array,
             metamusil::t_list::type_list<ArgTypes...>,
             std::index_sequence<ArgSeq...>)
    {
        // necessary to remove reference from types as any only stores
        // unqualified types, ie values only
        return FunctionPointerValue(
            argument_array[ArgSeq]
                .get<typename std::remove_reference_t<ArgTypes>>()...);
    }
};

template <>
struct return_type_specializer<void>
{
    // dispatch: unpacks argument type list and sequence to correctly index into
    // argument array and call get with the right types to retrieve raw values
    // from the anys
    template <class FunctionPointerType,
              FunctionPointerType FunctionPointerValue,
              class... ArgTypes,
              std::size_t... ArgSeq>
    static any
    dispatch(any* argument_array,
             metamusil::t_list::type_list<ArgTypes...>,
             std::index_sequence<ArgSeq...>)
    {
        // necessary to remove reference from types as any only stores
        // unqualified types, ie values only
        FunctionPointerValue(
            argument_array[ArgSeq]
                .get<typename std::remove_reference_t<ArgTypes>>()...);

        // return empty any, ie 'void'
        return any();
    }
};

// the value of the function pointer is stored at runtime in the template
// overload set
// this enables any function to be wrapped into uniform function signature that
// can be stored homogenously at runtime
template <class FunctionPointerType, FunctionPointerType FunctionPointerValue>
any
generic_free_function_bind_point(any* argument_array)
{
    typedef metamusil::deduce_return_type_t<FunctionPointerType> return_type;
    typedef metamusil::deduce_parameter_types_t<FunctionPointerType>
        parameter_types;
    // make integer sequence from type list
    typedef metamusil::t_list::index_sequence_for_t<parameter_types>
        parameter_sequence;

    return return_type_specializer<return_type>::
        template dispatch<FunctionPointerType, FunctionPointerValue>(
            argument_array, parameter_types(), parameter_sequence());
}
} // namespace free_function_detail

namespace member_function_detail
{

template <class ReturnType>
struct return_type_specializer
{
    template <class MemFunPointerType,
              MemFunPointerType MemFunPointerValue,
              class ObjectType,
              class... ParamTypes,
              std::size_t... ParamSequence>
    static any
    dispatch(any& object,
             any* argument_array,
             metamusil::t_list::type_list<ParamTypes...>,
             std::index_sequence<ParamSequence...>)
    {
        return (object.get<ObjectType>().*MemFunPointerValue)(
            argument_array[ParamSequence]
                .get<std::remove_reference_t<ParamTypes>>()...);
    }
};

template <>
struct return_type_specializer<void>
{
    template <class MemFunPointerType,
              MemFunPointerType MemFunPointerValue,
              class ObjectType,
              class... ParamTypes,
              std::size_t... ParamSequence>
    static any
    dispatch(any& object,
             any* argument_array,
             metamusil::t_list::type_list<ParamTypes...>,
             std::index_sequence<ParamSequence...>)
    {
        (object.get<ObjectType>().*MemFunPointerValue)(
            argument_array[ParamSequence]
                .get<std::remove_reference_t<ParamTypes>>()...);

        return any();
    }
};

template <class MemFunPointerType, MemFunPointerType MemFunPointerValue>
any
generic_member_function_bind_point(any& object, any* argument_array)
{
    // deduce return type
    typedef metamusil::deduce_return_type_t<MemFunPointerType> return_type;

    // deduce parameter types
    typedef metamusil::deduce_parameter_types_t<MemFunPointerType>
        parameter_types;

    // make integer sequence from parameter type list
    typedef metamusil::t_list::index_sequence_for_t<parameter_types>
        parameter_sequence;

    // deduce object type
    typedef metamusil::deduce_object_type_t<MemFunPointerType> object_type;

    return return_type_specializer<return_type>::
        template dispatch<MemFunPointerType, MemFunPointerValue, object_type>(
            object, argument_array, parameter_types(), parameter_sequence());
}
} // namespace member_function_detail

namespace member_variable_detail
{

template <class MemVarPointerType,
          MemVarPointerType MemVarPointerValue,
          class ObjectType,
          class MemVarType>
any
get_dispatch(const any& object)
{
    return (object.get<ObjectType>().*MemVarPointerValue);
}

template <class MemVarPointerType,
          MemVarPointerType MemVarPointerValue,
          class ObjectType,
          class MemVarType>
void
set_dispatch(any& object, const any& value)
{
    (object.get<ObjectType>().*MemVarPointerValue) = value.get<MemVarType>();
}

template <class MemVarPointerType, MemVarPointerType MemVarPointerValue>
any
generic_member_variable_get_bind_point(const any& object)
{
    typedef metamusil::deduce_member_variable_object_type_t<MemVarPointerType>
        object_type;
    typedef metamusil::deduce_member_variable_type_t<MemVarPointerType>
        member_variable_type;

    return get_dispatch<MemVarPointerType,
                        MemVarPointerValue,
                        object_type,
                        member_variable_type>(object);
}

template <class MemVarPointerType, MemVarPointerType MemVarPointerValue>
void
generic_member_variable_set_bind_point(any& object, const any& value)
{
    typedef metamusil::deduce_member_variable_object_type_t<MemVarPointerType>
        object_type;
    typedef metamusil::deduce_member_variable_type_t<MemVarPointerType>
        member_variable_type;

    return set_dispatch<MemVarPointerType,
                        MemVarPointerValue,
                        object_type,
                        member_variable_type>(object, value);
}
} // namespace member_variable_detail

namespace constructor_detail
{

// purpose of braced_init_selector is to attempt to use constructor T(...) if
// available, otherwise fall back to braced init list initialization
template <class, class T, class... ParamTypes>
struct braced_init_selector_impl
{
    template <std::size_t... Seq>
    static any
    constructor_dispatch(any* argument_array, std::index_sequence<Seq...>)
    {
        any out = T{argument_array[Seq].get<ParamTypes>()...};
        return out;
    }
};

template <class T, class... ParamTypes>
struct braced_init_selector_impl<
    metamusil::void_t<decltype(T(std::declval<ParamTypes>()...))>,
    T,
    ParamTypes...>
{
    template <std::size_t... Seq>
    static any
    constructor_dispatch(any* argument_array, std::index_sequence<Seq...>)
    {
        any out = T(argument_array[Seq].get<ParamTypes>()...);
        return out;
    }
};

template <class T, class... ParamTypes>
using braced_init_selector = braced_init_selector_impl<void, T, ParamTypes...>;

template <class T, class... ParamTypes>
any
generic_constructor_bind_point(any* argument_array)
{
    typedef std::index_sequence_for<ParamTypes...> param_sequence;

    return braced_init_selector<T, ParamTypes...>::constructor_dispatch(
        argument_array, param_sequence());
}
} // namespace constructor_detail

namespace conversion_detail
{
template <class TargetType, class SourceType, class = void>
struct conversion_specializer;

template <>
struct conversion_specializer<void, void>;

template <class TargetType, class SourceType>
struct conversion_specializer<
    TargetType,
    SourceType,
    std::enable_if_t<std::is_convertible<SourceType, TargetType>::value>>
{
    static any
    dispatch(const any& src)
    {
        TargetType temp = static_cast<TargetType>(src.get<SourceType>());
        return temp;
    }
};

template <class TargetType, class SourceType>
any
generic_conversion_bind_point(const any& src)
{
    return conversion_specializer<TargetType, SourceType>::dispatch(src);
}
} // namespace conversion_detail

namespace string_serialization_detail
{

template <class T, class = void>
struct string_serialize_type_selector;

template <class T>
struct string_serialize_type_selector<
    T,
    std::enable_if_t<std::is_arithmetic<T>::value>>
{
    static std::string
    dispatch(const any& value)
    {
        return std::to_string(value.get<T>());
    }
};

template <>
struct string_serialize_type_selector<std::string>
{
    static std::string
    dispatch(const any& value)
    {
        return value.get<std::string>();
    }
};

template <>
struct string_serialize_type_selector<char>
{
    static std::string
    dispatch(const any& value)
    {
        std::string out;
        out.push_back(value.get<char>());
        return out;
    }
};

template <>
struct string_serialize_type_selector<void>
{
    static std::string
    dispatch(const any& value)
    {
        return "empty";
    }
};

template <class T>
std::string
generic_string_serialization_bind_point(const any& value)
{
    return string_serialize_type_selector<T>::dispatch(value);
}

template <class T, class = void>
struct string_deserialize_type_selector;

template <class T>
struct string_deserialize_type_selector<
    T,
    std::enable_if_t<std::is_arithmetic<T>::value>>
{
    static any
    dispatch(const std::string& str_value)
    {
        T out = std::stold(str_value);
        return out;
    }
};

template <>
struct string_deserialize_type_selector<char>
{
    static any
    dispatch(const std::string& str_value)
    {
        return str_value[0];
    }
};

template <>
struct string_deserialize_type_selector<std::string>
{
    static any
    dispatch(const std::string& str_value)
    {
        return str_value;
    }
};

template <>
struct string_deserialize_type_selector<int>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoi(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stol(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoll(str_value);
    }
};

template <>
struct string_deserialize_type_selector<unsigned long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoul(str_value);
    }
};

template <>
struct string_deserialize_type_selector<unsigned long long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoull(str_value);
    }
};

template <>
struct string_deserialize_type_selector<float>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stof(str_value);
    }
};

template <>
struct string_deserialize_type_selector<double>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stod(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long double>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stold(str_value);
    }
};

template <>
struct string_deserialize_type_selector<void>
{
    static any
    dispatch(const std::string& str_value)
    {
        return shadow::any();
    }
};

template <class T>
any
generic_string_deserialization_bind_point(const std::string& str_value)
{
    return string_deserialize_type_selector<T>::dispatch(str_value);
}
} // namespace string_serialization_detail

namespace pointer_detail
{
template <class T>
inline any
generic_address_of_bind_point(any& value)
{
    return any(&(value.get<T>()));
}

template <>
inline any
generic_address_of_bind_point<void>(any& value)
{
    return any(nullptr);
}

template <class T>
inline any
generic_dereference_bind_point(any& value)
{
    return any(*(value.get<T*>()));
}

template <>
inline any
generic_dereference_bind_point<void>(any& value)
{
    return any();
}

} // namespace pointer_detail

} // namespace shadow

#endif
<commit_msg>Remove name of unused parameter. 	modified:   include/reflection_binding.hpp<commit_after>#ifndef REFLECTION_BINDING_HPP
#define REFLECTION_BINDING_HPP

#include <string>
#include <type_traits>
#include <utility>

#include "any.hpp"
#include <function_deduction.hpp>
#include <member_variable_deduction.hpp>
#include <type_list.hpp>
#include <void_t.hpp>

namespace shadow
{
// free function signature
typedef any (*free_function_binding_signature)(any*);
// member function signature
typedef any (*member_function_binding_signature)(any&, any*);
// member variable getter
typedef any (*member_variable_get_binding_signature)(const any&);
// member variable setter
typedef void (*member_variable_set_binding_signature)(any&, const any&);
// constructor signature
typedef any (*constructor_binding_signature)(any*);
// conversion signature
typedef any (*conversion_binding_signature)(const any&);
// string serialize signature
typedef std::string (*string_serialization_signature)(const any&);
// string deserialization signature
typedef any (*string_deserialization_signature)(const std::string&);
// address of signature
typedef any (*address_of_signature)(any&);
// dereference signature
typedef any (*dereference_signature)(any&);

////////////////////////////////////////////////////////////////////////////////
// generic bind point for free functions
// has the same signature as function pointer free_function_binding_signature
// which can be stored in the free_function_info struct

namespace free_function_detail
{
// necessary to handle void as return type differently when calling underlying
// free function
template <class ReturnType>
struct return_type_specializer
{
    // dispatch: unpacks argument type list and sequence to correctly index into
    // argument array and call get with the right types to retrieve raw values
    // from the anys
    template <class FunctionPointerType,
              FunctionPointerType FunctionPointerValue,
              class... ArgTypes,
              std::size_t... ArgSeq>
    static any
    dispatch(any* argument_array,
             metamusil::t_list::type_list<ArgTypes...>,
             std::index_sequence<ArgSeq...>)
    {
        // necessary to remove reference from types as any only stores
        // unqualified types, ie values only
        return FunctionPointerValue(
            argument_array[ArgSeq]
                .get<typename std::remove_reference_t<ArgTypes>>()...);
    }
};

template <>
struct return_type_specializer<void>
{
    // dispatch: unpacks argument type list and sequence to correctly index into
    // argument array and call get with the right types to retrieve raw values
    // from the anys
    template <class FunctionPointerType,
              FunctionPointerType FunctionPointerValue,
              class... ArgTypes,
              std::size_t... ArgSeq>
    static any
    dispatch(any* argument_array,
             metamusil::t_list::type_list<ArgTypes...>,
             std::index_sequence<ArgSeq...>)
    {
        // necessary to remove reference from types as any only stores
        // unqualified types, ie values only
        FunctionPointerValue(
            argument_array[ArgSeq]
                .get<typename std::remove_reference_t<ArgTypes>>()...);

        // return empty any, ie 'void'
        return any();
    }
};

// the value of the function pointer is stored at runtime in the template
// overload set
// this enables any function to be wrapped into uniform function signature that
// can be stored homogenously at runtime
template <class FunctionPointerType, FunctionPointerType FunctionPointerValue>
any
generic_free_function_bind_point(any* argument_array)
{
    typedef metamusil::deduce_return_type_t<FunctionPointerType> return_type;
    typedef metamusil::deduce_parameter_types_t<FunctionPointerType>
        parameter_types;
    // make integer sequence from type list
    typedef metamusil::t_list::index_sequence_for_t<parameter_types>
        parameter_sequence;

    return return_type_specializer<return_type>::
        template dispatch<FunctionPointerType, FunctionPointerValue>(
            argument_array, parameter_types(), parameter_sequence());
}
} // namespace free_function_detail

namespace member_function_detail
{

template <class ReturnType>
struct return_type_specializer
{
    template <class MemFunPointerType,
              MemFunPointerType MemFunPointerValue,
              class ObjectType,
              class... ParamTypes,
              std::size_t... ParamSequence>
    static any
    dispatch(any& object,
             any* argument_array,
             metamusil::t_list::type_list<ParamTypes...>,
             std::index_sequence<ParamSequence...>)
    {
        return (object.get<ObjectType>().*MemFunPointerValue)(
            argument_array[ParamSequence]
                .get<std::remove_reference_t<ParamTypes>>()...);
    }
};

template <>
struct return_type_specializer<void>
{
    template <class MemFunPointerType,
              MemFunPointerType MemFunPointerValue,
              class ObjectType,
              class... ParamTypes,
              std::size_t... ParamSequence>
    static any
    dispatch(any& object,
             any* argument_array,
             metamusil::t_list::type_list<ParamTypes...>,
             std::index_sequence<ParamSequence...>)
    {
        (object.get<ObjectType>().*MemFunPointerValue)(
            argument_array[ParamSequence]
                .get<std::remove_reference_t<ParamTypes>>()...);

        return any();
    }
};

template <class MemFunPointerType, MemFunPointerType MemFunPointerValue>
any
generic_member_function_bind_point(any& object, any* argument_array)
{
    // deduce return type
    typedef metamusil::deduce_return_type_t<MemFunPointerType> return_type;

    // deduce parameter types
    typedef metamusil::deduce_parameter_types_t<MemFunPointerType>
        parameter_types;

    // make integer sequence from parameter type list
    typedef metamusil::t_list::index_sequence_for_t<parameter_types>
        parameter_sequence;

    // deduce object type
    typedef metamusil::deduce_object_type_t<MemFunPointerType> object_type;

    return return_type_specializer<return_type>::
        template dispatch<MemFunPointerType, MemFunPointerValue, object_type>(
            object, argument_array, parameter_types(), parameter_sequence());
}
} // namespace member_function_detail

namespace member_variable_detail
{

template <class MemVarPointerType,
          MemVarPointerType MemVarPointerValue,
          class ObjectType,
          class MemVarType>
any
get_dispatch(const any& object)
{
    return (object.get<ObjectType>().*MemVarPointerValue);
}

template <class MemVarPointerType,
          MemVarPointerType MemVarPointerValue,
          class ObjectType,
          class MemVarType>
void
set_dispatch(any& object, const any& value)
{
    (object.get<ObjectType>().*MemVarPointerValue) = value.get<MemVarType>();
}

template <class MemVarPointerType, MemVarPointerType MemVarPointerValue>
any
generic_member_variable_get_bind_point(const any& object)
{
    typedef metamusil::deduce_member_variable_object_type_t<MemVarPointerType>
        object_type;
    typedef metamusil::deduce_member_variable_type_t<MemVarPointerType>
        member_variable_type;

    return get_dispatch<MemVarPointerType,
                        MemVarPointerValue,
                        object_type,
                        member_variable_type>(object);
}

template <class MemVarPointerType, MemVarPointerType MemVarPointerValue>
void
generic_member_variable_set_bind_point(any& object, const any& value)
{
    typedef metamusil::deduce_member_variable_object_type_t<MemVarPointerType>
        object_type;
    typedef metamusil::deduce_member_variable_type_t<MemVarPointerType>
        member_variable_type;

    return set_dispatch<MemVarPointerType,
                        MemVarPointerValue,
                        object_type,
                        member_variable_type>(object, value);
}
} // namespace member_variable_detail

namespace constructor_detail
{

// purpose of braced_init_selector is to attempt to use constructor T(...) if
// available, otherwise fall back to braced init list initialization
template <class, class T, class... ParamTypes>
struct braced_init_selector_impl
{
    template <std::size_t... Seq>
    static any
    constructor_dispatch(any* argument_array, std::index_sequence<Seq...>)
    {
        any out = T{argument_array[Seq].get<ParamTypes>()...};
        return out;
    }
};

template <class T, class... ParamTypes>
struct braced_init_selector_impl<
    metamusil::void_t<decltype(T(std::declval<ParamTypes>()...))>,
    T,
    ParamTypes...>
{
    template <std::size_t... Seq>
    static any
    constructor_dispatch(any* argument_array, std::index_sequence<Seq...>)
    {
        any out = T(argument_array[Seq].get<ParamTypes>()...);
        return out;
    }
};

template <class T, class... ParamTypes>
using braced_init_selector = braced_init_selector_impl<void, T, ParamTypes...>;

template <class T, class... ParamTypes>
any
generic_constructor_bind_point(any* argument_array)
{
    typedef std::index_sequence_for<ParamTypes...> param_sequence;

    return braced_init_selector<T, ParamTypes...>::constructor_dispatch(
        argument_array, param_sequence());
}
} // namespace constructor_detail

namespace conversion_detail
{
template <class TargetType, class SourceType, class = void>
struct conversion_specializer;

template <>
struct conversion_specializer<void, void>;

template <class TargetType, class SourceType>
struct conversion_specializer<
    TargetType,
    SourceType,
    std::enable_if_t<std::is_convertible<SourceType, TargetType>::value>>
{
    static any
    dispatch(const any& src)
    {
        TargetType temp = static_cast<TargetType>(src.get<SourceType>());
        return temp;
    }
};

template <class TargetType, class SourceType>
any
generic_conversion_bind_point(const any& src)
{
    return conversion_specializer<TargetType, SourceType>::dispatch(src);
}
} // namespace conversion_detail

namespace string_serialization_detail
{

template <class T, class = void>
struct string_serialize_type_selector;

template <class T>
struct string_serialize_type_selector<
    T,
    std::enable_if_t<std::is_arithmetic<T>::value>>
{
    static std::string
    dispatch(const any& value)
    {
        return std::to_string(value.get<T>());
    }
};

template <>
struct string_serialize_type_selector<std::string>
{
    static std::string
    dispatch(const any& value)
    {
        return value.get<std::string>();
    }
};

template <>
struct string_serialize_type_selector<char>
{
    static std::string
    dispatch(const any& value)
    {
        std::string out;
        out.push_back(value.get<char>());
        return out;
    }
};

template <>
struct string_serialize_type_selector<void>
{
    static std::string
    dispatch(const any&)
    {
        return "empty";
    }
};

template <class T>
std::string
generic_string_serialization_bind_point(const any& value)
{
    return string_serialize_type_selector<T>::dispatch(value);
}

template <class T, class = void>
struct string_deserialize_type_selector;

template <class T>
struct string_deserialize_type_selector<
    T,
    std::enable_if_t<std::is_arithmetic<T>::value>>
{
    static any
    dispatch(const std::string& str_value)
    {
        T out = std::stold(str_value);
        return out;
    }
};

template <>
struct string_deserialize_type_selector<char>
{
    static any
    dispatch(const std::string& str_value)
    {
        return str_value[0];
    }
};

template <>
struct string_deserialize_type_selector<std::string>
{
    static any
    dispatch(const std::string& str_value)
    {
        return str_value;
    }
};

template <>
struct string_deserialize_type_selector<int>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoi(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stol(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoll(str_value);
    }
};

template <>
struct string_deserialize_type_selector<unsigned long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoul(str_value);
    }
};

template <>
struct string_deserialize_type_selector<unsigned long long>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stoull(str_value);
    }
};

template <>
struct string_deserialize_type_selector<float>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stof(str_value);
    }
};

template <>
struct string_deserialize_type_selector<double>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stod(str_value);
    }
};

template <>
struct string_deserialize_type_selector<long double>
{
    static any
    dispatch(const std::string& str_value)
    {
        return std::stold(str_value);
    }
};

template <>
struct string_deserialize_type_selector<void>
{
    static any
    dispatch(const std::string&)
    {
        return shadow::any();
    }
};

template <class T>
any
generic_string_deserialization_bind_point(const std::string& str_value)
{
    return string_deserialize_type_selector<T>::dispatch(str_value);
}
} // namespace string_serialization_detail

namespace pointer_detail
{
template <class T>
inline any
generic_address_of_bind_point(any& value)
{
    return any(&(value.get<T>()));
}

template <>
inline any
generic_address_of_bind_point<void>(any&)
{
    return any(nullptr);
}

template <class T>
inline any
generic_dereference_bind_point(any& value)
{
    return any(*(value.get<T*>()));
}

template <>
inline any
generic_dereference_bind_point<void>(any&)
{
    return any();
}

} // namespace pointer_detail

} // namespace shadow

#endif
<|endoftext|>


<commit_before>// FileSections.cpp

/*
* (C) Copyright 2015 Noah Roth
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/

#include "stdafx.hpp"
#include "FileSections.hpp"

using namespace RCT3Asset;

DataEntry::DataEntry() : Size(0), Offset(0), Data(nullptr)
{

}

DataSection::DataSection() : Offset(0)
{

}

DataEntry& DataSection::CreateAndAdd(unsigned int size, RCT3Debugging::OutputLog& log)
{
	DataEntry entry;
	entry.Size = size;
	entry.Offset = 0;
	entry.Data = nullptr;
	if (size)
		entry.Data = new unsigned char[size]();
	Entries.push_back(entry);
	return Entries.back();
}

DataEntry& DataSection::CreateAndInsert(unsigned int size, RCT3Debugging::OutputLog& log)
{
	DataEntry entry;
	entry.Data = nullptr;
	entry.Size = size;
	entry.Offset = 0;
	if (size)
		entry.Data = new unsigned char[size]();
	Entries.insert(Entries.begin(), entry);
	return Entries.front();
}

DataSection& FileSections::Get(unsigned int index)
{
	if (index < 9)
		return _sections[index];

	return _sections[8];
}

DataSection& FileSections::operator[](unsigned int index)
{
	return Get(index);
}

unsigned int FileSections::UpdateOffsets(unsigned int startingOffset, RCT3Debugging::OutputLog& log)
{
	unsigned int currOffset = startingOffset;
	for (unsigned int i = 0; i < 9; i++)
	{
		for (unsigned int j = 0; j < _sections[i].Entries.size(); j++)
		{
			_sections[i].Entries[j].Offset = currOffset;
			currOffset += _sections[i].Entries[j].Size;
		}
		_sections[i].Offset = currOffset;
	}

	log.Debug("FileSections::UpdateOffsets(..): returned " + STR(currOffset));

	return currOffset;
}<commit_msg>Relocated ExtraData, reinforcing RAII<commit_after>// FileSections.cpp

/*
* (C) Copyright 2015 Noah Roth
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/

#include "stdafx.hpp"
#include "FileSections.hpp"

using namespace RCT3Asset;

ExtraData::ExtraData(unsigned int size, void* data)
	: Size(size), Data(reinterpret_cast<unsigned char*>(data))
{

}

ExtraData::ExtraData()
	: Size(0), Data(nullptr)
{

}

ExtraData::~ExtraData()
{
	if (Data != nullptr)
	{
		delete[] Data;
	}
}

DataEntry::DataEntry()
	: Size(0), Offset(0), Data(nullptr)
{

}

DataEntry::~DataEntry()
{
	if (Data != nullptr)
	{
		delete[] Data;
	}
}

DataSection::DataSection()
	 : Offset(0)
{

}

DataEntry& DataSection::CreateAndAdd(unsigned int size, RCT3Debugging::OutputLog& log)
{
	DataEntry entry;
	entry.Size = size;
	entry.Offset = 0;
	entry.Data = nullptr;
	if (size)
		entry.Data = new unsigned char[size]();
	Entries.push_back(entry);
	return Entries.back();
}

DataEntry& DataSection::CreateAndInsert(unsigned int size, RCT3Debugging::OutputLog& log)
{
	DataEntry entry;
	entry.Data = nullptr;
	entry.Size = size;
	entry.Offset = 0;
	if (size)
		entry.Data = new unsigned char[size]();
	Entries.insert(Entries.begin(), entry);
	return Entries.front();
}

DataSection& FileSections::Get(unsigned int index)
{
	if (index < 9)
		return _sections[index];

	return _sections[8];
}

DataSection& FileSections::operator[](unsigned int index)
{
	return Get(index);
}

unsigned int FileSections::UpdateOffsets(unsigned int startingOffset, RCT3Debugging::OutputLog& log)
{
	unsigned int currOffset = startingOffset;
	for (unsigned int i = 0; i < 9; i++)
	{
		for (unsigned int j = 0; j < _sections[i].Entries.size(); j++)
		{
			_sections[i].Entries[j].Offset = currOffset;
			currOffset += _sections[i].Entries[j].Size;
		}
		_sections[i].Offset = currOffset;
	}

	log.Debug("FileSections::UpdateOffsets(..): returned " + STR(currOffset));

	return currOffset;
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: b2dpolypolygoncutter.hxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _BGFX_POLYGON_B2DPOLYPOLYGONCUTTER_HXX
#define _BGFX_POLYGON_B2DPOLYPOLYGONCUTTER_HXX

//#ifndef _SAL_TYPES_H_
//#include <sal/types.h>
//#endif
//
//#ifndef _BGFX_POINT_B2DPOINT_HXX
//#include <basegfx/point/b2dpoint.hxx>
//#endif
//
//#ifndef _BGFX_RANGE_B2DRANGE_HXX
//#include <basegfx/range/b2drange.hxx>
//#endif

#include <basegfx/polygon/b2dpolypolygon.hxx>

//#include <vector>

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

namespace basegfx
{
    namespace tools
    {
        // solve all crossovers in a polyPolygon. This re-layouts all contained polygons so that the
        // result will contain only non-cutting polygons. For that reason, points will be added at
        // crossover and touch points and the single Polygons may be re-combined. The orientations
        // of the contained polygons in not changed but used as hints.
        // If bSelfCrossovers is set, first all self-intersections of the contained polygons will be
        // solved.
        B2DPolyPolygon SolveCrossovers(const B2DPolyPolygon& rCandidate, bool bSelfCrossovers = true);

        // version for single polygons. This is for solving self-intersections. Result will be free of
        // crossovers. When result contains multiple polygons, it may be necessary to rearrange their
        // orientations since holes may have been created (use correctOrientations eventually).
        B2DPolyPolygon SolveCrossovers(const B2DPolygon& rCandidate);

        // Neutral polygons will be stripped. Neutral polygons are ones who's orientation is
        // neutral, so normally they have no volume -> just closed paths. A polygon with the same
        // positive and negative oriented volume is also neutral, so this may not be wanted. It is
        // safe to call with crossover-free polygons, though (that's where it's mostly used).
        B2DPolyPolygon StripNeutralPolygons(const B2DPolyPolygon& rCandidate);

        // Remove not necessary polygons. Works only correct with crossover-free polygons. For each
        // polygon, the depth for the PolyPolygon is calculated. The orientation is used to identify holes.
        // Start value for holes is -1, for polygons it's zero. Ech time a polygon is contained in another one,
        // it's depth is increased when inside a polygon, decreased when inside a hole. The result is a depth
        // which e.g. is -1 for holes outside everything, 1 for a polygon covered by another polygon and zero
        // for e.g. holes in a polygon or polygons outside everythig else.
        // In the 2nd step, all polygons with depth other than zero are removed. If bKeepAboveZero is used,
        // all polygons < 1 are removed. The bKeepAboveZero mode is useful for clipping, e.g. just append
        // one polygon to another and use this mode -> only parts where two polygons overlapped will be kept.
        // In combination with correct orientation of the input orientations and the SolveCrossover calls this
        // can be combined for logical polygon operations or polygon clipping.
        B2DPolyPolygon StripDispensablePolygons(const B2DPolyPolygon& rCandidate, bool bKeepAboveZero = false);
    } // end of namespace tools
} // end of namespace basegfx

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

#endif /* _BGFX_POLYGON_B2DPOLYPOLYGONCUTTER_HXX */
<commit_msg>INTEGRATION: CWS aw033 (1.7.2); FILE MERGED 2008/05/14 14:42:30 aw 1.7.2.4: RESYNC: (1.8-1.9); FILE MERGED 2007/12/12 13:13:23 aw 1.7.2.3: #i39532# clipping changes 2007/12/03 13:53:13 aw 1.7.2.2: #i39532# checkin for resync 2005/10/28 11:21:56 aw 1.7.2.1: #i39532#<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: b2dpolypolygoncutter.hxx,v $
 * $Revision: 1.10 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _BGFX_POLYGON_B2DPOLYPOLYGONCUTTER_HXX
#define _BGFX_POLYGON_B2DPOLYPOLYGONCUTTER_HXX

#include <basegfx/polygon/b2dpolypolygon.hxx>

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

namespace basegfx
{
    namespace tools
    {
        // Solve all crossovers in a polyPolygon. This re-layouts all contained polygons so that the
        // result will contain only non-cutting polygons. For that reason, points will be added at
        // crossover and touch points and the single Polygons may be re-combined. The orientations
        // of the contained polygons in not changed but used as topological information.
        // Self crossovers of the contained sub-polygons are implicitely handled, but to not lose
        // the topological information, it may be necessary to remove self-intersections of the
        // contained sub-polygons in a preparing step and to explicitely correct their orientations.
        B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate);

        // Version for single polygons. This is for solving self-intersections. Result will be free of
        // crossovers. When result contains multiple polygons, it may be necessary to rearrange their
        // orientations since holes may have been created (use correctOrientations eventually).
        B2DPolyPolygon solveCrossovers(const B2DPolygon& rCandidate);

        // Neutral polygons will be stripped. Neutral polygons are ones who's orientation is
        // neutral, so normally they have no volume -> just closed paths. A polygon with the same
        // positive and negative oriented volume is also neutral, so this may not be wanted. It is
        // safe to call with crossover-free polygons, though (that's where it's mostly used).
        B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon& rCandidate);

        // Remove not necessary polygons. Works only correct with crossover-free polygons. For each
        // polygon, the depth for the PolyPolygon is calculated. The orientation is used to identify holes.
        // Start value for holes is -1, for polygons it's zero. Ech time a polygon is contained in another one,
        // it's depth is increased when inside a polygon, decreased when inside a hole. The result is a depth
        // which e.g. is -1 for holes outside everything, 1 for a polygon covered by another polygon and zero
        // for e.g. holes in a polygon or polygons outside everythig else.
        // In the 2nd step, all polygons with depth other than zero are removed. If bKeepAboveZero is used,
        // all polygons < 1 are removed. The bKeepAboveZero mode is useful for clipping, e.g. just append
        // one polygon to another and use this mode -> only parts where two polygons overlapped will be kept.
        // In combination with correct orientation of the input orientations and the SolveCrossover calls this
        // can be combined for logical polygon operations or polygon clipping.
        B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon& rCandidate, bool bKeepAboveZero = false);

        // For convenience: The four basic operations OR, XOR, AND and DIFF for
        // two PolyPolygons. These are combinations of the above methods. To not be forced
        // to do evtl. already done preparations twice, You have to do the operations Yourself.
        //
        // A source preparation consists of preparing it to be seen as XOR-Rule PolyPolygon,
        // so it is freed of intersections, self-intersections and the orientations are corrected.
        // Important is that it will define the same areas as before, but is intersection-free.
        // As an example think about a single polygon looping in itself and having holes. To
        // topologically correctly handle this, it is necessary to remove all intersections and
        // to correct the orientations. The orientation of the isolated holes e.g. will be negative.
        // Topologically it is necessary to prepare each polygon which is seen as entity. It is
        // not sufficient just to concatenate them and prepare the result, this may be topologically
        // different since the simple concatenation will be seen as XOR. To work correctly, You
        // may need to OR those polygons.

        // Preparations: solve self-intersections and intersections, remove neutral
        // parts and correct orientations.
        B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon& rCandidate);
        B2DPolyPolygon prepareForPolygonOperation(const B2DPolyPolygon& rCandidate);

        // OR: Return all areas where CandidateA or CandidateB exist
        B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB);

        // XOR: Return all areas where CandidateA or CandidateB exist, but not both
        B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB);

        // AND: Return all areas where CandidateA and CandidateB exist
        B2DPolyPolygon solvePolygonOperationAnd(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB);

        // DIFF: Return all areas where CandidateA is not covered by CandidateB (cut B out of A)
        B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB);

    } // end of namespace tools
} // end of namespace basegfx

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

#endif /* _BGFX_POLYGON_B2DPOLYPOLYGONCUTTER_HXX */
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Freeman Zhang <zhanggyb@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SKLAND_CORE_MEMORY_HPP_
#define SKLAND_CORE_MEMORY_HPP_

#include "defines.hpp"

#include <memory>
#include <atomic>

namespace skland {
namespace core {

/**
 * @ingroup core
 * @brief The base class for objects that may be shared by multiple objects.
 * @tparam T The type of reference count, must be int, int32_t, long, size_t etc.
 *
 * Though we can use std::shared_ptr to store any type of object, there still be situation
 * that we need to indicate what kind of object can be used in shared ptr.
 */
class SPCountedBase {

  template<typename T> friend
  class SharedPtr;

  template<typename T> friend
  class WeakPtr;

 public:

  SKLAND_DECLARE_NONCOPYABLE_AND_NONMOVALE(SPCountedBase);

  struct Counter {

    Counter()
        : use_count(0), weak_count(0) {
      _DEBUG("%s\n", __func__);
    }

    ~Counter() {
      _DEBUG("%s\n", __func__);
    }

    /**
     * @brief The number of SharedPtr instances pointing to the object
     */
    std::atomic_ulong use_count;

    /**
     * @brief The number of WeakPtr instances pointing to the object,
     * plus one if the "use_count" is still > 0
     */
    std::atomic_ulong weak_count;

  };

  SPCountedBase()
      : counter_(new Counter) {}

  virtual ~SPCountedBase() {
    if (nullptr != counter_) {
      _DEBUG("use_count: %ld, weak_count: %ld\n", counter_->use_count.load(), counter_->weak_count.load());
    }
    delete counter_;
  }

  size_t use_count() const {
    return counter_->use_count.load();
  }

  size_t weak_count() const {
    return counter_->weak_count.load();
  }

 private:

  Counter *counter_;

};

/**
 * @ingroup core
 * @brief Shared pointer
 * @tparam T
 */
template<typename T>
class SharedPtr {

  template<typename R> friend
  class WeakPtr;

  template<typename R>
  friend void swap(SharedPtr<R> &src, SharedPtr<R> &dst);

 public:

  SharedPtr() = default;

  explicit SharedPtr(T *obj) : ptr_(obj) {
    counter_ = ptr_->counter_;
    ++counter_->use_count;
  }

  SharedPtr(const SharedPtr &orig)
      : ptr_(orig.ptr_) {
    if (nullptr != ptr_) {
      counter_ = ptr_->counter_;
      ++counter_->use_count;
    }
  }

  /**
   * @brief Move constructor
   * @param orig
   */
  SharedPtr(SharedPtr &&orig) noexcept
      : ptr_(orig.ptr_), counter_(orig.counter_) {
    orig.ptr_ = nullptr;
    orig.counter_ = nullptr;
  }

  ~SharedPtr() {
    if (nullptr != counter_) {
      _ASSERT((nullptr != ptr_) && (ptr_->counter_ == counter_));

      --counter_->use_count;
      if (0 == counter_->use_count) {
        ptr_->counter_ = nullptr; // set this value to avoid destroying the counter

        // Important: avoid double delete counter_:
        ++counter_->weak_count;
        delete ptr_;
        --counter_->weak_count;

        if (0 == counter_->weak_count) delete counter_;
      }
    } else {
      _ASSERT(nullptr == ptr_);
    }
  }

  /**
   * @brief Copy assignment
   * @param other
   * @return
   */
  SharedPtr &operator=(const SharedPtr &other) noexcept {
    reset(other.ptr_);
    return *this;
  }

  /**
   * @brief Move assignment
   * @param other
   * @return
   */
  SharedPtr &operator=(SharedPtr &&other) noexcept {
    ptr_ = other.ptr_;
    counter_ = other.counter_;
    other.ptr_ = nullptr;
    other.counter_ = nullptr;
    return *this;
  }

  SharedPtr &operator=(T *obj) noexcept {
    reset(obj);
    return *this;
  }

  /**
   * @brief Swap content
   * @param other
   */
  void swap(SharedPtr &other) noexcept {
    T *object = ptr_;
    SPCountedBase::Counter *counter = counter_;

    ptr_ = other.ptr_;
    counter_ = other.counter_;

    other.ptr_ = object;
    other.counter_ = counter;
  }

  /**
   * @brief Reset pointer
   * @param obj
   */
  void reset(T *obj = nullptr) {
    T *old_object = ptr_;
    SPCountedBase::Counter *old_counter = counter_;

    ptr_ = obj;
    counter_ = nullptr;
    if (nullptr != ptr_) {
      counter_ = ptr_->counter_;
      ++counter_->use_count;
    }

    if (nullptr != old_counter) {
      _ASSERT((nullptr != old_object) && (old_object->counter_ == old_counter));

      --old_counter->use_count;
      if (0 == old_counter->use_count) {
        old_object->counter_ = nullptr;

        // Important: avoid double delete old_counter:
        ++old_counter->weak_count;
        delete old_object;
        --old_counter->weak_count;

        if (0 == old_counter->weak_count) delete old_counter;
      }
    } else {
      _ASSERT(nullptr == old_object);
    }
  }

  /**
   * @brief Get pointer
   * @return
   */
  T *get() const {
    return ptr_;
  }

  /**
   * @brief Dereference object
   * @return
   */
  T &operator*() const {
    return *ptr_;
  }

  /**
   * @brief Dereference object member
   * @return
   */
  T *operator->() const {
    return ptr_;
  }

  /**
   * @brief Use count
   * @return
   */
  size_t use_count() const noexcept {
    return nullptr == counter_ ? 0 : counter_->use_count.load();
  }

  size_t weak_count() const noexcept {
    return nullptr == counter_ ? 0 : counter_->weak_count.load();
  }

  /**
   * @brief Returns whether this shared pointer does not share ownership over its pointer with other.
   * @return
   */
  bool unique() const noexcept {
    return 1 == use_count();
  }

  explicit operator bool() const {
    if (nullptr == ptr_) {
      _ASSERT(nullptr == counter_);
      return false;
    }

    _ASSERT(ptr_->counter_ == counter_);
    return true;
  }

 private:

  T *ptr_ = nullptr;

  SPCountedBase::Counter *counter_ = nullptr;

};

template<typename T>
class WeakPtr {

 public:

  WeakPtr() = default;

  WeakPtr(const WeakPtr &orig) {
    ptr_ = orig.ptr_;
    counter_ = orig.counter_;
    if (nullptr != counter_) ++counter_->weak_count;
  }

  explicit WeakPtr(const SharedPtr<T> &orig) {
    ptr_ = orig.ptr_;
    counter_ = orig.counter_;
    if (nullptr != counter_) ++counter_->weak_count;
  }

  ~WeakPtr() {
    if (nullptr != counter_) {
      --counter_->weak_count;
      if ((0 == counter_->use_count) && (0 == counter_->weak_count)) {
        delete counter_;
      }
    }
  }

  WeakPtr &operator=(const SharedPtr<T> &other) {
    SPCountedBase::Counter *old_counter = counter_;

    ptr_ = other.ptr_;
    counter_ = other.counter_;

    if (nullptr != counter_) ++counter_->weak_count;

    if (nullptr != old_counter) {
      --old_counter->weak_count;
      if ((0 == old_counter->use_count) && (0 == old_counter->weak_count)) {
        delete old_counter;
      }
    }

    return *this;
  }

  WeakPtr &operator=(const WeakPtr &other) {
    SPCountedBase::Counter *old_counter = counter_;

    ptr_ = other.ptr_;
    counter_ = other.counter_;

    if (nullptr != counter_) ++counter_->weak_count;

    if (nullptr != old_counter) {
      --old_counter->weak_count;
      if ((0 == old_counter->use_count) && (0 == old_counter->weak_count)) {
        delete old_counter;
      }
    }

    return *this;
  }

  void reset() {
    ptr_ = nullptr;
    if (nullptr != counter_) {
      --counter_->weak_count;
      if ((0 == counter_->use_count) && (0 == counter_->weak_count)) {
        delete counter_;
      }
      counter_ = nullptr;
    }
  }

  size_t use_count() const noexcept {
    return nullptr == counter_ ? 0 : counter_->use_count.load();
  }

  size_t weak_count() const noexcept {
    return nullptr == counter_ ? 0 : counter_->weak_count.load();
  }

  SharedPtr<T> lock() const noexcept {
    return SharedPtr<T>(ptr_);
  }

 private:

  T *ptr_ = nullptr;

  SPCountedBase::Counter *counter_ = nullptr;

};

/**
 * @ingroup core
 * @brief Constructs an object of type T and wraps it in a std::unique_ptr
 * @tparam T
 * @tparam Args
 * @param args list of arguments with which an instance of T will be constructed
 * @return std::unique_ptr of an instance of type T
 *
 * This template function is the same as std::make_unique in C++14
 */
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&... args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template<typename T, typename ... Args>
SharedPtr<T> make_shared(Args &&... args) {
  return SharedPtr<T>(new T(std::forward<Args>(args)...));
};

template<typename T>
void swap(SharedPtr<T> &src, SharedPtr<T> &dst) {
  T *object = src.ptr_;
  SPCountedBase::Counter *counter = src.counter_;

  src.ptr_ = dst.ptr_;
  src.counter_ = dst.counter_;

  dst.ptr_ = object;
  dst.counter_ = counter;
}

} // namespace core
} // namespace skland

#endif // SKLAND_CORE_MEMORY_HPP_
<commit_msg>Documentation work.<commit_after>/*
 * Copyright 2016 Freeman Zhang <zhanggyb@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SKLAND_CORE_MEMORY_HPP_
#define SKLAND_CORE_MEMORY_HPP_

#include "defines.hpp"

#include <memory>
#include <atomic>

namespace skland {
namespace core {

/**
 * @ingroup core
 * @brief The base class for objects that may be shared by multiple objects.
 *
 * SPCountedBase is the base class to be used in SharedPtr and WeakPtr for
 * implementing our custom reference counting smart pointer. Though we can use
 * std::shared_ptr to store any type of object, there still be situation that we
 * need to indicate what kind of object can be used in a shared pointer.
 *
 * You usually define your own sub class of SPCountedBase, create and contain an
 * instance in a SharedPtr. Use WeakPtr to avoid curcular references in
 * appropriate time.
 *
 * Each SPCountedBase object has a pointer to a Counter object which stores 2
 * different counters:
 *
 *   - use_count: the number of SharedPtr instances pointing to this
 *     SPCountedBase object
 *
 *   - weak_count: the number of WeakPtr instances pointing to this
 *     SPCountedBase object
 *
 * A SPCountedBase object knows its reference status by checking the counters by
 * use_count() or weak_count(). When a SPCountedBase object is created by new
 * operator and not controled by any SharedPtr or WeakPtr, both use_count and
 * weak_count are zero, in this case you can safely delete the instance.
 */
class SPCountedBase {

  template<typename T> friend
  class SharedPtr;

  template<typename T> friend
  class WeakPtr;

 public:

  SKLAND_DECLARE_NONCOPYABLE_AND_NONMOVALE(SPCountedBase);

  struct Counter {

    Counter()
        : use_count(0), weak_count(0) {
      _DEBUG("%s\n", __func__);
    }

    ~Counter() {
      _DEBUG("%s\n", __func__);
    }

    /**
     * @brief The number of SharedPtr instances pointing to the object
     */
    std::atomic_ulong use_count;

    /**
     * @brief The number of WeakPtr instances pointing to the object, plus one
     * if the "use_count" is still > 0
     */
    std::atomic_ulong weak_count;

  };

  SPCountedBase()
      : counter_(new Counter) {}

  virtual ~SPCountedBase() {
    if (nullptr != counter_) {
      _DEBUG("use_count: %ld, weak_count: %ld\n",
             counter_->use_count.load(),
             counter_->weak_count.load());
    }
    delete counter_;
  }

  size_t use_count() const {
    return counter_->use_count.load();
  }

  size_t weak_count() const {
    return counter_->weak_count.load();
  }

 private:

  Counter *counter_;

};

/**
 * @ingroup core
 * @brief Shared pointer
 * @tparam T
 */
template<typename T>
class SharedPtr {

  template<typename R> friend
  class WeakPtr;

  template<typename R>
  friend void swap(SharedPtr<R> &src, SharedPtr<R> &dst);

 public:

  SharedPtr() = default;

  explicit SharedPtr(T *obj) : ptr_(obj) {
    counter_ = ptr_->counter_;
    ++counter_->use_count;
  }

  SharedPtr(const SharedPtr &orig)
      : ptr_(orig.ptr_) {
    if (nullptr != ptr_) {
      counter_ = ptr_->counter_;
      ++counter_->use_count;
    }
  }

  /**
   * @brief Move constructor
   * @param orig
   */
  SharedPtr(SharedPtr &&orig) noexcept
      : ptr_(orig.ptr_), counter_(orig.counter_) {
    orig.ptr_ = nullptr;
    orig.counter_ = nullptr;
  }

  ~SharedPtr() {
    if (nullptr != counter_) {
      _ASSERT((nullptr != ptr_) && (ptr_->counter_ == counter_));

      --counter_->use_count;
      if (0 == counter_->use_count) {
        ptr_->counter_ = nullptr; // set this value to avoid destroying the counter

        // Important: avoid double delete counter_:
        ++counter_->weak_count;
        delete ptr_;
        --counter_->weak_count;

        if (0 == counter_->weak_count) delete counter_;
      }
    } else {
      _ASSERT(nullptr == ptr_);
    }
  }

  /**
   * @brief Copy assignment
   * @param other
   * @return
   */
  SharedPtr &operator=(const SharedPtr &other) noexcept {
    reset(other.ptr_);
    return *this;
  }

  /**
   * @brief Move assignment
   * @param other
   * @return
   */
  SharedPtr &operator=(SharedPtr &&other) noexcept {
    ptr_ = other.ptr_;
    counter_ = other.counter_;
    other.ptr_ = nullptr;
    other.counter_ = nullptr;
    return *this;
  }

  SharedPtr &operator=(T *obj) noexcept {
    reset(obj);
    return *this;
  }

  /**
   * @brief Swap content
   * @param other
   */
  void swap(SharedPtr &other) noexcept {
    T *object = ptr_;
    SPCountedBase::Counter *counter = counter_;

    ptr_ = other.ptr_;
    counter_ = other.counter_;

    other.ptr_ = object;
    other.counter_ = counter;
  }

  /**
   * @brief Reset pointer
   * @param obj
   */
  void reset(T *obj = nullptr) {
    T *old_object = ptr_;
    SPCountedBase::Counter *old_counter = counter_;

    ptr_ = obj;
    counter_ = nullptr;
    if (nullptr != ptr_) {
      counter_ = ptr_->counter_;
      ++counter_->use_count;
    }

    if (nullptr != old_counter) {
      _ASSERT((nullptr != old_object) && (old_object->counter_ == old_counter));

      --old_counter->use_count;
      if (0 == old_counter->use_count) {
        old_object->counter_ = nullptr;

        // Important: avoid double delete old_counter:
        ++old_counter->weak_count;
        delete old_object;
        --old_counter->weak_count;

        if (0 == old_counter->weak_count) delete old_counter;
      }
    } else {
      _ASSERT(nullptr == old_object);
    }
  }

  /**
   * @brief Get pointer
   * @return
   */
  T *get() const {
    return ptr_;
  }

  /**
   * @brief Dereference object
   * @return
   */
  T &operator*() const {
    return *ptr_;
  }

  /**
   * @brief Dereference object member
   * @return
   */
  T *operator->() const {
    return ptr_;
  }

  /**
   * @brief Use count
   * @return
   */
  size_t use_count() const noexcept {
    return nullptr == counter_ ? 0 : counter_->use_count.load();
  }

  size_t weak_count() const noexcept {
    return nullptr == counter_ ? 0 : counter_->weak_count.load();
  }

  /**
   * @brief Returns whether this shared pointer does not share ownership over
   * its pointer with other.
   * @return
   */
  bool unique() const noexcept {
    return 1 == use_count();
  }

  explicit operator bool() const {
    if (nullptr == ptr_) {
      _ASSERT(nullptr == counter_);
      return false;
    }

    _ASSERT(ptr_->counter_ == counter_);
    return true;
  }

 private:

  T *ptr_ = nullptr;

  SPCountedBase::Counter *counter_ = nullptr;

};

/**
 * @ingroup core
 * @brief Weak ptr
 * @tparam T
 */
template<typename T>
class WeakPtr {

 public:

  WeakPtr() = default;

  WeakPtr(const WeakPtr &orig) {
    ptr_ = orig.ptr_;
    counter_ = orig.counter_;
    if (nullptr != counter_) ++counter_->weak_count;
  }

  explicit WeakPtr(const SharedPtr<T> &orig) {
    ptr_ = orig.ptr_;
    counter_ = orig.counter_;
    if (nullptr != counter_) ++counter_->weak_count;
  }

  ~WeakPtr() {
    if (nullptr != counter_) {
      --counter_->weak_count;
      if ((0 == counter_->use_count) && (0 == counter_->weak_count)) {
        delete counter_;
      }
    }
  }

  WeakPtr &operator=(const SharedPtr<T> &other) {
    SPCountedBase::Counter *old_counter = counter_;

    ptr_ = other.ptr_;
    counter_ = other.counter_;

    if (nullptr != counter_) ++counter_->weak_count;

    if (nullptr != old_counter) {
      --old_counter->weak_count;
      if ((0 == old_counter->use_count) && (0 == old_counter->weak_count)) {
        delete old_counter;
      }
    }

    return *this;
  }

  WeakPtr &operator=(const WeakPtr &other) {
    SPCountedBase::Counter *old_counter = counter_;

    ptr_ = other.ptr_;
    counter_ = other.counter_;

    if (nullptr != counter_) ++counter_->weak_count;

    if (nullptr != old_counter) {
      --old_counter->weak_count;
      if ((0 == old_counter->use_count) && (0 == old_counter->weak_count)) {
        delete old_counter;
      }
    }

    return *this;
  }

  void reset() {
    ptr_ = nullptr;
    if (nullptr != counter_) {
      --counter_->weak_count;
      if ((0 == counter_->use_count) && (0 == counter_->weak_count)) {
        delete counter_;
      }
      counter_ = nullptr;
    }
  }

  size_t use_count() const noexcept {
    return nullptr == counter_ ? 0 : counter_->use_count.load();
  }

  size_t weak_count() const noexcept {
    return nullptr == counter_ ? 0 : counter_->weak_count.load();
  }

  /**
   * @brief Returns a SharedPtr with the object preserved if it is not expired.
   *
   * When you try to obtain a SharedPtr by this method, the WeakPtr checks the
   * "use count", and if it's > 0 returns a valid SharedPtr . If the "use count"
   * was already zero you get an empty SharedPtr instance instead.
   */
  SharedPtr<T> lock() const noexcept {
    if (counter_->use_count > 0) {
      return SharedPtr<T>(ptr_);
    }

    return SharedPtr<T>();
  }

 private:

  T *ptr_ = nullptr;

  SPCountedBase::Counter *counter_ = nullptr;

};

/**
 * @ingroup core
 * @brief Constructs an object of type T and wraps it in a std::unique_ptr
 * @tparam T
 * @tparam Args
 * @param args list of arguments with which an instance of T will be constructed
 * @return std::unique_ptr of an instance of type T
 *
 * This template function is the same as std::make_unique in C++14
 */
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args &&... args) {
  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

template<typename T, typename ... Args>
SharedPtr<T> make_shared(Args &&... args) {
  return SharedPtr<T>(new T(std::forward<Args>(args)...));
};

template<typename T>
void swap(SharedPtr<T> &src, SharedPtr<T> &dst) {
  T *object = src.ptr_;
  SPCountedBase::Counter *counter = src.counter_;

  src.ptr_ = dst.ptr_;
  src.counter_ = dst.counter_;

  dst.ptr_ = object;
  dst.counter_ = counter;
}

} // namespace core
} // namespace skland

#endif // SKLAND_CORE_MEMORY_HPP_
<|endoftext|>