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