1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef dom_ipc_SharedPrefMap_h
8 #define dom_ipc_SharedPrefMap_h
10 #include "mozilla/AutoMemMap.h"
11 #include "mozilla/HashFunctions.h"
12 #include "mozilla/Preferences.h"
13 #include "mozilla/Result.h"
14 #include "mozilla/dom/ipc/StringTable.h"
15 #include "nsTHashMap.h"
19 // The approximate number of preferences expected to be in an ordinary
20 // preferences database.
22 // This number is used to determine initial allocation sizes for data structures
23 // when building the shared preference map, and should be slightly higher than
24 // the expected number of preferences in an ordinary database to avoid
25 // unnecessary reallocations/rehashes.
26 constexpr size_t kExpectedPrefCount
= 4000;
28 class SharedPrefMapBuilder
;
30 // This class provides access to a compact, read-only copy of a preference
31 // database, backed by a shared memory buffer which can be shared between
32 // processes. All state data for the database is stored in the shared memory
33 // region, so individual instances require no dynamic memory allocation.
35 // Further, all strings returned from this API are nsLiteralCStrings with
36 // pointers into the shared memory region, which means that they can be copied
37 // into new nsCString instances without additional allocations. For instance,
38 // the following (where `pref` is a Pref object) will not cause any string
39 // copies, memory allocations, or atomic refcount changes:
41 // nsCString prefName(pref.NameString());
43 // whereas if we returned a nsDependentCString or a dynamically allocated
44 // nsCString, it would.
46 // The set of entries is stored in sorted order by preference name, so look-ups
47 // are done by binary search. This means that look-ups have O(log n) complexity,
48 // rather than the O(1) complexity of a dynamic hashtable. Consumers should keep
49 // this in mind when planning their accesses.
51 // Important: The mapped memory created by this class is persistent. Once an
52 // instance has been initialized, the memory that it allocates can never be
53 // freed before process shutdown. Do not use it for short-lived mappings.
55 using FileDescriptor
= mozilla::ipc::FileDescriptor
;
57 friend class SharedPrefMapBuilder
;
59 // Describes a block of memory within the shared memory region.
61 // The byte offset from the start of the shared memory region to the start
64 // The size of the block, in bytes. This is typically used only for bounds
65 // checking in debug builds.
69 // Describes the contents of the shared memory region, which is laid-out as
72 // - The Header struct
74 // - An array of Entry structs with mEntryCount elements, lexicographically
75 // sorted by preference name.
77 // - A set of data blocks, with offsets and sizes described by the DataBlock
78 // entries in the header, described below.
80 // Each entry stores its name string and values as indices into these blocks,
81 // as documented in the Entry struct, but with some important optimizations:
83 // - Boolean values are always stored inline. Both the default and user
84 // values can be retrieved directly from the entry. Other types have only
85 // one value index, and their values appear at the same indices in the
86 // default and user value arrays.
88 // Aside from reducing our memory footprint, this space-efficiency means
89 // that we can fit more entries in the CPU cache at once, and reduces the
90 // number of likely cache misses during lookups.
92 // - Key strings are stored in a separate string table from value strings. As
93 // above, this makes it more likely that the strings we need will be
94 // available in the CPU cache during lookups by not interleaving them with
97 // - Default and user values are stored in separate arrays. Entries with user
98 // values always appear before entries with default values in the value
99 // arrays, and entries without user values do not have entries in the user
100 // array at all. Since the same index is used for both arrays, this means
101 // that entries with a default value but no user value do not allocate any
102 // space to store their user value.
104 // - For preferences with no user value, the entries in the default value are
105 // de-duplicated. All preferences with the same default value (and no user
106 // value) point to the same index in the default value array.
109 // For example, a preference database containing:
111 // +---------+-------------------------------+-------------------------------+
112 // | Name | Default Value | User Value | |
113 // +---------+---------------+---------------+-------------------------------+
114 // | string1 | "meh" | "hem" | |
115 // | string2 | | "b" | |
116 // | string3 | "a" | | |
117 // | string4 | "foo" | | |
118 // | string5 | "foo" | | |
119 // | string6 | "meh" | | |
120 // +---------+---------------+---------------+-------------------------------+
121 // | bool1 | false | true | |
122 // | bool2 | | false | |
123 // | bool3 | true | | |
124 // +---------+---------------+---------------+-------------------------------+
125 // | int1 | 18 | 16 | |
131 // +---------+---------------+---------------+-------------------------------+
133 // Results in a database that looks like:
135 // +-------------------------------------------------------------------------+
137 // +-------------------------------------------------------------------------+
138 // | mEntryCount = 15 |
140 // +-------------------------------------------------------------------------+
142 // +-------------------------------------------------------------------------+
144 // +--------+----------------------------------------------------------------+
145 // | Offset | Value |
146 // +--------+----------------------------------------------------------------+
149 // | 16 | string3\0 |
150 // | 24 | string4\0 |
151 // | 32 | string5\0 |
152 // | 40 | string6\0 |
162 // +--------+----------------------------------------------------------------+
164 // +-------------------------------------------------------------------------+
166 // +---------------------+------+------------+------------+------------------+
167 // | Key[1] | Type | HasDefault | HasUser | Value |
168 // +---------------------+------+------------+------------+------------------+
169 // | K["bool1", 48, 5] | 3 | true | true | { false, true } |
170 // | K["bool2", 54, 5] | 3 | false | true | { 0, false } |
171 // | K["bool3", 60, 5] | 3 | true | false | { true, 0 } |
172 // | K["int1", 66, 4] | 2 | true | true | 0 |
173 // | K["int2", 71, 4] | 2 | false | true | 1 |
174 // | K["int3", 76, 4] | 2 | true | false | 2 |
175 // | K["int4", 81, 4] | 2 | true | false | 3 |
176 // | K["int5", 86, 4] | 2 | true | false | 3 |
177 // | K["int6", 91, 4] | 2 | true | false | 4 |
178 // | K["string1", 0, 6] | 1 | true | true | 0 |
179 // | K["string2", 8, 6] | 1 | false | true | 1 |
180 // | K["string3", 16, 6] | 1 | true | false | 2 |
181 // | K["string4", 24, 6] | 1 | true | false | 3 |
182 // | K["string5", 32, 6] | 1 | true | false | 3 |
183 // | K["string6", 40, 6] | 1 | true | false | 4 |
184 // +---------------------+------+------------+------------+------------------+
185 // | [1]: Encoded as an offset into the key table and a length. Specified |
186 // | as K[string, offset, length] for clarity. |
187 // +-------------------------------------------------------------------------+
189 // +------------------------------------+------------------------------------+
190 // | User integer values | Default integer values |
191 // +-------+----------------------------+-------+----------------------------+
192 // | Index | Contents | Index | Contents |
193 // +-------+----------------------------+-------+----------------------------+
194 // | 0 | 16 | 0 | 18 |
199 // +-------+----------------------------+-------+----------------------------+
200 // | * Note: Tables are laid out sequentially in memory, but displayed |
201 // | here side-by-side for clarity. |
202 // +-------------------------------------------------------------------------+
204 // +------------------------------------+------------------------------------+
205 // | User string values | Default string values |
206 // +-------+----------------------------+-------+----------------------------+
207 // | Index | Contents[1] | Index | Contents[1] |
208 // +-------+----------------------------+-------+----------------------------+
209 // | 0 | V["hem", 0, 3] | 0 | V["meh", 4, 3] |
210 // | 1 | V["b", 8, 1] | 1 | |
211 // | | | 2 | V["a", 10, 1] |
212 // | | | 3 | V["foo", 12, 3] |
213 // | | | 4 | V["meh", 4, 3] |
214 // |-------+----------------------------+-------+----------------------------+
215 // | [1]: Encoded as an offset into the value table and a length. Specified |
216 // | as V[string, offset, length] for clarity. |
217 // +-------------------------------------------------------------------------+
218 // | * Note: Tables are laid out sequentially in memory, but displayed |
219 // | here side-by-side for clarity. |
220 // +-------------------------------------------------------------------------+
222 // +-------------------------------------------------------------------------+
223 // | Value strings: |
224 // +--------+----------------------------------------------------------------+
225 // | Offset | Value |
226 // +--------+----------------------------------------------------------------+
232 // +--------+----------------------------------------------------------------+
234 // The number of entries in this map.
235 uint32_t mEntryCount
;
237 // The StringTable data block for preference name strings, which act as keys
239 DataBlock mKeyStrings
;
241 // The int32_t arrays of user and default int preference values. Entries in
242 // the map store their values as indices into these arrays.
243 DataBlock mUserIntValues
;
244 DataBlock mDefaultIntValues
;
246 // The StringTableEntry arrays of user and default string preference values.
248 // Strings are stored as StringTableEntry structs with character offsets
249 // into the mValueStrings string table and their corresponding lengths.
251 // Entries in the map, likewise, store their string values as indices into
253 DataBlock mUserStringValues
;
254 DataBlock mDefaultStringValues
;
256 // The StringTable data block for string preference values, referenced by
257 // the above two data blocks.
258 DataBlock mValueStrings
;
261 using StringTableEntry
= mozilla::dom::ipc::StringTableEntry
;
263 // Represents a preference value, as either a pair of boolean values, or an
264 // index into one of the above value arrays.
266 Value(bool aDefaultValue
, bool aUserValue
)
267 : mDefaultBool(aDefaultValue
), mUserBool(aUserValue
) {}
269 MOZ_IMPLICIT
Value(uint16_t aIndex
) : mIndex(aIndex
) {}
271 // The index of this entry in the value arrays.
273 // User and default preference values have the same indices in their
274 // respective arrays. However, entries without a user value are not
275 // guaranteed to have space allocated for them in the user value array, and
276 // likewise for preferences without default values in the default value
277 // array. This means that callers must only access value entries for entries
278 // which claim to have a value of that type.
286 // Represents a preference entry in the map, containing its name, type info,
287 // flags, and a reference to its value.
289 // A pointer to the preference name in the KeyTable string table.
290 StringTableEntry mKey
;
292 // The preference's value, either as a pair of booleans, or an index into
293 // the value arrays. Please see the documentation for the Value struct
297 // The preference's type, as a PrefType enum value. This must *never* be
298 // PrefType::None for values in a shared array.
300 // True if the preference has a default value. Callers must not attempt to
301 // access the entry's default value if this is false.
302 uint8_t mHasDefaultValue
: 1;
303 // True if the preference has a user value. Callers must not attempt to
304 // access the entry's user value if this is false.
305 uint8_t mHasUserValue
: 1;
306 // True if the preference is sticky, as defined by the preference service.
307 uint8_t mIsSticky
: 1;
308 // True if the preference is locked, as defined by the preference service.
309 uint8_t mIsLocked
: 1;
310 // True if the preference is sanitized, as defined by the preference
312 uint8_t mIsSanitized
: 1;
313 // True if the preference should be skipped while iterating over the
314 // SharedPrefMap. This is used to internally store Once StaticPrefs.
315 // This property is not visible to users the way sticky and locked are.
316 uint8_t mIsSkippedByIteration
: 1;
320 NS_INLINE_DECL_REFCOUNTING(SharedPrefMap
)
322 // A temporary wrapper class for accessing entries in the array. Instances of
323 // this class are valid as long as SharedPrefMap instance is alive, but
324 // generally should not be stored long term, or allocated on the heap.
326 // The class is implemented as two pointers, one to the SharedPrefMap
327 // instance, and one to the Entry that corresponds to the preference, and is
328 // meant to be cheaply returned by value from preference lookups and
329 // iterators. All property accessors lazily fetch the appropriate values from
330 // the shared memory region.
331 class MOZ_STACK_CLASS Pref final
{
333 const char* Name() const { return mMap
->KeyTable().GetBare(mEntry
->mKey
); }
335 nsCString
NameString() const { return mMap
->KeyTable().Get(mEntry
->mKey
); }
337 PrefType
Type() const {
338 MOZ_ASSERT(PrefType(mEntry
->mType
) != PrefType::None
);
339 return PrefType(mEntry
->mType
);
342 bool HasDefaultValue() const { return mEntry
->mHasDefaultValue
; }
343 bool HasUserValue() const { return mEntry
->mHasUserValue
; }
344 bool IsLocked() const { return mEntry
->mIsLocked
; }
345 bool IsSanitized() const { return mEntry
->mIsSanitized
; }
346 bool IsSticky() const { return mEntry
->mIsSticky
; }
347 bool IsSkippedByIteration() const { return mEntry
->mIsSkippedByIteration
; }
349 bool GetBoolValue(PrefValueKind aKind
= PrefValueKind::User
) const {
350 MOZ_ASSERT(Type() == PrefType::Bool
);
351 MOZ_ASSERT(aKind
== PrefValueKind::Default
? HasDefaultValue()
354 return aKind
== PrefValueKind::Default
? mEntry
->mValue
.mDefaultBool
355 : mEntry
->mValue
.mUserBool
;
358 int32_t GetIntValue(PrefValueKind aKind
= PrefValueKind::User
) const {
359 MOZ_ASSERT(Type() == PrefType::Int
);
360 MOZ_ASSERT(aKind
== PrefValueKind::Default
? HasDefaultValue()
363 return aKind
== PrefValueKind::Default
364 ? mMap
->DefaultIntValues()[mEntry
->mValue
.mIndex
]
365 : mMap
->UserIntValues()[mEntry
->mValue
.mIndex
];
369 const StringTableEntry
& GetStringEntry(PrefValueKind aKind
) const {
370 MOZ_ASSERT(Type() == PrefType::String
);
371 MOZ_ASSERT(aKind
== PrefValueKind::Default
? HasDefaultValue()
374 return aKind
== PrefValueKind::Default
375 ? mMap
->DefaultStringValues()[mEntry
->mValue
.mIndex
]
376 : mMap
->UserStringValues()[mEntry
->mValue
.mIndex
];
380 nsCString
GetStringValue(PrefValueKind aKind
= PrefValueKind::User
) const {
381 return mMap
->ValueTable().Get(GetStringEntry(aKind
));
384 const char* GetBareStringValue(
385 PrefValueKind aKind
= PrefValueKind::User
) const {
386 return mMap
->ValueTable().GetBare(GetStringEntry(aKind
));
389 // Returns the entry's index in the map, as understood by GetKeyAt() and
391 size_t Index() const { return mEntry
- mMap
->Entries().get(); }
393 bool operator==(const Pref
& aPref
) const { return mEntry
== aPref
.mEntry
; }
394 bool operator!=(const Pref
& aPref
) const { return !(*this == aPref
); }
396 // This is odd, but necessary in order for the C++ range iterator protocol
398 Pref
& operator*() { return *this; }
400 // Updates this wrapper to point to the next visible entry in the map. This
401 // should not be attempted unless Index() is less than the map's Count().
405 } while (mEntry
->mIsSkippedByIteration
&& Index() < mMap
->Count());
409 Pref(const Pref
& aPref
) = default;
412 friend class SharedPrefMap
;
414 Pref(const SharedPrefMap
* aPrefMap
, const Entry
* aEntry
)
415 : mMap(aPrefMap
), mEntry(aEntry
) {}
418 const SharedPrefMap
* const mMap
;
422 // Note: These constructors are infallible, because the preference database is
423 // critical to platform functionality, and we cannot operate without it.
424 SharedPrefMap(const FileDescriptor
&, size_t);
425 explicit SharedPrefMap(SharedPrefMapBuilder
&&);
427 // Searches for the given preference in the map, and returns true if it
429 bool Has(const char* aKey
) const;
431 bool Has(const nsCString
& aKey
) const { return Has(aKey
.get()); }
433 // Searches for the given preference in the map, and if it exists, returns
434 // a Some<Pref> containing its details.
435 Maybe
<const Pref
> Get(const char* aKey
) const;
437 Maybe
<const Pref
> Get(const nsCString
& aKey
) const { return Get(aKey
.get()); }
440 // Searches for an entry for the given key. If found, returns true, and
441 // places its index in the entry array in aIndex.
442 bool Find(const char* aKey
, size_t* aIndex
) const;
445 // Returns the number of entries in the map.
446 uint32_t Count() const { return EntryCount(); }
448 // Returns the string entry at the given index. Keys are guaranteed to be
449 // sorted lexicographically.
451 // The given index *must* be less than the value returned by Count().
453 // The returned value is a literal string which references the mapped memory
455 nsCString
GetKeyAt(uint32_t aIndex
) const {
456 MOZ_ASSERT(aIndex
< Count());
457 return KeyTable().Get(Entries()[aIndex
].mKey
);
460 // Returns the value for the entry at the given index.
462 // The given index *must* be less than the value returned by Count().
464 // The returned value is valid for the lifetime of this map instance.
465 const Pref
GetValueAt(uint32_t aIndex
) const {
466 MOZ_ASSERT(aIndex
< Count());
467 return UncheckedGetValueAt(aIndex
);
471 // Returns a wrapper with a pointer to an entry without checking its bounds.
472 // This should only be used by range iterators, to check their end positions.
474 // Note: In debug builds, the RangePtr returned by entries will still assert
475 // that aIndex is no more than 1 past the last element in the array, since it
476 // also takes into account the ranged iteration use case.
477 Pref
UncheckedGetValueAt(uint32_t aIndex
) const {
478 return {this, (Entries() + aIndex
).get()};
482 // C++ range iterator protocol. begin() and end() return references to the
483 // first (non-skippable) and last entries in the array. The begin wrapper
484 // can be incremented until it matches the last element in the array, at which
485 // point it becomes invalid and the iteration is over.
487 for (uint32_t aIndex
= 0; aIndex
< Count(); aIndex
++) {
488 Pref pref
= UncheckedGetValueAt(aIndex
);
489 if (!pref
.IsSkippedByIteration()) {
495 Pref
end() const { return UncheckedGetValueAt(Count()); }
497 // A cosmetic helper for range iteration. Returns a reference value from a
498 // pointer to this instance so that its .begin() and .end() methods can be
499 // accessed in a ranged for loop. `map->Iter()` is equivalent to `*map`, but
500 // makes its purpose slightly clearer.
501 const SharedPrefMap
& Iter() const { return *this; }
503 // Returns a copy of the read-only file descriptor which backs the shared
504 // memory region for this map. The file descriptor may be passed between
505 // processes, and used to construct new instances of SharedPrefMap with
506 // the same data as this instance.
507 FileDescriptor
CloneFileDescriptor() const;
509 // Returns the size of the mapped memory region. This size must be passed to
510 // the constructor when mapping the shared region in another process.
511 size_t MapSize() const { return mMap
.size(); }
514 ~SharedPrefMap() = default;
517 template <typename T
>
518 using StringTable
= mozilla::dom::ipc::StringTable
<T
>;
520 // Type-safe getters for values in the shared memory region:
521 const Header
& GetHeader() const { return mMap
.get
<Header
>()[0]; }
523 RangedPtr
<const Entry
> Entries() const {
524 return {reinterpret_cast<const Entry
*>(&GetHeader() + 1), EntryCount()};
527 uint32_t EntryCount() const { return GetHeader().mEntryCount
; }
529 template <typename T
>
530 RangedPtr
<const T
> GetBlock(const DataBlock
& aBlock
) const {
531 return RangedPtr
<uint8_t>(&mMap
.get
<uint8_t>()[aBlock
.mOffset
],
533 .ReinterpretCast
<const T
>();
536 RangedPtr
<const int32_t> DefaultIntValues() const {
537 return GetBlock
<int32_t>(GetHeader().mDefaultIntValues
);
539 RangedPtr
<const int32_t> UserIntValues() const {
540 return GetBlock
<int32_t>(GetHeader().mUserIntValues
);
543 RangedPtr
<const StringTableEntry
> DefaultStringValues() const {
544 return GetBlock
<StringTableEntry
>(GetHeader().mDefaultStringValues
);
546 RangedPtr
<const StringTableEntry
> UserStringValues() const {
547 return GetBlock
<StringTableEntry
>(GetHeader().mUserStringValues
);
550 StringTable
<nsCString
> KeyTable() const {
551 auto& block
= GetHeader().mKeyStrings
;
552 return {{&mMap
.get
<uint8_t>()[block
.mOffset
], block
.mSize
}};
555 StringTable
<nsCString
> ValueTable() const {
556 auto& block
= GetHeader().mValueStrings
;
557 return {{&mMap
.get
<uint8_t>()[block
.mOffset
], block
.mSize
}};
560 loader::AutoMemMap mMap
;
563 // A helper class which builds the contiguous look-up table used by
564 // SharedPrefMap. Each preference in the final map is added to the builder,
565 // before it is finalized and transformed into a read-only snapshot.
566 class MOZ_RAII SharedPrefMapBuilder
{
568 SharedPrefMapBuilder() = default;
570 // The set of flags for the preference, as documented in SharedPrefMap::Entry.
572 uint8_t mHasDefaultValue
: 1;
573 uint8_t mHasUserValue
: 1;
574 uint8_t mIsSticky
: 1;
575 uint8_t mIsLocked
: 1;
576 uint8_t mIsSanitized
: 1;
577 uint8_t mIsSkippedByIteration
: 1;
580 void Add(const nsCString
& aKey
, const Flags
& aFlags
, bool aDefaultValue
,
583 void Add(const nsCString
& aKey
, const Flags
& aFlags
, int32_t aDefaultValue
,
586 void Add(const nsCString
& aKey
, const Flags
& aFlags
,
587 const nsCString
& aDefaultValue
, const nsCString
& aUserValue
);
589 // Finalizes the binary representation of the map, writes it to a shared
590 // memory region, and then initializes the given AutoMemMap with a reference
591 // to the read-only copy of it.
593 // This should generally not be used directly by callers. The
594 // SharedPrefMapBuilder instance should instead be passed to the SharedPrefMap
595 // constructor as a move reference.
596 Result
<Ok
, nsresult
> Finalize(loader::AutoMemMap
& aMap
);
599 using StringTableEntry
= mozilla::dom::ipc::StringTableEntry
;
600 template <typename T
, typename U
>
601 using StringTableBuilder
= mozilla::dom::ipc::StringTableBuilder
<T
, U
>;
603 // An opaque descriptor of the index of a preference entry in a value array,
604 // which can be converted numeric index after the ValueTableBuilder is
607 // The relative index of the entry, based on its class. Entries for
608 // preferences with user values appear at the value arrays. Entries with
609 // only default values begin after the last entry with a user value.
614 // A helper class for building default and user value arrays for preferences.
616 // As described in the SharedPrefMap class, this helper optimizes the way that
617 // it builds its value arrays, in that:
619 // - It stores value entries for all preferences with user values before
620 // entries for preferences with only default values, and allocates no
621 // entries for preferences with only default values in the user value array.
622 // Since most preferences have only default values, this dramatically
623 // reduces the space required for value storage.
625 // - For preferences with only default values, it de-duplicates value entries,
626 // and returns the same indices for all preferences with the same value.
628 // One important complication of this approach is that it means we cannot know
629 // the final index of any entry with only a default value until all entries
630 // have been added to the builder, since it depends on the final number of
631 // user entries in the output.
633 // To deal with this, when entries are added, we return an opaque ValueIndex
634 // struct, from which we can calculate the final index after the map has been
636 template <typename HashKey
, typename ValueType_
>
637 class ValueTableBuilder
{
639 using ValueType
= ValueType_
;
641 // Adds an entry for a preference with only a default value to the array,
642 // and returns an opaque descriptor for its index.
643 ValueIdx
Add(const ValueType
& aDefaultValue
) {
644 auto index
= uint16_t(mDefaultEntries
.Count());
646 return mDefaultEntries
.WithEntryHandle(aDefaultValue
, [&](auto&& entry
) {
647 entry
.OrInsertWith([&] { return Entry
{index
, false, aDefaultValue
}; });
649 return ValueIdx
{entry
->mIndex
, false};
653 // Adds an entry for a preference with a user value to the array. Regardless
654 // of whether the preference has a default value, space must be allocated
655 // for it. For preferences with no default value, the actual value which
656 // appears in the array at its value index is ignored.
657 ValueIdx
Add(const ValueType
& aDefaultValue
, const ValueType
& aUserValue
) {
658 auto index
= uint16_t(mUserEntries
.Length());
660 mUserEntries
.AppendElement(Entry
{index
, true, aDefaultValue
, aUserValue
});
662 return {index
, true};
665 // Returns the final index for an entry based on its opaque index
666 // descriptor. This must only be called after the caller has finished adding
667 // entries to the builder.
668 uint16_t GetIndex(const ValueIdx
& aIndex
) const {
669 uint16_t base
= aIndex
.mHasUserValue
? 0 : UserCount();
670 return base
+ aIndex
.mIndex
;
673 // Writes out the array of default values at the block beginning at the
674 // given pointer. The block must be at least as large as the value returned
676 void WriteDefaultValues(const RangedPtr
<uint8_t>& aBuffer
) const {
677 auto buffer
= aBuffer
.ReinterpretCast
<ValueType
>();
679 for (const auto& entry
: mUserEntries
) {
680 buffer
[entry
.mIndex
] = entry
.mDefaultValue
;
683 size_t defaultsOffset
= UserCount();
684 for (const auto& data
: mDefaultEntries
.Values()) {
685 buffer
[defaultsOffset
+ data
.mIndex
] = data
.mDefaultValue
;
689 // Writes out the array of user values at the block beginning at the
690 // given pointer. The block must be at least as large as the value returned
692 void WriteUserValues(const RangedPtr
<uint8_t>& aBuffer
) const {
693 auto buffer
= aBuffer
.ReinterpretCast
<ValueType
>();
695 for (const auto& entry
: mUserEntries
) {
696 buffer
[entry
.mIndex
] = entry
.mUserValue
;
700 // These return the number of entries in the default and user value arrays,
702 uint32_t DefaultCount() const {
703 return UserCount() + mDefaultEntries
.Count();
705 uint32_t UserCount() const { return mUserEntries
.Length(); }
707 // These return the byte sizes of the default and user value arrays,
709 uint32_t DefaultSize() const { return DefaultCount() * sizeof(ValueType
); }
710 uint32_t UserSize() const { return UserCount() * sizeof(ValueType
); }
713 mUserEntries
.Clear();
714 mDefaultEntries
.Clear();
717 static constexpr size_t Alignment() { return alignof(ValueType
); }
723 ValueType mDefaultValue
;
724 ValueType mUserValue
{};
727 AutoTArray
<Entry
, 256> mUserEntries
;
729 nsTHashMap
<HashKey
, Entry
> mDefaultEntries
;
732 // A special-purpose string table builder for keys which are already
733 // guaranteed to be unique. Duplicate values will not be detected or
735 template <typename CharType
>
736 class UniqueStringTableBuilder
{
738 using ElemType
= CharType
;
740 explicit UniqueStringTableBuilder(size_t aCapacity
) : mEntries(aCapacity
) {}
742 StringTableEntry
Add(const nsTString
<CharType
>& aKey
) {
743 auto entry
= mEntries
.AppendElement(
744 Entry
{mSize
, uint32_t(aKey
.Length()), aKey
.get()});
746 mSize
+= entry
->mLength
+ 1;
748 return {entry
->mOffset
, entry
->mLength
};
751 void Write(const RangedPtr
<uint8_t>& aBuffer
) {
752 auto buffer
= aBuffer
.ReinterpretCast
<ElemType
>();
754 for (auto& entry
: mEntries
) {
755 memcpy(&buffer
[entry
.mOffset
], entry
.mValue
,
756 sizeof(ElemType
) * (entry
.mLength
+ 1));
760 uint32_t Count() const { return mEntries
.Length(); }
762 uint32_t Size() const { return mSize
* sizeof(ElemType
); }
764 void Clear() { mEntries
.Clear(); }
766 static constexpr size_t Alignment() { return alignof(ElemType
); }
772 const CharType
* mValue
;
775 nsTArray
<Entry
> mEntries
;
779 // A preference value entry, roughly corresponding to the
780 // SharedPrefMap::Value struct, but with a temporary place-holder value rather
781 // than a final value index.
783 Value(bool aDefaultValue
, bool aUserValue
)
784 : mDefaultBool(aDefaultValue
), mUserBool(aUserValue
) {}
786 MOZ_IMPLICIT
Value(const ValueIdx
& aIndex
) : mIndex(aIndex
) {}
788 // For Bool preferences, their default and user bool values.
793 // For Int and String preferences, an opaque descriptor for their entries in
794 // their value arrays. This must be passed to the appropriate
795 // ValueTableBuilder to obtain the final index when the entry is serialized.
799 // A preference entry, to be converted to a SharedPrefMap::Entry struct during
802 // The entry's preference name, as passed to Add(). The caller is
803 // responsible for keeping this pointer alive until the builder is
805 const char* mKeyString
;
806 // The entry in mKeyTable corresponding to mKeyString.
807 StringTableEntry mKey
;
811 uint8_t mHasDefaultValue
: 1;
812 uint8_t mHasUserValue
: 1;
813 uint8_t mIsSticky
: 1;
814 uint8_t mIsLocked
: 1;
815 uint8_t mIsSanitized
: 1;
816 uint8_t mIsSkippedByIteration
: 1;
819 // Converts a builder Value struct to a SharedPrefMap::Value struct for
820 // serialization. This must not be called before callers have finished adding
821 // entries to the value array builders.
822 SharedPrefMap::Value
GetValue(const Entry
& aEntry
) const {
823 switch (PrefType(aEntry
.mType
)) {
825 return {aEntry
.mValue
.mDefaultBool
, aEntry
.mValue
.mUserBool
};
827 return {mIntValueTable
.GetIndex(aEntry
.mValue
.mIndex
)};
828 case PrefType::String
:
829 return {mStringValueTable
.GetIndex(aEntry
.mValue
.mIndex
)};
831 MOZ_ASSERT_UNREACHABLE("Invalid pref type");
832 return {false, false};
836 UniqueStringTableBuilder
<char> mKeyTable
{kExpectedPrefCount
};
837 StringTableBuilder
<nsCStringHashKey
, nsCString
> mValueStringTable
;
839 ValueTableBuilder
<nsUint32HashKey
, uint32_t> mIntValueTable
;
840 ValueTableBuilder
<nsGenericHashKey
<StringTableEntry
>, StringTableEntry
>
843 nsTArray
<Entry
> mEntries
{kExpectedPrefCount
};
846 } // namespace mozilla
848 #endif // dom_ipc_SharedPrefMap_h