///////////////////////////////////////////////////////////////////////////// // Name: wx/private/flagscheck.h // Purpose: helpers for checking that (bit)flags don't overlap // Author: Vaclav Slavik // Created: 2008-02-21 // RCS-ID: $Id$ // Copyright: (c) 2008 Vaclav Slavik // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifndef _WX_PRIVATE_FLAGSCHECK_H_ #define _WX_PRIVATE_FLAGSCHECK_H_ #include "wx/debug.h" #include "wx/meta/if.h" namespace wxPrivate { // These templates are used to implement wxADD_FLAG macro below. // // The idea is that we want to trigger *compilation* error if the flags // overlap, not just runtime assert failure. We can't implement the check // using just a simple logical operation, we need checks equivalent to this // code: // // mask = wxFLAG_1; // assert( (mask & wxFLAG_2) == 0 ); // no overlap // mask |= wxFLAG_3; // assert( (mask & wxFLAG_3) == 0 ); // no overlap // mask |= wxFLAG_3; // ... // // This can be done at compilation time by using templates metaprogramming // technique that makes the compiler carry on the computation. // // NB: If any of this doesn't compile with your compiler and would be too // hard to make work, it's probably best to disable this code and replace // the macros below with empty stubs, this isn't anything criticial. template struct FlagsHaveConflictingValues { // no value here - triggers compilation error }; template struct FlagValue { enum { value = val }; }; // This template adds its template parameter integer 'add' to another integer // 'all' and produces their OR-combination (all | add). The result is "stored" // as constant SafelyAddToMask<>::value. Combination of many flags is achieved // by chaining parameter lists: the 'add' parameter is value member of // another (different) SafelyAddToMask<> instantiation. template struct SafelyAddToMask { // This typedefs ensures that no flags in the list conflict. If there's // any overlap between the already constructed part of the mask ('all') // and the value being added to it ('add'), the test that is wxIf<>'s // first parameter will be non-zero and so Added value will be // FlagsHaveConflictingValues. The next statement will try to use // AddedValue::value, but there's no such thing in // FlagsHaveConflictingValues<> and so compilation will fail. typedef typename wxIf<(all & add) == 0, FlagValue, FlagsHaveConflictingValues >::value AddedValue; enum { value = all | AddedValue::value }; }; } // wxPrivate namespace // This macro is used to ensure that no two flags that can be combined in // the same integer value have overlapping bits. This is sometimes not entirely // trivial to ensure, for example in wxWindow styles or flags for wxSizerItem // that span several enums, some of them used for multiple purposes. // // By constructing allowed flags mask using wxADD_FLAG macro and then using // this mask to check flags passed as arguments, you can ensure that // // a) if any of the allowed flags overlap, you will get compilation error // b) if invalid flag is used, there will be an assert at runtime // // Example usage: // // static const int SIZER_FLAGS_MASK = // wxADD_FLAG(wxCENTRE, // wxADD_FLAG(wxHORIZONTAL, // wxADD_FLAG(wxVERTICAL, // ... // 0))...); // // And wherever flags are used: // // wxASSERT_VALID_FLAG( m_flag, SIZER_FLAGS_MASK ); #define wxADD_FLAG(f, others) \ ::wxPrivate::SafelyAddToMask::value // Checks if flags value 'f' is within the mask of allowed values #define wxASSERT_VALID_FLAGS(f, mask) \ wxASSERT_MSG( (f & mask) == f, \ "invalid flag: not within " #mask ) #endif // _WX_PRIVATE_FLAGSCHECK_H_