/*! \file traits.hpp \brief Internal type trait support \ingroup Internal */ /* Copyright (c) 2013, Randolph Voorhies, Shane Grant All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of cereal nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef CEREAL_DETAILS_TRAITS_HPP_ #define CEREAL_DETAILS_TRAITS_HPP_ #include #include #include #include namespace cereal { namespace traits { typedef std::true_type yes; typedef std::false_type no; namespace { //! Tests whether a type has a const member save function template struct has_const_member_save_impl { template static auto test(int) -> decltype( cereal::access::non_member_save( std::declval(), std::declval() ) == 1, yes()); static no test(...); static const bool value = std::is_same(0)), yes>::value; }; } // end anon namespace template struct has_const_member_save : std::integral_constant::value> {}; //! Tests whether a type has a non const member save function namespace { template struct has_non_const_member_save_impl { template static auto test(int) -> decltype( cereal::access::non_const_member_save( std::declval(), std::declval() ) == 1, yes()); static no test(...); static const bool value = std::is_same(0)), yes>::value; }; } // end anon namespace template struct has_non_const_member_save : std::integral_constant::value> {}; //! Creates a test for whether a non const member function exists /*! This should be used to create tests for things that have access through cereal::access adn begin with the name "member_". name will be combined with this to create the name of the function that is tested. */ #define CEREAL_MAKE_HAS_MEMBER_TEST(name) \ namespace \ { \ template \ struct has_member_##name##_impl \ { \ template \ static auto test(int) -> decltype( cereal::access::member_##name( std::declval(), std::declval() ) == 1, yes()); \ template \ static no test(...); \ static const bool value = std::is_same(0)), yes>::value; \ }; \ } /* end anon namespace */ \ template \ struct has_member_##name## : std::integral_constant::value> {}; template struct Void { typedef void type; }; // ###################################################################### // Member load_and_allocate template struct has_member_load_and_allocate : std::integral_constant( std::declval() ) ), T*>::value> {}; // ###################################################################### // Non Member load_and_allocate template struct has_non_member_load_and_allocate : std::integral_constant::load_and_allocate( std::declval() ) ), T*>::value> {}; // ###################################################################### // Has either a member or non member allocate template struct has_load_and_allocate : std::integral_constant::value || has_non_member_load_and_allocate::value> { }; // ###################################################################### // Member Serialize CEREAL_MAKE_HAS_MEMBER_TEST(serialize); // ###################################################################### // Non Member Serialize template char & serialize(...); template struct has_non_member_serialize : std::integral_constant(), std::declval()))>::value> {}; // ###################################################################### // Non Member Serialize //char & serialize(...); //template //struct has_non_member_serialize : std::integral_constant(), std::declval()))>::value> //{ }; } // namespace traits // // ###################################################################### // // Member Load // template // struct has_member_load: std::false_type {}; // template // struct has_member_load< T, A, // typename Void< // decltype( access::member_load(std::declval(), std::declval() ) ) // >::type // >: std::true_type {}; // // ###################################################################### // // Non Member Load // char & load(...); // template // bool constexpr has_non_member_load() // { return std::is_void(), std::declval()))>::value; }; // // ###################################################################### // // Member Save // template // struct has_member_save: std::false_type {}; // template // struct has_member_save< T, A, // typename Void< // decltype( access::member_save(std::declval(), std::declval() ) ) // >::type // >: std::true_type {}; // // ###################################################################### // // Non-const Member Save // namespace detail // { // // Detection of any (const or non const) member save // template // struct has_member_save_any: std::false_type {}; // template // struct has_member_save_any< T, A, // typename Void< // decltype( access::non_const_member_save(std::declval(), std::declval::type &>() ) ) // >::type // >: std::true_type {}; // } // // Returns true if we detect a member save function that is not const // template // constexpr bool is_non_const_member_save() // { // return !has_member_save() && detail::has_member_save_any(); // } // // ###################################################################### // // Non Member Save // char & save(...); // template // bool constexpr has_non_member_save() // { return std::is_void(), std::declval()))>::value; } // // ###################################################################### // // Non-const Non member Save // namespace detail // { // template // bool constexpr has_non_member_save_any() // { return std::is_void(), std::declval::type &>()))>::value; } // } // // Returns true if we detect a non-member save function that is not const // template // bool constexpr is_non_const_non_member_save() // { return !has_non_member_save() && detail::has_non_member_save_any(); } // // ###################################################################### // // Returns true if we have an invalid save function (non const) // template // bool constexpr has_non_const_save() // { return is_non_const_member_save() || is_non_const_non_member_save(); } // // ###################################################################### // template // constexpr bool has_member_split() // { return has_member_load() && has_member_save(); } // // ###################################################################### // template // constexpr bool has_non_member_split() // { return has_non_member_load() && has_non_member_save(); } // // ###################################################################### // template // constexpr bool is_output_serializable() // { // static_assert( !has_non_const_save(), // "cereal detected a non const save. \n " // "save functions must either be const member functions or accept const type aguments if non-member" ); // return // has_member_save() ^ // has_non_member_save() ^ // has_member_serialize() ^ // has_non_member_serialize(); // } // // ###################################################################### // template // constexpr bool is_input_serializable() // { // return // has_member_load() ^ // has_non_member_load() ^ // has_member_serialize() ^ // has_non_member_serialize(); // } // // ###################################################################### // namespace detail // { // template // constexpr auto is_specialized_member_serialize() -> bool // { return !std::is_base_of>(); } // template // constexpr auto is_specialized_member_load_save() -> bool // { return !std::is_base_of>(); } // template // constexpr auto is_specialized_non_member_serialize() -> bool // { return !std::is_base_of>(); } // template // constexpr auto is_specialized_non_member_load_save() -> bool // { return !std::is_base_of>(); } // // Considered an error if specialization exists for more than one type // template // constexpr auto is_specialized_error() -> bool // { // return (is_specialized_member_serialize() + // is_specialized_member_load_save() + // is_specialized_non_member_serialize() + // is_specialized_non_member_load_save()) <= 1; // } // } // namespace detail // template // constexpr auto is_specialized() -> bool // { // static_assert(detail::is_specialized_error(), "More than one explicit specialization detected for type."); // return detail::is_specialized_member_serialize() || // detail::is_specialized_member_load_save() || // detail::is_specialized_non_member_serialize() || // detail::is_specialized_non_member_load_save(); // } // template // constexpr auto is_specialized_member_serialize() -> bool // { // static_assert( (is_specialized() && detail::is_specialized_member_serialize() && has_member_serialize()) // || !(is_specialized() && detail::is_specialized_member_serialize()), // "cereal detected member serialization specialization but no member serialize function" ); // return is_specialized() && detail::is_specialized_member_serialize(); // } // template // constexpr auto is_specialized_member_load() -> bool // { // static_assert( (is_specialized() && detail::is_specialized_member_load_save() && has_member_load()) // || !(is_specialized() && detail::is_specialized_member_load_save()), // "cereal detected member load specialization but no member load function" ); // return is_specialized() && detail::is_specialized_member_load_save(); // } // template // constexpr auto is_specialized_member_save() -> bool // { // static_assert( (is_specialized() && detail::is_specialized_member_load_save() && has_member_save()) // || !(is_specialized() && detail::is_specialized_member_load_save()), // "cereal detected member save specialization but no member save function" ); // return is_specialized() && detail::is_specialized_member_load_save(); // } // template // constexpr auto is_specialized_non_member_serialize() -> bool // { // static_assert( (is_specialized() && detail::is_specialized_non_member_serialize() && has_non_member_serialize()) // || !(is_specialized() && detail::is_specialized_non_member_serialize()), // "cereal detected non-member serialization specialization but no non-member serialize function" ); // return is_specialized() && detail::is_specialized_non_member_serialize(); // } // template // constexpr auto is_specialized_non_member_load() -> bool // { // static_assert( (is_specialized() && detail::is_specialized_non_member_load_save() && has_non_member_load()) // || !(is_specialized() && detail::is_specialized_non_member_load_save()), // "cereal detected non-member load specialization but no non-member load function" ); // return is_specialized() && detail::is_specialized_non_member_load_save(); // } // template // constexpr auto is_specialized_non_member_save() -> bool // { // static_assert( (is_specialized() && detail::is_specialized_non_member_load_save() && has_non_member_save()) // || !(is_specialized() && detail::is_specialized_non_member_load_save()), // "cereal detected non-member save specialization but no non-member save function" ); // return is_specialized() && detail::is_specialized_non_member_load_save(); // } // // ###################################################################### // template // constexpr size_t sizeof_array( size_t rank = std::rank::value ) // { // return rank == 0 ? 1 : std::extent::value * sizeof_array::type>( rank - 1 ); // } // // ###################################################################### // namespace detail // { // template // struct is_empty_class_impl // { static constexpr bool value = false; }; // template // struct is_empty_class_impl::value>::type> // { // struct S : T // { uint8_t t; }; // static constexpr bool value = sizeof(S) == sizeof(uint8_t); // }; // struct base_class_id // { // template // base_class_id(T const * const t) : // type(typeid(T)), // ptr(t), // hash(std::hash()(typeid(T)) ^ (std::hash()(t) << 1)) // { } // bool operator==(base_class_id const & other) const // { return (type == other.type) && (ptr == other.ptr); } // std::type_index type; // void const * ptr; // size_t hash; // }; // struct base_class_id_hash { size_t operator()(base_class_id const & id) const { return id.hash; } }; // } // template // using is_empty_class = std::integral_constant::value>; // // ###################################################################### // //! A macro to use to restrict which types of archives your function will work for. // /*! This requires you to have a template class parameter named Archive and replaces the void return // type for your function. // INTYPE refers to the input archive type you wish to restrict on. // OUTTYPE refers to the output archive type you wish to restrict on. // For example, if we want to limit a serialize to only work with binary serialization: // @code{.cpp} // template // CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive) // serialize( Archive & ar, MyCoolType & m ) // { // ar & m; // } // @endcode // If you need to do more restrictions in your enable_if, you will need to do this by hand. // */ // #define CEREAL_ARCHIVE_RESTRICT(INTYPE, OUTTYPE) \ // typename std::enable_if::value || std::is_same::value, void>::type //} // namespace traits //namespace detail //{ // template (), bool NonMember = traits::has_non_member_load_and_allocate()> // struct Load // { // static_assert( !sizeof(T), "Cereal detected both member and non member load_and_allocate functions!" ); // static T * load_andor_allocate( A & ar ) // { return nullptr; } // }; // template // struct Load // { // static_assert( std::is_default_constructible::value, // "Trying to serialize a an object with no default constructor.\n\n" // "Types must either be default constructible or define either a member or non member Construct function.\n" // "Construct functions generally have the signature:\n\n" // "template \n" // "static T * load_and_allocate(Archive & ar)\n" // "{\n" // " var a;\n" // " ar & a\n" // " return new T(a);\n" // "}\n\n" ); // static T * load_andor_allocate( A & ar ) // { return new T(); } // }; // template // struct Load // { // static T * load_andor_allocate( A & ar ) // { // return access::load_and_allocate( ar ); // } // }; // template // struct Load // { // static T * load_andor_allocate( A & ar ) // { // return LoadAndAllocate::load_and_allocate( ar ); // } // }; //} // namespace detail } // namespace cereal #endif // CEREAL_DETAILS_TRAITS_HPP_