Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
LayeredDataSource.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cstring>
5#include <limits>
6#include <utility>
7
8namespace monopoly::data
9{
10 namespace
11 {
12 [[nodiscard]] DataError itemError(
13 DataErrorCode code,
14 DataId id,
15 std::string detail)
16 {
17 return {
18 code,
19 {},
20 dataTag(id),
21 std::move(detail)
22 };
23 }
24
25
26 [[nodiscard]] std::expected<std::uint32_t, DataError> checkedSize(
27 DataId id,
29 {
30 if (!bytes)
31 {
32 return std::unexpected(itemError(
34 id,
35 "DATA override payload is null"));
36 }
37
38 if (bytes->size() >
39 static_cast<std::size_t>(
40 std::numeric_limits<std::uint32_t>::max()))
41 {
42 return std::unexpected(itemError(
44 id,
45 "DATA override payload exceeds the 32-bit runtime size"));
46 }
47
48 return static_cast<std::uint32_t>(bytes->size());
49 }
50 }
51
52
53 LayeredDataSource::LayeredDataSource(
54 std::shared_ptr<const DataSource> fallback)
55 : fallback_(std::move(fallback))
56 {
57 }
58
59
60 std::expected<
61 std::shared_ptr<const LayeredDataSource>,
62 DataError>
63 LayeredDataSource::create(
64 std::shared_ptr<const DataSource> fallback,
65 std::span<const DataSourceOverride> overrides)
66 {
67 auto result = std::shared_ptr<LayeredDataSource>(
68 new LayeredDataSource(std::move(fallback)));
69
70 for (const auto& replacement : overrides)
71 {
72 if (isEmptyDataId(replacement.id))
73 {
74 return std::unexpected(itemError(
75 DataErrorCode::EmptyItem,
76 replacement.id,
77 "DATA override cannot replace EmptyDataId"));
78 }
79
80 if (replacement.type == LegacyDataType::Unknown)
81 {
82 return std::unexpected(itemError(
83 DataErrorCode::InvalidItemType,
84 replacement.id,
85 "DATA override requires an explicit runtime type"));
86 }
87
88 const auto size = checkedSize(
89 replacement.id,
90 replacement.bytes);
91 if (!size)
92 {
93 return std::unexpected(size.error());
94 }
95
96 const auto [_, inserted] = result->overrides_.emplace(
97 replacement.id,
98 Item{replacement.type, replacement.bytes});
99 if (!inserted)
100 {
101 return std::unexpected(itemError(
102 DataErrorCode::DuplicateDataId,
103 replacement.id,
104 "DATA override contains the same logical DataId twice"));
105 }
106 }
107
108 return std::shared_ptr<const LayeredDataSource>(
109 std::move(result));
110 }
111
112
113 std::size_t LayeredDataSource::overrideCount() const noexcept
114 {
115 return overrides_.size();
116 }
117
118
119 bool LayeredDataSource::overrides(DataId id) const noexcept
120 {
121 return overrides_.contains(id);
122 }
123
124
125 const LayeredDataSource::Item* LayeredDataSource::find(
126 DataId id) const noexcept
127 {
128 const auto item = overrides_.find(id);
129 return item == overrides_.end() ? nullptr : &item->second;
130 }
131
132
133 DataError LayeredDataSource::missing(DataId id) const
134 {
135 return itemError(
136 DataErrorCode::ResourceNotFound,
137 id,
138 "logical DATA item is absent from the layered source");
139 }
140
141
142 std::expected<ArchiveItemMetadata, DataError>
143 LayeredDataSource::metadata(DataId id) const
144 {
145 if (const auto* item = find(id))
146 {
147 const auto size = checkedSize(id, item->bytes);
148 if (!size) return std::unexpected(size.error());
149 return ArchiveItemMetadata{
150 dataTag(id),
151 item->type,
152 0,
153 *size,
154 *size
155 };
156 }
157
158 if (fallback_) return fallback_->metadata(id);
159 return std::unexpected(missing(id));
160 }
161
162
163 std::expected<LegacyDataType, DataError>
164 LayeredDataSource::initialDataType(DataId id) const
165 {
166 if (const auto* item = find(id)) return item->type;
167 if (fallback_) return fallback_->initialDataType(id);
168 return std::unexpected(missing(id));
169 }
170
171
172 std::expected<std::uint32_t, DataError>
173 LayeredDataSource::initialSize(DataId id) const
174 {
175 if (const auto* item = find(id))
176 return checkedSize(id, item->bytes);
177 if (fallback_) return fallback_->initialSize(id);
178 return std::unexpected(missing(id));
179 }
180
181
182 std::expected<std::uint32_t, DataError>
183 LayeredDataSource::loadedRawSize(DataId id) const
184 {
185 if (const auto* item = find(id))
186 return checkedSize(id, item->bytes);
187 if (fallback_) return fallback_->loadedRawSize(id);
188 return std::unexpected(missing(id));
189 }
190
191
192 std::expected<SharedDataBytes, DataError>
193 LayeredDataSource::load(DataId id) const
194 {
195 if (const auto* item = find(id)) return item->bytes;
196 if (fallback_) return fallback_->load(id);
197 return std::unexpected(missing(id));
198 }
199
200
201 std::expected<std::size_t, DataError>
202 LayeredDataSource::readRaw(
203 DataId id,
204 std::span<std::byte> destination,
205 std::uint32_t startOffset) const
206 {
207 if (const auto* item = find(id))
208 {
209 const auto size = item->bytes->size();
210 const auto start = static_cast<std::size_t>(startOffset);
211 if (destination.empty() || start >= size)
212 return std::size_t{0};
213
214 const auto amount = std::min(
215 destination.size(),
216 size - start);
217 std::memcpy(
218 destination.data(),
219 item->bytes->data() + start,
220 amount);
221 return amount;
222 }
223
224 if (fallback_)
225 return fallback_->readRaw(
226 id,
229 return std::unexpected(missing(id));
230 }
231
232
233 std::expected<bool, DataError>
234 LayeredDataSource::isLoaded(DataId id) const
235 {
236 if (find(id)) return true;
237 if (fallback_) return fallback_->isLoaded(id);
238 return std::unexpected(missing(id));
239 }
240}
std::vector< std::byte > bytes
unsigned index
std::uint32_t DataId
Definition DataBanks.hpp:10
constexpr DataTag dataTag(DataId id) noexcept
Definition DataBanks.hpp:64
std::shared_ptr< const DataBytes > SharedDataBytes
constexpr bool isEmptyDataId(DataId id) noexcept
Definition DataBanks.hpp:83