00001 /* 00002 * Copyright 2006-2008 The FLWOR Foundation. 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #ifndef ZORBA_INTERNAL_ZTD_H 00018 #define ZORBA_INTERNAL_ZTD_H 00019 00020 #include <cstring> 00021 #include <functional> 00022 #include <sstream> 00023 #include <string> 00024 00025 #include <zorba/config.h> 00026 00027 #include "type_traits.h" 00028 00029 /////////////////////////////////////////////////////////////////////////////// 00030 00031 namespace zorba { 00032 namespace internal { 00033 namespace ztd { 00034 00035 ////////// tr1 //////////////////////////////////////////////////////////////// 00036 00037 /** 00038 * \internal 00039 * Base class for SFINAE (Substitution Failure Is Not An Error) types. 00040 */ 00041 class sfinae_base { 00042 protected: 00043 typedef char no; 00044 typedef char yes[2]; 00045 public: 00046 void suppress_all_member_functions_are_private_warning(); 00047 }; 00048 00049 /** 00050 * \internal 00051 * Declares a class that can be used to determine whether a given type \c T has 00052 * a particular member function with a certain signature. 00053 * For example: 00054 * \code 00055 * ZORBA_DECL_HAS_MEM_FN( c_str ); 00056 * 00057 * template<typename T> inline 00058 * typename enable_if<has_c_str<T,char const* (T::*)() const>::value, 00059 * std::string>::type 00060 * to_string( T const &t ) { 00061 * // case where T has c_str() 00062 * } 00063 * 00064 * template<typename T> inline 00065 * typename enable_if<!has_c_str<T,char const* (T::*)() const>::value, 00066 * std::string>::type 00067 * to_string( T const &t ) { 00068 * // case where T does not have c_str() 00069 * } 00070 * \endcode 00071 * \hideinitializer 00072 */ 00073 #define ZORBA_DECL_HAS_MEM_FN(FN_NAME) \ 00074 template<typename T,typename S> \ 00075 class has_##FN_NAME : public sfinae_base { \ 00076 template<typename SignatureType,SignatureType> struct type_check; \ 00077 template<class U> static yes& test(type_check<S,&U::FN_NAME>*); \ 00078 template<class U> static no& test(...); \ 00079 public: \ 00080 static bool const value = sizeof( test<T>(0) ) == sizeof( yes ); \ 00081 } 00082 00083 /** 00084 * \internal 00085 * This namespace is used only to bundle the implementation details for 00086 * implementing \c has_insertion_operator<T>. 00087 * This implementation is based on http://stackoverflow.com/questions/4434569/ 00088 */ 00089 namespace has_insertion_operator_impl { 00090 typedef char no; 00091 typedef char yes[2]; 00092 00093 /** 00094 * This dummy class is used to make the matching of the dummy operator<<() 00095 * \e worse than the global \c operator<<(), if any. 00096 */ 00097 struct any_t { 00098 template<typename T> any_t( T const& ); 00099 }; 00100 00101 /** 00102 * This dummy operator is matched only when there is \e no global 00103 * operator<<() otherwise declared for type \c T. 00104 * 00105 * @return Returns a \c no that selects defined(no). 00106 */ 00107 no operator<<( std::ostream const&, any_t const& ); 00108 00109 /** 00110 * This function is matched only when there \e is a global \c operator<<() 00111 * declared for type \c T because \c operator<<()'s return type is 00112 * \c std::ostream&. 00113 * 00114 * @return Returns a yes& whose \c sizeof() equals \c sizeof(yes). 00115 */ 00116 yes& defined( std::ostream& ); 00117 00118 /** 00119 * This function is matched only when the dummy \c operator<<() is matched. 00120 * 00121 * @return Returns a no whose \c sizeof() equals \c sizeof(no). 00122 */ 00123 no defined( no ); 00124 00125 /** 00126 * The implementation class that can be used to determine whether a given 00127 * type \c T has a global <code>std::ostream& operator<<(std::ostream&,T 00128 * const&)</code> defined for it. However, do not use this class directly. 00129 * 00130 * @tparam T The type to check. 00131 */ 00132 template<typename T> 00133 class has_insertion_operator { 00134 static std::ostream &s; 00135 static T const &t; 00136 public: 00137 /** 00138 * This is \c true only when the type \c T has a global \c operator<<() 00139 * declared for it. 00140 * \hideinitializer 00141 */ 00142 static bool const value = sizeof( defined( s << t ) ) == sizeof( yes ); 00143 }; 00144 } // namespace has_insertion_operator_impl 00145 00146 /** 00147 * \internal 00148 * A class that can be used to determine whether a given type \c T has a global 00149 * <code>std::ostream& operator<<(std::ostream&,T const&)</code> defined for 00150 * it. 00151 * For example: 00152 * \code 00153 * template<typename T> inline 00154 * typename enable_if<has_insertion_operator<T>::value,std::string>::value 00155 * to_string( T const &t ) { 00156 * // case where T has operator<<(ostream&,T const&) 00157 * } 00158 * \endcode 00159 * 00160 * @tparam T The type to check. 00161 */ 00162 template<typename T> 00163 struct has_insertion_operator : 00164 has_insertion_operator_impl::has_insertion_operator<T> 00165 { 00166 }; 00167 00168 ////////// c_str() ///////////////////////////////////////////////////////////// 00169 00170 /** 00171 * \internal 00172 * Gets the \c char* to the given string. 00173 * 00174 * @tparam OutputStringType The string's type. 00175 * @param s The string to get the \c char* of. 00176 * @return Returns said \c char*. 00177 */ 00178 template<class StringType> inline 00179 typename StringType::const_pointer c_str( StringType const &s ) { 00180 return s.c_str(); 00181 } 00182 00183 /** 00184 * \internal 00185 * Specialization of global c_str() for \c char* argument. 00186 * 00187 * @param s The C string to get the \c char* of. 00188 * @return Returns said \c char*. 00189 */ 00190 inline char const* c_str( char const *s ) { 00191 return s; 00192 } 00193 00194 ////////// destroy_delete (for unique_ptr) //////////////////////////////////// 00195 00196 /** 00197 * A deleter class that can be used with unique_ptr. Instead of calling \c 00198 * delete on the pointed-to object, it calls its \c destroy() member function. 00199 */ 00200 template<typename T> 00201 struct destroy_delete { 00202 destroy_delete() { } 00203 00204 /** 00205 * Copy constructor. 00206 * 00207 * @tparam U The delete type of the deleter to copy-construct from such that 00208 * \c U* is convertible to \c T*. 00209 */ 00210 template<typename U> 00211 destroy_delete( destroy_delete<U> const&, 00212 typename 00213 std::enable_if<ZORBA_TR1_NS::is_convertible<U*,T*>::value>::type* = 0 ) 00214 { 00215 } 00216 00217 /** 00218 * Calls the \c destroy() member function of the pointed-to object. 00219 * 00220 * @param p A pointer to the object. 00221 */ 00222 void operator()( T *p ) { 00223 if ( p ) 00224 p->destroy(); 00225 } 00226 }; 00227 00228 ////////// less<char const*> /////////////////////////////////////////////////// 00229 00230 // This declaration exists only to declare that less is a template class. 00231 template<typename T> struct less { 00232 }; 00233 00234 /** 00235 * \internal 00236 * Specialize the binary_function "less" so that C-style strings (char const*) 00237 * will work properly with STL containers. 00238 * 00239 * See also: Bjarne Stroustrup. "The C++ Programming Language, 3rd ed." 00240 * Addison-Wesley, Reading, MA, 1997. p. 468. 00241 */ 00242 template<> struct less<char const*> : 00243 std::binary_function<char const*,char const*,bool> 00244 { 00245 less() { } 00246 // This default constructor doesn't need to be defined, but g++ complains if 00247 // it isn't and you try to define a "const less" object. 00248 00249 result_type 00250 operator()( first_argument_type a, second_argument_type b ) const { 00251 return std::strcmp( a, b ) < 0; 00252 } 00253 }; 00254 00255 ////////// To-string conversion //////////////////////////////////////////////// 00256 00257 ZORBA_DECL_HAS_MEM_FN( c_str ); 00258 ZORBA_DECL_HAS_MEM_FN( str ); 00259 ZORBA_DECL_HAS_MEM_FN( toString ); 00260 00261 /** 00262 * \internal 00263 * Converts an object to its string representation. 00264 * 00265 * @tparam T The object type that: 00266 * - is not a pointer 00267 * - has an <code>ostream& operator<<(ostream&,T const&)</code> defined 00268 * @param t The object. 00269 * @return Returns a string representation of the object. 00270 */ 00271 template<typename T> inline 00272 typename std::enable_if<!ZORBA_TR1_NS::is_pointer<T>::value 00273 && has_insertion_operator<T>::value, 00274 std::string>::type 00275 to_string( T const &t ) { 00276 std::ostringstream o; 00277 o << t; 00278 return o.str(); 00279 } 00280 00281 /** 00282 * \internal 00283 * Specialization of \c to_string() for class types that have a \c c_str() 00284 * member function, i.e., string types. 00285 * 00286 * @tparam T The class type that: 00287 * - has no <code>ostream& operator<<(ostream&,T const&)</code> defined 00288 * - has <code>char const* T::c_str() const</code> defined 00289 * @param t The object. 00290 * @return Returns a string representation of the object. 00291 */ 00292 template<class T> inline 00293 typename std::enable_if<!has_insertion_operator<T>::value 00294 && has_c_str<T,char const* (T::*)() const>::value, 00295 std::string>::type 00296 to_string( T const &t ) { 00297 return t.c_str(); 00298 } 00299 00300 /** 00301 * \internal 00302 * Specialization of \c to_string() for class types that have a \c str() 00303 * member function. 00304 * 00305 * @tparam T The class type that: 00306 * - has no <code>ostream& operator<<(ostream&,T const&)</code> defined 00307 * - has no <code>char const* T::c_str() const</code> defined 00308 * - has no <code>std::string T::toString() const</code> defined 00309 * - has <code>std::string T::str() const</code> defined 00310 * @param t The object. 00311 * @return Returns a string representation of the object. 00312 */ 00313 template<class T> inline 00314 typename std::enable_if<!has_insertion_operator<T>::value 00315 && !has_c_str<T,char const* (T::*)() const>::value 00316 && has_str<T,std::string (T::*)() const>::value 00317 && !has_toString<T,std::string (T::*)() const>::value, 00318 std::string>::type 00319 to_string( T const &t ) { 00320 return t.str(); 00321 } 00322 00323 /** 00324 * \internal 00325 * Specialization of \c to_string() for class types that have a \c toString() 00326 * member function. 00327 * 00328 * @tparam T The class type that: 00329 * - has no <code>ostream& operator<<(ostream&,T const&)</code> defined 00330 * - has no <code>char const* T::c_str() const</code> defined 00331 * - has no <code>std::string T::str() const</code> defined 00332 * - has <code>std::string T::toString() const</code> defined 00333 * @param t The object. 00334 * @return Returns a string representation of the object. 00335 */ 00336 template<class T> inline 00337 typename std::enable_if<!has_insertion_operator<T>::value 00338 && !has_c_str<T,char const* (T::*)() const>::value 00339 && !has_str<T,std::string (T::*)() const>::value 00340 && has_toString<T,std::string (T::*)() const>::value, 00341 std::string>::type 00342 to_string( T const &t ) { 00343 return t.toString(); 00344 } 00345 00346 /** 00347 * \internal 00348 * Specialization of \c to_string() for pointer types. 00349 * 00350 * @tparam T The pointer type. 00351 * @param p The pointer. 00352 * @return If \a p is not \c NULL, returns the result of \c to_string(*p); 00353 * otherwise returns \c "<null>". 00354 */ 00355 template<typename T> inline 00356 typename std::enable_if<ZORBA_TR1_NS::is_pointer<T>::value,std::string>::type 00357 to_string( T p ) { 00358 return p ? to_string( *p ) : "<null>"; 00359 } 00360 00361 /** 00362 * \internal 00363 * Specialization of \c to_string() for C strings. 00364 * 00365 * @param s The C string. 00366 * @return Returns a string representation of the object. 00367 */ 00368 inline std::string to_string( char const *s ) { 00369 return s ? s : "<null>"; 00370 } 00371 00372 /////////////////////////////////////////////////////////////////////////////// 00373 00374 } // namespace ztd 00375 } // namespace internal 00376 } // namespace zorba 00377 #endif /* ZORBA_INTERNAL_ZTD_H */ 00378 /* vim:set et sw=2 ts=2: */