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