Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / base / String.h
index e69a106..285c7dd 100644 (file)
 #include <string>
 #include <sstream>
 #include <boost/format.hpp>
+#include <boost/utility/string_ref.hpp>
 
 #include "zypp/base/Easy.h"
 #include "zypp/base/PtrTypes.h"
 #include "zypp/base/Function.h"
 
-
 ///////////////////////////////////////////////////////////////////
-namespace boost
-{
-  /** A formater with (N)o (A)rgument (C)heck.
-   * It won't complain about missing or excess arguments. Sometimes
-   * usefull when dealing with translations or classes providing a
-   * default formater.
-   */
-  inline format formatNAC( const std::string & string_r ) {
-    using namespace boost::io;
-    format fmter( string_r );
-    fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit ) );
-    return fmter;
-  }
-} // namespace boost
-namespace zypp { using boost::formatNAC; }
+namespace boost { namespace logic { class tribool; } }
+namespace zypp { typedef boost::logic::tribool TriBool; }
 ///////////////////////////////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 {
-  /** Request a human readable (translated) string representation of _Tp [_Tp.asUserString()]
+  /** Request a human readable (translated) string representation of Tp [Tp.asUserString()]
    * Classes may implement a default as member function.
    */
-  template <class _Tp>
-  std::string asUserString( const _Tp & val_r )
+  template <class Tp>
+  std::string asUserString( const Tp & val_r )
   { return val_r.asUserString(); }
 
 }// namespace zypp
@@ -60,16 +47,6 @@ namespace zypp
 namespace zypp
 { /////////////////////////////////////////////////////////////////
 
-  struct MessageString : public std::string
-  {
-    MessageString() {}
-    MessageString( const char * str_r )                : std::string( str_r ? str_r : "" ) {}
-    MessageString( const std::string & str_r )         : std::string( str_r ) {}
-    // boost::format, std::ostringstream, str::Str ...
-    template<class _Str>
-    MessageString( const _Str & str_r )        : std::string( str_r.str() ) {}
-  };
-
   /** Convenience \c char* constructible from \c std::string and \c char*,
    *  it maps \c (char*)0 to an empty string.
    *
@@ -107,6 +84,8 @@ namespace zypp
    * bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
    * { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
    * \endcode
+   *
+   * \todo Check whether to replace by boost::string_ref
    */
   class C_Str
   {
@@ -118,6 +97,7 @@ namespace zypp
       C_Str( char * c_str_r )            : _val( c_str_r ),       _sze( std::string::npos ) {}
       C_Str( const char * c_str_r )      : _val( c_str_r ),       _sze( std::string::npos ) {}
       C_Str( const std::string & str_r ) : _val( str_r.c_str() ), _sze( str_r.size() ) {}
+      C_Str( const boost::string_ref & str_r ) : _val( str_r.data() ), _sze( str_r.size() ) {}
 
     public:
       bool      isNull()       const { return !_val; }
@@ -153,11 +133,11 @@ namespace zypp
     /**
      * Global asString() that works with std::string too
      */
-    inline std::string asString( const std::string &t )
+    inline const std::string & asString( const std::string & t )
     { return t; }
 
 #ifndef SWIG // Swig treats it as syntax error
-    inline std::string asString( std::string && t )
+    inline std::string && asString( std::string && t )
     { return std::move(t); }
 #endif
 
@@ -167,16 +147,16 @@ namespace zypp
     inline std::string asString( char * t )
     { return t; }
 
-    template<class _T>
-        inline std::string asString( const _T &t )
+    template<class Tp>
+        inline std::string asString( const Tp &t )
         { return t.asString(); }
 
-    template<class _T>
-        inline std::string asString( const intrusive_ptr<_T> &p )
+    template<class Tp>
+        inline std::string asString( const intrusive_ptr<Tp> &p )
         { return p->asString(); }
 
-    template<class _T>
-        inline std::string asString( const weak_ptr<_T> &p )
+    template<class Tp>
+        inline std::string asString( const weak_ptr<Tp> &p )
         { return p->asString(); }
 
     template<>
@@ -216,41 +196,99 @@ namespace zypp
     };
 
     ///////////////////////////////////////////////////////////////////
-    /** Convenient building of std::string via std::ostream::operator<<.
-     * Basically this is an \ref ostringstream which is autocenvertible
-     * into a \ref string.
-     * \code
-     *  void fnc( const std::string & txt_r );
-     *  fnc( str::Str() << "Hello " << 13 );
-     *
-     *  std::string txt( str::Str() << 45 );
-     * \endcode
-    */
+    /// \class Str
+    /// \brief Convenient building of std::string via \ref std::ostringstream
+    /// Basically a \ref std::ostringstream autoconvertible to \ref std::string
+    /// for building string arguments.
+    /// \code
+    ///   void fnc( const std::string & txt_r );
+    ///   fnc( str::Str() << "Hello " << 13 );
+    ///
+    ///   std::string txt( str::Str() << 45 );
+    /// \endcode
+    ///////////////////////////////////////////////////////////////////
     struct Str
     {
-      template<class _Tp>
-      Str & operator<<( const _Tp & val )
-      { _str << val; return *this; }
+      template<class Tp>
+      Str & operator<<( Tp && val )
+      { _str << std::forward<Tp>(val); return *this; }
 
-      operator std::string() const
-      { return _str.str(); }
+      Str & operator<<( std::ostream& (*iomanip)( std::ostream& ) )
+      { _str << iomanip; return *this; }
 
-      std::string str() const
-      { return _str.str(); }
+      operator std::string() const             { return _str.str(); }
+      std::string asString() const             { return _str.str(); }
+      std::string str() const                  { return _str.str(); }
 
-      std::ostream & stream()
-      { return _str; }
+      const std::ostream & stream() const      { return _str; }
+      std::ostream & stream()                  { return _str; }
 
-      void clear()
-      { _str.str( std::string() ); }
+      void clear()                             { _str.str( std::string() ); }
 
+    private:
       std::ostringstream _str;
     };
 
+    /** \relates Str Stream output */
     inline std::ostream & operator<<( std::ostream & str, const Str & obj )
-    { return str << (std::string)obj; }
+    { return str << obj.str(); }
 
     ///////////////////////////////////////////////////////////////////
+    /// \class Format
+    /// \brief Convenient building of std::string with \ref boost::format.
+    /// Basically a \ref boost::format autoconvertible to \ref std::string
+    /// for building string arguments.
+    /// \code
+    ///   void fnc( const std::string & txt_r );
+    ///   fnc( str::Format("Hello %1%") % 13 );
+    ///
+    ///   std::string txt( str::Format("Hello %1%") % 13 );
+    /// \endcode
+    ///////////////////////////////////////////////////////////////////
+    struct Format
+    {
+      Format() {}
+      Format( const std::string & format_r ) : _fmter( format_r ) {}
+
+      template<class Tp>
+      Format & operator%( Tp && arg )
+      { _fmter % std::forward<Tp>(arg); return *this; }
+
+      operator std::string() const             { return _fmter.str(); }
+      std::string asString() const             { return _fmter.str(); }
+      std::string str() const                  { return _fmter.str(); }
+
+      const boost::format & fmter() const      { return _fmter; }
+      boost::format & fmter()                  { return _fmter; }
+
+    protected:
+      boost::format _fmter;
+    };
+
+    /** \relates Format Stream output */
+    inline std::ostream & operator<<( std::ostream & str, const Format & obj )
+    { return str << obj.fmter(); }
+
+    ///////////////////////////////////////////////////////////////////
+    /// \class FormatNAC
+    /// \brief \ref Format with (N)o (A)rgument (C)heck.
+    /// It won't complain about missing or excess arguments. Sometimes
+    /// usefull when dealing with translations or classes providing a
+    /// default formater.
+    ///////////////////////////////////////////////////////////////////
+    struct FormatNAC : public Format
+    {
+      FormatNAC() { relax(); }
+      FormatNAC( const std::string & format_r ) : Format( format_r ) { relax(); }
+
+    private:
+      void relax()
+      {
+       using namespace boost::io;
+       _fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit ) );
+      }
+    };
+    ///////////////////////////////////////////////////////////////////
     /** \name String representation of number.
      *
      * Optional second argument sets the minimal string width (' ' padded).
@@ -335,6 +373,20 @@ namespace zypp
     inline std::string octstring( unsigned long long n, int w = 0 ) { return form( "%#0*llo",  w, n ); }
     //@}
 
+
+    ///////////////////////////////////////////////////////////////////
+    /** String representation of number as bit-string with leading '0's. */
+    template <typename TInt>
+    std::string binstring( TInt val_r )
+    {
+      constexpr unsigned bits = sizeof(TInt)*8;
+      std::string ret( bits, ' ' );
+      TInt bit = 1;
+      for ( unsigned pos = bits; pos > 0; )
+      { --pos; ret[pos] = ((val_r & bit)?'1':'0'); bit = bit<<1; }
+      return ret;
+    }
+    
     ///////////////////////////////////////////////////////////////////
     /** Parsing numbers from string.
     */
@@ -345,8 +397,8 @@ namespace zypp
      * time_t t = strtonum<time_t>( "42" );
      * \endcode
     */
-    template<typename _It>
-      _It strtonum( const C_Str & str );
+    template<typename TInt>
+      TInt strtonum( const C_Str & str );
 
     template<>
       inline short              strtonum( const C_Str & str ) { return ::strtol  ( str, NULL, 0 ); }
@@ -371,9 +423,9 @@ namespace zypp
      * time_t t; strtonum( "42", t );
      * \endcode
     */
-    template<typename _It>
-      inline _It strtonum( const C_Str & str, _It & i )
-      { return i = strtonum<_It>( str ); }
+    template<typename TInt>
+      inline TInt strtonum( const C_Str & str, TInt & i )
+      { return i = strtonum<TInt>( str ); }
     //@}
 
     ///////////////////////////////////////////////////////////////////
@@ -404,6 +456,9 @@ namespace zypp
       return return_r;
     }
 
+    /** Parse \c str into a bool if it's a legal \c true or \c false string; else \c indterminate. */
+    TriBool strToTriBool( const C_Str & str );
+
     //@}
 
     /**
@@ -460,10 +515,8 @@ namespace zypp
      * \endcode
      *
     */
-    template<class _OutputIterator>
-      unsigned split( const C_Str &   line_r,
-                      _OutputIterator result_r,
-                      const C_Str &   sepchars_r = " \t" )
+    template<class TOutputIterator>
+      unsigned split( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = " \t" )
       {
         const char * beg = line_r;
         const char * cur = beg;
@@ -521,11 +574,8 @@ namespace zypp
      *
      * \endcode
      */
-    template<class _OutputIterator>
-      unsigned splitEscaped( const C_Str &   line_r,
-                      _OutputIterator result_r,
-                      const C_Str &   sepchars_r = " \t",
-                      bool withEmpty = false)
+    template<class TOutputIterator>
+      unsigned splitEscaped( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = " \t", bool withEmpty = false)
       {
         const char * beg = line_r;
         const char * cur = beg;
@@ -654,10 +704,8 @@ namespace zypp
      * \endcode
      *
     */
-    template<class _OutputIterator>
-      unsigned splitFields( const C_Str &   line_r,
-                            _OutputIterator result_r,
-                            const C_Str &   sepchars_r = ":" )
+    template<class TOutputIterator>
+      unsigned splitFields( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = ":" )
       {
         const char * beg = line_r;
         const char * cur = beg;
@@ -695,13 +743,10 @@ namespace zypp
      * \see splitFields()
      * \see splitEscaped()
      */
-    template<class _OutputIterator>
-      unsigned splitFieldsEscaped( const C_Str &   line_r,
-                            _OutputIterator result_r,
-                            const C_Str &   sepchars_r = ":" )
+    template<class TOutputIterator>
+      unsigned splitFieldsEscaped( const C_Str & line_r, TOutputIterator result_r, const C_Str & sepchars_r = ":" )
       {
-        return
-          splitEscaped( line_r, result_r, sepchars_r, true /* withEmpty */ );
+        return splitEscaped( line_r, result_r, sepchars_r, true /* withEmpty */ );
       }
 
     //@}
@@ -710,12 +755,11 @@ namespace zypp
     /** \name Join. */
     //@{
     /** Join strings using separator \a sep_r (defaults to BLANK). */
-    template <class _Iterator>
-      std::string join( _Iterator begin, _Iterator end,
-                        const C_Str & sep_r = " " )
+    template <class TIterator>
+      std::string join( TIterator begin, TIterator end, const C_Str & sep_r = " " )
       {
         std::string res;
-        for ( _Iterator iter = begin; iter != end; ++ iter )
+        for ( TIterator iter = begin; iter != end; ++ iter )
           {
             if ( iter != begin )
               res += sep_r;
@@ -725,21 +769,19 @@ namespace zypp
       }
 
     /** Join strings using separator \a sep_r (defaults to BLANK). */
-    template <class _Container>
-      std::string join( const _Container & cont_r,
-                        const C_Str & sep_r = " " )
+    template <class TContainer>
+      std::string join( const TContainer & cont_r, const C_Str & sep_r = " " )
       { return join( cont_r.begin(), cont_r.end(), sep_r ); }
 
     /** Join strings using separator \a sep_r, quoting or escaping the values.
      * Separator defaults to BLANK. Use \ref splitEscaped to restore the
      * values.
      */
-    template <class _Iterator>
-      std::string joinEscaped( _Iterator begin, _Iterator end,
-                               const char sep_r = ' ' )
+    template <class TIterator>
+      std::string joinEscaped( TIterator begin, TIterator end, const char sep_r = ' ' )
       {
         std::vector<char> buf;
-        for ( _Iterator iter = begin; iter != end; ++ iter )
+        for ( TIterator iter = begin; iter != end; ++ iter )
         {
           if ( iter != begin )
             buf.push_back( sep_r );
@@ -895,6 +937,7 @@ namespace zypp
      * \todo improve
     */
     std::string toLower( const std::string & s );
+    std::string toLower( std::string && s );
     /** \overload */
     inline std::string toLower( const char * s )
     { return( s ? toLower( std::string(s) ) : std::string() ); }
@@ -903,6 +946,7 @@ namespace zypp
      * \todo improve
     */
     std::string toUpper( const std::string & s );
+    std::string toUpper( std::string && s );
     /** \overload */
     inline std::string toUpper( const char * s )
     { return( s ? toUpper( std::string(s) ) : std::string() ); }
@@ -939,12 +983,17 @@ namespace zypp
     };
 
     std::string trim( const std::string & s, const Trim trim_r = TRIM );
+    std::string trim( std::string && s, const Trim trim_r = TRIM );
 
     inline std::string ltrim( const std::string & s )
     { return trim( s, L_TRIM ); }
+    inline std::string ltrim( std::string && s )
+    { return trim( std::move(s), L_TRIM ); }
 
     inline std::string rtrim( const std::string & s )
     { return trim( s, R_TRIM ); }
+    inline std::string rtrim( std::string && s )
+    { return trim( std::move(s), R_TRIM ); }
     //@}
 
     std::string stripFirstWord( std::string & line, const bool ltrim_first = true );
@@ -978,14 +1027,23 @@ namespace zypp
     /** Return whether \a str_r has prefix \a prefix_r. */
     inline bool hasPrefix( const C_Str & str_r, const C_Str & prefix_r )
     { return( ::strncmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
+    /** \overload Case insensitive */
+    inline bool hasPrefixCI( const C_Str & str_r, const C_Str & prefix_r )
+    { return( ::strncasecmp( str_r, prefix_r, prefix_r.size() ) == 0 ); }
 
     /** Strip a \a prefix_r from \a str_r and return the resulting string. */
     inline std::string stripPrefix( const C_Str & str_r, const C_Str & prefix_r )
     { return( hasPrefix( str_r, prefix_r ) ? str_r + prefix_r.size() : str_r.c_str() ); }
+    /** \overload Case insensitive */
+    inline std::string stripPrefixCI( const C_Str & str_r, const C_Str & prefix_r )
+    { return( hasPrefixCI( str_r, prefix_r ) ? str_r + prefix_r.size() : str_r.c_str() ); }
 
     /** Return whether \a str_r has suffix \a suffix_r. */
     inline bool hasSuffix( const C_Str & str_r, const C_Str & suffix_r )
     { return( str_r.size() >= suffix_r.size() && ::strncmp( str_r + str_r.size() - suffix_r.size() , suffix_r, suffix_r.size() ) == 0 ); }
+    /** \overload Case insensitive */
+    inline bool hasSuffixCI( const C_Str & str_r, const C_Str & suffix_r )
+    { return( str_r.size() >= suffix_r.size() && ::strncasecmp( str_r + str_r.size() - suffix_r.size() , suffix_r, suffix_r.size() ) == 0 ); }
 
     /** Strip a \a suffix_r from \a str_r and return the resulting string. */
     inline std::string stripSuffix( const C_Str & str_r, const C_Str & suffix_r )
@@ -994,6 +1052,14 @@ namespace zypp
         return std::string( str_r, str_r.size() - suffix_r.size() );
       return str_r.c_str();
     }
+    /** \overload Case insensitive */
+    inline std::string stripSuffixCI( const C_Str & str_r, const C_Str & suffix_r )
+    {
+      if ( hasSuffixCI( str_r, suffix_r ) )
+        return std::string( str_r, str_r.size() - suffix_r.size() );
+      return str_r.c_str();
+    }
+
     /** Return size of the common prefix of \a lhs and \a rhs. */
     inline std::string::size_type commonPrefix( const C_Str & lhs, const C_Str & rhs )
     {
@@ -1004,13 +1070,31 @@ namespace zypp
       { ++lp, ++rp, ++ret; }
       return ret;
     }
+    /** \overload Case insensitive */
+    inline std::string::size_type commonPrefixCI( const C_Str & lhs, const C_Str & rhs )
+    {
+      const char * lp = lhs.c_str();
+      const char * rp = rhs.c_str();
+      std::string::size_type ret = 0;
+      while ( tolower(*lp) == tolower(*rp) && *lp != '\0' )
+      { ++lp, ++rp, ++ret; }
+      return ret;
+    }
+
 
     /** alias for \ref hasPrefix */
     inline bool startsWith( const C_Str & str_r, const C_Str & prefix_r )
     { return hasPrefix( str_r, prefix_r ); }
+    /** \overload Case insensitive */
+    inline bool startsWithCI( const C_Str & str_r, const C_Str & prefix_r )
+    { return hasPrefixCI( str_r, prefix_r ); }
+
     /** alias for \ref hasSuffix */
     inline bool endsWith( const C_Str & str_r, const C_Str & prefix_r )
     { return hasSuffix( str_r, prefix_r ); }
+    /** \overload Case insensitive */
+    inline bool endsWithCI( const C_Str & str_r, const C_Str & prefix_r )
+    { return hasSuffixCI( str_r, prefix_r ); }
     //@}
   } // namespace str
   ///////////////////////////////////////////////////////////////////