| /* |
| * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "oops/array.hpp" |
| #include "utilities/globalDefinitions.hpp" |
| |
| // Base for space-optimized structure supporting binary search. Each element |
| // consists of up to 32-bit key, and up to 32-bit value; these are packed |
| // into a bit-record with 1-byte alignment. |
| // The keys are ordered according to a custom comparator. |
| class PackedTableBase { |
| protected: |
| unsigned int _element_bytes; |
| uint32_t _key_mask; |
| unsigned int _value_shift; |
| uint32_t _value_mask; |
| |
| public: |
| PackedTableBase(uint32_t max_key, uint32_t max_value); |
| |
| // Returns number of bytes each element will occupy. |
| inline unsigned int element_bytes(void) const { return _element_bytes; } |
| }; |
| |
| // Helper class for constructing a packed table in the provided array. |
| class PackedTableBuilder: public PackedTableBase { |
| public: |
| class Supplier { |
| public: |
| // Returns elements with already ordered keys. |
| // This function should return true when the key and value was set, |
| // and false when there's no more elements. |
| // Packed table does NOT support duplicate keys. |
| virtual bool next(uint32_t* key, uint32_t* value) = 0; |
| }; |
| |
| // The thresholds are inclusive, and in practice the limits are rounded |
| // to the nearest power-of-two - 1. |
| // See PackedTableBase constructor for details. |
| PackedTableBuilder(uint32_t max_key, uint32_t max_value): PackedTableBase(max_key, max_value) {} |
| |
| // Constructs a packed table in the provided array, filling it with elements |
| // from the supplier. Note that no comparator is requied by this method - |
| // the supplier must return elements with already ordered keys. |
| // The table_length (in bytes) should match number of elements provided |
| // by the supplier (when Supplier::next() returns false the whole array should |
| // be filled). |
| void fill(u1* table, size_t table_length, Supplier &supplier) const; |
| }; |
| |
| // Helper class for lookup in a packed table. |
| class PackedTableLookup: public PackedTableBase { |
| const u1* const _table; |
| const size_t _table_length; |
| |
| uint64_t read_element(size_t offset) const; |
| |
| public: |
| |
| // The comparator implementation does not have to store a key (uint32_t); |
| // the idea is that key can point into a different structure that hosts data |
| // suitable for the actual comparison. That's why PackedTableLookup::search(...) |
| // returns the key it found as well as the value. |
| class Comparator { |
| public: |
| // Returns negative/0/positive if the target referred to by this comparator |
| // is lower/equal/higher than the target referred to by the key. |
| virtual int compare_to(uint32_t key) = 0; |
| // Changes the target this comparator refers to. |
| DEBUG_ONLY(virtual void reset(uint32_t key) = 0); |
| }; |
| |
| // The thresholds are inclusive, and in practice the limits are rounded |
| // to the nearest power-of-two - 1. |
| // See PackedTableBase constructor for details. |
| PackedTableLookup(uint32_t max_key, uint32_t max_value, const u1 *table, size_t table_length): |
| PackedTableBase(max_key, max_value), _table(table), _table_length(table_length) {} |
| |
| PackedTableLookup(uint32_t max_key, uint32_t max_value, const Array<u1> *table): |
| PackedTableLookup(max_key, max_value, table->data(), static_cast<size_t>(table->length())) {} |
| |
| // Performs a binary search in the packed table, looking for an element with key |
| // referring to a target equal according to the comparator. |
| // When the element is found, found_key and found_value are updated from the element |
| // and the function returns true. |
| // When the element is not found, found_key and found_value are not changed and |
| // the function returns false. |
| bool search(Comparator& comparator, uint32_t* found_key, uint32_t* found_value) const; |
| |
| // Asserts that elements in the packed table follow the order defined by the comparator. |
| DEBUG_ONLY(void validate_order(Comparator &comparator) const); |
| |
| template<typename Function> |
| void iterate(Function func) const { |
| for (size_t offset = 0; offset < _table_length; offset += _element_bytes) { |
| uint64_t element = read_element(offset); |
| uint32_t key = static_cast<uint32_t>(element) & _key_mask; |
| uint32_t value = checked_cast<uint32_t>(element >> _value_shift) & _value_mask; |
| func(offset, key, value); |
| } |
| } |
| }; |