diff options
Diffstat (limited to 'dom/ipc/SharedStringMap.h')
-rw-r--r-- | dom/ipc/SharedStringMap.h | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/dom/ipc/SharedStringMap.h b/dom/ipc/SharedStringMap.h new file mode 100644 index 0000000000..cb14e09dbc --- /dev/null +++ b/dom/ipc/SharedStringMap.h @@ -0,0 +1,220 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef dom_ipc_SharedStringMap_h +#define dom_ipc_SharedStringMap_h + +#include "mozilla/AutoMemMap.h" +#include "mozilla/Result.h" +#include "mozilla/dom/ipc/StringTable.h" +#include "nsTHashMap.h" + +namespace mozilla::dom::ipc { + +class SharedStringMapBuilder; + +/** + * This class provides a simple, read-only key-value string store, with all + * data packed into a single segment of memory, which can be shared between + * processes. + * + * Look-ups are performed by binary search of a static table in the mapped + * memory region, and all returned strings are literals which reference the + * mapped data. No copies are performed on instantiation or look-up. + * + * Important: The mapped memory created by this class is persistent. Once an + * instance has been initialized, the memory that it allocates can never be + * freed before process shutdown. Do not use it for short-lived mappings. + */ +class SharedStringMap { + using FileDescriptor = mozilla::ipc::FileDescriptor; + + public: + /** + * The header at the beginning of the shared memory region describing its + * layout. The layout of the shared memory is as follows: + * + * - Header: + * A Header struct describing the contents of the rest of the memory region. + * + * - Optional alignment padding for Header[]. + * + * - Entry[header.mEntryCount]: + * An array of Entry structs, one for each entry in the map. Entries are + * lexocographically sorted by key. + * + * - StringTable<nsCString>: + * A region of flat, null-terminated C strings. Entry key strings are + * encoded as character offsets into this region. + * + * - Optional alignment padding for char16_t[] + * + * - StringTable<nsString>: + * A region of flat, null-terminated UTF-16 strings. Entry value strings are + * encoded as character (*not* byte) offsets into this region. + */ + struct Header { + uint32_t mMagic; + // The number of entries in this map. + uint32_t mEntryCount; + + // The raw byte offset of the beginning of the key string table, from the + // start of the shared memory region, and its size in bytes. + size_t mKeyStringsOffset; + size_t mKeyStringsSize; + + // The raw byte offset of the beginning of the value string table, from the + // start of the shared memory region, and its size in bytes (*not* + // characters). + size_t mValueStringsOffset; + size_t mValueStringsSize; + }; + + /** + * Describes a value in the string map, as offsets into the key and value + * string tables. + */ + struct Entry { + // The offset and size of the entry's UTF-8 key in the key string table. + StringTableEntry mKey; + // The offset and size of the entry's UTF-16 value in the value string + // table. + StringTableEntry mValue; + }; + + NS_INLINE_DECL_REFCOUNTING(SharedStringMap) + + // Note: These constructors are infallible on the premise that this class + // is used primarily in cases where it is critical to platform + // functionality. + explicit SharedStringMap(const FileDescriptor&, size_t); + explicit SharedStringMap(SharedStringMapBuilder&&); + + /** + * Searches for the given value in the map, and returns true if it exists. + */ + bool Has(const nsCString& aKey); + + /** + * Searches for the given value in the map, and, if it exists, returns true + * and places its value in aValue. + * + * The returned value is a literal string which references the mapped memory + * region. + */ + bool Get(const nsCString& aKey, nsAString& aValue); + + private: + /** + * Searches for an entry for the given key. If found, returns true, and + * places its index in the entry array in aIndex. + */ + bool Find(const nsCString& aKey, size_t* aIndex); + + public: + /** + * Returns the number of entries in the map. + */ + uint32_t Count() const { return EntryCount(); } + + /** + * Returns the string entry at the given index. Keys are guaranteed to be + * sorted lexographically. + * + * The given index *must* be less than the value returned by Count(). + * + * The returned value is a literal string which references the mapped memory + * region. + */ + nsCString GetKeyAt(uint32_t aIndex) const { + MOZ_ASSERT(aIndex < Count()); + return KeyTable().Get(Entries()[aIndex].mKey); + } + + /** + * Returns the string value for the entry at the given index. + * + * The given index *must* be less than the value returned by Count(). + * + * The returned value is a literal string which references the mapped memory + * region. + */ + nsString GetValueAt(uint32_t aIndex) const { + MOZ_ASSERT(aIndex < Count()); + return ValueTable().Get(Entries()[aIndex].mValue); + } + + /** + * Returns a copy of the read-only file descriptor which backs the shared + * memory region for this map. The file descriptor may be passed between + * processes, and used to construct new instances of SharedStringMap with + * the same data as this instance. + */ + FileDescriptor CloneFileDescriptor() const; + + size_t MapSize() const { return mMap.size(); } + + protected: + ~SharedStringMap() = default; + + private: + // Type-safe getters for values in the shared memory region: + const Header& GetHeader() const { return mMap.get<Header>()[0]; } + + RangedPtr<const Entry> Entries() const { + return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()}; + } + + uint32_t EntryCount() const { return GetHeader().mEntryCount; } + + StringTable<nsCString> KeyTable() const { + auto& header = GetHeader(); + return {{&mMap.get<uint8_t>()[header.mKeyStringsOffset], + header.mKeyStringsSize}}; + } + + StringTable<nsString> ValueTable() const { + auto& header = GetHeader(); + return {{&mMap.get<uint8_t>()[header.mValueStringsOffset], + header.mValueStringsSize}}; + } + + loader::AutoMemMap mMap; +}; + +/** + * A helper class which builds the contiguous look-up table used by + * SharedStringMap. Each key-value pair in the final map is added to the + * builder, before it is finalized and transformed into a snapshot. + */ +class MOZ_RAII SharedStringMapBuilder { + public: + SharedStringMapBuilder() = default; + + /** + * Adds a key-value pair to the map. + */ + void Add(const nsCString& aKey, const nsString& aValue); + + /** + * Finalizes the binary representation of the map, writes it to a shared + * memory region, and then initializes the given AutoMemMap with a reference + * to the read-only copy of it. + */ + Result<Ok, nsresult> Finalize(loader::AutoMemMap& aMap); + + private: + using Entry = SharedStringMap::Entry; + + StringTableBuilder<nsCStringHashKey, nsCString> mKeyTable; + StringTableBuilder<nsStringHashKey, nsString> mValueTable; + + nsTHashMap<nsCStringHashKey, Entry> mEntries; +}; + +} // namespace mozilla::dom::ipc + +#endif // dom_ipc_SharedStringMap_h |