1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
7 
8 #include <stddef.h>
9 
10 #include <string>
11 
12 #include "base/logging.h"
13 #include "mojo/public/cpp/bindings/lib/array_internal.h"
14 #include "mojo/public/cpp/bindings/type_converter.h"
15 
16 namespace mojo {
17 
18 // A UTF-8 encoded character string that can be null. Provides functions that
19 // are similar to std::string, along with access to the underlying std::string
20 // object.
21 class String {
22  public:
23   // Constructs an empty string.
String()24   String() : is_null_(false) {}
String(const std::string & str)25   String(const std::string& str) : value_(str), is_null_(false) {}
String(const char * chars)26   String(const char* chars) : is_null_(!chars) {
27     if (chars)
28       value_ = chars;
29   }
String(const char * chars,size_t num_chars)30   String(const char* chars, size_t num_chars)
31       : value_(chars, num_chars), is_null_(false) {}
String(const mojo::String & str)32   String(const mojo::String& str)
33       : value_(str.value_), is_null_(str.is_null_) {}
34 
35   template <size_t N>
String(const char chars[N])36   String(const char chars[N])
37       : value_(chars, N - 1), is_null_(false) {}
38 
String(std::string && other)39   String(std::string&& other) : value_(std::move(other)), is_null_(false) {}
String(String && other)40   String(String&& other) : is_null_(true) { Swap(&other); }
41 
42   template <typename U>
From(const U & other)43   static String From(const U& other) {
44     return TypeConverter<String, U>::Convert(other);
45   }
46 
47   template <typename U>
To()48   U To() const {
49     return TypeConverter<U, String>::Convert(*this);
50   }
51 
52   String& operator=(const mojo::String& str) {
53     value_ = str.value_;
54     is_null_ = str.is_null_;
55     return *this;
56   }
57   String& operator=(const std::string& str) {
58     value_ = str;
59     is_null_ = false;
60     return *this;
61   }
62   String& operator=(const char* chars) {
63     is_null_ = !chars;
64     if (chars) {
65       value_ = chars;
66     } else {
67       value_.clear();
68     }
69     return *this;
70   }
71 
72   String& operator=(std::string&& other) {
73     value_ = std::move(other);
74     is_null_ = false;
75     return *this;
76   }
77   String& operator=(String&& other) {
78     is_null_ = true;
79     value_.clear();
80     Swap(&other);
81     return *this;
82   }
83 
is_null()84   bool is_null() const { return is_null_; }
85 
size()86   size_t size() const { return value_.size(); }
87 
data()88   const char* data() const { return value_.data(); }
89 
at(size_t offset)90   const char& at(size_t offset) const { return value_.at(offset); }
91   const char& operator[](size_t offset) const { return value_[offset]; }
92 
get()93   const std::string& get() const { return value_; }
94   operator const std::string&() const { return value_; }
95 
96   // Returns a const reference to the |std::string| managed by this class. If
97   // the string is null, this will be an empty std::string.
storage()98   const std::string& storage() const { return value_; }
99 
100   // Passes the underlying storage and resets this string to null.
PassStorage()101   std::string PassStorage() {
102     is_null_ = true;
103     return std::move(value_);
104   }
105 
Swap(String * other)106   void Swap(String* other) {
107     std::swap(is_null_, other->is_null_);
108     value_.swap(other->value_);
109   }
110 
Swap(std::string * other)111   void Swap(std::string* other) {
112     is_null_ = false;
113     value_.swap(*other);
114   }
115 
116  private:
117   typedef std::string String::*Testable;
118 
119  public:
Testable()120   operator Testable() const { return is_null_ ? 0 : &String::value_; }
121 
122  private:
123   std::string value_;
124   bool is_null_;
125 };
126 
127 inline bool operator==(const String& a, const String& b) {
128   return a.is_null() == b.is_null() && a.get() == b.get();
129 }
130 inline bool operator==(const char* a, const String& b) {
131   return !b.is_null() && a == b.get();
132 }
133 inline bool operator==(const String& a, const char* b) {
134   return !a.is_null() && a.get() == b;
135 }
136 inline bool operator!=(const String& a, const String& b) {
137   return !(a == b);
138 }
139 inline bool operator!=(const char* a, const String& b) {
140   return !(a == b);
141 }
142 inline bool operator!=(const String& a, const char* b) {
143   return !(a == b);
144 }
145 
146 inline std::ostream& operator<<(std::ostream& out, const String& s) {
147   return out << s.get();
148 }
149 
150 inline bool operator<(const String& a, const String& b) {
151   if (a.is_null())
152     return !b.is_null();
153   if (b.is_null())
154     return false;
155 
156   return a.get() < b.get();
157 }
158 
159 // TODO(darin): Add similar variants of operator<,<=,>,>=
160 
161 template <>
162 struct TypeConverter<String, std::string> {
163   static String Convert(const std::string& input) { return String(input); }
164 };
165 
166 template <>
167 struct TypeConverter<std::string, String> {
168   static std::string Convert(const String& input) { return input; }
169 };
170 
171 template <size_t N>
172 struct TypeConverter<String, char[N]> {
173   static String Convert(const char input[N]) {
174     DCHECK(input);
175     return String(input, N - 1);
176   }
177 };
178 
179 // Appease MSVC.
180 template <size_t N>
181 struct TypeConverter<String, const char[N]> {
182   static String Convert(const char input[N]) {
183     DCHECK(input);
184     return String(input, N - 1);
185   }
186 };
187 
188 template <>
189 struct TypeConverter<String, const char*> {
190   // |input| may be null, in which case a null String will be returned.
191   static String Convert(const char* input) { return String(input); }
192 };
193 
194 }  // namespace mojo
195 
196 #endif  // MOJO_PUBLIC_CPP_BINDINGS_STRING_H_
197