/*! \file adapters.hpp \brief Archive adapters that provide additional functionality on top of an existing archive */ /* Copyright (c) 2014, 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_ARCHIVES_ADAPTERS_HPP_ #define CEREAL_ARCHIVES_ADAPTERS_HPP_ #include #include namespace cereal { #ifdef CEREAL_FUTURE_EXPERIMENTAL // Forward declaration for friend access template U & get_user_data( A & ); //! Wraps an archive and gives access to user data /*! This adapter is useful if you require access to either raw pointers or references within your serialization functions. While cereal does not directly support serialization raw pointers or references, it is sometimes the case that you may want to supply something such as a raw pointer or global reference to some constructor. In this situation this adapter would likely be used with the construct class to allow for non-default constructors. @note This feature is experimental and may be altered or removed in a future release. See issue #46. @code{.cpp} struct MyUserData { int * myRawPointer; std::reference_wrapper myReference; }; struct MyClass { // Note the raw pointer parameter MyClass( int xx, int * rawP ); int x; template void serialize( Archive & ar ) { ar( x ); } template static void load_and_construct( Archive & ar, cereal::construct & construct ) { int xx; ar( xx ); // note the need to use get_user_data to retrieve user data from the archive construct( xx, cereal::get_user_data( ar ).myRawPointer ); } }; int main() { { MyUserData md; md.myRawPointer = &something; md.myReference = someInstanceOfType; std::ifstream is( "data.xml" ); cereal::UserDataAdapter ar( md, is ); std::unique_ptr sc; ar( sc ); // use as normal } return 0; } @endcode @relates get_user_data @tparam UserData The type to give the archive access to @tparam Archive The archive to wrap */ template class UserDataAdapter : public Archive { public: //! Construct the archive with some user data struct /*! This will forward all arguments (other than the user data) to the wrapped archive type. The UserDataAdapter can then be used identically to the wrapped archive type @tparam Args The arguments to pass to the constructor of the archive. */ template UserDataAdapter( UserData & ud, Args && ... args ) : Archive( std::forward( args )... ), userdata( ud ) { } private: //! Overload the rtti function to enable dynamic_cast void rtti() {} friend UserData & get_user_data( Archive & ar ); UserData & userdata; //!< The actual user data }; //! Retrieves user data from an archive wrapped by UserDataAdapter /*! This will attempt to retrieve the user data associated with some archive wrapped by UserDataAdapter. If this is used on an archive that is not wrapped, a run-time exception will occur. @note This feature is experimental and may be altered or removed in a future release. See issue #46. @note The correct use of this function cannot be enforced at compile time. @relates UserDataAdapter @tparam UserData The data struct contained in the archive @tparam Archive The archive, which should be wrapped by UserDataAdapter @param ar The archive @throws Exception if the archive this is used upon is not wrapped with UserDataAdapter. */ template UserData & get_user_data( Archive & ar ) { try { return dynamic_cast &>( ar ).userdata; } catch( std::bad_cast const & ) { throw ::cereal::Exception("Attempting to get user data from archive not wrapped in UserDataAdapter"); } } #endif // CEREAL_FUTURE_EXPERIMENTAL } // namespace cereal #endif // CEREAL_ARCHIVES_ADAPTERS_HPP_