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