gecko-dev/dom/ipc/SharedStringMap.h

225 lines
7.2 KiB
C++

/* -*- 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/Result.h"
#include "mozilla/dom/ipc/StringTable.h"
#include "mozilla/ipc/SharedMemory.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 {
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 mozilla::ipc::SharedMemoryHandle&, 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 shared memory handle which backs the shared
* memory region for this map. The handle may be passed between processes, and
* used to construct new instances of SharedStringMap with the same data as
* this instance.
*/
mozilla::ipc::SharedMemoryHandle CloneHandle() const;
size_t MapSize() const { return mMappedMemory.size(); }
protected:
~SharedStringMap() = default;
private:
// Type-safe getters for values in the shared memory region:
const Header& GetHeader() const {
return *reinterpret_cast<const Header*>(mMappedMemory.data());
}
RangedPtr<const Entry> Entries() const {
return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
}
uint32_t EntryCount() const { return GetHeader().mEntryCount; }
StringTable<nsCString> KeyTable() const {
const auto& header = GetHeader();
return {{&mMappedMemory.data()[header.mKeyStringsOffset],
header.mKeyStringsSize}};
}
StringTable<nsString> ValueTable() const {
const auto& header = GetHeader();
return {{&mMappedMemory.data()[header.mValueStringsOffset],
header.mValueStringsSize}};
}
mozilla::ipc::SharedMemoryHandle mHandle;
// This is a leaked shared memory mapping (see the constructor definition for
// an explanation). It replaces AutoMemMap::setPersistent behavior as part of
// bug 1454816.
Span<uint8_t> mMappedMemory;
};
/**
* 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 SharedMemory with a reference
* to the read-only copy of it.
*/
Result<Ok, nsresult> Finalize(RefPtr<mozilla::ipc::SharedMemory>& 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