Skip to content

Commit 5343da5

Browse files
committed
Implement call-by-need; tests pass
1 parent e15e62b commit 5343da5

12 files changed

+651
-280
lines changed

icu4c/source/i18n/messageformat2.cpp

Lines changed: 118 additions & 64 deletions
Large diffs are not rendered by default.

icu4c/source/i18n/messageformat2_allocation.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ namespace message2 {
131131
return result;
132132
}
133133

134+
template<typename T>
135+
inline T* create(const T& node, UErrorCode& status) {
136+
if (U_FAILURE(status)) {
137+
return nullptr;
138+
}
139+
T* result = new T(node);
140+
if (result == nullptr) {
141+
status = U_MEMORY_ALLOCATION_ERROR;
142+
}
143+
return result;
144+
}
145+
134146
} // namespace message2
135147

136148
U_NAMESPACE_END

icu4c/source/i18n/messageformat2_evaluation.cpp

Lines changed: 181 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,10 @@ ResolvedFunctionOption::ResolvedFunctionOption(ResolvedFunctionOption&& other) {
6464
}
6565

6666
ResolvedFunctionOption::ResolvedFunctionOption(const UnicodeString& n,
67-
FunctionValue* f) : name(n), value(f) {
68-
U_ASSERT(f != nullptr);
69-
}
67+
const FunctionValue& f) : name(n), value(&f) {}
7068

7169
ResolvedFunctionOption::~ResolvedFunctionOption() {
72-
if (value != nullptr) {
73-
delete value;
74-
value = nullptr;
75-
}
70+
value = nullptr; // value is not owned
7671
}
7772

7873

@@ -98,7 +93,7 @@ FunctionOptions::getFunctionOption(const UnicodeString& key,
9893
for (int32_t i = 0; i < functionOptionsLen; i++) {
9994
const ResolvedFunctionOption& opt = options[i];
10095
if (opt.getName() == key) {
101-
return opt.getValue();
96+
return &opt.getValue();
10297
}
10398
}
10499
status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -128,16 +123,22 @@ UnicodeString FunctionOptions::getStringFunctionOption(const UnicodeString& key)
128123
return result;
129124
}
130125

131-
FunctionOptions& FunctionOptions::operator=(FunctionOptions&& other) noexcept {
132-
functionOptionsLen = other.functionOptionsLen;
133-
options = other.options;
134-
other.functionOptionsLen = 0;
135-
other.options = nullptr;
126+
FunctionOptions& FunctionOptions::operator=(FunctionOptions other) noexcept {
127+
swap(*this, other);
136128
return *this;
137129
}
138130

139-
FunctionOptions::FunctionOptions(FunctionOptions&& other) {
140-
*this = std::move(other);
131+
FunctionOptions::FunctionOptions(const FunctionOptions& other) {
132+
U_ASSERT(!other.bogus);
133+
functionOptionsLen = other.functionOptionsLen;
134+
options = nullptr;
135+
if (functionOptionsLen != 0) {
136+
UErrorCode localStatus = U_ZERO_ERROR;
137+
options = copyArray<ResolvedFunctionOption>(other.options, functionOptionsLen, localStatus);
138+
if (U_FAILURE(localStatus)) {
139+
bogus = true;
140+
}
141+
}
141142
}
142143

143144
FunctionOptions::~FunctionOptions() {
@@ -158,36 +159,35 @@ static bool containsOption(const UVector& opts, const ResolvedFunctionOption& op
158159
}
159160

160161
// Options in `this` take precedence
161-
// `this` can't be used after mergeOptions is called
162-
FunctionOptions FunctionOptions::mergeOptions(FunctionOptions&& other,
163-
UErrorCode& status) {
162+
FunctionOptions FunctionOptions::mergeOptions(const FunctionOptions& other,
163+
UErrorCode& status) const {
164164
UVector mergedOptions(status);
165165
mergedOptions.setDeleter(uprv_deleteUObject);
166166

167167
if (U_FAILURE(status)) {
168168
return {};
169169
}
170+
if (bogus || other.bogus) {
171+
status = U_MEMORY_ALLOCATION_ERROR;
172+
return {};
173+
}
170174

171175
// Create a new vector consisting of the options from this `FunctionOptions`
172176
for (int32_t i = 0; i < functionOptionsLen; i++) {
173-
mergedOptions.adoptElement(create<ResolvedFunctionOption>(std::move(options[i]), status),
177+
mergedOptions.adoptElement(create<ResolvedFunctionOption>(options[i], status),
174178
status);
175179
}
176180

177181
// Add each option from `other` that doesn't appear in this `FunctionOptions`
178182
for (int i = 0; i < other.functionOptionsLen; i++) {
179183
// Note: this is quadratic in the length of `options`
180184
if (!containsOption(mergedOptions, other.options[i])) {
181-
mergedOptions.adoptElement(create<ResolvedFunctionOption>(std::move(other.options[i]),
182-
status),
185+
mergedOptions.adoptElement(create<ResolvedFunctionOption>(other.options[i],
186+
status),
183187
status);
184188
}
185189
}
186190

187-
delete[] options;
188-
options = nullptr;
189-
functionOptionsLen = 0;
190-
191191
return FunctionOptions(std::move(mergedOptions), status);
192192
}
193193

@@ -198,12 +198,8 @@ FunctionOptions FunctionOptions::mergeOptions(FunctionOptions&& other,
198198
InternalValue::~InternalValue() {}
199199

200200
InternalValue& InternalValue::operator=(InternalValue&& other) {
201-
isFallbackValue = other.isFallbackValue;
202201
fallbackString = other.fallbackString;
203-
if (!isFallbackValue) {
204-
U_ASSERT(other.val.isValid());
205-
val.adoptInstead(other.val.orphan());
206-
}
202+
val = std::move(other.val);
207203
return *this;
208204
}
209205

@@ -214,48 +210,109 @@ InternalValue::InternalValue(InternalValue&& other) {
214210
InternalValue::InternalValue(UErrorCode& errorCode) {
215211
CHECK_ERROR(errorCode);
216212

217-
NullValue* nv = new NullValue();
218-
if (nv == nullptr) {
213+
LocalPointer<FunctionValue> nv(new NullValue());
214+
if (!nv.isValid()) {
219215
errorCode = U_MEMORY_ALLOCATION_ERROR;
220216
return;
221217
}
222-
val.adoptInstead(nv);
218+
val = std::move(nv);
223219
}
224220

225221
InternalValue::InternalValue(FunctionValue* v, const UnicodeString& fb)
226-
: fallbackString(fb), val(v) {
222+
: fallbackString(fb) {
227223
U_ASSERT(v != nullptr);
224+
val = LocalPointer<FunctionValue>(v);
228225
}
229226

230-
FunctionValue* InternalValue::takeValue(UErrorCode& status) {
227+
const FunctionValue* InternalValue::getValue(UErrorCode& status) const {
231228
if (U_FAILURE(status)) {
232-
return {};
229+
return nullptr;
233230
}
234-
if (isFallback()) {
231+
// If this is a closure or fallback, error out
232+
if (!isEvaluated()) {
235233
status = U_ILLEGAL_ARGUMENT_ERROR;
236-
return {};
234+
return nullptr;
237235
}
238-
U_ASSERT(val.isValid());
239-
return val.orphan();
236+
// Follow the indirection to get the value
237+
if (isIndirection()) {
238+
const InternalValue* other = *std::get_if<const InternalValue*>(&val);
239+
U_ASSERT(other != nullptr);
240+
return other->getValue(status);
241+
}
242+
// Otherwise, return the contained FunctionValue
243+
const LocalPointer<FunctionValue>* result = std::get_if<LocalPointer<FunctionValue>>(&val);
244+
U_ASSERT(result->isValid());
245+
return (*result).getAlias();
240246
}
241247

242-
const FunctionValue* InternalValue::getValue(UErrorCode& status) const {
243-
if (U_FAILURE(status)) {
244-
return {};
248+
bool InternalValue::isSelectable() const {
249+
UErrorCode localStatus = U_ZERO_ERROR;
250+
const FunctionValue* val = getValue(localStatus);
251+
if (U_FAILURE(localStatus)) {
252+
return false;
245253
}
246-
if (isFallback()) {
247-
status = U_ILLEGAL_ARGUMENT_ERROR;
248-
return {};
254+
return val->isSelectable();
255+
}
256+
257+
/* static */ LocalPointer<InternalValue> InternalValue::null(UErrorCode& status) {
258+
if (U_SUCCESS(status)) {
259+
InternalValue* result = new InternalValue(status);
260+
if (U_SUCCESS(status)) {
261+
return LocalPointer<InternalValue>(result);
262+
}
249263
}
250-
U_ASSERT(val.isValid());
251-
return val.getAlias();
264+
return LocalPointer<InternalValue>();
252265
}
253266

254-
bool InternalValue::isSelectable() const {
255-
if (isFallbackValue) {
267+
/* static */ LocalPointer<InternalValue> InternalValue::fallback(const UnicodeString& s,
268+
UErrorCode& status) {
269+
if (U_SUCCESS(status)) {
270+
InternalValue* result = new InternalValue(s);
271+
if (U_SUCCESS(status)) {
272+
return LocalPointer<InternalValue>(result);
273+
}
274+
}
275+
return LocalPointer<InternalValue>();
276+
}
277+
278+
/* static */ InternalValue InternalValue::closure(Closure* c, const UnicodeString& fb) {
279+
U_ASSERT(c != nullptr);
280+
return InternalValue(c, fb);
281+
}
282+
283+
bool InternalValue::isClosure() const {
284+
return std::holds_alternative<LocalPointer<Closure>>(val);
285+
}
286+
287+
bool InternalValue::isEvaluated() const {
288+
return std::holds_alternative<LocalPointer<FunctionValue>>(val) || isIndirection();
289+
}
290+
291+
bool InternalValue::isIndirection() const {
292+
return std::holds_alternative<const InternalValue*>(val);
293+
}
294+
295+
bool InternalValue::isNullOperand() const {
296+
UErrorCode localStatus = U_ZERO_ERROR;
297+
const FunctionValue* val = getValue(localStatus);
298+
if (U_FAILURE(localStatus)) {
256299
return false;
257300
}
258-
return val->isSelectable();
301+
return val->isNullOperand();
302+
}
303+
304+
void InternalValue::update(InternalValue& newVal) {
305+
fallbackString = newVal.fallbackString;
306+
val = &newVal;
307+
}
308+
309+
void InternalValue::update(LocalPointer<FunctionValue> newVal) {
310+
val = std::move(newVal);
311+
}
312+
313+
void InternalValue::update(const UnicodeString& fb) {
314+
fallbackString = fb;
315+
val = fb;
259316
}
260317

261318
// PrioritizedVariant
@@ -272,9 +329,11 @@ PrioritizedVariant::~PrioritizedVariant() {}
272329

273330
// ---------------- Environments and closures
274331

275-
Environment* Environment::create(const VariableName& var, Closure&& c, Environment* parent, UErrorCode& errorCode) {
332+
Environment* Environment::create(const VariableName& var, Closure* c,
333+
const UnicodeString& fallbackStr,
334+
Environment* parent, UErrorCode& errorCode) {
276335
NULL_ON_ERROR(errorCode);
277-
Environment* result = new NonEmptyEnvironment(var, std::move(c), parent);
336+
Environment* result = new NonEmptyEnvironment(var, InternalValue::closure(c, fallbackStr), parent);
278337
if (result == nullptr) {
279338
errorCode = U_MEMORY_ALLOCATION_ERROR;
280339
return nullptr;
@@ -284,21 +343,20 @@ PrioritizedVariant::~PrioritizedVariant() {}
284343

285344
Environment* Environment::create(UErrorCode& errorCode) {
286345
NULL_ON_ERROR(errorCode);
287-
Environment* result = new EmptyEnvironment();
288-
if (result == nullptr) {
346+
Environment* result = new EmptyEnvironment(errorCode);
347+
if (U_SUCCESS(errorCode) && result == nullptr) {
289348
errorCode = U_MEMORY_ALLOCATION_ERROR;
290349
return nullptr;
291350
}
292351
return result;
293352
}
294353

295-
const Closure& EmptyEnvironment::lookup(const VariableName& v) const {
296-
(void) v;
354+
InternalValue& EmptyEnvironment::lookup(const VariableName&) {
297355
U_ASSERT(false);
298356
UPRV_UNREACHABLE_EXIT;
299357
}
300358

301-
const Closure& NonEmptyEnvironment::lookup(const VariableName& v) const {
359+
InternalValue& NonEmptyEnvironment::lookup(const VariableName& v) {
302360
if (v == var) {
303361
return rhs;
304362
}
@@ -317,10 +375,75 @@ PrioritizedVariant::~PrioritizedVariant() {}
317375
return parent->has(v);
318376
}
319377

378+
InternalValue& EmptyEnvironment::createNull(UErrorCode& status) {
379+
if (U_FAILURE(status)) {
380+
return bogus();
381+
}
382+
LocalPointer<InternalValue> val(InternalValue::null(status));
383+
return addUnnamedValue(std::move(val), status);
384+
}
385+
386+
InternalValue& EmptyEnvironment::createFallback(const UnicodeString& s, UErrorCode& status) {
387+
if (U_FAILURE(status)) {
388+
return bogus();
389+
}
390+
LocalPointer<InternalValue> val(InternalValue::fallback(s, status));
391+
return addUnnamedValue(std::move(val), status);
392+
}
393+
394+
InternalValue& EmptyEnvironment::createUnnamed(InternalValue&& v, UErrorCode& status) {
395+
if (U_FAILURE(status)) {
396+
return bogus();
397+
}
398+
LocalPointer<InternalValue> val(new InternalValue(std::move(v)));
399+
if (!val.isValid()) {
400+
return bogus();
401+
}
402+
return addUnnamedValue(std::move(val), status);
403+
}
404+
405+
InternalValue& NonEmptyEnvironment::createNull(UErrorCode& status) {
406+
return parent->createNull(status);
407+
}
408+
409+
InternalValue& NonEmptyEnvironment::createFallback(const UnicodeString& s, UErrorCode& status) {
410+
return parent->createFallback(s, status);
411+
}
412+
413+
InternalValue& NonEmptyEnvironment::createUnnamed(InternalValue&& v, UErrorCode& status) {
414+
return parent->createUnnamed(std::move(v), status);
415+
}
416+
417+
InternalValue& EmptyEnvironment::addUnnamedValue(LocalPointer<InternalValue> val,
418+
UErrorCode& status) {
419+
if (U_FAILURE(status)) {
420+
return bogus();
421+
}
422+
U_ASSERT(val.isValid());
423+
InternalValue* v = val.orphan();
424+
unnamedValues.adoptElement(v, status);
425+
return *v;
426+
}
427+
428+
EmptyEnvironment::EmptyEnvironment(UErrorCode& status) : unnamedValues(UVector(status)) {
429+
unnamedValues.setDeleter(uprv_deleteUObject);
430+
}
431+
320432
Environment::~Environment() {}
321433
NonEmptyEnvironment::~NonEmptyEnvironment() {}
322434
EmptyEnvironment::~EmptyEnvironment() {}
323435

436+
/* static */ Closure* Closure::create(const Expression& expr, Environment& env,
437+
UErrorCode& status) {
438+
NULL_ON_ERROR(status);
439+
440+
Closure* result = new Closure(expr, env);
441+
if (result == nullptr) {
442+
status = U_MEMORY_ALLOCATION_ERROR;
443+
}
444+
return result;
445+
}
446+
324447
Closure::~Closure() {}
325448

326449
// MessageContext methods

0 commit comments

Comments
 (0)