text: // Copyright 2014 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 MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
  #define MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
  
  #include <string>
  
  #include "mojo/public/cpp/bindings/lib/array_internal.h"
  #include "mojo/public/cpp/bindings/type_converter.h"
  #include "mojo/public/cpp/environment/logging.h"
  
  namespace mojo {
  
  class String {
   public:
    typedef internal::String_Data Data_;
  
    String() : is_null_(true) {}
    String(const std::string& str) : value_(str), is_null_(false) {}
    String(const char* chars) : is_null_(!chars) {
      if (chars)
        value_ = chars;
    }
    String(const char* chars, size_t num_chars)
        : value_(chars, num_chars),
          is_null_(false) {
    }
    template <size_t N>
    String(const char chars[N]) : value_(chars, N-1), is_null_(false) {}
  
    template <typename U>
    static String From(const U& other) {
      return TypeConverter<String, U>::Convert(other);
    }
  
    template <typename U>
    U To() const {
      return TypeConverter<U, String>::Convert(*this);
    }
  
    String& operator=(const std::string& str) {
      value_ = str;
      is_null_ = false;
      return *this;
    }
    String& operator=(const char* chars) {
      is_null_ = !chars;
      if (chars) {
        value_ = chars;
      } else {
        value_.clear();
      }
      return *this;
    }
  
    void reset() {
      value_.clear();
      is_null_ = true;
    }
  
    bool is_null() const { return is_null_; }
  
    size_t size() const { return value_.size(); }
  
    const char* data() const { return value_.data(); }
  
    const char& at(size_t offset) const { return value_.at(offset); }
    const char& operator[](size_t offset) const { return value_[offset]; }
  
    const std::string& get() const { return value_; }
    operator const std::string&() const { return value_; }
  
    void Swap(String* other) {
      std::swap(is_null_, other->is_null_);
      value_.swap(other->value_);
    }
  
    void Swap(std::string* other) {
      is_null_ = false;
      value_.swap(*other);
    }
  
   private:
    typedef std::string String::*Testable;
  
   public:
    operator Testable() const { return is_null_ ? 0 : &String::value_; }
  
   private:
    std::string value_;
    bool is_null_;
  };
  
  inline bool operator==(const String& a, const String& b) {
    return a.is_null() == b.is_null() && a.get() == b.get();
  }
  inline bool operator==(const char* a, const String& b) {
    return !b.is_null() && a == b.get();
  }
  inline bool operator==(const String& a, const char* b) {
    return !a.is_null() && a.get() == b;
  }
  inline bool operator!=(const String& a, const String& b) { return !(a == b); }
  inline bool operator!=(const char* a, const String& b) { return !(a == b); }
  inline bool operator!=(const String& a, const char* b) { return !(a == b); }
  
  inline std::ostream& operator<<(std::ostream& out, const String& s) {
    return out << s.get();
  }
  
  // TODO(darin): Add similar variants of operator<,<=,>,>=
  
  template <>
  struct TypeConverter<String, std::string> {
    static String Convert(const std::string& input) { return String(input); }
  };
  
  template <>
  struct TypeConverter<std::string, String> {
    static std::string Convert(const String& input) { return input; }
  };
  
  template <size_t N>
  struct TypeConverter<String, char[N]> {
    static String Convert(const char input[N]) {
      MOJO_DCHECK(input);
      return String(input, N-1);
    }
  };
  
  // Appease MSVC.
  template <size_t N>
  struct TypeConverter<String, const char[N]> {
    static String Convert(const char input[N]) {
      MOJO_DCHECK(input);
      return String(input, N-1);
    }
  };
  
  template <>
  struct TypeConverter<String, const char*> {
    // |input| may be null, in which case a null String will be returned.
    static String Convert(const char* input) { return String(input); }
  };
  
  }  // namespace mojo
  
  #endif  // MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
  