// Purpose: macros for implementing type-safe vararg passing of strings
// Author: Vaclav Slavik
// Created: 2007-02-19
-// RCS-ID: $Id$
// Copyright: (c) 2007 REA Elektronik GmbH
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include "wx/buffer.h"
#include "wx/unichar.h"
+#if defined(HAVE_TYPE_TRAITS)
+ #include <type_traits>
+#elif defined(HAVE_TR1_TYPE_TRAITS)
+ #ifdef __VISUALC__
+ #include <type_traits>
+ #else
+ #include <tr1/type_traits>
+ #endif
+#endif
+
class WXDLLIMPEXP_FWD_BASE wxCStrData;
class WXDLLIMPEXP_FWD_BASE wxString;
// accounts for string changes done by wxArgNormalizer<>
//
// Note that this class can _only_ be used for function arguments!
-#ifdef __VISUALC__
- // "struct 'wx[W]CharBuffer<T>' needs to have dll-interface to be used by
- // clients of class 'wxString'" - this is private, we don't care
- #pragma warning (disable:4251)
-#endif
class WXDLLIMPEXP_BASE wxFormatString
{
public:
wxFormatString(const char *str)
- : m_char(wxCharBuffer::CreateNonOwned(str)), m_str(NULL), m_cstr(NULL) {}
+ : m_char(wxScopedCharBuffer::CreateNonOwned(str)), m_str(NULL), m_cstr(NULL) {}
wxFormatString(const wchar_t *str)
- : m_wchar(wxWCharBuffer::CreateNonOwned(str)), m_str(NULL), m_cstr(NULL) {}
+ : m_wchar(wxScopedWCharBuffer::CreateNonOwned(str)), m_str(NULL), m_cstr(NULL) {}
wxFormatString(const wxString& str)
: m_str(&str), m_cstr(NULL) {}
wxFormatString(const wxCStrData& str)
: m_str(NULL), m_cstr(&str) {}
- wxFormatString(const wxCharBuffer& str)
+ wxFormatString(const wxScopedCharBuffer& str)
: m_char(str), m_str(NULL), m_cstr(NULL) {}
- wxFormatString(const wxWCharBuffer& str)
+ wxFormatString(const wxScopedWCharBuffer& str)
: m_wchar(str), m_str(NULL), m_cstr(NULL) {}
-
+ // Possible argument types. These are or-combinable for wxASSERT_ARG_TYPE
+ // convenience. Some of the values are or-combined with another value, this
+ // expresses "supertypes" for use with wxASSERT_ARG_TYPE masks. For example,
+ // a char* string is also a pointer and an integer is also a char.
enum ArgumentType
{
- Arg_Char, // character as char
+ Arg_Char = 0x0001, // character as char %c
+ Arg_Pointer = 0x0002, // %p
+ Arg_String = 0x0004 | Arg_Pointer, // any form of string (%s and %p too)
+
+ Arg_Int = 0x0008 | Arg_Char, // (ints can be used with %c)
+#if SIZEOF_INT == SIZEOF_LONG
+ Arg_LongInt = Arg_Int,
+#else
+ Arg_LongInt = 0x0010,
+#endif
+#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG_LONG == SIZEOF_LONG
+ Arg_LongLongInt = Arg_LongInt,
+#elif defined(wxLongLong_t)
+ Arg_LongLongInt = 0x0020,
+#endif
+
+ Arg_Double = 0x0040,
+ Arg_LongDouble = 0x0080,
+
+#if defined(wxSIZE_T_IS_UINT)
+ Arg_Size_t = Arg_Int,
+#elif defined(wxSIZE_T_IS_ULONG)
+ Arg_Size_t = Arg_LongInt,
+#elif defined(SIZEOF_LONG_LONG) && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
+ Arg_Size_t = Arg_LongLongInt,
+#else
+ Arg_Size_t = 0x0100,
+#endif
- Arg_Other // something else, for example int for %d
+ Arg_IntPtr = 0x0200, // %n -- store # of chars written
+ Arg_ShortIntPtr = 0x0400,
+ Arg_LongIntPtr = 0x0800,
+
+ Arg_Unknown = 0x8000 // unrecognized specifier (likely error)
};
// returns the type of format specifier for n-th variadic argument (this is
// n-th variadic argument desired representation
ArgumentType GetArgumentType(unsigned n) const;
+ // returns the value passed to ctor, only converted to wxString, similarly
+ // to other InputAsXXX() methods
+ wxString InputAsString() const;
+
#if !wxUSE_UNICODE_WCHAR
operator const char*() const
- { return wx_const_cast(wxFormatString*, this)->AsChar(); }
+ { return const_cast<wxFormatString*>(this)->AsChar(); }
private:
- // InputAsChar() returns the value converted passed to ctor, only converted
- // to char, while AsChar() takes the the string returned by InputAsChar()
+ // InputAsChar() returns the value passed to ctor, only converted
+ // to char, while AsChar() takes the string returned by InputAsChar()
// and does format string conversion on it as well (and similarly for
// ..AsWChar() below)
const char* InputAsChar();
const char* AsChar();
- wxCharBuffer m_convertedChar;
+ wxScopedCharBuffer m_convertedChar;
#endif // !wxUSE_UNICODE_WCHAR
#if wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY
public:
operator const wchar_t*() const
- { return wx_const_cast(wxFormatString*, this)->AsWChar(); }
+ { return const_cast<wxFormatString*>(this)->AsWChar(); }
private:
const wchar_t* InputAsWChar();
const wchar_t* AsWChar();
- wxWCharBuffer m_convertedWChar;
+ wxScopedWCharBuffer m_convertedWChar;
#endif // wxUSE_UNICODE && !wxUSE_UTF8_LOCALE_ONLY
private:
- wxCharBuffer m_char;
- wxWCharBuffer m_wchar;
-#ifdef __VISUALC__
- #pragma warning (default:4251)
-#endif
+ wxScopedCharBuffer m_char;
+ wxScopedWCharBuffer m_wchar;
// NB: we can use a pointer here, because wxFormatString is only used
// as function argument, so it has shorter life than the string
const wxString * const m_str;
const wxCStrData * const m_cstr;
- DECLARE_NO_ASSIGN_CLASS(wxFormatString)
+ wxDECLARE_NO_ASSIGN_CLASS(wxFormatString);
};
// these two helper classes are used to find wxFormatString argument among fixed
template<>
struct wxFormatStringArgumentFinder<wxFormatString>
-{
- static wxFormatStringArgument find(const wxFormatString& arg)
- { return wxFormatStringArgument(&arg); }
-};
+ : public wxFormatStringArgumentFinder<const wxFormatString&> {};
+
+// avoid passing big objects by value to wxFormatStringArgumentFinder::find()
+// (and especially wx[W]CharBuffer with its auto_ptr<> style semantics!):
+template<>
+struct wxFormatStringArgumentFinder<wxString>
+ : public wxFormatStringArgumentFinder<const wxString&> {};
+
+template<>
+struct wxFormatStringArgumentFinder<wxScopedCharBuffer>
+ : public wxFormatStringArgumentFinder<const wxScopedCharBuffer&> {};
+
+template<>
+struct wxFormatStringArgumentFinder<wxScopedWCharBuffer>
+ : public wxFormatStringArgumentFinder<const wxScopedWCharBuffer&> {};
+
+template<>
+struct wxFormatStringArgumentFinder<wxCharBuffer>
+ : public wxFormatStringArgumentFinder<const wxCharBuffer&> {};
+
+template<>
+struct wxFormatStringArgumentFinder<wxWCharBuffer>
+ : public wxFormatStringArgumentFinder<const wxWCharBuffer&> {};
// ----------------------------------------------------------------------------
// wxArgNormalizer*<T> converters
// ----------------------------------------------------------------------------
+#if wxDEBUG_LEVEL
+ // Check that the format specifier for index-th argument in 'fmt' has
+ // the correct type (one of wxFormatString::Arg_XXX or-combination in
+ // 'expected_mask').
+ #define wxASSERT_ARG_TYPE(fmt, index, expected_mask) \
+ wxSTATEMENT_MACRO_BEGIN \
+ if ( !fmt ) \
+ break; \
+ const int argtype = fmt->GetArgumentType(index); \
+ wxASSERT_MSG( (argtype & (expected_mask)) == argtype, \
+ "format specifier doesn't match argument type" ); \
+ wxSTATEMENT_MACRO_END
+#else
+ // Just define it to suppress "unused parameter" warnings for the
+ // parameters which we don't use otherwise
+ #define wxASSERT_ARG_TYPE(fmt, index, expected_mask) \
+ wxUnusedVar(fmt); \
+ wxUnusedVar(index)
+#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
+
+
+#if defined(HAVE_TYPE_TRAITS) || defined(HAVE_TR1_TYPE_TRAITS)
+
+// Note: this type is misnamed, so that the error message is easier to
+// understand (no error happens for enums, because the IsEnum=true case is
+// specialized).
+template<bool IsEnum>
+struct wxFormatStringSpecifierNonPodType {};
+
+template<>
+struct wxFormatStringSpecifierNonPodType<true>
+{
+ enum { value = wxFormatString::Arg_Int };
+};
+
+template<typename T>
+struct wxFormatStringSpecifier
+{
+#ifdef HAVE_TYPE_TRAITS
+ typedef std::is_enum<T> is_enum;
+#elif defined HAVE_TR1_TYPE_TRAITS
+ typedef std::tr1::is_enum<T> is_enum;
+#endif
+ enum { value = wxFormatStringSpecifierNonPodType<is_enum::value>::value };
+};
+
+#else // !HAVE_(TR1_)TYPE_TRAITS
+
+template<typename T>
+struct wxFormatStringSpecifier
+{
+ // We can't detect enums without is_enum, so the only thing we can
+ // do is to accept unknown types. However, the only acceptable unknown
+ // types still are enums, which are promoted to ints, so return Arg_Int
+ // here. This will at least catch passing of non-POD types through ... at
+ // runtime.
+ //
+ // Furthermore, if the compiler doesn't have partial template
+ // specialization, we didn't cover pointers either.
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+ enum { value = wxFormatString::Arg_Int };
+#else
+ enum { value = wxFormatString::Arg_Int | wxFormatString::Arg_Pointer };
+#endif
+};
+
+#endif // HAVE_TR1_TYPE_TRAITS/!HAVE_TR1_TYPE_TRAITS
+
+
+#ifdef HAVE_PARTIAL_SPECIALIZATION
+template<typename T>
+struct wxFormatStringSpecifier<T*>
+{
+ enum { value = wxFormatString::Arg_Pointer };
+};
+
+template<typename T>
+struct wxFormatStringSpecifier<const T*>
+{
+ enum { value = wxFormatString::Arg_Pointer };
+};
+#endif // !HAVE_PARTIAL_SPECIALIZATION
+
+
+#define wxFORMAT_STRING_SPECIFIER(T, arg) \
+ template<> struct wxFormatStringSpecifier<T> \
+ { \
+ enum { value = arg }; \
+ };
+
+wxFORMAT_STRING_SPECIFIER(bool, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(int, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(unsigned int, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(short int, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(short unsigned int, wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(long int, wxFormatString::Arg_LongInt)
+wxFORMAT_STRING_SPECIFIER(long unsigned int, wxFormatString::Arg_LongInt)
+#ifdef wxLongLong_t
+wxFORMAT_STRING_SPECIFIER(wxLongLong_t, wxFormatString::Arg_LongLongInt)
+wxFORMAT_STRING_SPECIFIER(wxULongLong_t, wxFormatString::Arg_LongLongInt)
+#endif
+wxFORMAT_STRING_SPECIFIER(float, wxFormatString::Arg_Double)
+wxFORMAT_STRING_SPECIFIER(double, wxFormatString::Arg_Double)
+wxFORMAT_STRING_SPECIFIER(long double, wxFormatString::Arg_LongDouble)
+
+#if wxWCHAR_T_IS_REAL_TYPE
+wxFORMAT_STRING_SPECIFIER(wchar_t, wxFormatString::Arg_Char | wxFormatString::Arg_Int)
+#endif
+
+#if !wxUSE_UNICODE
+wxFORMAT_STRING_SPECIFIER(char, wxFormatString::Arg_Char | wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(signed char, wxFormatString::Arg_Char | wxFormatString::Arg_Int)
+wxFORMAT_STRING_SPECIFIER(unsigned char, wxFormatString::Arg_Char | wxFormatString::Arg_Int)
+#endif
+
+wxFORMAT_STRING_SPECIFIER(char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(unsigned char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(signed char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(const char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(const unsigned char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(const signed char*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(wchar_t*, wxFormatString::Arg_String)
+wxFORMAT_STRING_SPECIFIER(const wchar_t*, wxFormatString::Arg_String)
+
+wxFORMAT_STRING_SPECIFIER(int*, wxFormatString::Arg_IntPtr | wxFormatString::Arg_Pointer)
+wxFORMAT_STRING_SPECIFIER(short int*, wxFormatString::Arg_ShortIntPtr | wxFormatString::Arg_Pointer)
+wxFORMAT_STRING_SPECIFIER(long int*, wxFormatString::Arg_LongIntPtr | wxFormatString::Arg_Pointer)
+
+#undef wxFORMAT_STRING_SPECIFIER
+
+
// Converts an argument passed to wxPrint etc. into standard form expected,
// by wxXXX functions, e.g. all strings (wxString, char*, wchar_t*) are
// converted into wchar_t* or char* depending on the build.
// use format string and 'index' is index of 'value' in variadic arguments
// list (starting at 1)
wxArgNormalizer(T value,
- const wxFormatString *WXUNUSED(fmt), unsigned WXUNUSED(index))
- : m_value(value) {}
+ const wxFormatString *fmt, unsigned index)
+ : m_value(value)
+ {
+ wxASSERT_ARG_TYPE( fmt, index, wxFormatStringSpecifier<T>::value );
+ }
// Returns the value in a form that can be safely passed to real vararg
// functions. In case of strings, this is char* in ANSI build and wchar_t*
template<typename CharType>
struct wxArgNormalizerWithBuffer
{
- typedef wxCharTypeBuffer<CharType> CharBuffer;
+ typedef wxScopedCharTypeBuffer<CharType> CharBuffer;
wxArgNormalizerWithBuffer() {}
wxArgNormalizerWithBuffer(const CharBuffer& buf,
- const wxFormatString *WXUNUSED(fmt),
- unsigned WXUNUSED(index))
- : m_value(buf) {}
+ const wxFormatString *fmt,
+ unsigned index)
+ : m_value(buf)
+ {
+ wxASSERT_ARG_TYPE( fmt, index, wxFormatString::Arg_String );
+ }
const CharType *get() const { return m_value; }
struct WXDLLIMPEXP_BASE wxArgNormalizerNative<const wxString&>
{
wxArgNormalizerNative(const wxString& s,
- const wxFormatString *WXUNUSED(fmt),
- unsigned WXUNUSED(index))
- : m_value(s) {}
+ const wxFormatString *fmt,
+ unsigned index)
+ : m_value(s)
+ {
+ wxASSERT_ARG_TYPE( fmt, index, wxFormatString::Arg_String );
+ }
const wxStringCharType *get() const;
struct WXDLLIMPEXP_BASE wxArgNormalizerNative<const wxCStrData&>
{
wxArgNormalizerNative(const wxCStrData& value,
- const wxFormatString *WXUNUSED(fmt),
- unsigned WXUNUSED(index))
- : m_value(value) {}
+ const wxFormatString *fmt,
+ unsigned index)
+ : m_value(value)
+ {
+ wxASSERT_ARG_TYPE( fmt, index, wxFormatString::Arg_String );
+ }
const wxStringCharType *get() const;
: public wxArgNormalizerWithBuffer<char>
{
wxArgNormalizerUtf8(const char* s,
- const wxFormatString *WXUNUSED(fmt),
- unsigned WXUNUSED(index))
+ const wxFormatString *fmt,
+ unsigned index)
{
+ wxASSERT_ARG_TYPE( fmt, index, wxFormatString::Arg_String );
+
if ( wxLocaleIsUtf8 )
{
- m_value = wxCharBuffer::CreateNonOwned(s);
+ m_value = wxScopedCharBuffer::CreateNonOwned(s);
}
else
{
// convert to widechar string first:
- wxWCharBuffer buf(wxConvLibc.cMB2WC(s));
+ wxScopedWCharBuffer buf(wxConvLibc.cMB2WC(s));
// then to UTF-8:
if ( buf )
WX_ARG_NORMALIZER_FORWARD(wchar_t*, const wchar_t*);
// versions for passing wx[W]CharBuffer:
+WX_ARG_NORMALIZER_FORWARD(wxScopedCharBuffer, const char*);
+WX_ARG_NORMALIZER_FORWARD(const wxScopedCharBuffer&, const char*);
+WX_ARG_NORMALIZER_FORWARD(wxScopedWCharBuffer, const wchar_t*);
+WX_ARG_NORMALIZER_FORWARD(const wxScopedWCharBuffer&, const wchar_t*);
WX_ARG_NORMALIZER_FORWARD(wxCharBuffer, const char*);
WX_ARG_NORMALIZER_FORWARD(const wxCharBuffer&, const char*);
WX_ARG_NORMALIZER_FORWARD(wxWCharBuffer, const wchar_t*);
wxArgNormalizerNarrowChar(T value,
const wxFormatString *fmt, unsigned index)
{
+ wxASSERT_ARG_TYPE( fmt, index,
+ wxFormatString::Arg_Char | wxFormatString::Arg_Int );
+
// FIXME-UTF8: which one is better default in absence of fmt string
// (i.e. when used like e.g. Foo("foo", "bar", 'c', NULL)?
if ( !fmt || fmt->GetArgumentType(index) == wxFormatString::Arg_Char )
- m_value = wxUniChar(value).GetValue();
+ m_value = wx_truncate_cast(T, wxUniChar(value).GetValue());
else
m_value = value;
}
: wxArgNormalizerNarrowChar<unsigned char>(value, fmt, index) {}
};
+template<>
+struct wxArgNormalizer<signed char>
+ : public wxArgNormalizerNarrowChar<signed char>
+{
+ wxArgNormalizer(signed char value,
+ const wxFormatString *fmt, unsigned index)
+ : wxArgNormalizerNarrowChar<signed char>(value, fmt, index) {}
+};
+
#endif // wxUSE_UNICODE
// convert references:
WX_ARG_NORMALIZER_FORWARD(const char&, char);
WX_ARG_NORMALIZER_FORWARD(const unsigned char&, unsigned char);
+WX_ARG_NORMALIZER_FORWARD(const signed char&, signed char);
#undef WX_ARG_NORMALIZER_FORWARD
#undef _WX_ARG_NORMALIZER_FORWARD_IMPL
+// NB: Don't #undef wxASSERT_ARG_TYPE here as it's also used in wx/longlong.h.
+
// ----------------------------------------------------------------------------
// WX_VA_ARG_STRING
// ----------------------------------------------------------------------------