Bug 1837643 [wpt PR 40475] - [RemoveLegacy] GridTrackList::legacy_track_list_, a...
[gecko.git] / modules / libpref / SharedPrefMap.cpp
blob81f8d92485376575be9e6f5239f62935d2860a77
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 #include "SharedPrefMap.h"
9 #include "mozilla/dom/ipc/MemMapSnapshot.h"
11 #include "mozilla/BinarySearch.h"
12 #include "mozilla/ResultExtensions.h"
13 #include "mozilla/ipc/FileDescriptor.h"
15 using namespace mozilla::loader;
17 namespace mozilla {
19 using namespace ipc;
21 static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) {
22 auto mod = aOffset % aAlign;
23 return mod ? aAlign - mod : 0;
26 SharedPrefMap::SharedPrefMap(const FileDescriptor& aMapFile, size_t aMapSize) {
27 auto result = mMap.initWithHandle(aMapFile, aMapSize);
28 MOZ_RELEASE_ASSERT(result.isOk());
29 // We return literal nsCStrings pointing to the mapped data for preference
30 // names and string values, which means that we may still have references to
31 // the mapped data even after this instance is destroyed. That means that we
32 // need to keep the mapping alive until process shutdown, in order to be safe.
33 mMap.setPersistent();
36 SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) {
37 auto result = aBuilder.Finalize(mMap);
38 MOZ_RELEASE_ASSERT(result.isOk());
39 mMap.setPersistent();
42 mozilla::ipc::FileDescriptor SharedPrefMap::CloneFileDescriptor() const {
43 return mMap.cloneHandle();
46 bool SharedPrefMap::Has(const char* aKey) const {
47 size_t index;
48 return Find(aKey, &index);
51 Maybe<const SharedPrefMap::Pref> SharedPrefMap::Get(const char* aKey) const {
52 Maybe<const Pref> result;
54 size_t index;
55 if (Find(aKey, &index)) {
56 result.emplace(Pref{this, &Entries()[index]});
59 return result;
62 bool SharedPrefMap::Find(const char* aKey, size_t* aIndex) const {
63 const auto& keys = KeyTable();
65 return BinarySearchIf(
66 Entries(), 0, EntryCount(),
67 [&](const Entry& aEntry) {
68 return strcmp(aKey, keys.GetBare(aEntry.mKey));
70 aIndex);
73 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
74 bool aDefaultValue, bool aUserValue) {
75 mEntries.AppendElement(Entry{
76 aKey.get(),
77 mKeyTable.Add(aKey),
78 {aDefaultValue, aUserValue},
79 uint8_t(PrefType::Bool),
80 aFlags.mHasDefaultValue,
81 aFlags.mHasUserValue,
82 aFlags.mIsSticky,
83 aFlags.mIsLocked,
84 aFlags.mIsSanitized,
85 aFlags.mIsSkippedByIteration,
86 });
89 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
90 int32_t aDefaultValue, int32_t aUserValue) {
91 ValueIdx index;
92 if (aFlags.mHasUserValue) {
93 index = mIntValueTable.Add(aDefaultValue, aUserValue);
94 } else {
95 index = mIntValueTable.Add(aDefaultValue);
98 mEntries.AppendElement(Entry{
99 aKey.get(),
100 mKeyTable.Add(aKey),
101 {index},
102 uint8_t(PrefType::Int),
103 aFlags.mHasDefaultValue,
104 aFlags.mHasUserValue,
105 aFlags.mIsSticky,
106 aFlags.mIsLocked,
107 aFlags.mIsSanitized,
108 aFlags.mIsSkippedByIteration,
112 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
113 const nsCString& aDefaultValue,
114 const nsCString& aUserValue) {
115 ValueIdx index;
116 StringTableEntry defaultVal = mValueStringTable.Add(aDefaultValue);
117 if (aFlags.mHasUserValue) {
118 StringTableEntry userVal = mValueStringTable.Add(aUserValue);
119 index = mStringValueTable.Add(defaultVal, userVal);
120 } else {
121 index = mStringValueTable.Add(defaultVal);
124 mEntries.AppendElement(Entry{
125 aKey.get(),
126 mKeyTable.Add(aKey),
127 {index},
128 uint8_t(PrefType::String),
129 aFlags.mHasDefaultValue,
130 aFlags.mHasUserValue,
131 aFlags.mIsSticky,
132 aFlags.mIsLocked,
133 aFlags.mIsSanitized,
134 aFlags.mIsSkippedByIteration,
138 Result<Ok, nsresult> SharedPrefMapBuilder::Finalize(loader::AutoMemMap& aMap) {
139 using Header = SharedPrefMap::Header;
141 // Create an array of entry pointers for the entry array, and sort it by
142 // preference name prior to serialization, so that entries can be looked up
143 // using binary search.
144 nsTArray<Entry*> entries(mEntries.Length());
145 for (auto& entry : mEntries) {
146 entries.AppendElement(&entry);
148 entries.Sort([](const Entry* aA, const Entry* aB) {
149 return strcmp(aA->mKeyString, aB->mKeyString);
152 Header header = {uint32_t(entries.Length())};
154 size_t offset = sizeof(header);
155 offset += GetAlignmentOffset(offset, alignof(Header));
157 offset += entries.Length() * sizeof(SharedPrefMap::Entry);
159 header.mKeyStrings.mOffset = offset;
160 header.mKeyStrings.mSize = mKeyTable.Size();
161 offset += header.mKeyStrings.mSize;
163 offset += GetAlignmentOffset(offset, mIntValueTable.Alignment());
164 header.mUserIntValues.mOffset = offset;
165 header.mUserIntValues.mSize = mIntValueTable.UserSize();
166 offset += header.mUserIntValues.mSize;
168 offset += GetAlignmentOffset(offset, mIntValueTable.Alignment());
169 header.mDefaultIntValues.mOffset = offset;
170 header.mDefaultIntValues.mSize = mIntValueTable.DefaultSize();
171 offset += header.mDefaultIntValues.mSize;
173 offset += GetAlignmentOffset(offset, mStringValueTable.Alignment());
174 header.mUserStringValues.mOffset = offset;
175 header.mUserStringValues.mSize = mStringValueTable.UserSize();
176 offset += header.mUserStringValues.mSize;
178 offset += GetAlignmentOffset(offset, mStringValueTable.Alignment());
179 header.mDefaultStringValues.mOffset = offset;
180 header.mDefaultStringValues.mSize = mStringValueTable.DefaultSize();
181 offset += header.mDefaultStringValues.mSize;
183 header.mValueStrings.mOffset = offset;
184 header.mValueStrings.mSize = mValueStringTable.Size();
185 offset += header.mValueStrings.mSize;
187 MemMapSnapshot mem;
188 MOZ_TRY(mem.Init(offset));
190 auto headerPtr = mem.Get<Header>();
191 headerPtr[0] = header;
193 auto* entryPtr = reinterpret_cast<SharedPrefMap::Entry*>(&headerPtr[1]);
194 for (auto* entry : entries) {
195 *entryPtr = {
196 entry->mKey,
197 GetValue(*entry),
198 entry->mType,
199 entry->mHasDefaultValue,
200 entry->mHasUserValue,
201 entry->mIsSticky,
202 entry->mIsLocked,
203 entry->mIsSanitized,
204 entry->mIsSkippedByIteration,
206 entryPtr++;
209 auto ptr = mem.Get<uint8_t>();
211 mKeyTable.Write({&ptr[header.mKeyStrings.mOffset], header.mKeyStrings.mSize});
213 mValueStringTable.Write(
214 {&ptr[header.mValueStrings.mOffset], header.mValueStrings.mSize});
216 mIntValueTable.WriteDefaultValues(
217 {&ptr[header.mDefaultIntValues.mOffset], header.mDefaultIntValues.mSize});
218 mIntValueTable.WriteUserValues(
219 {&ptr[header.mUserIntValues.mOffset], header.mUserIntValues.mSize});
221 mStringValueTable.WriteDefaultValues(
222 {&ptr[header.mDefaultStringValues.mOffset],
223 header.mDefaultStringValues.mSize});
224 mStringValueTable.WriteUserValues(
225 {&ptr[header.mUserStringValues.mOffset], header.mUserStringValues.mSize});
227 mKeyTable.Clear();
228 mValueStringTable.Clear();
229 mIntValueTable.Clear();
230 mStringValueTable.Clear();
231 mEntries.Clear();
233 return mem.Finalize(aMap);
236 } // namespace mozilla