/* Copyright 2015-2017 The MathWorks, Inc. */ #ifndef MATLAB_EXTDATA_ARRAY_ELEMENT_REF_HPP #define MATLAB_EXTDATA_ARRAY_ELEMENT_REF_HPP #include "matlab_data_array_defs.hpp" #include "ArrayType.hpp" #include "Exception.hpp" #include "String.hpp" #include "GetArrayType.hpp" #include "ReferenceHolder.hpp" #include "detail/enum_interface.hpp" #include "detail/string_interface.hpp" #include "detail/reference_interface.hpp" #include "detail/HelperFunctions.hpp" #include "detail/ExceptionHelpers.hpp" #include "detail/ReferenceHelpers.hpp" #include #include #include #include #include namespace matlab { namespace data { namespace detail { class Access; class ReferenceImpl; } class Array; template class IndexableArrayRef; /** * ArrayElementRef is created when using operator[] into an Array or a * Reference. It is untyped since Array and Reference do not have * type information. It collects up the indexes specified by the user and can be * cast to an element if the array holds primitive data or can be used to create a * Reference instance. The template argument indicates if this reference is * const. The non-const version of this class support assignment. Note that * indexing is zero-based. * * @code * Array arr = factory.createArray({2,2}); * arr[0][0] = 5.5; * double val = arr[0][0]; * * Array cell_arr = factory.createArray({1,2}); * cell_arr[0] = factory.createScalar(10.5); * cell_arr[1] = factory.createScalar(false); * * ArrayRef ref_to_element = cell_arr[0]; * TypedArrayRef typed_ref_to_element = cell_arr[0]; * * Array const shared_copy_of_element = cell_arr[1]; * TypedArray const typed_shared_copy_of_element = cell_arr[1]; * * @endcode */ template class ArrayElementRef { public: /** * operator[] adds another index to the indexing operation. It is called when 2 * or more indices are used in an indexing operation. * * @param idx - the index to be added * * @return ArrayElementRef - a new ArrayElementRef with the additional index * * @throw TooManyIndicesProvidedException - if the number of indices is more than the number of dimensions in the Array * @throw StringIndexMustBeLastException - if a numeric index is provided after a string index */ ArrayElementRef operator[](size_t idx) { detail::throwIfError(reference_add_index(pImpl.get(), idx)); return ArrayElementRef(pImpl); } /** * operator[] adds string index to the indexing operation. It is only valid if the * Array being indexed support string indexing (StructArrays) * * @code * double val = arr[2][7]["f1"]; * @endcode * * @param idx - the index to be added * * @return ArrayElementRef - a new ArrayElementRef with the string index * * @throw StringIndexNotValidException - if this Array does not support indexing with a string * @throw CanOnlyUseOneStringIndexException - if more than one string index is supplied */ ArrayElementRef operator[](std::string idx) { detail::throwIfError(reference_add_string_index(pImpl.get(), idx.c_str(), idx.size())); return ArrayElementRef(pImpl); } /** * Cast a value. Can be cast to the element type of the array, or to a reference to an element of the * array if the element type is not a primitive type * * @code * double val = dblArray_const[1][2]; * @endcode * * @return T - the value * * @throw NotEnoughIndicesProvidedException - if not enough indices were provided * @throw InvalidArrayIndexException - if an array index is out of range * @throw TypeMismatchException - if the element of the Array cannot be cast to T */ template operator T() const { return detail::castTo(pImpl); } /** * Assign data into the Array. * throw an error if the Array does not contain the same type being assigned. * * @code * arr[1][2] = 5.0; * @endcode * * @param rhs - primitive data to be assigned into the Array * * @return ArrayElementRef& - this * * @throw InvalidArrayIndexException - if one of the indices is out of range for this Array * @throw NotEnoughIndicesProvidedException - if not enough indices were provided * @throw TypeMismatchException - if the element of the Array does not contain T's */ template ArrayElementRef& operator= (T rhs) { static_assert(!is_const_ref, "Can't modify a const reference"); typedef typename std::conditional::value || std::is_same::value, GetStringType, GetArrayType>::type GetNonArrayType; typedef typename std::conditional::value, GetCellType, GetNonArrayType>::type GetType; detail::setElement(pImpl.get(), std::move(rhs), static_cast(GetType::type)); return *this; } private: std::shared_ptr pImpl; ArrayElementRef(ArrayElementRef&& rhs) MW_NOEXCEPT : pImpl(std::move(rhs.pImpl)) {} ArrayElementRef(detail::ReferenceImpl* impl) MW_NOEXCEPT : pImpl(std::shared_ptr (impl, [](detail::ReferenceImpl* ptr) { reference_destroy_impl(ptr); })) {} ArrayElementRef(std::shared_ptr impl) MW_NOEXCEPT : pImpl(impl) {} friend class detail::Access; friend class Array; friend class IndexableArrayRef; friend class IndexableArrayRef; ArrayElementRef() = delete; ArrayElementRef(const ArrayElementRef& rhs) = delete; ArrayElementRef& operator=(const ArrayElementRef& rhs) = delete; ArrayElementRef& operator=(ArrayElementRef&& rhs) = delete; }; } } #endif