// Copyright 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MINI_CHROMIUM_BASE_STRINGS_STRING_PIECE_H_
#define MINI_CHROMIUM_BASE_STRINGS_STRING_PIECE_H_

#include <algorithm>
#include <iterator>
#include <ostream>
#include <string>

namespace base {

template<typename StringType>
class BasicStringPiece {
 public:
  typedef typename StringType::traits_type traits_type;
  typedef typename StringType::value_type value_type;
  typedef typename StringType::size_type size_type;
  typedef typename StringType::difference_type difference_type;
  typedef const value_type& reference;
  typedef const value_type& const_reference;
  typedef const value_type* pointer;
  typedef const value_type* const_pointer;
  typedef const value_type* const_iterator;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

  static const size_type npos;

  BasicStringPiece()
      : pointer_(NULL),
        length_(0) {
  }

  BasicStringPiece(const value_type* string)
      : pointer_(string),
        length_((string == NULL) ? 0 : traits_type::length(string)) {
  }

  BasicStringPiece(const StringType& string)
      : pointer_(string.data()),
        length_(string.size()) {
  }

  BasicStringPiece(const value_type* offset, size_type length)
      : pointer_(offset),
        length_(length) {
  }

  BasicStringPiece(const typename StringType::const_iterator& begin,
                   const typename StringType::const_iterator& end)
      : pointer_((end > begin) ? &(*begin) : NULL),
        length_((end > begin) ? static_cast<size_type>(end - begin) : 0) {
  }

  value_type operator[](size_type index) const { return pointer_[index]; }

  const value_type* data() const { return pointer_; }

  const_iterator begin() const { return pointer_; }
  const_iterator end() const { return pointer_ + length_; }
  const_reverse_iterator rbegin() const {
    return const_reverse_iterator(pointer_ + length_);
  }
  const_reverse_iterator rend() const {
    return const_reverse_iterator(pointer_);
  }

  bool empty() const { return length_ == 0; }
  size_type size() const { return length_; }
  size_type length() const { return length_; }
  size_type max_size() const { return length_; }
  size_type capacity() const { return length_; }

  static int wordmemcmp(const value_type* p,
                        const value_type* p2,
                        size_type N) {
    return StringType::traits_type::compare(p, p2, N);
  }

  void clear() {
    pointer_ = NULL;
    length_ = 0;
  }

  int compare(const BasicStringPiece<StringType>& that) const {
    int result = traits_type::compare(pointer_,
                                      that.pointer_,
                                      std::min(length_, that.length_));
    if (result == 0) {
      if (length_ < that.length_) {
        result = -1;
      } else if (length_ > that.length_) {
        result = 1;
      }
    }
    return result;
  }

  BasicStringPiece<StringType> substr(size_type position = 0,
                                      size_type count = npos) const {
    position = std::min(position, size());
    count = std::min(count, size() - position);
    return BasicStringPiece<StringType>(data() + position, count);
  }

  size_type copy(value_type* dest,
                 size_type count,
                 size_type position = 0) const {
    size_type ret = std::min(size() - position, count);
    traits_type::copy(dest, data() + position, ret);
    return ret;
  }

  size_type find(const BasicStringPiece<StringType>& str, size_type pos) const {
    if (pos >= size()) {
      return npos;
    }
    const_iterator result = std::search(begin() + pos,
                                        end(),
                                        str.begin(),
                                        str.end());
    size_type xpos = static_cast<size_type>(result - begin());
    return xpos + str.size() <= size() ? xpos : npos;
  }

  size_type find(value_type c, size_type pos) const {
    if (pos >= size()) {
      return npos;
    }
    const_iterator result = std::find(begin() + pos, end(), c);
    return result != end() ? static_cast<size_type>(result - begin()) : npos;
  }

  void set(const value_type* string) {
    pointer_ = string;
    length_ = string ? traits_type::length(string) : 0;
  }

  StringType as_string() const {
    return empty() ? StringType() : StringType(data(), size());
  }

 private:
  const value_type* pointer_;
  size_type length_;
};

template <typename StringType>
const typename BasicStringPiece<StringType>::size_type
    BasicStringPiece<StringType>::npos = StringType::npos;

template<typename StringType>
std::ostream& operator<<(std::ostream& ostream,
                         const BasicStringPiece<StringType>& string_piece) {
  ostream.write(string_piece.data(), string_piece.size());
  return ostream;
}

typedef BasicStringPiece<std::string> StringPiece;
typedef BasicStringPiece<std::u16string> StringPiece16;
typedef BasicStringPiece<std::wstring> WStringPiece;

inline bool operator==(const StringPiece& x, const StringPiece& y) {
  if (x.size() != y.size())
    return false;

  return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
}

inline bool operator==(const StringPiece16& x, const StringPiece16& y) {
  if (x.size() != y.size())
    return false;

  return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0;
}

// This is a custom hash function. We don't use the ones already defined for
// string and std::u16string directly because it would require the string
// constructors to be called, which we don't want.
#define HASH_STRING_PIECE(StringPieceType, string_piece)         \
  std::size_t result = 0;                                        \
  for (StringPieceType::const_iterator i = string_piece.begin(); \
       i != string_piece.end(); ++i)                             \
    result = (result * 131) + *i;                                \
  return result;

struct StringPieceHash {
  std::size_t operator()(const StringPiece& sp) const {
    HASH_STRING_PIECE(StringPiece, sp);
  }
};
struct StringPiece16Hash {
  std::size_t operator()(const StringPiece16& sp16) const {
    HASH_STRING_PIECE(StringPiece16, sp16);
  }
};

}  // namespace base;

#endif  // MINI_CHROMIUM_BASE_STRINGS_STRING_PIECE_H_
