deprecated.h 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #ifndef EATHREAD_INTERNAL_DEPRECATED_H
  5. #define EATHREAD_INTERNAL_DEPRECATED_H
  6. #include <EABase/eabase.h>
  7. #if defined(EA_PRAGMA_ONCE_SUPPORTED)
  8. #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
  9. #endif
  10. ////////////////////////////////////////////////////////////////////////////////
  11. // This header provides facilities for nudging users off of deprecated code.
  12. //
  13. // The goal is to provide a gradual migration where users become aware of the
  14. // accumulated technical debt considerably before they are required to address
  15. // the problem. To this end, once a feature has been deprecated, we may escalate
  16. // from warnings, to assertions, to build warnings before actual removal.
  17. //
  18. // EATHREAD_REMOVE_DEPRECATED_API can be defined in client code to force build time errors
  19. // EATHREAD_DEPRECATED_MEMBER_WARN_ON_USE generate runtime warnings on write to deprecated members
  20. // EATHREAD_DEPRECATED_MEMBER_ASSERT_ON_USE generate runtime assertions on write to deprecated members
  21. // EATHREAD_DEPRECATED_MEMBER_WARN_ON_BUILD generate runtime assertions and build warnings on access
  22. //
  23. // TODO: consider migrating these facilities to a shared location once they're stable (EAStdC)
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // EATHREAD_REMOVE_DEPRECATED_API
  26. //
  27. // Defining this macro in client code will remove any deprecated API from the
  28. // EAThread public headers. This can be useful to temporarily define locally
  29. // in dependent modules to find and eliminate any contained code that depends
  30. // on any deprecated EAThread features.
  31. //
  32. // Another approach is to enable broader deprecate culling by defining
  33. // EA_REMOVE_DEPRECATED_API within the build for the module you wish to
  34. // eliminate deprecated code. This should remove deprecates for all libraries
  35. // that support it.
  36. //
  37. // Note: Deprecated API culling macros should not be defined globally for a
  38. // build. Doing so will flag all use of deprecated API across all modules
  39. // in a game which is typically more noise than desired and makes a piecewise
  40. // approach more difficult. Instead, define the flags only when building the
  41. // module where you wish to eliminate use of deprecated code.
  42. #if defined(EA_REMOVE_DEPRECATED_API)
  43. // respect the master control if it has been provided
  44. #define EATHREAD_REMOVE_DEPRECATED_API
  45. #endif
  46. ////////////////////////////////////////////////////////////////////////////////
  47. // EATHREAD_DEPRECATED_MEMBER_WARN_ON_USE
  48. //
  49. // Simplifies the process of disabling public members of EAThread classes when
  50. // building with deprecated code removed. This macro renames the member variable
  51. // when deprecate culling is enabled to avoid changing the size of the structure
  52. // which can cause binary incompatibility issues.
  53. #if defined(EATHREAD_REMOVE_DEPRECATED_API)
  54. // rename deprecated members to trigger a build error
  55. #define EATHREAD_DEPRECATED_MEMBER_WARN_ON_USE(Type, Name) EA_DEPRECATED Type EA_PREPROCESSOR_JOIN2(name, _deprecated)
  56. #else
  57. // member enabled, but use runtime deprecation warnings only
  58. #define EATHREAD_DEPRECATED_MEMBER_WARN_ON_USE(Type, Name) EA::Thread::DeprecatedMemberWarn<Type> Name
  59. #endif
  60. ////////////////////////////////////////////////////////////////////////////////
  61. // EATHREAD_DEPRECATED_MEMBER_ASSERT_ON_USE
  62. //
  63. // This is similar to recently deprecated member except that it will generate
  64. // an assertion failure on assignment.
  65. #if defined(EATHREAD_REMOVE_DEPRECATED_API)
  66. // rename deprecated members to trigger a build error
  67. #define EATHREAD_DEPRECATED_MEMBER_ASSERT_ON_USE(Type, Name) EA_DEPRECATED Type EA_PREPROCESSOR_JOIN2(name, _deprecated)
  68. #else
  69. // member enabled, but use runtime assertions only
  70. #define EATHREAD_DEPRECATED_MEMBER_ASSERT_ON_USE(Type, Name) EA::Thread::DeprecatedMemberError<Type> Name
  71. #endif
  72. ////////////////////////////////////////////////////////////////////////////////
  73. // EATHREAD_DEPRECATED_MEMBER_WARN_ON_BUILD
  74. //
  75. // This is similar to deprecated member except that it additionally
  76. // add deprecation markup which will trigger warnings during the build. Note,
  77. // this will often get converted into a build error with warnings as error
  78. // enabled. For this reason, consider using the other macros first.
  79. #if defined(EATHREAD_REMOVE_DEPRECATED_API)
  80. // rename deprecated members to trigger a build error
  81. #define EATHREAD_DEPRECATED_MEMBER_WARN_ON_BUILD(Type, Name) EATHREAD_DEPRECATED_MEMBER_ASSERT_ON_USE(Type, Member)
  82. #else
  83. // member enabled, assert on set but also use build-time deprecation warnings
  84. #define EATHREAD_DEPRECATED_MEMBER_WARN_ON_BUILD(Type, Name) EA_DEPRECATED EATHREAD_DEPRECATED_MEMBER_ASSERT_ON_USE(Type, Name)
  85. #endif
  86. namespace EA {
  87. namespace Thread {
  88. // Issues the given warning if the flag is unset (and sets it), otherwise does nothing. This can be use to limit the
  89. // amount of message spam coming from a specific usage.
  90. EATHREADLIB_API void WarnOnce(bool* pHasTriggered, const char* message);
  91. EATHREADLIB_API void ErrorOnce(bool* pHasTriggered, const char* message);
  92. // This template allows the creation of classes that implicitly convert to the wrapped type but will warn on assignment.
  93. // This is useful in removing public member variables from our public API. The goal here is to provide a softer nudge
  94. // than a build error. Deprecation markup on the member is a similar approach but will often trigger a build failure
  95. // as warnings as errors is commonly enabled.
  96. // TODO: does not work for types that support dereferencing
  97. // TODO: also missing other operator forwarding
  98. template <typename T>
  99. class DeprecatedMemberWarn
  100. {
  101. public:
  102. #ifdef EA_COMPILER_NO_DEFAULTED_FUNCTIONS
  103. DeprecatedMemberWarn(){}
  104. #else
  105. DeprecatedMemberWarn() = default;
  106. #endif
  107. DeprecatedMemberWarn(T rhs): mValue(rhs) {}
  108. //DeprecatedMemberWarn& operator=(DeprecatedMemberWarn&&) = default; // TODO: Why doesn't this work
  109. #ifdef EA_COMPILER_NO_DEFAULTED_FUNCTIONS
  110. DeprecatedMemberWarn& operator=(const DeprecatedMemberWarn& rhs)
  111. {
  112. mValue = rhs.mValue;
  113. return *this;
  114. }
  115. #else
  116. DeprecatedMemberWarn& operator=(const DeprecatedMemberWarn& rhs) = default;
  117. #endif
  118. DeprecatedMemberWarn& operator=(const T& rhs)
  119. {
  120. #if EAT_ASSERT_ENABLED
  121. static bool hasTriggered = false;
  122. WarnOnce(&hasTriggered, "Client code is accessing a deprecated structure member.");
  123. #endif
  124. this->mValue = rhs;
  125. return *this;
  126. }
  127. DeprecatedMemberWarn& operator=(T&& rhs)
  128. {
  129. #if EAT_ASSERT_ENABLED
  130. static bool hasTriggered = false;
  131. WarnOnce(&hasTriggered, "Client code is accessing a deprecated structure member.");
  132. #endif
  133. this->mValue = rhs;
  134. return *this;
  135. }
  136. operator T() const
  137. {
  138. #if EAT_ASSERT_ENABLED
  139. static bool hasTriggered = false;
  140. WarnOnce(&hasTriggered, "Client code is accessing a deprecated structure member.");
  141. #endif
  142. return mValue;
  143. }
  144. // accessor for fetching the value without tripping the error
  145. const T& GetValue() const { return mValue; }
  146. // TODO: use sfinae to enable/disable when the wrapped type supports dereferencing
  147. //auto operator->() const
  148. //{
  149. //return T::operator->(mValue);
  150. //}
  151. private:
  152. T mValue;
  153. int foo;
  154. };
  155. // This template allows the creation of classes that implicitly convert to the wrapped type but will assert on assignment.
  156. // This is useful in removing public member variables from our public API. The goal here is to provide a softer nudge
  157. // than a build error. Deprecation markup on the member is a similar approach but will often trigger a build failure
  158. // as warnings as errors is commonly enabled.
  159. // TODO: does not work for types that support dereferencing
  160. template <typename T>
  161. class DeprecatedMemberError
  162. {
  163. public:
  164. #ifdef EA_COMPILER_NO_DEFAULTED_FUNCTIONS
  165. DeprecatedMemberError(){};
  166. #else
  167. DeprecatedMemberError() = default;
  168. #endif
  169. DeprecatedMemberError(T rhs): mValue(rhs) {}
  170. //DeprecatedMemberError& operator=(DeprecatedMemberError&&) = default; // TODO: Why doesn't this work
  171. #ifdef EA_COMPILER_NO_DEFAULTED_FUNCTIONS
  172. DeprecatedMemberError& operator=(const DeprecatedMemberError& rhs)
  173. {
  174. mValue = rhs.mValue;
  175. return *this;
  176. };
  177. #else
  178. DeprecatedMemberError& operator=(const DeprecatedMemberError& rhs) = default;
  179. #endif
  180. DeprecatedMemberError& operator=(const T& rhs)
  181. {
  182. #if EAT_ASSERT_ENABLED
  183. static bool hasTriggered = false;
  184. ErrorOnce(&hasTriggered, "Client code is accessing a deprecated structure member.");
  185. #endif
  186. this->mValue = rhs;
  187. return *this;
  188. }
  189. DeprecatedMemberError& operator=(T&& rhs)
  190. {
  191. #if EAT_ASSERT_ENABLED
  192. static bool hasTriggered = false;
  193. ErrorOnce(&hasTriggered, "Client code is accessing a deprecated structure member.");
  194. #endif
  195. this->mValue = rhs;
  196. return *this;
  197. }
  198. operator T() const
  199. {
  200. #if EAT_ASSERT_ENABLED
  201. static bool hasTriggered = false;
  202. ErrorOnce(&hasTriggered, "Client code is accessing a deprecated structure member.");
  203. #endif
  204. return mValue;
  205. }
  206. // accessor for fetching the value without tripping the error
  207. const T& GetValue() const { return mValue; }
  208. private:
  209. T mValue;
  210. };
  211. }} // end namespace EA::Thread
  212. #endif