// Copyright (C) 2018 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 #ifndef QV4PROPERTYKEY_H #define QV4PROPERTYKEY_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include QT_BEGIN_NAMESPACE class QString; namespace QV4 { struct PropertyKey { private: // Property keys are Strings, Symbols or unsigned integers. // For convenience we derive them from Values, allowing us to store them // on the JS stack // // They do however behave somewhat different than a Value: // * If the key is a String, the pointer to the string is stored in the identifier // table and thus unique. // * If the key is a Symbol it simply points to the referenced symbol object // * if the key is an array index (a uint < UINT_MAX), it's encoded as an // integer value QV4::StaticValue val; inline bool isManaged() const { return val.isManaged(); } inline quint32 value() const { return val.value(); } public: static PropertyKey invalid() { PropertyKey key; key.val = StaticValue::undefinedValue(); return key; } static PropertyKey fromArrayIndex(uint idx) { PropertyKey key; key.val.setInt_32(idx); return key; } bool isStringOrSymbol() const { return isManaged(); } uint asArrayIndex() const { Q_ASSERT(isArrayIndex()); return value(); } bool isArrayIndex() const { return val.isInteger(); } bool isValid() const { return !val.isUndefined(); } // We cannot #include the declaration of Heap::StringOrSymbol here. // Therefore we do some gymnastics to enforce the type safety. template static PropertyKey fromStringOrSymbol(Engine *engine, StringOrSymbol *b) { static_assert(std::is_base_of_v); PropertyKey key; QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) { if constexpr (QV4::WriteBarrier::isInsertionBarrier) { // treat this as an insertion - the StringOrSymbol becomes reachable // via the propertykey, so we consequently need to mark it durnig gc b->mark(stack); } }); key.val.setM(b); Q_ASSERT(key.isManaged()); return key; } template StringOrSymbol *asStringOrSymbol() const { static_assert(std::is_base_of_v); if (!isManaged()) return nullptr; return static_cast(val.m()); } Q_QML_EXPORT bool isString() const; Q_QML_EXPORT bool isSymbol() const; bool isCanonicalNumericIndexString() const; Q_QML_EXPORT QString toQString() const; Heap::StringOrSymbol *toStringOrSymbol(ExecutionEngine *e); quint64 id() const { return val._val; } static PropertyKey fromId(quint64 id) { PropertyKey key; key.val._val = id; return key; } enum FunctionNamePrefix { None, Getter, Setter }; Heap::String *asFunctionName(ExecutionEngine *e, FunctionNamePrefix prefix) const; bool operator ==(const PropertyKey &other) const { return val._val == other.val._val; } bool operator !=(const PropertyKey &other) const { return val._val != other.val._val; } bool operator <(const PropertyKey &other) const { return val._val < other.val._val; } friend size_t qHash(const PropertyKey &key, size_t seed = 0) { return qHash(key.val._val, seed); } }; } QT_END_NAMESPACE #endif