/*************************************************************************************************** Copyright (C) 2023 The Qt Company Ltd. SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only ***************************************************************************************************/ #pragma once #include "qdotnetobject.h" #ifdef __GNUC__ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wconversion" #endif #include #include #ifdef __GNUC__ # pragma GCC diagnostic pop #endif template || std::is_same_v || std::is_base_of_v, bool> = true> class QDotNetArray : public QDotNetObject { class Element; static QString arrayOf(const QString& typeName) { const auto idx = typeName.indexOf(QRegularExpression(",|$")); return QString("%1[]%2").arg(typeName.left(idx)).arg(typeName.mid(idx)); } public: Q_DOTNET_OBJECT_INLINE(QDotNetArray, arrayOf(QDotNetTypeOf::TypeName)); QDotNetArray(qint32 length) { const QString elementTypeName = QDotNetTypeOf::TypeName; const QDotNetType elementType = QDotNetType::typeOf(elementTypeName); QDotNetType arrayType = QDotNetType::typeOf(QDotNetArray::AssemblyQualifiedName); auto ctor = constructor(); *this = ctor(length); } qint32 length() const { return method("get_Length", fnLength).invoke(*this); } T get(qint32 idx) const { if constexpr (std::is_fundamental_v) return method("Get", fnGetValue).invoke(*this, idx); if constexpr (std::is_same_v) return method("Get", fnGetObject).invoke(*this, idx).toString(); if constexpr (std::is_base_of_v) return method("Get", fnGetObject).invoke(*this, idx).template cast(); throw std::invalid_argument("T"); } void set(qint32 idx, const T &value) { if constexpr (std::is_same_v) { if (!fnSetString.isValid()) { QDotNetFunction const func = adapter() .resolveInstanceMethod(*this, "Set", { UnmanagedType::Void, UnmanagedType::I4, QDotNetParameter::String }); fnSetString = func; } return method("Set", fnSet).invoke(*this, idx, value); } return method("Set", fnSet).invoke(*this, idx, value); } Element operator[](qint32 idx) { return Element(this, idx); } Element begin() { return Element(this, 0); } Element end() { return Element(this, length()); } private: class Element { friend class QDotNetArray; public: operator T() { return value = a->get(idx); } T *operator->() { value = a->get(idx); return &value; } T &operator*() { value = a->get(idx); return value; } Element &operator=(const T &value) { a->set(idx, value); return *this; } bool isEnd() const { return idx >= a->length(); } Element &operator++() { ++idx; return *this; } bool operator !=(const Element &that) const { if (isEnd() && that.isEnd()) return false; return a != that.a || idx != that.idx; } private: Element(QDotNetArray *a, qint32 idx) : a(a) , idx(idx) {} QDotNetArray* a = nullptr; qint32 idx; T value; }; mutable QDotNetSafeMethod fnLength; mutable QDotNetSafeMethod fnGetValue; mutable QDotNetSafeMethod fnGetObject; QDotNetSafeMethod fnSet; QDotNetSafeMethod fnSetString; };