]> git.saurik.com Git - wxWidgets.git/blame_incremental - include/wx/private/flagscheck.h
Fix wxPropertyGrid::GetPropertyRect when the last item is collapsed.
[wxWidgets.git] / include / wx / private / flagscheck.h
... / ...
CommitLineData
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
20namespace 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
44template<int val> struct FlagsHaveConflictingValues
45{
46 // no value here - triggers compilation error
47};
48
49template<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.
59template<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_