Skip to content

Commit bf3eed8

Browse files
committed
Implement call-by-need; tests pass
1 parent 24b9d02 commit bf3eed8

12 files changed

+656
-287
lines changed

icu4c/source/i18n/messageformat2.cpp

Lines changed: 123 additions & 71 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
@@ -133,6 +133,18 @@ namespace message2 {
133133
return result;
134134
}
135135

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

138150
U_NAMESPACE_END

icu4c/source/i18n/messageformat2_evaluation.cpp

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

6868
ResolvedFunctionOption::ResolvedFunctionOption(const UnicodeString& n,
69-
FunctionValue* f) : name(n), value(f) {
70-
U_ASSERT(f != nullptr);
71-
}
69+
const FunctionValue& f) : name(n), value(&f) {}
7270

7371
ResolvedFunctionOption::~ResolvedFunctionOption() {
74-
if (value != nullptr) {
75-
delete value;
76-
value = nullptr;
77-
}
72+
value = nullptr; // value is not owned
7873
}
7974

8075

@@ -100,7 +95,7 @@ FunctionOptions::getFunctionOption(const UnicodeString& key,
10095
for (int32_t i = 0; i < functionOptionsLen; i++) {
10196
const ResolvedFunctionOption& opt = options[i];
10297
if (opt.getName() == key) {
103-
return opt.getValue();
98+
return &opt.getValue();
10499
}
105100
}
106101
status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -130,16 +125,22 @@ UnicodeString FunctionOptions::getStringFunctionOption(const UnicodeString& key)
130125
return result;
131126
}
132127

133-
FunctionOptions& FunctionOptions::operator=(FunctionOptions&& other) noexcept {
134-
functionOptionsLen = other.functionOptionsLen;
135-
options = other.options;
136-
other.functionOptionsLen = 0;
137-
other.options = nullptr;
128+
FunctionOptions& FunctionOptions::operator=(FunctionOptions other) noexcept {
129+
swap(*this, other);
138130
return *this;
139131
}
140132

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

145146
FunctionOptions::~FunctionOptions() {
@@ -160,36 +161,35 @@ static bool containsOption(const UVector& opts, const ResolvedFunctionOption& op
160161
}
161162

162163
// Options in `this` take precedence
163-
// `this` can't be used after mergeOptions is called
164-
FunctionOptions FunctionOptions::mergeOptions(FunctionOptions&& other,
165-
UErrorCode& status) {
164+
FunctionOptions FunctionOptions::mergeOptions(const FunctionOptions& other,
165+
UErrorCode& status) const {
166166
UVector mergedOptions(status);
167167
mergedOptions.setDeleter(uprv_deleteUObject);
168168

169169
if (U_FAILURE(status)) {
170170
return {};
171171
}
172+
if (bogus || other.bogus) {
173+
status = U_MEMORY_ALLOCATION_ERROR;
174+
return {};
175+
}
172176

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

179183
// Add each option from `other` that doesn't appear in this `FunctionOptions`
180184
for (int i = 0; i < other.functionOptionsLen; i++) {
181185
// Note: this is quadratic in the length of `options`
182186
if (!containsOption(mergedOptions, other.options[i])) {
183-
mergedOptions.adoptElement(create<ResolvedFunctionOption>(std::move(other.options[i]),
184-
status),
187+
mergedOptions.adoptElement(create<ResolvedFunctionOption>(other.options[i],
188+
status),
185189
status);
186190
}
187191
}
188192

189-
delete[] options;
190-
options = nullptr;
191-
functionOptionsLen = 0;
192-
193193
return FunctionOptions(std::move(mergedOptions), status);
194194
}
195195

@@ -200,12 +200,8 @@ FunctionOptions FunctionOptions::mergeOptions(FunctionOptions&& other,
200200
InternalValue::~InternalValue() {}
201201

202202
InternalValue& InternalValue::operator=(InternalValue&& other) {
203-
isFallbackValue = other.isFallbackValue;
204203
fallbackString = other.fallbackString;
205-
if (!isFallbackValue) {
206-
U_ASSERT(other.val.isValid());
207-
val.adoptInstead(other.val.orphan());
208-
}
204+
val = std::move(other.val);
209205
return *this;
210206
}
211207

@@ -216,48 +212,109 @@ InternalValue::InternalValue(InternalValue&& other) {
216212
InternalValue::InternalValue(UErrorCode& errorCode) {
217213
CHECK_ERROR(errorCode);
218214

219-
NullValue* nv = new NullValue();
220-
if (nv == nullptr) {
215+
LocalPointer<FunctionValue> nv(new NullValue());
216+
if (!nv.isValid()) {
221217
errorCode = U_MEMORY_ALLOCATION_ERROR;
222218
return;
223219
}
224-
val.adoptInstead(nv);
220+
val = std::move(nv);
225221
}
226222

227223
InternalValue::InternalValue(FunctionValue* v, const UnicodeString& fb)
228-
: fallbackString(fb), val(v) {
224+
: fallbackString(fb) {
229225
U_ASSERT(v != nullptr);
226+
val = LocalPointer<FunctionValue>(v);
230227
}
231228

232-
FunctionValue* InternalValue::takeValue(UErrorCode& status) {
229+
const FunctionValue* InternalValue::getValue(UErrorCode& status) const {
233230
if (U_FAILURE(status)) {
234-
return {};
231+
return nullptr;
235232
}
236-
if (isFallback()) {
233+
// If this is a closure or fallback, error out
234+
if (!isEvaluated()) {
237235
status = U_ILLEGAL_ARGUMENT_ERROR;
238-
return {};
236+
return nullptr;
237+
}
238+
// Follow the indirection to get the value
239+
if (isIndirection()) {
240+
const InternalValue* other = *std::get_if<const InternalValue*>(&val);
241+
U_ASSERT(other != nullptr);
242+
return other->getValue(status);
243+
}
244+
// Otherwise, return the contained FunctionValue
245+
const LocalPointer<FunctionValue>* result = std::get_if<LocalPointer<FunctionValue>>(&val);
246+
U_ASSERT(result->isValid());
247+
return (*result).getAlias();
248+
}
249+
250+
bool InternalValue::isSelectable() const {
251+
UErrorCode localStatus = U_ZERO_ERROR;
252+
const FunctionValue* val = getValue(localStatus);
253+
if (U_FAILURE(localStatus)) {
254+
return false;
239255
}
240-
U_ASSERT(val.isValid());
241-
return val.orphan();
256+
return val->isSelectable();
242257
}
243258

244-
const FunctionValue* InternalValue::getValue(UErrorCode& status) const {
245-
if (U_FAILURE(status)) {
246-
return {};
259+
/* static */ LocalPointer<InternalValue> InternalValue::null(UErrorCode& status) {
260+
if (U_SUCCESS(status)) {
261+
InternalValue* result = new InternalValue(status);
262+
if (U_SUCCESS(status)) {
263+
return LocalPointer<InternalValue>(result);
264+
}
247265
}
248-
if (isFallback()) {
249-
status = U_ILLEGAL_ARGUMENT_ERROR;
250-
return {};
266+
return LocalPointer<InternalValue>();
267+
}
268+
269+
/* static */ LocalPointer<InternalValue> InternalValue::fallback(const UnicodeString& s,
270+
UErrorCode& status) {
271+
if (U_SUCCESS(status)) {
272+
InternalValue* result = new InternalValue(s);
273+
if (U_SUCCESS(status)) {
274+
return LocalPointer<InternalValue>(result);
275+
}
251276
}
252-
U_ASSERT(val.isValid());
253-
return val.getAlias();
277+
return LocalPointer<InternalValue>();
254278
}
255279

256-
bool InternalValue::isSelectable() const {
257-
if (isFallbackValue) {
280+
/* static */ InternalValue InternalValue::closure(Closure* c, const UnicodeString& fb) {
281+
U_ASSERT(c != nullptr);
282+
return InternalValue(c, fb);
283+
}
284+
285+
bool InternalValue::isClosure() const {
286+
return std::holds_alternative<LocalPointer<Closure>>(val);
287+
}
288+
289+
bool InternalValue::isEvaluated() const {
290+
return std::holds_alternative<LocalPointer<FunctionValue>>(val) || isIndirection();
291+
}
292+
293+
bool InternalValue::isIndirection() const {
294+
return std::holds_alternative<const InternalValue*>(val);
295+
}
296+
297+
bool InternalValue::isNullOperand() const {
298+
UErrorCode localStatus = U_ZERO_ERROR;
299+
const FunctionValue* val = getValue(localStatus);
300+
if (U_FAILURE(localStatus)) {
258301
return false;
259302
}
260-
return val->isSelectable();
303+
return val->isNullOperand();
304+
}
305+
306+
void InternalValue::update(InternalValue& newVal) {
307+
fallbackString = newVal.fallbackString;
308+
val = &newVal;
309+
}
310+
311+
void InternalValue::update(LocalPointer<FunctionValue> newVal) {
312+
val = std::move(newVal);
313+
}
314+
315+
void InternalValue::update(const UnicodeString& fb) {
316+
fallbackString = fb;
317+
val = fb;
261318
}
262319

263320
// PrioritizedVariant
@@ -274,9 +331,11 @@ PrioritizedVariant::~PrioritizedVariant() {}
274331

275332
// ---------------- Environments and closures
276333

277-
Environment* Environment::create(const VariableName& var, Closure&& c, Environment* parent, UErrorCode& errorCode) {
334+
Environment* Environment::create(const VariableName& var, Closure* c,
335+
const UnicodeString& fallbackStr,
336+
Environment* parent, UErrorCode& errorCode) {
278337
NULL_ON_ERROR(errorCode);
279-
Environment* result = new NonEmptyEnvironment(var, std::move(c), parent);
338+
Environment* result = new NonEmptyEnvironment(var, InternalValue::closure(c, fallbackStr), parent);
280339
if (result == nullptr) {
281340
errorCode = U_MEMORY_ALLOCATION_ERROR;
282341
return nullptr;
@@ -286,21 +345,20 @@ PrioritizedVariant::~PrioritizedVariant() {}
286345

287346
Environment* Environment::create(UErrorCode& errorCode) {
288347
NULL_ON_ERROR(errorCode);
289-
Environment* result = new EmptyEnvironment();
290-
if (result == nullptr) {
348+
Environment* result = new EmptyEnvironment(errorCode);
349+
if (U_SUCCESS(errorCode) && result == nullptr) {
291350
errorCode = U_MEMORY_ALLOCATION_ERROR;
292351
return nullptr;
293352
}
294353
return result;
295354
}
296355

297-
const Closure& EmptyEnvironment::lookup(const VariableName& v) const {
298-
(void) v;
356+
InternalValue& EmptyEnvironment::lookup(const VariableName&) {
299357
U_ASSERT(false);
300358
UPRV_UNREACHABLE_EXIT;
301359
}
302360

303-
const Closure& NonEmptyEnvironment::lookup(const VariableName& v) const {
361+
InternalValue& NonEmptyEnvironment::lookup(const VariableName& v) {
304362
if (v == var) {
305363
return rhs;
306364
}
@@ -319,10 +377,75 @@ PrioritizedVariant::~PrioritizedVariant() {}
319377
return parent->has(v);
320378
}
321379

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

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

328451
// MessageContext methods

0 commit comments

Comments
 (0)