flagscheck.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: wx/private/flagscheck.h
  3. // Purpose: helpers for checking that (bit)flags don't overlap
  4. // Author: Vaclav Slavik
  5. // Created: 2008-02-21
  6. // Copyright: (c) 2008 Vaclav Slavik
  7. // Licence: wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9. #ifndef _WX_PRIVATE_FLAGSCHECK_H_
  10. #define _WX_PRIVATE_FLAGSCHECK_H_
  11. #include "wx/debug.h"
  12. // IBM xlC 8 can't parse the template syntax
  13. #if !defined(__IBMCPP__)
  14. #include "wx/meta/if.h"
  15. namespace wxPrivate
  16. {
  17. // These templates are used to implement wxADD_FLAG macro below.
  18. //
  19. // The idea is that we want to trigger *compilation* error if the flags
  20. // overlap, not just runtime assert failure. We can't implement the check
  21. // using just a simple logical operation, we need checks equivalent to this
  22. // code:
  23. //
  24. // mask = wxFLAG_1;
  25. // assert( (mask & wxFLAG_2) == 0 ); // no overlap
  26. // mask |= wxFLAG_3;
  27. // assert( (mask & wxFLAG_3) == 0 ); // no overlap
  28. // mask |= wxFLAG_3;
  29. // ...
  30. //
  31. // This can be done at compilation time by using templates metaprogramming
  32. // technique that makes the compiler carry on the computation.
  33. //
  34. // NB: If any of this doesn't compile with your compiler and would be too
  35. // hard to make work, it's probably best to disable this code and replace
  36. // the macros below with empty stubs, this isn't anything critical.
  37. template<int val> struct FlagsHaveConflictingValues
  38. {
  39. // no value here - triggers compilation error
  40. };
  41. template<int val> struct FlagValue
  42. {
  43. enum { value = val };
  44. };
  45. // This template adds its template parameter integer 'add' to another integer
  46. // 'all' and produces their OR-combination (all | add). The result is "stored"
  47. // as constant SafelyAddToMask<>::value. Combination of many flags is achieved
  48. // by chaining parameter lists: the 'add' parameter is value member of
  49. // another (different) SafelyAddToMask<> instantiation.
  50. template<int all, int add> struct SafelyAddToMask
  51. {
  52. // This typedefs ensures that no flags in the list conflict. If there's
  53. // any overlap between the already constructed part of the mask ('all')
  54. // and the value being added to it ('add'), the test that is wxIf<>'s
  55. // first parameter will be non-zero and so Added value will be
  56. // FlagsHaveConflictingValues<add>. The next statement will try to use
  57. // AddedValue::value, but there's no such thing in
  58. // FlagsHaveConflictingValues<> and so compilation will fail.
  59. typedef typename wxIf<(all & add) == 0,
  60. FlagValue<add>,
  61. FlagsHaveConflictingValues<add> >::value
  62. AddedValue;
  63. enum { value = all | AddedValue::value };
  64. };
  65. } // wxPrivate namespace
  66. // This macro is used to ensure that no two flags that can be combined in
  67. // the same integer value have overlapping bits. This is sometimes not entirely
  68. // trivial to ensure, for example in wxWindow styles or flags for wxSizerItem
  69. // that span several enums, some of them used for multiple purposes.
  70. //
  71. // By constructing allowed flags mask using wxADD_FLAG macro and then using
  72. // this mask to check flags passed as arguments, you can ensure that
  73. //
  74. // a) if any of the allowed flags overlap, you will get compilation error
  75. // b) if invalid flag is used, there will be an assert at runtime
  76. //
  77. // Example usage:
  78. //
  79. // static const int SIZER_FLAGS_MASK =
  80. // wxADD_FLAG(wxCENTRE,
  81. // wxADD_FLAG(wxHORIZONTAL,
  82. // wxADD_FLAG(wxVERTICAL,
  83. // ...
  84. // 0))...);
  85. //
  86. // And wherever flags are used:
  87. //
  88. // wxASSERT_VALID_FLAG( m_flag, SIZER_FLAGS_MASK );
  89. #define wxADD_FLAG(f, others) \
  90. ::wxPrivate::SafelyAddToMask<f, others>::value
  91. #else
  92. #define wxADD_FLAG(f, others) (f | others)
  93. #endif
  94. // Checks if flags value 'f' is within the mask of allowed values
  95. #define wxASSERT_VALID_FLAGS(f, mask) \
  96. wxASSERT_MSG( (f & mask) == f, \
  97. "invalid flag: not within " #mask )
  98. #endif // _WX_PRIVATE_FLAGSCHECK_H_