Repository: LadybirdBrowser/ladybird
File: Libraries/LibWeb/IndexedDB/Internal/Key.h (C/C++)

Code before:
    // * a list of other keys if type is array.
    using KeyValue = Variant<double, AK::String, ByteBuffer, GC::Root<GC::HeapVector<GC::Ref<Key>>>>;

    // A key has an associated type which is one of: number, date, string, binary, or array.
    enum KeyType {
        Invalid,
        Number,
        Date,
        String,
        Binary,
        Array,
    };

public:
    [[nodiscard]] static GC::Ref<Key> create(JS::Realm&, KeyType, KeyValue);
    virtual ~Key();

    [[nodiscard]] KeyType type() { return m_type; }
    [[nodiscard]] KeyValue value() { return m_value; }

    [[nodiscard]] bool is_invalid() { return m_type == Invalid; }

    [[nodiscard]] double value_as_double() { return m_value.get<double>(); }
    [[nodiscard]] AK::String value_as_string() { return m_value.get<AK::String>(); }
    [[nodiscard]] ByteBuffer value_as_byte_buffer() { return m_value.get<ByteBuffer>(); }
    [[nodiscard]] GC::Root<GC::HeapVector<GC::Ref<Key>>> value_as_vector() { return m_value.get<GC::Root<GC::HeapVector<GC::Ref<Key>>>>(); }
    [[nodiscard]] GC::Root<GC::HeapVector<GC::Ref<Key>>> subkeys()
    {
        VERIFY(m_type == Array);
        return value_as_vector();
    }

    [[nodiscard]] static GC::Ref<Key> create_number(JS::Realm& realm, double value) { return create(realm, Number, value); }
    [[nodiscard]] static GC::Ref<Key> create_date(JS::Realm& realm, double value) { return create(realm, Date, value); }
    [[nodiscard]] static GC::Ref<Key> create_string(JS::Realm& realm, AK::String const& value) { return create(realm, String, value); }
    [[nodiscard]] static GC::Ref<Key> create_binary(JS::Realm& realm, ByteBuffer const& value) { return create(realm, Binary, value); }
    [[nodiscard]] static GC::Ref<Key> create_array(JS::Realm& realm, GC::Root<GC::HeapVector<GC::Ref<Key>>> const& value) { return create(realm, Array, value); }
    [[nodiscard]] static GC::Ref<Key> create_invalid(JS::Realm& realm, AK::String const& value) { return create(realm, Invalid, value); }

    [[nodiscard]] static i8 compare_two_keys(GC::Ref<Key> a, GC::Ref<Key> b);
    [[nodiscard]] static bool equals(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) == 0; }
    [[nodiscard]] static bool less_than(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) < 0; }
    [[nodiscard]] static bool greater_than(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) > 0; }
    [[nodiscard]] static bool less_than_or_equal(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) <= 0; }
    [[nodiscard]] static bool greater_than_or_equal(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) >= 0; }

    AK::String dump() const;

private:
    Key(KeyType type, KeyValue value)
        : m_type(type)

Review comment (suggestion):
I think `ReadonlySpan<GC::Ref<Key>>` would suffice? Looking at the callers, I don't think we need to create a root here.

That would be:
```c++
[[nodiscard]] ReadonlySpan<GC::Ref<Key>> value_as_vector() { return m_value.get<GC::Ref<GC::HeapVector<GC::Ref<Key>>>>()->elements(); }
```

That would also make several of the changed lines in Algorithms.cpp unnecessary 

Code after:
    // * a byte sequence if type is binary,
    // * a list of other keys if type is array.
    using KeyValue = Variant<double, AK::String, ByteBuffer, GC::Root<GC::HeapVector<GC::Ref<Key>>>>;
    using KeyValueInternal = Variant<double, AK::String, ByteBuffer, GC::Ref<GC::HeapVector<GC::Ref<Key>>>>;

    // A key has an associated type which is one of: number, date, string, binary, or array.
    enum KeyType {
        Invalid,
        Number,
        Date,
        String,
        Binary,
        Array,
    };

    [[nodiscard]] static GC::Ref<Key> create(JS::Realm&, KeyType, KeyValue);
    virtual ~Key();

    [[nodiscard]] KeyType type() { return m_type; }
    [[nodiscard]] KeyValue value();

    [[nodiscard]] bool is_invalid() { return m_type == Invalid; }

    [[nodiscard]] double value_as_double() { return m_value.get<double>(); }
    [[nodiscard]] AK::String value_as_string() { return m_value.get<AK::String>(); }
    [[nodiscard]] ByteBuffer value_as_byte_buffer() { return m_value.get<ByteBuffer>(); }
    [[nodiscard]] ReadonlySpan<GC::Ref<Key>> value_as_vector() { return m_value.get<GC::Ref<GC::HeapVector<GC::Ref<Key>>>>()->elements(); }
    [[nodiscard]] ReadonlySpan<GC::Ref<Key>> subkeys()
    {
        VERIFY(m_type == Array);
        return value_as_vector();
    }

    [[nodiscard]] static GC::Ref<Key> create_number(JS::Realm& realm, double value) { return create(realm, Number, value); }
    [[nodiscard]] static GC::Ref<Key> create_date(JS::Realm& realm, double value) { return create(realm, Date, value); }
    [[nodiscard]] static GC::Ref<Key> create_string(JS::Realm& realm, AK::String const& value) { return create(realm, String, value); }
    [[nodiscard]] static GC::Ref<Key> create_binary(JS::Realm& realm, ByteBuffer const& value) { return create(realm, Binary, value); }
    [[nodiscard]] static GC::Ref<Key> create_array(JS::Realm& realm, GC::Root<GC::HeapVector<GC::Ref<Key>>> const& value) { return create(realm, Array, value); }
    [[nodiscard]] static GC::Ref<Key> create_invalid(JS::Realm& realm, AK::String const& value) { return create(realm, Invalid, value); }

    [[nodiscard]] static i8 compare_two_keys(GC::Ref<Key> a, GC::Ref<Key> b);
    [[nodiscard]] static bool equals(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) == 0; }
    [[nodiscard]] static bool less_than(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) < 0; }
    [[nodiscard]] static bool greater_than(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) > 0; }
    [[nodiscard]] static bool less_than_or_equal(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) <= 0; }
    [[nodiscard]] static bool greater_than_or_equal(GC::Ref<Key> a, GC::Ref<Key> b) { return compare_two_keys(a, b) >= 0; }

    AK::String dump() const;

private:
    Key(KeyType, KeyValue);