]> git.saurik.com Git - wxWidgets.git/blame - include/wx/private/flagscheck.h
Resolve GCC's 'type-punned pointer will break strict-aliasing rules' warning by break...
[wxWidgets.git] / include / wx / private / flagscheck.h
CommitLineData
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
21namespace 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
45template<int val> struct FlagsHaveConflictingValues
46{
47 // no value here - triggers compilation error
48};
49
50template<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.
60template<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_