ztd.h
Go to the documentation of this file.
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&lt;&lt;(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&lt;&lt;(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&lt;&lt;(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&lt;&lt;(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   typedef typename ZORBA_TR1_NS::remove_pointer<T>::type const* T_const_ptr;
00359   return p ? to_string( *static_cast<T_const_ptr>( p ) ) : "<null>";
00360 }
00361 
00362 /**
00363  * \internal
00364  * Specialization of \c to_string() for C strings.
00365  *
00366  * @param s The C string.
00367  * @return Returns a string representation of the object.
00368  */
00369 inline std::string to_string( char const *s ) {
00370   return s ? s : "<null>";
00371 }
00372 
00373 ///////////////////////////////////////////////////////////////////////////////
00374 
00375 } // namespace ztd
00376 } // namespace internal
00377 } // namespace zorba
00378 #endif /* ZORBA_INTERNAL_ZTD_H */
00379 /* vim:set et sw=2 ts=2: */
blog comments powered by Disqus