text: #if !defined(CETTY_UTIL_STRINGPIECE_H)
  #define CETTY_UTIL_STRINGPIECE_H
  
  // Taken from PCRE pcre_stringpiece.h
  // Copyright (c) 2005, Google Inc.
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are
  // met:
  //
  //     * Redistributions of source code must retain the above copyright
  // notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above
  // copyright notice, this list of conditions and the following disclaimer
  // in the documentation and/or other materials provided with the
  // distribution.
  //     * Neither the name of Google Inc. nor the names of its
  // contributors may be used to endorse or promote products derived from
  // this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // Author: Sanjay Ghemawat
  //
  // A string like object that points into another piece of memory.
  // Useful for providing an interface that allows clients to easily
  // pass in either a "const char*" or a "string".
  //
  // Arghh!  I wish C++ literals were automatically of type "string".
  
  #include <string.h>
  #include <string>
  #include <iosfwd>    // for ostream forward-declaration
  #include <boost/assert.hpp>
  
  namespace cetty {
  namespace util {
  
  class StringPiece {
  public:
      // We provide non-explicit singleton constructors so users can pass
      // in a "const char*" or a "string" wherever a "StringPiece" is
      // expected.
      StringPiece()
          : ptr_(NULL), length_(0) { }
      StringPiece(const char* str)
          : ptr_(str), length_(static_cast<int>(strlen(str))) { }
      StringPiece(const unsigned char* str)
          : ptr_(reinterpret_cast<const char*>(str)),
            length_(static_cast<int>(strlen(ptr_))) { }
      StringPiece(const std::string& str)
          : ptr_(str.data()), length_(static_cast<int>(str.size())) { }
      StringPiece(const char* offset, int len)
          : ptr_(offset), length_(len) { }
  
      // data() may return a pointer to a buffer with embedded NULs, and the
      // returned buffer may or may not be null terminated.  Therefore it is
      // typically a mistake to pass data() to a routine that expects a NUL
      // terminated string.  Use "as_string().c_str()" if you really need to do
      // this.  Or better yet, change your routine so it does not rely on NUL
      // termination.
      const char* data() const { return ptr_; }
      const char* c_str() const { return ptr_; }
      int size() const { return length_; }
      int length() const { return length_; }
      bool empty() const { return length_ == 0; }
  
      void clear() { ptr_ = NULL; length_ = 0; }
      void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; }
      void set(const char* str) {
          ptr_ = str;
          length_ = static_cast<int>(strlen(str));
      }
      void set(const void* buffer, int len) {
          ptr_ = reinterpret_cast<const char*>(buffer);
          length_ = len;
      }
  
      char operator[](int i) const { return ptr_[i]; }
      char at(int i) const {
          BOOST_ASSERT(i < length_);
          return ptr_[i];
      }
  
      void remove_prefix(int n) {
          ptr_ += n;
          length_ -= n;
      }
  
      void remove_suffix(int n) {
          length_ -= n;
      }
  
      bool operator==(const StringPiece& x) const {
          return ((length_ == x.length_) &&
                  (memcmp(ptr_, x.ptr_, length_) == 0));
      }
      bool operator!=(const StringPiece& x) const {
          return !(*this == x);
      }
  
  #define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp)                             \
      bool operator cmp (const StringPiece& x) const {                           \
          int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
          return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_)));          \
      }
      STRINGPIECE_BINARY_PREDICATE(<,  <);
      STRINGPIECE_BINARY_PREDICATE(<=, <);
      STRINGPIECE_BINARY_PREDICATE(>=, >);
      STRINGPIECE_BINARY_PREDICATE(>,  >);
  #undef STRINGPIECE_BINARY_PREDICATE
  
      int compare(const StringPiece& x) const {
          int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_);
  
          if (r == 0) {
              if (length_ < x.length_) { r = -1; }
              else if (length_ > x.length_) { r = +1; }
          }
  
          return r;
      }
  
      std::string as_string() const {
          return std::string(data(), size());
      }
  
      std::string to_string() const {
          return std::string(data(), size());
      }
  
      void copy_to(std::string* target) const {
          target->assign(ptr_, length_);
      }
  
      void append_to(std::string* target) const {
          target->append(ptr_, length_);
      }
  
      // Does "this" start with "x"
      bool starts_with(const StringPiece& x) const {
          return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0));
      }
  
      StringPiece substr(int pos, int cnt = -1) const {
          if (pos < 0 || cnt == 0) {
              return StringPiece();
          }
  
          if (cnt < 0) {
              cnt = length_ - pos;
          }
  
          return StringPiece(ptr_ + pos, cnt);
      }
  
      StringPiece trim() const {
          const char* newData = ptr_;
          int   newSize = length_;
  
          while ((*newData == ' ' || *newData == '\t') && newSize > 0) {
              newData++;
              --newData;
          }
  
          while ((newData[newSize - 1] == ' ' || newData[newSize - 1] == '\t')
                  && newSize > 0) {
              --newSize;
          }
  
          return StringPiece(newData, newSize);
      }
  
      bool equals(const StringPiece& str) const {
          if (ptr_ == NULL || str.ptr_ == NULL || length_ != str.length_) {
              return false;
          }
  
          for (int i = 0, j = length_; i < j; ++i) {
              if (ptr_[i] != str[i]) {
                  return false;
              }
          }
  
          return true;
      }
  
      bool iequals(const StringPiece& str) const {
          if (ptr_ == NULL || str.ptr_ == NULL || length_ != str.length_) {
              return false;
          }
  
          for (int i = 0, j = length_; i < j; ++i) {
              if (ptr_[i] != str[i]
                      && ptr_[i] + 0x20 != str[i]
                      && ptr_[i] != str[i] + 0x20) {
                  return false;
              }
          }
  
          return true;
      }
  
  private:
      const char*   ptr_;
      int           length_;
  };
  
  } // namespace util
  } // namespace cetty
  
  // ------------------------------------------------------------------
  // Functions used to create STL containers that use StringPiece
  //  Remember that a StringPiece's lifetime had better be less than
  //  that of the underlying string or char*.  If it is not, then you
  //  cannot safely store a StringPiece into an STL container
  // ------------------------------------------------------------------
  
  #ifdef HAVE_TYPE_TRAITS
  // This makes vector<StringPiece> really fast for some STL implementations
  template<> struct __type_traits<cetty::util::StringPiece> {
      typedef __true_type    has_trivial_default_constructor;
      typedef __true_type    has_trivial_copy_constructor;
      typedef __true_type    has_trivial_assignment_operator;
      typedef __true_type    has_trivial_destructor;
      typedef __true_type    is_POD_type;
  };
  #endif
  
  // allow StringPiece to be logged
  std::ostream& operator<<(std::ostream& o, const cetty::util::StringPiece& piece);
  
  
  #endif //#if !defined(CETTY_UTIL_STRINGPIECE_H)
  
  // Local Variables:
  // mode: c++
  // End:
  