From: Václav Slavík Date: Tue, 4 Mar 2008 12:03:02 +0000 (+0000) Subject: added macros for checking for conflicts between flags values; use it in wxSizer code X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/df44dcedaab506c016a07ffdfda2b6a89a529186 added macros for checking for conflicts between flags values; use it in wxSizer code git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52310 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/private/flagscheck.h b/include/wx/private/flagscheck.h new file mode 100644 index 0000000000..751278eedf --- /dev/null +++ b/include/wx/private/flagscheck.h @@ -0,0 +1,109 @@ +///////////////////////////////////////////////////////////////////////////// +// 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_ diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp index 6d70ae0bc3..930aa061bb 100644 --- a/src/common/sizer.cpp +++ b/src/common/sizer.cpp @@ -19,6 +19,7 @@ #include "wx/display.h" #include "wx/sizer.h" +#include "wx/private/flagscheck.h" #ifndef WX_PRECOMP #include "wx/string.h" @@ -87,6 +88,31 @@ WX_DEFINE_EXPORTED_LIST( wxSizerItemList ) // wxSizerItem // ---------------------------------------------------------------------------- +// check for flags conflicts +static const int SIZER_FLAGS_MASK = + wxADD_FLAG(wxCENTRE, + wxADD_FLAG(wxHORIZONTAL, + wxADD_FLAG(wxVERTICAL, + wxADD_FLAG(wxLEFT, + wxADD_FLAG(wxRIGHT, + wxADD_FLAG(wxUP, + wxADD_FLAG(wxDOWN, + wxADD_FLAG(wxALIGN_NOT, + wxADD_FLAG(wxALIGN_CENTER_HORIZONTAL, + wxADD_FLAG(wxALIGN_RIGHT, + wxADD_FLAG(wxALIGN_BOTTOM, + wxADD_FLAG(wxALIGN_CENTER_VERTICAL, + wxADD_FLAG(wxFIXED_MINSIZE, + wxADD_FLAG(wxRESERVE_SPACE_EVEN_IF_HIDDEN, + wxADD_FLAG(wxSTRETCH_NOT, + wxADD_FLAG(wxSHRINK, + wxADD_FLAG(wxGROW, + wxADD_FLAG(wxSHAPED, + 0)))))))))))))))))); + +#define ASSERT_VALID_SIZER_FLAGS(f) wxASSERT_VALID_FLAGS(f, SIZER_FLAGS_MASK) + + void wxSizerItem::Init(const wxSizerFlags& flags) { Init(); @@ -94,6 +120,8 @@ void wxSizerItem::Init(const wxSizerFlags& flags) m_proportion = flags.GetProportion(); m_flag = flags.GetFlags(); m_border = flags.GetBorderInPixels(); + + ASSERT_VALID_SIZER_FLAGS( m_flag ); } wxSizerItem::wxSizerItem() @@ -136,6 +164,8 @@ wxSizerItem::wxSizerItem(wxWindow *window, m_id(wxID_NONE), m_userData(userData) { + ASSERT_VALID_SIZER_FLAGS( m_flag ); + DoSetWindow(window); } @@ -160,6 +190,8 @@ wxSizerItem::wxSizerItem(wxSizer *sizer, m_ratio(0.0), m_userData(userData) { + ASSERT_VALID_SIZER_FLAGS( m_flag ); + DoSetSizer(sizer); // m_minSize is set later @@ -189,6 +221,8 @@ wxSizerItem::wxSizerItem(int width, m_id(wxID_NONE), m_userData(userData) { + ASSERT_VALID_SIZER_FLAGS( m_flag ); + DoSetSpacer(wxSize(width, height)); }