muduo::StringPiece

15551 ワード

muduo::StringPiece
なぜこのStringPieceクラスがあるのですか?C++にはstringとchar*があり、const string&sで関数パラメータを作ると、2つの文字列を同時に互換性があります.しかし、長いchar*を入力すると、char*はstringを回転し、一時的なstringオブジェクトを作成し、メモリスペースを開き、文字列をコピーし、オーバーヘッドが大きくなります.文字列の値を読み取るだけを目的としている場合は、このStringPieceを使用すると、4+ポインタのメモリオーバーヘッドだけでなく、互換性も保証されます.このクラスの目的は文字列の文字面値を入力することであり、その内部のptr_このメモリは彼の所有ではない.だから何も変えることはできません.要するに、効率的な文字列伝達を実現するために性能を考慮しているが、ここではconst char*としてもstd::stringタイプをパラメータとしてもよく、メモリコピーには関与しない.実際、このクラスはgoogleが提供しているクラスです.
// For passing C-style string argument to a function.
class StringArg // copyable
{
 public:
  StringArg(const char* str)
    : str_(str)
  { }

  StringArg(const string& str)
    : str_(str.c_str())
  { }

#ifndef MUDUO_STD_STRING
  StringArg(const std::string& str)
    : str_(str.c_str())
  { }
#endif

  const char* c_str() const { return str_; }

 private:
  const char* str_;
};

class StringPiece {
 private:
  const char*   ptr_;
  int           length_;

 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(ptr_))) { }
  StringPiece(const unsigned char* str)
    : ptr_(reinterpret_cast<const char*>(str)),
      length_(static_cast<int>(strlen(ptr_))) { }
  StringPiece(const string& str)
    : ptr_(str.data()), length_(static_cast<int>(str.size())) { }
#ifndef MUDUO_STD_STRING
  StringPiece(const std::string& str)
    : ptr_(str.data()), length_(static_cast<int>(str.size())) { }
#endif
  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_; }
  int size() const { return length_; }
  bool empty() const { return length_ == 0; }
  const char* begin() const { return ptr_; }
  const char* end() const { return ptr_ + length_; }

  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]; }

  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(>,  >);
#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;
  }

  string as_string() const {
    return string(data(), size());
  }

  void CopyToString(string* target) const {
    target->assign(ptr_, length_);
  }

#ifndef MUDUO_STD_STRING
  void CopyToStdString(std::string* target) const {
    target->assign(ptr_, length_);
  }
#endif

  // Does "this" start with "x"
  bool starts_with(const StringPiece& x) const {
    return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0));
  }
};

}   // namespace muduo

// ------------------------------------------------------------------
// 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 really fast for some STL implementations
template<> struct __type_traits<: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 muduo::StringPiece& piece);

また、この2つの関数を見てみましょう.void remove_prefix(int n) { ptr_ += n; length_ -= n; } void remove_suffix(int n) { length_ -= n; } StringPieceというクラスは実際には文字列の1つのproxyクラス(つまり設計モードのエージェントモード)にすぎないが、このクラスの構造関数はconstタイプであり、このクラスは抽出にのみ使用され、修正には使用されないはずで、C++17のstring_viewに相当し、C++17のstring_viewの紹介はこの文章を見ることができる.http://purecpp.org/?p=1315ウィンドウを提供し、外部ではこのウィンドウの文字列の内容しか観察できません.ウィンドウのサイズを調整するときに元の文字列を変更する必要はありません.開始ポインタを移動し、長さを調整すればいいだけです.また、このクラス自体はこの文字列を格納していないので、その有効生存期間はソース文字列ポインタの生存期間に依存します.このクラスは検証作業を行わず、検証作業を呼び出し者に渡します.remove_suffixはなぜ長さを変えただけなのか、末尾を「0」と記入しなかった.末尾を「0」と記入するため、文字列を修正し、このクラスの設計の初心に反している.このような初期文字列「abcde」があると仮定します.ウィンドウは[0,length)=5です.では、abという2つの前置文字を削除したい場合はどうしますか.ソース列を操作する必要はありません.ptrポインタを変更して2つのグリッドに進むだけです.しかし、前に進むと長さが短くなります.この場合、length_をn減算する必要があります.この場合、ウィンドウは[2,length)では「de」を外したいのであれば?length_をnだけ減算すればよい.このときのウィンドウは[0,length-2)void remove_prefix(int){ptr_+=n;length_-=n;}void remove_suffix(int n) { length_ -= n; } 独立したlengthがあります長さを保証すると同時に、operator==などの関数の動作もlength_だけを保証します.終止の判断とする.
StringPieceクラスには、<、<=、>=、>の演算子が再ロードされます.これらの演算子は、マクロSTRINGPIECE_を介して実装されます.BINARY_PREDICATEで実現します.
#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(>,  >);
#undef STRINGPIECE_BINARY_PREDICATE

注意してSTRINGPIECE_BINARY_PREDICATEには2つのパラメータがあり、2つ目は補助比較演算子ですが、なぜこの補助比較演算子が必要なのでしょうか.小号を栗とし、マクロ展開後のコードは以下の通りです.
bool operator < (const StringPiece& x) const {                           \
    int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \
    return ((r < 0) || ((r == 0) && (length_ < x.length_)));          \
  }

例えば、「abcd」<「abcdefg」では、memcpがそれらの最初の4バイトを比較し、得られたrの値は0であり、明らかに「adbcd」は「abcdefg」より小さいが、returnの後の演算によって返される結果はtrueである.例えば「abcdx」<「abcdefg」、memcpはそれらの最初の5バイトを比較し、rの値は0より大きく、明らかに((r<0)|((r==0)&&&(length_参考資料:http://blog.csdn.net/huntinux/article/details/51969326 https://www.zhihu.com/question/34499426/answer/58891014