-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce til::linear_flat_set #15089
Conversation
This comment has been minimized.
This comment has been minimized.
I think the spelling bot isn't correctly segmenting |
This comment has been minimized.
This comment has been minimized.
c536a1c
to
567550a
Compare
I didn't manage to read all this yet but a unittest might help clarify how this is supposed to be used (even if it's just as a |
This comment has been minimized.
This comment has been minimized.
I've simplified the code a lot and it should be way easier to review now. 🙂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love it, but I don't totally get why you got rid of the (concept??) thing that probably made better error messages if you tried to make a lfs
with a type that didn't support it?
I felt like it made understanding the flow of code unnecessarily complex and required you to understand all parts of the code at once. For instance, this is a realistic implementation of the trait: namespace til
{
template<>
struct flat_set_trait<BackendD3D::AtlasFontFaceEntry>
{
using T = BackendD3D::AtlasFontFaceEntry;
static size_t hash(const BackendD3D::AtlasFontFaceKey& key) noexcept
{
return flat_set_hash_integer(std::bit_cast<uintptr_t>(key.fontFace) | static_cast<u8>(key.lineRendition));
}
static size_t hash(const T& slot) noexcept
{
const auto& inner = *slot.inner;
return flat_set_hash_integer(std::bit_cast<uintptr_t>(inner.fontFace.get()) | static_cast<u8>(inner.lineRendition));
}
static bool equals(const T& slot, const BackendD3D::AtlasFontFaceKey& key) noexcept
{
const auto& inner = *slot.inner;
return inner.fontFace.get() == key.fontFace && inner.lineRendition == key.lineRendition;
}
static bool empty(const T& slot) noexcept
{
return !slot.inner;
}
static void fill(T& slot, const BackendD3D::AtlasFontFaceKey& key)
{
slot.inner = std::make_unique<BackendD3D::AtlasFontFaceEntryInner>();
auto& inner = *slot.inner;
inner.fontFace = key.fontFace;
inner.lineRendition = key.lineRendition;
}
static std::unique_ptr<T[]> allocate(size_t capacity)
{
return std::make_unique<T[]>(capacity);
}
static void clear(T* data, size_t capacity) noexcept
{
for (auto& slot : std::span{ data, capacity })
{
slot.inner.reset();
}
}
};
} The definition of the |
Got it. Well, do you think that we would benefit from a concept that guides an implementer in, at least, the right direction? |
I can't quite figure out how to do that. I tried: template<typename U>
std::pair<T&, bool> insert(U&& key)
requires Hashable<U> && std::equality_comparable_with<T, U> && std::assignable_from<T, U> but it failed to compile. I'm not sure what's wrong with that, but tbh, that concept code didn't even result in a particularly easy to understand message on MSVC in the first place. It said:
|
eh, screw it then :) |
til::linear_flat_set
is a primitive hash map with linear probing.The implementation is slightly complicated due to the use of templates.
I've strongly considered just writing multiple copies of this class,
by hand since the code is indeed fairly trivial but ended up deciding
against it, because this templated approach makes testing easier.
This class is in the order of 10x faster than
std::unordered_map
.