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
This commit is contained in:
109
include/wx/private/flagscheck.h
Normal file
109
include/wx/private/flagscheck.h
Normal file
@@ -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<int val> struct FlagsHaveConflictingValues
|
||||
{
|
||||
// no value here - triggers compilation error
|
||||
};
|
||||
|
||||
template<int val> 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<int all, int add> 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<add>. 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<add>,
|
||||
FlagsHaveConflictingValues<add> >::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<f, others>::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_
|
@@ -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));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user