summaryrefslogtreecommitdiff
path: root/zen/string_traits.h
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:15:39 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:15:39 +0200
commitd2854834e18443876c8f75e0a7f3b88d1d549fc4 (patch)
treee967b628081e50abc7c34cd264e6586271c7e728 /zen/string_traits.h
parent4.1 (diff)
downloadFreeFileSync-d2854834e18443876c8f75e0a7f3b88d1d549fc4.tar.gz
FreeFileSync-d2854834e18443876c8f75e0a7f3b88d1d549fc4.tar.bz2
FreeFileSync-d2854834e18443876c8f75e0a7f3b88d1d549fc4.zip
4.2
Diffstat (limited to 'zen/string_traits.h')
-rw-r--r--zen/string_traits.h157
1 files changed, 86 insertions, 71 deletions
diff --git a/zen/string_traits.h b/zen/string_traits.h
index 59da2f79..6c51f6dd 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -9,35 +9,48 @@
#define STRING_TRAITS_HEADER_813274321443234
#include "type_tools.h"
+#include "type_traits.h"
#include "assert_static.h"
-//uniform access to string-like types: classes and character arrays
+//uniform access to string-like types, both classes and character arrays
namespace zen
{
/*
+IsStringLike<>::result:
+ IsStringLike<const wchar_t*>::result; //equals "true"
+ IsStringLike<const int*> ::result; //equals "false"
+
+GetCharType<>::Result:
+ GetCharType<std::wstring>::Result //equals wchar_t
+ GetCharType<wchar_t[5]> ::Result //equals wchar_t
+
strBegin():
std::wstring str(L"dummy");
char array[] = "dummy";
- const wchar_t* iter = strBegin(str); //returns str.c_str()
- const char* iter2 = strBegin(array); //returns array
+ strBegin(str); //returns str.c_str()
+ strBegin(array); //returns array
strLength():
- strLength(str); //equals str.size()
+ strLength(str); //equals str.length()
strLength(array); //equals cStringLength(array)
+*/
-StringTraits<>::CharType:
- StringTraits<std::wstring>::CharType //equals wchar_t
- StringTraits<wchar_t[5]> ::CharType //equals wchar_t
+//wrap a sub-string or a char* as an intermediate string class when the length is already known
+template <class Char>
+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) {}
-StringTraits<>::isStringLike:
- StringTraits<const wchar_t*>::isStringLike; //equals "true"
- StringTraits<const int*> ::isStringLike; //equals "false"
+ const Char* c_str() const { return cstr_; }
+ size_t length() const { return length_; }
-StringTraits<>::isStringClass:
- StringTraits<std::wstring>::isStringClass //equals "true"
- StringTraits<wchar_t[5]> ::isStringClass //equals "false"
-*/
+private:
+ const Char* cstr_;
+ size_t length_;
+};
@@ -54,91 +67,87 @@ StringTraits<>::isStringClass:
//---------------------- implementation ----------------------
namespace implementation
{
-template<typename T>
-class HasValueTypedef
-{
- typedef char Yes[1];
- typedef char No [2];
-
- template <typename U> class HelperTp {};
+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) //
- //detect presence of a member type called value_type
- template <class U> static Yes& hasMemberValueType(HelperTp<typename U::value_type>*);
- template <class U> static No& hasMemberValueType(...);
+template<typename T, bool isClassType>
+struct HasStringMembers { enum { result = false }; };
-public:
- enum { result = sizeof(hasMemberValueType<T>(NULL)) == sizeof(Yes)
+template<typename T>
+struct HasStringMembers<T, true> //Note: we can apply non-typed member-check on class types only!
+{
+ enum { result = HasMember_c_str <T>::result &&
+ HasMember_length<T>::result
};
};
-template<typename T, bool isClassType>
-class HasStringMembers
-{
-public:
- enum { result = false };
-};
-
-template<typename T>
-class HasStringMembers<T, true>
+template<class S, class Char> //test if result of S::c_str() can convert to const Char*
+class HasConversion
{
typedef char Yes[1];
typedef char No [2];
- //detect presence of member functions (without specific restriction on return type, within T or one of it's base classes)
- template <typename U, U t> class HelperFn {};
+ static Yes& hasConversion(const Char*);
+ static No& hasConversion(...);
- struct Fallback
- {
- int c_str;
- int length;
- };
+ static S createInstance();
- template <class U>
- struct Helper2 : public U, public Fallback {}; //U must be a class-type!
+public:
+ enum { result = sizeof(hasConversion(createInstance().c_str())) == sizeof(Yes) };
+};
- //we don't know the exact declaration of the member attribute (may be in base class), but we know what NOT to expect:
- template <class U> static No& hasMemberCstr(HelperFn<int Fallback::*, &Helper2<U>::c_str>*);
- template <class U> static Yes& hasMemberCstr(...);
- template <class U> static No& hasMemberLength(HelperFn<int Fallback::*, &Helper2<U>::length>*);
- template <class U> static Yes& hasMemberLength(...);
-public:
- enum { result = sizeof(hasMemberCstr <T>(NULL)) == sizeof(Yes) &&
- sizeof(hasMemberLength<T>(NULL)) == sizeof(Yes)
- };
+template <class S, bool isStringClass> struct GetCharTypeImpl { typedef EmptyType Result; };
+template <class S> struct GetCharTypeImpl<S, true >
+{
+ //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<HasConversion<S, wchar_t>::result, wchar_t,
+ typename SelectIf<HasConversion<S, char>::result, char, EmptyType>::Result
+ >::Result Result;
};
-template <class S, bool isStringClass> struct StringTraits2 { typedef EmptyType Result; }; //"StringTraits2": fix some VS bug with namespace and partial template specialization
-template <class S> struct StringTraits2<S, true > { typedef typename S::value_type Result; };
-template <> struct StringTraits2<char, false> { typedef char Result; };
-template <> struct StringTraits2<wchar_t, false> { typedef wchar_t Result; };
-}
+template <> struct GetCharTypeImpl<char, false> { typedef char Result; };
+template <> struct GetCharTypeImpl<wchar_t, false> { typedef wchar_t Result; };
+ZEN_INIT_DETECT_MEMBER_TYPE(value_type);
template <class S>
-struct StringTraits
+class StringTraits
{
-private:
typedef typename RemoveRef <S >::Result NonRefType;
typedef typename RemoveConst <NonRefType >::Result NonConstType;
typedef typename RemoveArray <NonConstType>::Result NonArrayType;
typedef typename RemovePointer<NonArrayType>::Result NonPtrType;
typedef typename RemoveConst <NonPtrType >::Result UndecoratedType; //handle "const char* const"
+
public:
enum
{
- isStringClass = implementation::HasStringMembers<NonConstType, implementation::HasValueTypedef<NonConstType>::result>::result
+ isStringClass = HasStringMembers<NonConstType, HasMemberType_value_type<NonConstType>::result>::result
};
- typedef typename implementation::StringTraits2<UndecoratedType, isStringClass>::Result CharType;
+ typedef typename GetCharTypeImpl<UndecoratedType, isStringClass>::Result CharType;
enum
{
- isStringLike = IsSameType<CharType, char>::result || IsSameType<CharType, wchar_t>::result
+ isStringLike = IsSameType<CharType, char>::result ||
+ IsSameType<CharType, wchar_t>::result
};
};
+}
+
+template <class T>
+struct IsStringLike { enum { result = implementation::StringTraits<T>::isStringLike }; };
+
+template <class T>
+struct GetCharType { typedef typename implementation::StringTraits<T>::CharType Result; };
namespace implementation
@@ -156,19 +165,25 @@ size_t cStringLength(const C* str) //strlen()
template <class S> inline
-const typename StringTraits<S>::CharType* strBegin(const S& str, typename S::value_type dummy = 0) { return str.c_str(); } //SFINAE: T must be a "string"
+const typename GetCharType<S>::Result* strBegin(const S& str, typename EnableIf<implementation::StringTraits<S>::isStringClass>::Result* = NULL) //SFINAE: T must be a "string"
+{
+ return str.c_str();
+}
-template <class Char>
-inline const typename StringTraits<Char>::CharType* strBegin(const Char* str) { return str; }
-inline const char* strBegin(const char& ch) { return &ch; }
-inline const wchar_t* strBegin(const wchar_t& ch) { return &ch; }
+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 <class S> inline
-size_t strLength(const S& str, typename S::value_type dummy = 0) { return str.length(); } //SFINAE: T must be a "string"
+size_t strLength(const S& str, typename EnableIf<implementation::StringTraits<S>::isStringClass>::Result* = NULL) //SFINAE: T must be a "string"
+{
+ return str.length();
+}
-template <class Char>
-inline size_t strLength(const Char* str) { return implementation::cStringLength(str); }
+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; }
}
bgstack15