/* Copyright 2014-2018 The MathWorks, Inc. */ #ifndef MDA_ARRAY_HPP_ #define MDA_ARRAY_HPP_ #if defined(matrix_h) && !defined(export_matrix_h) #error Using MATLAB Data API with C Matrix API is not supported. #endif #include "matlab_data_array_defs.hpp" #include "matlab_extdata_defs.hpp" #include "ArrayDimensions.hpp" #include "ArrayType.hpp" #include "ArrayElementRef.hpp" #include "MemoryLayout.hpp" #include "detail/publish_util.hpp" #include "detail/FunctionType.hpp" #include "detail/HelperFunctions.hpp" #include <functional> #include <stdint.h> #include <exception> namespace matlab { namespace data { template <template <class> class IteratorType, class ElementType> class Range; template <typename T> class TypedIterator; namespace impl { class ArrayImpl; } namespace detail { class Access; } /** * Array provides an API to access general information about an * array. Specific subclasses will provide access to type-specific * data for different kinds of arrays. */ class Array { public: static const ArrayType type = ArrayType::UNKNOWN; /** * Default constructor - creates an empty Array * @return - newly constructed Array * @throw - none */ Array() MW_NOEXCEPT { typedef impl::ArrayImpl* (*ArrayCreateEmptyFcnPtr)(); static const ArrayCreateEmptyFcnPtr fcn = detail::resolveFunction<ArrayCreateEmptyFcnPtr>( detail::FunctionType::ARRAY_CREATE_EMPTY); pImpl = std::shared_ptr<impl::ArrayImpl>(fcn(), [](impl::ArrayImpl* ptr) { typedef void (*ArrayDestroyFcnPtr)(impl::ArrayImpl*); static const ArrayDestroyFcnPtr fcn2 = detail::resolveFunction<ArrayDestroyFcnPtr>(detail::FunctionType::ARRAY_DESTROY); fcn2(ptr); }); } /** * Destructor * * @throw none */ virtual ~Array() MW_NOEXCEPT { } /** * Move constructor * * @param - rhs Array value to be moved * @return - newly constructed Array * @throw none */ Array(Array&& rhs) MW_NOEXCEPT : pImpl(std::move(rhs.pImpl)) { } /** * Move assignment operator * * @param - rhs Array value to be moved * @return - the updated Array * @throw none */ Array& operator=(Array&& rhs) MW_NOEXCEPT { pImpl = std::move(rhs.pImpl); return *this; } /** * Assignment operator. The updated Array becomes a shared copy of the input Array * * @param - rhs Array value to be copied * @return - the updated Array * @throw none */ Array& operator=(const Array& rhs) MW_NOEXCEPT { pImpl = rhs.pImpl; return *this; } /** * Copy consructor. The newly constructed Array becomes a shared copy of the input Array * * @param - rhs Array value to be copied * @return - new constructed Array * @throw none */ Array(const Array& rhs) MW_NOEXCEPT : pImpl(rhs.pImpl) { } /** * Returns the ArrayType of the array * * @return - the ArrayType * @throw InvalidArrayType - if array type returned is not recognized as valid */ ArrayType getType() const { typedef int (*ArrayGetTypeFcnPtr)(impl::ArrayImpl*, int*); static const ArrayGetTypeFcnPtr fcn = detail::resolveFunction<ArrayGetTypeFcnPtr>(detail::FunctionType::ARRAY_GET_TYPE); int type; detail::throwIfError(fcn(pImpl.get(), &type)); return static_cast<ArrayType>(type); } /** * Returns the memory layout of the array * * @return - the MemroyLayout * @throw InvalidMemoryLayout - if array type returned is not recognized as valid */ MemoryLayout getMemoryLayout() const { typedef int (*ArrayGetMemoryLayoutFcnPtr)(impl::ArrayImpl*, int*); static const ArrayGetMemoryLayoutFcnPtr fcn = detail::resolveFunction<ArrayGetMemoryLayoutFcnPtr>( detail::FunctionType::ARRAY_GET_MEMORY_LAYOUT); int layout; detail::throwIfError(fcn(pImpl.get(), &layout)); return static_cast<MemoryLayout>(layout); } /** * Get the array's dimensions. * * @return ArrayDimensions vector of each dimension. * @throw none */ ArrayDimensions getDimensions() const MW_NOEXCEPT { size_t numDims = 0; size_t* dims = nullptr; typedef void (*ArrayGetDimensionsFcnPtr)(impl::ArrayImpl*, size_t*, size_t**); static const ArrayGetDimensionsFcnPtr fcn = detail::resolveFunction<ArrayGetDimensionsFcnPtr>( detail::FunctionType::ARRAY_GET_DIMENSIONS); fcn(pImpl.get(), &numDims, &dims); return ArrayDimensions(dims, dims + numDims); } /** * Get the number of elements in this array * * @return the number of elements in the array * @throw none */ size_t getNumberOfElements() const MW_NOEXCEPT { typedef size_t (*ArrayGetNumElementsFcnPtr)(impl::ArrayImpl*); static const ArrayGetNumElementsFcnPtr fcn = detail::resolveFunction<ArrayGetNumElementsFcnPtr>( detail::FunctionType::ARRAY_GET_NUM_ELEMENTS); return fcn(pImpl.get()); } /** * Determine if this is an empty array * * @return true if the array is empty * @throw none */ bool isEmpty() const MW_NOEXCEPT { typedef bool (*ArrayIsEmptyFcnPtr)(impl::ArrayImpl*); static const ArrayIsEmptyFcnPtr fcn = detail::resolveFunction<ArrayIsEmptyFcnPtr>(detail::FunctionType::ARRAY_IS_EMPTY); return fcn(pImpl.get()); } /** * Enables [] indexing on a array. * * The return value ArrayElementRef<false> allows the element of the array to be * modified or retrieved: For example: * arr[1][1] = 5.5; * double val = arr[0][3]; * * @param idx - the first array index * @return ArrayElementRef<false> - contains the index specified * @throw InvalidArrayIndexException - if the index is invalid * @throw CantIndexIntoEmptyArrayException - if the array is empty */ ArrayElementRef<false> operator[](size_t idx) { impl::ArrayImpl* newImpl = nullptr; typedef bool (*ArrayUnshareFcnPtr)(impl::ArrayImpl*, bool, impl::ArrayImpl**); static const ArrayUnshareFcnPtr fcn = detail::resolveFunction<ArrayUnshareFcnPtr>(detail::FunctionType::ARRAY_UNSHARE); if (fcn(pImpl.get(), (pImpl.use_count() == 1), &newImpl)) { pImpl.reset(newImpl, [](impl::ArrayImpl* ptr) { typedef void (*ArrayDestroyFcnPtr)(impl::ArrayImpl*); static const ArrayDestroyFcnPtr fcn2 = detail::resolveFunction<ArrayDestroyFcnPtr>( detail::FunctionType::ARRAY_DESTROY); fcn2(ptr); }); } detail::ReferenceImpl* impl = nullptr; typedef int (*ArrayCreateReferenceFcnPtr)(impl::ArrayImpl*, size_t, detail::ReferenceImpl**); static const ArrayCreateReferenceFcnPtr fcn3 = detail::resolveFunction<ArrayCreateReferenceFcnPtr>( detail::FunctionType::ARRAY_CREATE_REFERENCE); detail::throwIfError(fcn3(pImpl.get(), idx, &impl)); return detail::Access::createObj<ArrayElementRef<false>>(impl); } /** * Enables [] indexing on a const array. * * The return value ArrayElementRef<true> allows the element of the array to be * retrieved, but not modified: For example: * double val = arr[0][3]; * * @param idx - the first array index * @return ArrayElementRef<true> - contains the index specified * @throw InvalidArrayIndexException - if the index is invalid * @throw CantIndexIntoEmptyArrayException - if the array is empty */ ArrayElementRef<true> operator[](size_t idx) const { detail::ReferenceImpl* impl = nullptr; typedef int (*ArrayCreateReferenceFcnPtr)(impl::ArrayImpl*, size_t, detail::ReferenceImpl**); static const ArrayCreateReferenceFcnPtr fcn = detail::resolveFunction<ArrayCreateReferenceFcnPtr>( detail::FunctionType::ARRAY_CREATE_REFERENCE); detail::throwIfError(fcn(pImpl.get(), idx, &impl)); return detail::Access::createObj<ArrayElementRef<true>>(impl); } protected: Array(impl::ArrayImpl* impl) MW_NOEXCEPT : pImpl(std::shared_ptr<impl::ArrayImpl>(impl, [](impl::ArrayImpl* ptr) { typedef void (*ArrayDestroyFcnPtr)(impl::ArrayImpl*); static const ArrayDestroyFcnPtr fcn2 = detail::resolveFunction<ArrayDestroyFcnPtr>(detail::FunctionType::ARRAY_DESTROY); fcn2(ptr); })) { } std::shared_ptr<impl::ArrayImpl> pImpl; friend class detail::Access; template <typename T> friend Range<TypedIterator, T> getWritableElements(Array& a); }; } // namespace data } // namespace matlab #endif