// ************************************************************************** // * This file is part of the zenXML project. It is distributed under the * // * Boost Software License, Version 1.0. See accompanying file * // * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt. * // * Copyright (C) 2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** #ifndef STRING_TRAITS_HEADER_813274321443234 #define STRING_TRAITS_HEADER_813274321443234 #include "type_tools.h" #include "type_traits.h" #include "assert_static.h" //uniform access to string-like types, both classes and character arrays namespace zen { /* IsStringLike<>::result: IsStringLike::result; //equals "true" IsStringLike ::result; //equals "false" GetCharType<>::Result: GetCharType::Result //equals wchar_t GetCharType ::Result //equals wchar_t strBegin(): std::wstring str(L"dummy"); char array[] = "dummy"; strBegin(str); //returns str.c_str() strBegin(array); //returns array strLength(): strLength(str); //equals str.length() strLength(array); //equals cStringLength(array) */ //wrap a sub-string or a char* as an intermediate string class when the length is already known template class StringProxy { public: StringProxy(const Char* cstr, size_t len ) : cstr_(cstr), length_(len) {} StringProxy(const Char* cstrBegin, const Char* cstrEnd) : cstr_(cstrBegin), length_(cstrEnd - cstrBegin) {} const Char* c_str() const { return cstr_; } size_t length() const { return length_; } private: const Char* cstr_; size_t length_; }; //---------------------- implementation ---------------------- namespace implementation { ZEN_INIT_DETECT_MEMBER(c_str) //we don't know the exact declaration of the member attribute and it may be in a base class! ZEN_INIT_DETECT_MEMBER(length) // template struct HasStringMembers { enum { result = false }; }; template struct HasStringMembers //Note: we can apply non-typed member-check on class types only! { enum { result = HasMember_c_str ::result && HasMember_length::result }; }; template //test if result of S::c_str() can convert to const Char* class HasConversion { typedef char Yes[1]; typedef char No [2]; static Yes& hasConversion(const Char*); static No& hasConversion(...); static S createInstance(); public: enum { result = sizeof(hasConversion(createInstance().c_str())) == sizeof(Yes) }; }; template struct GetCharTypeImpl { typedef EmptyType Result; }; template struct GetCharTypeImpl { //typedef typename S::value_type Result; /*DON'T use S::value_type: 1. support Glib::ustring: value_type is "unsigned int" but c_str() returns "const char*" 2. wxString, wxWidgets v2.9, has some questionable string design: wxString::c_str() returns a proxy (wxCStrData) which is implicitly convertible to *both* "const char*" and "const wchar_t*" while wxString::value_type is a wrapper around an unsigned int */ typedef typename SelectIf::result, wchar_t, typename SelectIf::result, char, EmptyType>::Result >::Result Result; }; template <> struct GetCharTypeImpl { typedef char Result; }; template <> struct GetCharTypeImpl { typedef wchar_t Result; }; ZEN_INIT_DETECT_MEMBER_TYPE(value_type); template class StringTraits { typedef typename RemoveRef ::Result NonRefType; typedef typename RemoveConst ::Result NonConstType; typedef typename RemoveArray ::Result NonArrayType; typedef typename RemovePointer::Result NonPtrType; typedef typename RemoveConst ::Result UndecoratedType; //handle "const char* const" public: enum { isStringClass = HasStringMembers::result>::result }; typedef typename GetCharTypeImpl::Result CharType; enum { isStringLike = IsSameType::result || IsSameType::result }; }; } template struct IsStringLike { enum { result = implementation::StringTraits::isStringLike }; }; template struct GetCharType { typedef typename implementation::StringTraits::CharType Result; }; namespace implementation { template inline size_t cStringLength(const C* str) //strlen() { assert_static((IsSameType::result || IsSameType::result)); size_t len = 0; while (*str++ != 0) ++len; return len; } } template inline const typename GetCharType::Result* strBegin(const S& str, typename EnableIf::isStringClass>::Result* = NULL) //SFINAE: T must be a "string" { return str.c_str(); } inline const char* strBegin(const char* str) { return str; } inline const wchar_t* strBegin(const wchar_t* str) { return str; } inline const char* strBegin(const char& ch) { return &ch; } inline const wchar_t* strBegin(const wchar_t& ch) { return &ch; } template inline size_t strLength(const S& str, typename EnableIf::isStringClass>::Result* = NULL) //SFINAE: T must be a "string" { return str.length(); } inline size_t strLength(const char* str) { return implementation::cStringLength(str); } inline size_t strLength(const wchar_t* str) { return implementation::cStringLength(str); } inline size_t strLength(char) { return 1; } inline size_t strLength(wchar_t) { return 1; } } #endif //STRING_TRAITS_HEADER_813274321443234