| // Copyright 2013 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_ARRAY_H_ | 
 | #define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ | 
 |  | 
 | #include <stddef.h> | 
 | #include <string.h> | 
 |  | 
 | #include <algorithm> | 
 | #include <cstddef> | 
 | #include <set> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "mojo/public/cpp/bindings/lib/array_internal.h" | 
 | #include "mojo/public/cpp/bindings/lib/bindings_internal.h" | 
 | #include "mojo/public/cpp/bindings/lib/template_util.h" | 
 | #include "mojo/public/cpp/bindings/type_converter.h" | 
 |  | 
 | namespace mojo { | 
 |  | 
 | // Represents a moveable array with contents of type |T|. The array can be null, | 
 | // meaning that no value has been assigned to it. Null is distinct from empty. | 
 | template <typename T> | 
 | class Array { | 
 |  public: | 
 |   using ConstRefType = typename std::vector<T>::const_reference; | 
 |   using RefType = typename std::vector<T>::reference; | 
 |  | 
 |   using Traits = internal::ArrayTraits<T, internal::IsMoveOnlyType<T>::value>; | 
 |   using ForwardType = typename Traits::ForwardType; | 
 |  | 
 |   typedef internal::Array_Data<typename internal::WrapperTraits<T>::DataType> | 
 |       Data_; | 
 |  | 
 |   // Constructs a new array that is null. | 
 |   Array() : is_null_(true) {} | 
 |  | 
 |   // Makes null arrays implicitly constructible from |nullptr|. | 
 |   Array(std::nullptr_t) : is_null_(true) {} | 
 |  | 
 |   ~Array() {} | 
 |  | 
 |   // Moves the contents of |other| into this array. | 
 |   Array(Array&& other) : is_null_(true) { Take(&other); } | 
 |   Array& operator=(Array&& other) { | 
 |     Take(&other); | 
 |     return *this; | 
 |   } | 
 |  | 
 |   // Creates a non-null array of the specified size. The elements will be | 
 |   // value-initialized (meaning that they will be initialized by their default | 
 |   // constructor, if any, or else zero-initialized). | 
 |   static Array New(size_t size) { | 
 |     Array ret; | 
 |     ret.resize(size); | 
 |     return ret; | 
 |   } | 
 |  | 
 |   // Creates a new array with a copy of the contents of |other|. | 
 |   template <typename U> | 
 |   static Array From(const U& other) { | 
 |     return TypeConverter<Array, U>::Convert(other); | 
 |   } | 
 |  | 
 |   // Copies the contents of this array to a new object of type |U|. | 
 |   template <typename U> | 
 |   U To() const { | 
 |     return TypeConverter<U, Array>::Convert(*this); | 
 |   } | 
 |  | 
 |   // Resets the contents of this array back to null. | 
 |   void reset() { | 
 |     vec_.clear(); | 
 |     is_null_ = true; | 
 |   } | 
 |  | 
 |   // Tests as true if non-null, false if null. | 
 |   explicit operator bool() const { return !is_null_; } | 
 |  | 
 |   // Indicates whether the array is null (which is distinct from empty). | 
 |   bool is_null() const { return is_null_; } | 
 |  | 
 |   // Returns a reference to the first element of the array. Calling this on a | 
 |   // null or empty array causes undefined behavior. | 
 |   ConstRefType front() const { return vec_.front(); } | 
 |   RefType front() { return vec_.front(); } | 
 |  | 
 |   // Returns the size of the array, which will be zero if the array is null. | 
 |   size_t size() const { return vec_.size(); } | 
 |  | 
 |   // For non-null arrays of non-bool types, returns a pointer to the first | 
 |   // element, if any. (If the array is empty, the semantics are the same as for | 
 |   // |std::vector<T>::data()|. The behavior is undefined if the array is null.) | 
 |   const T* data() const { return vec_.data(); } | 
 |   T* data() { return vec_.data(); } | 
 |  | 
 |   // Returns a reference to the element at zero-based |offset|. Calling this on | 
 |   // an array with size less than |offset|+1 causes undefined behavior. | 
 |   ConstRefType at(size_t offset) const { return vec_.at(offset); } | 
 |   ConstRefType operator[](size_t offset) const { return at(offset); } | 
 |   RefType at(size_t offset) { return vec_.at(offset); } | 
 |   RefType operator[](size_t offset) { return at(offset); } | 
 |  | 
 |   // Pushes |value| onto the back of the array. If this array was null, it will | 
 |   // become non-null with a size of 1. | 
 |   void push_back(ForwardType value) { | 
 |     is_null_ = false; | 
 |     Traits::PushBack(&vec_, value); | 
 |   } | 
 |  | 
 |   // Resizes the array to |size| and makes it non-null. Otherwise, works just | 
 |   // like the resize method of |std::vector|. | 
 |   void resize(size_t size) { | 
 |     is_null_ = false; | 
 |     vec_.resize(size); | 
 |   } | 
 |  | 
 |   // Returns a const reference to the |std::vector| managed by this class. If | 
 |   // the array is null, this will be an empty vector. | 
 |   const std::vector<T>& storage() const { return vec_; } | 
 |   operator const std::vector<T>&() const { return vec_; } | 
 |  | 
 |   // Swaps the contents of this array with the |other| array, including | 
 |   // nullness. | 
 |   void Swap(Array* other) { | 
 |     std::swap(is_null_, other->is_null_); | 
 |     vec_.swap(other->vec_); | 
 |   } | 
 |  | 
 |   // Swaps the contents of this array with the specified vector, making this | 
 |   // array non-null. Since the vector cannot represent null, it will just be | 
 |   // made empty if this array is null. | 
 |   void Swap(std::vector<T>* other) { | 
 |     is_null_ = false; | 
 |     vec_.swap(*other); | 
 |   } | 
 |  | 
 |   // Returns a copy of the array where each value of the new array has been | 
 |   // "cloned" from the corresponding value of this array. If this array contains | 
 |   // primitive data types, this is equivalent to simply copying the contents. | 
 |   // However, if the array contains objects, then each new element is created by | 
 |   // calling the |Clone| method of the source element, which should make a copy | 
 |   // of the element. | 
 |   // | 
 |   // Please note that calling this method will fail compilation if the element | 
 |   // type cannot be cloned (which usually means that it is a Mojo handle type or | 
 |   // a type contains Mojo handles). | 
 |   Array Clone() const { | 
 |     Array result; | 
 |     result.is_null_ = is_null_; | 
 |     Traits::Clone(vec_, &result.vec_); | 
 |     return result; | 
 |   } | 
 |  | 
 |   // Indicates whether the contents of this array are equal to |other|. A null | 
 |   // array is only equal to another null array. Elements are compared using the | 
 |   // |ValueTraits::Equals| method, which in most cases calls the |Equals| method | 
 |   // of the element. | 
 |   bool Equals(const Array& other) const { | 
 |     if (is_null() != other.is_null()) | 
 |       return false; | 
 |     if (size() != other.size()) | 
 |       return false; | 
 |     for (size_t i = 0; i < size(); ++i) { | 
 |       if (!internal::ValueTraits<T>::Equals(at(i), other.at(i))) | 
 |         return false; | 
 |     } | 
 |     return true; | 
 |   } | 
 |  | 
 |  public: | 
 |   // Array<>::Iterator satisfies the RandomAccessIterator concept: | 
 |   //   http://en.cppreference.com/w/cpp/concept/RandomAccessIterator. | 
 |   class Iterator { | 
 |    public: | 
 |     using difference_type = std::ptrdiff_t; | 
 |  | 
 |     // The following satisfy BidirectionalIterator: | 
 |     Iterator() : arr_(nullptr), pos_(0u) {} | 
 |     Iterator(Array<T>* arr, size_t pos) : arr_(arr), pos_(pos) {} | 
 |     Iterator& operator++() { | 
 |       ++pos_; | 
 |       return *this; | 
 |     } | 
 |     Iterator operator++(int) { | 
 |       Iterator original = *this; | 
 |       ++pos_; | 
 |       return original; | 
 |     } | 
 |     Iterator& operator--() { | 
 |       --pos_; | 
 |       return *this; | 
 |     } | 
 |     Iterator operator--(int) { | 
 |       Iterator original = *this; | 
 |       --pos_; | 
 |       return original; | 
 |     } | 
 |     bool operator==(const Iterator& o) const { | 
 |       return o.arr_ == arr_ && o.pos_ == pos_; | 
 |     } | 
 |     bool operator!=(const Iterator& o) const { return !(*this == o); } | 
 |     RefType operator*() const { return arr_->at(pos_); } | 
 |     T* operator->() const { return &arr_->at(pos_); } | 
 |  | 
 |     // The following satisfy RandomAccessIterator: | 
 |     Iterator& operator+=(difference_type dist) { | 
 |       pos_ += dist; | 
 |       return *this; | 
 |     } | 
 |     Iterator& operator-=(difference_type dist) { | 
 |       pos_ -= dist; | 
 |       return *this; | 
 |     } | 
 |     friend Iterator operator+(difference_type dist, const Iterator& o_it) { | 
 |       return Iterator(o_it.arr_, dist + o_it.pos_); | 
 |     } | 
 |     Iterator operator+(difference_type dist) const { | 
 |       return Iterator(arr_, pos_ + dist); | 
 |     } | 
 |     Iterator operator-(difference_type dist) const { | 
 |       return Iterator(arr_, pos_ - dist); | 
 |     } | 
 |     difference_type operator-(const Iterator& o_it) const { | 
 |       return pos_ - o_it.pos_; | 
 |     } | 
 |     bool operator<(const Iterator& o_it) const { return pos_ < o_it.pos_; } | 
 |     bool operator>(const Iterator& o_it) const { return pos_ > o_it.pos_; } | 
 |     bool operator<=(const Iterator& o_it) const { return pos_ <= o_it.pos_; } | 
 |     bool operator>=(const Iterator& o_it) const { return pos_ >= o_it.pos_; } | 
 |     RefType operator[](difference_type dist) { return arr_->at(pos_ + dist); } | 
 |  | 
 |    private: | 
 |     Array<T>* arr_; | 
 |     size_t pos_; | 
 |   }; | 
 |  | 
 |   Iterator begin() { return Iterator(this, 0); } | 
 |   Iterator end() { return Iterator(this, size()); } | 
 |  | 
 |  private: | 
 |   void Take(Array* other) { | 
 |     reset(); | 
 |     Swap(other); | 
 |   } | 
 |  | 
 |   std::vector<T> vec_; | 
 |   bool is_null_; | 
 |  | 
 |   MOJO_MOVE_ONLY_TYPE(Array); | 
 | }; | 
 |  | 
 | // A |TypeConverter| that will create an |Array<T>| containing a copy of the | 
 | // contents of an |std::vector<E>|, using |TypeConverter<T, E>| to copy each | 
 | // element. The returned array will always be non-null. | 
 | template <typename T, typename E> | 
 | struct TypeConverter<Array<T>, std::vector<E>> { | 
 |   static Array<T> Convert(const std::vector<E>& input) { | 
 |     auto result = Array<T>::New(input.size()); | 
 |     for (size_t i = 0; i < input.size(); ++i) | 
 |       result[i] = TypeConverter<T, E>::Convert(input[i]); | 
 |     return result; | 
 |   } | 
 | }; | 
 |  | 
 | // A |TypeConverter| that will create an |std::vector<E>| containing a copy of | 
 | // the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each | 
 | // element. If the input array is null, the output vector will be empty. | 
 | template <typename E, typename T> | 
 | struct TypeConverter<std::vector<E>, Array<T>> { | 
 |   static std::vector<E> Convert(const Array<T>& input) { | 
 |     std::vector<E> result; | 
 |     if (!input.is_null()) { | 
 |       result.resize(input.size()); | 
 |       for (size_t i = 0; i < input.size(); ++i) | 
 |         result[i] = TypeConverter<E, T>::Convert(input[i]); | 
 |     } | 
 |     return result; | 
 |   } | 
 | }; | 
 |  | 
 | // A |TypeConverter| that will create an |Array<T>| containing a copy of the | 
 | // contents of an |std::set<E>|, using |TypeConverter<T, E>| to copy each | 
 | // element. The returned array will always be non-null. | 
 | template <typename T, typename E> | 
 | struct TypeConverter<Array<T>, std::set<E>> { | 
 |   static Array<T> Convert(const std::set<E>& input) { | 
 |     Array<T> result = Array<T>::New(0u); | 
 |     for (auto i : input) | 
 |       result.push_back(TypeConverter<T, E>::Convert(i)); | 
 |     return result; | 
 |   } | 
 | }; | 
 |  | 
 | // A |TypeConverter| that will create an |std::set<E>| containing a copy of | 
 | // the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each | 
 | // element. If the input array is null, the output set will be empty. | 
 | template <typename E, typename T> | 
 | struct TypeConverter<std::set<E>, Array<T>> { | 
 |   static std::set<E> Convert(const Array<T>& input) { | 
 |     std::set<E> result; | 
 |     if (!input.is_null()) { | 
 |       for (size_t i = 0; i < input.size(); ++i) | 
 |         result.insert(TypeConverter<E, T>::Convert(input[i])); | 
 |     } | 
 |     return result; | 
 |   } | 
 | }; | 
 |  | 
 | }  // namespace mojo | 
 |  | 
 | #endif  // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_H_ |