mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 08:51:04 +01:00
This works to leverage the capabilities of the hashtable as much as possible, for example using the key context in the value stores. However, there may still be opportunities to refactor more deeply and use the functionality even better. Hopefully this is at least a reasonable start and gets us a clean baseline. On an Arm M1, this is a 15% improvement on my large lexing stress test, but ends up a wash on my x86-64 server. This is a smaller benefit than I expected, and it's because we're using a set-of-IDs and looking up values with a key context for things like identifiers. This pattern has a surprising tradeoff. The new hashtable uses significantly less memory, a 10% peak RSS reduction just from the hashtable change. But indirecting through the vector of values makes growing the hashtable dramatically less cache-friendly: it causes growth to randomly access every key when rehashing. On x86, everything gained by the faster hashtable is lost in even slower growth. And even on Arm, this eats into the benefits. But I have a plan to tweak how identifiers specifically work to avoid most of the growth, and so I suspect this is the right tradeoff on the whole. It gives us significant working set size reduction and we can likely avoid the regressed operation (growth with rehash) in most cases by clever reserving and if necessary by adding a hash caching layer to the table infrastructure. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
80 lines
2.6 KiB
C++
80 lines
2.6 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef CARBON_TOOLCHAIN_BASE_INDEX_BASE_H_
|
|
#define CARBON_TOOLCHAIN_BASE_INDEX_BASE_H_
|
|
|
|
#include <compare>
|
|
#include <concepts>
|
|
|
|
#include "common/ostream.h"
|
|
|
|
namespace Carbon {
|
|
|
|
template <typename DataType>
|
|
class DataIterator;
|
|
|
|
// A lightweight handle to an item identified by an opaque ID.
|
|
//
|
|
// This class is intended to be derived from by classes representing a specific
|
|
// kind of ID, whose meaning as an integer is an implementation detail of the
|
|
// type that vends the IDs. Typically this will be a vector index.
|
|
//
|
|
// Classes derived from IdBase are designed to be passed by value, not
|
|
// reference or pointer. They are also designed to be small and efficient to
|
|
// store in data structures.
|
|
struct IdBase : public Printable<IdBase> {
|
|
static constexpr int32_t InvalidIndex = -1;
|
|
|
|
IdBase() = delete;
|
|
constexpr explicit IdBase(int index) : index(index) {}
|
|
|
|
auto Print(llvm::raw_ostream& output) const -> void {
|
|
if (is_valid()) {
|
|
output << index;
|
|
} else {
|
|
output << "<invalid>";
|
|
}
|
|
}
|
|
|
|
constexpr auto is_valid() const -> bool { return index != InvalidIndex; }
|
|
|
|
int32_t index;
|
|
};
|
|
|
|
// A lightweight handle to an item that behaves like an index.
|
|
//
|
|
// Unlike IdBase, classes derived from IndexBase are not completely opaque, and
|
|
// provide at least an ordering between indexes that has meaning to an API
|
|
// user. Additional semantics may be specified by the derived class.
|
|
struct IndexBase : public IdBase {
|
|
using IdBase::IdBase;
|
|
};
|
|
|
|
// Support equality comparison when one operand is a child of `IdBase`
|
|
// (including `IndexBase`) and the other operand is either the same type or
|
|
// convertible to that type.
|
|
template <typename IndexType>
|
|
requires std::derived_from<IndexType, IdBase>
|
|
constexpr auto operator==(IndexType lhs, IndexType rhs) -> bool {
|
|
return lhs.index == rhs.index;
|
|
}
|
|
template <typename IndexType, typename RHSType>
|
|
requires std::derived_from<IndexType, IdBase> &&
|
|
std::convertible_to<RHSType, IndexType>
|
|
auto operator==(IndexType lhs, RHSType rhs) -> bool {
|
|
return lhs.index == IndexType(rhs).index;
|
|
}
|
|
|
|
// Relational comparisons are only supported for types derived from `IndexBase`.
|
|
template <typename IndexType>
|
|
requires std::derived_from<IndexType, IndexBase>
|
|
auto operator<=>(IndexType lhs, IndexType rhs) -> std::strong_ordering {
|
|
return lhs.index <=> rhs.index;
|
|
}
|
|
|
|
} // namespace Carbon
|
|
|
|
#endif // CARBON_TOOLCHAIN_BASE_INDEX_BASE_H_
|