/* Copyright 2016-2020 The MathWorks, Inc. */ #ifndef MATLAB_EXTDATA_REFERENCE_HPP #define MATLAB_EXTDATA_REFERENCE_HPP #include "Enumeration.hpp" #include "String.hpp" #include "ReferenceHolder.hpp" #include "ArrayReferenceExt.hpp" #include "MATLABStringReferenceExt.hpp" #include "Exception.hpp" #include "GetArrayType.hpp" #include "detail/publish_util.hpp" #include "detail/FunctionType.hpp" #include "detail/HelperFunctions.hpp" #include "detail/ReferenceHelpers.hpp" #include <memory> #include <type_traits> namespace matlab { namespace data { namespace detail { class Access; } template <typename T> struct GetReferenceExt { using type = ReferenceHolder; }; template <> struct GetReferenceExt<Array> { using type = IndexableArrayRef<false>; }; template <> struct GetReferenceExt<MATLABString> { using type = MATLABStringReferenceExt; }; template <typename T> class Reference : public GetReferenceExt<T>::type { public: typedef typename std::remove_const<T>::type ref_type; using Parent = typename GetReferenceExt<T>::type; using Parent::pImpl; /** * Cast to element from the array. Makes a copy of the element from the array * * @code * Reference<Array> ref = cell_arr[0]; * Array cpy(ref); * @endcode * * @return ref_type the element being referred to * @throw ObjectNotAccessibleException - if iterating through an object array and the object in the array cannot be accessed */ operator ref_type() const { return detail::getElement<ref_type>(pImpl); } /** * Assign a value into an Array. The Array being indexed must be non-const. * * @code * Reference<Array> ref = cell_arr[0]; * ref = factory.createScalar(false); * @endcode * * @param rhs - value to be assigned into the Array * * @return Reference<T>& - this * @throw InvalidHeterogeneousArrayException - if assigning an object to an ObjectArray that is not valid */ Reference<T>& operator= (T rhs) { static_assert(!std::is_const<T>::value, "Can't modify a Reference to const data"); detail::setElement(pImpl.get(), std::move(rhs), static_cast<int>(GetArrayType<T>::type)); return *this; } /** * Cast to std::string from the array. Makes a copy of the std::string. Only * valid for types that can be cast to a std::string * * @code * Reference<String> ref = str_arr[0]; * std::string cpy(ref); * @endcode * * @return std::string - a string representation of the value * * @throw std::runtime_error - for a Reference<MATLABString> if the MATLABString is missing * @throw NonAsciiCharInInputDataException for a Reference<MATLABString> if the MATLABString contains non-ascii characters */ operator std::string() const { static_assert(std::is_same<ref_type, Enumeration>::value || std::is_same<ref_type, MATLABString>::value, "Invalid Reference to get a string"); return detail::getString<ref_type>(pImpl.get()); } /** * Assign a std::string into an Array. The Array being indexed must be non-const and allow strings to be assigned * * @code * Reference<String> ref = str_arr[0]; * ref = "MyString"; * @endcode * * @param rhs - std::string to be assigned into the Array * * @return Reference<T>& - this * @throw none */ Reference<T>& operator=(std::string rhs) MW_NOEXCEPT { static_assert(!std::is_const<T>::value, "Can't modify a Reference to const data"); static_assert(std::is_same<ref_type, Enumeration>::value || std::is_same<ref_type, MATLABString>::value, "Invalid Reference to set a string"); detail::setString<ref_type>(pImpl.get(), std::move(rhs)); return *this; } /** * Assign a String value into a MATLABString Array. The Array being indexed must be non-const. * * @code * Reference<MATLABString> ref = string_arr[0]; * ref = String(u"hello"); * @endcode * * @param rhs - value to be assigned into the Array * * @return Reference<T>& - this * * @throw none */ Reference<T>& operator= (String rhs) MW_NOEXCEPT { static_assert(!std::is_const<T>::value, "Can't modify a Reference to const data"); static_assert(std::is_same<ref_type, MATLABString>::value, "Invalid Reference to set a String"); detail::setElement(pImpl.get(), std::move(rhs), static_cast<int>(ArrayType::MATLAB_STRING)); return *this; } /** * Move constructor * * @param - rhs Reference value to be moved * @return - newly constructed Reference * @throw none */ Reference(Reference<T>&& rhs) MW_NOEXCEPT : Parent(std::move(rhs)) {} /** * Move assignment * * @param - rhs Reference value to be moved * @return - updated Reference * @throw none */ Reference<T>& operator= (Reference<T>&& rhs) MW_NOEXCEPT { Parent::operator= (std::move(rhs)); return *this; } /** * Copy constructor * * @param - rhs Reference value to be copied * @return - newly constructed Reference * @throw none */ Reference(const Reference<T>& rhs) MW_NOEXCEPT : Parent(rhs) {} /** * Copy assignment * * @param - rhs Reference value to be copied * @return - updated Reference * @throw none */ Reference<T>& operator= (const Reference<T>& rhs) MW_NOEXCEPT { Parent::operator= (rhs); return *this; } protected: Reference(std::shared_ptr<detail::ReferenceImpl> impl) MW_NOEXCEPT : Parent(impl) {} Reference(detail::ReferenceImpl* impl) MW_NOEXCEPT : Parent(impl) {} private: friend class detail::Access; Reference() = delete; }; inline bool operator ==(Reference<MATLABString> const& lhs, std::string const& rhs) MW_NOEXCEPT { typedef bool(*ReferenceMATLABStringEqualStringFcnPtr)(detail::ReferenceImpl*, const char*, size_t idx); static const ReferenceMATLABStringEqualStringFcnPtr fcn = detail::resolveFunction<ReferenceMATLABStringEqualStringFcnPtr> (detail::FunctionType::REFERENCE_MATLAB_STRING_EQUAL_STRING); return fcn(detail::Access::getImpl<detail::ReferenceImpl>(lhs), rhs.c_str(), rhs.size()); } inline bool operator ==(std::string const& lhs, Reference<MATLABString> const& rhs) MW_NOEXCEPT { typedef bool(*ReferenceMATLABStringEqualStringFcnPtr)(detail::ReferenceImpl*, const char*, size_t idx); static const ReferenceMATLABStringEqualStringFcnPtr fcn = detail::resolveFunction<ReferenceMATLABStringEqualStringFcnPtr> (detail::FunctionType::REFERENCE_MATLAB_STRING_EQUAL_STRING); return fcn(detail::Access::getImpl<detail::ReferenceImpl>(rhs), lhs.c_str(), lhs.size()); } inline bool operator ==(Reference<MATLABString> const& lhs, String const& rhs) MW_NOEXCEPT { typedef bool(*ReferenceMATLABStringEqualString16FcnPtr)(detail::ReferenceImpl*, const char16_t*, size_t idx); static const ReferenceMATLABStringEqualString16FcnPtr fcn = detail::resolveFunction<ReferenceMATLABStringEqualString16FcnPtr> (detail::FunctionType::REFERENCE_MATLAB_STRING_EQUAL_STRING16); return fcn(detail::Access::getImpl<detail::ReferenceImpl>(lhs), rhs.c_str(), rhs.size()); } inline bool operator ==(String const& lhs, Reference<MATLABString> const& rhs) MW_NOEXCEPT { typedef bool(*ReferenceMATLABStringEqualString16FcnPtr)(detail::ReferenceImpl*, const char16_t*, size_t idx); static const ReferenceMATLABStringEqualString16FcnPtr fcn = detail::resolveFunction<ReferenceMATLABStringEqualString16FcnPtr> (detail::FunctionType::REFERENCE_MATLAB_STRING_EQUAL_STRING16); return fcn(detail::Access::getImpl<detail::ReferenceImpl>(rhs), lhs.c_str(), lhs.size()); } inline bool operator ==(Reference<MATLABString> const& lhs, MATLABString const& rhs) MW_NOEXCEPT { if (rhs.has_value()) { const String& str = *rhs; return (lhs == str); } return false; } inline bool operator ==(MATLABString const& lhs, Reference<MATLABString> const& rhs) MW_NOEXCEPT { if (lhs.has_value()) { const String& str = *lhs; return (rhs == str); } return false; } inline bool operator ==(Reference<MATLABString> const& lhs, Reference<MATLABString> const& rhs) MW_NOEXCEPT { typedef bool(*ReferenceMATLABStringEqualReferenceFcnPtr)(detail::ReferenceImpl*, detail::ReferenceImpl*); static const ReferenceMATLABStringEqualReferenceFcnPtr fcn = detail::resolveFunction<ReferenceMATLABStringEqualReferenceFcnPtr> (detail::FunctionType::REFERENCE_MATLAB_STRING_EQUAL_REFERENCE); return fcn(detail::Access::getImpl<detail::ReferenceImpl>(lhs), detail::Access::getImpl<detail::ReferenceImpl>(rhs)); } template<typename T1, typename T2> inline bool operator !=( T1 const& lhs, T2 const& rhs) MW_NOEXCEPT { return !(lhs == rhs); } template<typename T> bool operator ==(Reference<T> const& lhs, T const& rhs) MW_NOEXCEPT { using ref_type = typename Reference<T>::ref_type; return static_cast<ref_type>(lhs) == rhs; } template<typename T> bool operator ==(T const& lhs, Reference<T> const& rhs) MW_NOEXCEPT { using ref_type = typename Reference<T>::ref_type; return lhs == static_cast<ref_type>(rhs); } template<typename T> bool operator ==(Reference<T> const& lhs, Reference<T> const& rhs) MW_NOEXCEPT { using ref_type = typename Reference<T>::ref_type; return static_cast<ref_type>(lhs) == static_cast<ref_type>(rhs); } template<typename T> std::ostream& operator <<(std::ostream& os, Reference<T> const& rhs) MW_NOEXCEPT { using ref_type = typename Reference<T>::ref_type; return os << static_cast<ref_type>(rhs); } template<typename T> bool operator <(Reference<T> const& lhs, Reference<T> const& rhs) { using ref_type = typename Reference<T>::ref_type; return static_cast<ref_type>(lhs) < static_cast<ref_type>(rhs); } template<typename T> bool operator >(Reference<T> const& lhs, Reference<T> const& rhs) { using ref_type = typename Reference<T>::ref_type; return static_cast<ref_type>(lhs) > static_cast<ref_type>(rhs); } template<typename T> bool operator <=(Reference<T> const& lhs, Reference<T> const& rhs) { using ref_type = typename Reference<T>::ref_type; return static_cast<ref_type>(lhs) <= static_cast<ref_type>(rhs); } template<typename T> bool operator >=(Reference<T> const& lhs, Reference<T> const& rhs) { using ref_type = typename Reference<T>::ref_type; return static_cast<ref_type>(lhs) >= static_cast<ref_type>(rhs); } } } #endif