]>
Commit | Line | Data |
---|---|---|
df44dced VS |
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 | |
df44dced VS |
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" | |
be467427 PC |
14 | |
15 | // IBM xlC 8 can't parse the template syntax | |
16 | #if !defined(__IBMCPP__) | |
17 | ||
df44dced VS |
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 | |
be467427 | 42 | // the macros below with empty stubs, this isn't anything critical. |
df44dced VS |
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 | ||
be467427 PC |
107 | #else |
108 | #define wxADD_FLAG(f, others) (f | others) | |
109 | #endif | |
110 | ||
df44dced VS |
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_ |