1 // Copyright 2013 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_ARRAY_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ 7 8 #include <stddef.h> 9 #include <string.h> 10 #include <algorithm> 11 #include <set> 12 #include <string> 13 #include <utility> 14 #include <vector> 15 16 #include "base/macros.h" 17 #include "mojo/public/cpp/bindings/lib/array_internal.h" 18 #include "mojo/public/cpp/bindings/lib/bindings_internal.h" 19 #include "mojo/public/cpp/bindings/lib/clone_equals_util.h" 20 #include "mojo/public/cpp/bindings/lib/template_util.h" 21 #include "mojo/public/cpp/bindings/type_converter.h" 22 23 namespace mojo { 24 25 // Represents a moveable array with contents of type |T|. The array can be null, 26 // meaning that no value has been assigned to it. Null is distinct from empty. 27 template <typename T> 28 class Array { 29 public: 30 using ConstRefType = typename std::vector<T>::const_reference; 31 using RefType = typename std::vector<T>::reference; 32 33 using Element = T; 34 35 using iterator = typename std::vector<T>::iterator; 36 using const_iterator = typename std::vector<T>::const_iterator; 37 38 // Constructs an empty array. Array()39 Array() : is_null_(false) {} 40 // Constructs a null array. Array(std::nullptr_t null_pointer)41 Array(std::nullptr_t null_pointer) : is_null_(true) {} 42 43 // Constructs a new non-null array of the specified size. The elements will 44 // be value-initialized (meaning that they will be initialized by their 45 // default constructor, if any, or else zero-initialized). Array(size_t size)46 explicit Array(size_t size) : vec_(size), is_null_(false) {} ~Array()47 ~Array() {} 48 49 // Copies the contents of |other| into this array. Array(const std::vector<T> & other)50 Array(const std::vector<T>& other) : vec_(other), is_null_(false) {} 51 52 // Moves the contents of |other| into this array. Array(std::vector<T> && other)53 Array(std::vector<T>&& other) : vec_(std::move(other)), is_null_(false) {} Array(Array && other)54 Array(Array&& other) : is_null_(true) { Take(&other); } 55 56 Array& operator=(std::vector<T>&& other) { 57 vec_ = std::move(other); 58 is_null_ = false; 59 return *this; 60 } 61 Array& operator=(Array&& other) { 62 Take(&other); 63 return *this; 64 } 65 66 Array& operator=(std::nullptr_t null_pointer) { 67 is_null_ = true; 68 vec_.clear(); 69 return *this; 70 } 71 72 // Creates a non-null array of the specified size. The elements will be 73 // value-initialized (meaning that they will be initialized by their default 74 // constructor, if any, or else zero-initialized). New(size_t size)75 static Array New(size_t size) { return Array(size); } 76 77 // Creates a new array with a copy of the contents of |other|. 78 template <typename U> From(const U & other)79 static Array From(const U& other) { 80 return TypeConverter<Array, U>::Convert(other); 81 } 82 83 // Copies the contents of this array to a new object of type |U|. 84 template <typename U> To()85 U To() const { 86 return TypeConverter<U, Array>::Convert(*this); 87 } 88 89 // Indicates whether the array is null (which is distinct from empty). is_null()90 bool is_null() const { return is_null_; } 91 92 // Indicates whether the array is empty (which is distinct from null). empty()93 bool empty() const { return vec_.empty() && !is_null_; } 94 95 // Returns a reference to the first element of the array. Calling this on a 96 // null or empty array causes undefined behavior. front()97 ConstRefType front() const { return vec_.front(); } front()98 RefType front() { return vec_.front(); } 99 begin()100 iterator begin() { return vec_.begin(); } begin()101 const_iterator begin() const { return vec_.begin(); } end()102 iterator end() { return vec_.end(); } end()103 const_iterator end() const { return vec_.end(); } 104 105 // Returns the size of the array, which will be zero if the array is null. size()106 size_t size() const { return vec_.size(); } 107 108 // Returns a reference to the element at zero-based |offset|. Calling this on 109 // an array with size less than |offset|+1 causes undefined behavior. at(size_t offset)110 ConstRefType at(size_t offset) const { return vec_.at(offset); } 111 ConstRefType operator[](size_t offset) const { return at(offset); } at(size_t offset)112 RefType at(size_t offset) { return vec_.at(offset); } 113 RefType operator[](size_t offset) { return at(offset); } 114 115 // Pushes |value| onto the back of the array. If this array was null, it will 116 // become non-null with a size of 1. push_back(const T & value)117 void push_back(const T& value) { 118 is_null_ = false; 119 vec_.push_back(value); 120 } push_back(T && value)121 void push_back(T&& value) { 122 is_null_ = false; 123 vec_.push_back(std::move(value)); 124 } 125 126 // Resizes the array to |size| and makes it non-null. Otherwise, works just 127 // like the resize method of |std::vector|. resize(size_t size)128 void resize(size_t size) { 129 is_null_ = false; 130 vec_.resize(size); 131 } 132 133 // Sets the array to empty (even if previously it was null.) SetToEmpty()134 void SetToEmpty() { resize(0); } 135 136 // Returns a const reference to the |std::vector| managed by this class. If 137 // the array is null, this will be an empty vector. storage()138 const std::vector<T>& storage() const { return vec_; } 139 140 // Passes the underlying storage and resets this array to null. PassStorage()141 std::vector<T> PassStorage() { 142 is_null_ = true; 143 return std::move(vec_); 144 } 145 146 operator const std::vector<T>&() const { return vec_; } 147 Swap(Array * other)148 void Swap(Array* other) { 149 std::swap(is_null_, other->is_null_); 150 vec_.swap(other->vec_); 151 } 152 153 // Swaps the contents of this array with the specified vector, making this 154 // array non-null. Since the vector cannot represent null, it will just be 155 // made empty if this array is null. Swap(std::vector<T> * other)156 void Swap(std::vector<T>* other) { 157 is_null_ = false; 158 vec_.swap(*other); 159 } 160 161 // Returns a copy of the array where each value of the new array has been 162 // "cloned" from the corresponding value of this array. If the element type 163 // defines a Clone() method, it will be used; otherwise copy 164 // constructor/assignment will be used. 165 // 166 // Please note that calling this method will fail compilation if the element 167 // type cannot be cloned (which usually means that it is a Mojo handle type or 168 // a type containing Mojo handles). Clone()169 Array Clone() const { 170 Array result; 171 result.is_null_ = is_null_; 172 result.vec_ = internal::Clone(vec_); 173 return result; 174 } 175 176 // Indicates whether the contents of this array are equal to |other|. A null 177 // array is only equal to another null array. If the element type defines an 178 // Equals() method, it will be used; otherwise == operator will be used. Equals(const Array & other)179 bool Equals(const Array& other) const { 180 if (is_null() != other.is_null()) 181 return false; 182 return internal::Equals(vec_, other.vec_); 183 } 184 185 private: 186 typedef std::vector<T> Array::*Testable; 187 188 public: Testable()189 operator Testable() const { return is_null_ ? 0 : &Array::vec_; } 190 191 private: 192 // Forbid the == and != operators explicitly, otherwise Array will be 193 // converted to Testable to do == or != comparison. 194 template <typename U> 195 bool operator==(const Array<U>& other) const = delete; 196 template <typename U> 197 bool operator!=(const Array<U>& other) const = delete; 198 Take(Array * other)199 void Take(Array* other) { 200 operator=(nullptr); 201 Swap(other); 202 } 203 204 std::vector<T> vec_; 205 bool is_null_; 206 207 DISALLOW_COPY_AND_ASSIGN(Array); 208 }; 209 210 // A |TypeConverter| that will create an |Array<T>| containing a copy of the 211 // contents of an |std::vector<E>|, using |TypeConverter<T, E>| to copy each 212 // element. The returned array will always be non-null. 213 template <typename T, typename E> 214 struct TypeConverter<Array<T>, std::vector<E>> { 215 static Array<T> Convert(const std::vector<E>& input) { 216 Array<T> result(input.size()); 217 for (size_t i = 0; i < input.size(); ++i) 218 result[i] = TypeConverter<T, E>::Convert(input[i]); 219 return std::move(result); 220 } 221 }; 222 223 // A |TypeConverter| that will create an |std::vector<E>| containing a copy of 224 // the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each 225 // element. If the input array is null, the output vector will be empty. 226 template <typename E, typename T> 227 struct TypeConverter<std::vector<E>, Array<T>> { 228 static std::vector<E> Convert(const Array<T>& input) { 229 std::vector<E> result; 230 if (!input.is_null()) { 231 result.resize(input.size()); 232 for (size_t i = 0; i < input.size(); ++i) 233 result[i] = TypeConverter<E, T>::Convert(input[i]); 234 } 235 return result; 236 } 237 }; 238 239 // A |TypeConverter| that will create an |Array<T>| containing a copy of the 240 // contents of an |std::set<E>|, using |TypeConverter<T, E>| to copy each 241 // element. The returned array will always be non-null. 242 template <typename T, typename E> 243 struct TypeConverter<Array<T>, std::set<E>> { 244 static Array<T> Convert(const std::set<E>& input) { 245 Array<T> result; 246 for (auto i : input) 247 result.push_back(TypeConverter<T, E>::Convert(i)); 248 return std::move(result); 249 } 250 }; 251 252 // A |TypeConverter| that will create an |std::set<E>| containing a copy of 253 // the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each 254 // element. If the input array is null, the output set will be empty. 255 template <typename E, typename T> 256 struct TypeConverter<std::set<E>, Array<T>> { 257 static std::set<E> Convert(const Array<T>& input) { 258 std::set<E> result; 259 if (!input.is_null()) { 260 for (size_t i = 0; i < input.size(); ++i) 261 result.insert(TypeConverter<E, T>::Convert(input[i])); 262 } 263 return result; 264 } 265 }; 266 267 // Less than operator to allow Arrays as keys in std maps and sets. 268 template <typename T> 269 inline bool operator<(const Array<T>& a, const Array<T>& b) { 270 if (a.is_null()) 271 return !b.is_null(); 272 if (b.is_null()) 273 return false; 274 return a.storage() < b.storage(); 275 } 276 277 } // namespace mojo 278 279 #endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ 280