/* String-interning set Copyright (C) 2025 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program 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 for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef GDBSUPPORT_STRING_SET_H #define GDBSUPPORT_STRING_SET_H #include "gdbsupport/unordered_set.h" #include <string_view> namespace gdb { /* This is a string-interning set. It manages storage for strings, ensuring that just a single copy of a given string is kept. The underlying C string will remain valid for the lifetime of this object. */ class string_set { public: /* Insert STR into this set. Returns a pointer to the interned string. */ const char *insert (const char *str) { /* We need to take the length to hash the string anyway, so it's convenient to just wrap it here. */ return insert (std::string_view (str)); } /* An overload accepting a string view. */ const char *insert (std::string_view str) { return m_set.insert (str).first->get (); } /* An overload that takes ownership of the string. */ const char *insert (gdb::unique_xmalloc_ptr<char> str) { return m_set.insert (local_string (std::move (str))).first->get (); } private: /* The type of string we store. Note that we do not store std::string here to avoid the small-string optimization invalidating a pointer on rehash. */ struct local_string { explicit local_string (std::string_view str) : contents (xstrndup (str.data (), str.size ())), len (str.size ()) { } explicit local_string (gdb::unique_xmalloc_ptr<char> str) : contents (std::move (str)), len (strlen (contents.get ())) { } const char *get () const { return contents.get (); } std::string_view as_view () const { return std::string_view (contents.get (), len); } /* \0-terminated string contents. */ gdb::unique_xmalloc_ptr<char> contents; /* Length of the string. */ size_t len; }; /* Equality object for the set. */ struct str_eq { using is_transparent = void; bool operator() (std::string_view lhs, const local_string &rhs) const noexcept { return lhs == rhs.as_view (); } bool operator() (const local_string &lhs, const local_string &rhs) const noexcept { return (*this) (lhs.as_view (), rhs); } }; /* Hash object for the set. */ struct str_hash { using is_transparent = void; using is_avalanching = void; uint64_t operator() (const local_string &rhs) const noexcept { return (*this) (rhs.as_view ()); } uint64_t operator() (std::string_view rhs) const noexcept { return ankerl::unordered_dense::hash<std::string_view> () (rhs); } }; /* The strings. */ gdb::unordered_set<local_string, str_hash, str_eq> m_set; }; } #endif /* GDBSUPPORT_STRING_SET_H */