static_object.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*! \file static_object.hpp
  2. \brief Internal polymorphism static object support
  3. \ingroup Internal */
  4. /*
  5. Copyright (c) 2014, Randolph Voorhies, Shane Grant
  6. All rights reserved.
  7. Redistribution and use in source and binary forms, with or without
  8. modification, are permitted provided that the following conditions are met:
  9. * Redistributions of source code must retain the above copyright
  10. notice, this list of conditions and the following disclaimer.
  11. * Redistributions in binary form must reproduce the above copyright
  12. notice, this list of conditions and the following disclaimer in the
  13. documentation and/or other materials provided with the distribution.
  14. * Neither the name of the copyright holder nor the
  15. names of its contributors may be used to endorse or promote products
  16. derived from this software without specific prior written permission.
  17. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
  21. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #ifndef CEREAL_DETAILS_STATIC_OBJECT_HPP_
  29. #define CEREAL_DETAILS_STATIC_OBJECT_HPP_
  30. #include "cereal/macros.hpp"
  31. #if CEREAL_THREAD_SAFE
  32. #include <mutex>
  33. #endif
  34. //! Prevent link optimization from removing non-referenced static objects
  35. /*! Especially for polymorphic support, we create static objects which
  36. may not ever be explicitly referenced. Most linkers will detect this
  37. and remove the code causing various unpleasant runtime errors. These
  38. macros, adopted from Boost (see force_include.hpp) prevent this
  39. (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
  40. Use, modification and distribution is subject to the Boost Software
  41. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  42. http://www.boost.org/LICENSE_1_0.txt) */
  43. #if defined(_MSC_VER) && !defined(__clang__)
  44. # define CEREAL_DLL_EXPORT __declspec(dllexport)
  45. # define CEREAL_USED
  46. #else // clang or gcc
  47. # define CEREAL_DLL_EXPORT __attribute__ ((visibility("default")))
  48. # define CEREAL_USED __attribute__ ((__used__))
  49. #endif
  50. namespace cereal
  51. {
  52. namespace detail
  53. {
  54. //! A static, pre-execution object
  55. /*! This class will create a single copy (singleton) of some
  56. type and ensures that merely referencing this type will
  57. cause it to be instantiated and initialized pre-execution.
  58. For example, this is used heavily in the polymorphic pointer
  59. serialization mechanisms to bind various archive types with
  60. different polymorphic classes */
  61. template <class T>
  62. class CEREAL_DLL_EXPORT StaticObject
  63. {
  64. private:
  65. static T & create()
  66. {
  67. static T t;
  68. //! Forces instantiation at pre-execution time
  69. (void)instance;
  70. return t;
  71. }
  72. StaticObject( StaticObject const & /*other*/ ) {}
  73. public:
  74. static T & getInstance()
  75. {
  76. return create();
  77. }
  78. //! A class that acts like std::lock_guard
  79. class LockGuard
  80. {
  81. #if CEREAL_THREAD_SAFE
  82. public:
  83. LockGuard(std::mutex & m) : lock(m) {}
  84. private:
  85. std::unique_lock<std::mutex> lock;
  86. #else
  87. public:
  88. LockGuard() = default;
  89. LockGuard(LockGuard const &) = default; // prevents implicit copy ctor warning
  90. ~LockGuard() CEREAL_NOEXCEPT {} // prevents variable not used
  91. #endif
  92. };
  93. //! Attempts to lock this static object for the current scope
  94. /*! @note This function is a no-op if cereal is not compiled with
  95. thread safety enabled (CEREAL_THREAD_SAFE = 1).
  96. This function returns an object that holds a lock for
  97. this StaticObject that will release its lock upon destruction. This
  98. call will block until the lock is available. */
  99. static LockGuard lock()
  100. {
  101. #if CEREAL_THREAD_SAFE
  102. static std::mutex instanceMutex;
  103. return LockGuard{instanceMutex};
  104. #else
  105. return LockGuard{};
  106. #endif
  107. }
  108. private:
  109. static T & instance;
  110. };
  111. template <class T> T & StaticObject<T>::instance = StaticObject<T>::create();
  112. } // namespace detail
  113. } // namespace cereal
  114. #endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_