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