template <typename T, typename Context>
void processKeyWithDefault(const char *Key, Optional<T> &Val,
const Optional<T> &DefaultValue, bool Required,
- Context &Ctx) {
- assert(DefaultValue.hasValue() == false &&
- "Optional<T> shouldn't have a value!");
- void *SaveInfo;
- bool UseDefault = true;
- const bool sameAsDefault = outputting() && !Val.hasValue();
- if (!outputting() && !Val.hasValue())
- Val = T();
- if (Val.hasValue() &&
- this->preflightKey(Key, Required, sameAsDefault, UseDefault,
- SaveInfo)) {
- yamlize(*this, Val.getValue(), Required, Ctx);
- this->postflightKey(SaveInfo);
- } else {
- if (UseDefault)
- Val = DefaultValue;
- }
- }
+ Context &Ctx);
template <typename T, typename Context>
void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue,
StringRef PaddingBeforeContainer;
};
+template <typename T, typename Context>
+void IO::processKeyWithDefault(const char *Key, Optional<T> &Val,
+ const Optional<T> &DefaultValue, bool Required,
+ Context &Ctx) {
+ assert(DefaultValue.hasValue() == false &&
+ "Optional<T> shouldn't have a value!");
+ void *SaveInfo;
+ bool UseDefault = true;
+ const bool sameAsDefault = outputting() && !Val.hasValue();
+ if (!outputting() && !Val.hasValue())
+ Val = T();
+ if (Val.hasValue() &&
+ this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) {
+
+ // When reading an Optional<X> key from a YAML description, we allow the
+ // special "<none>" value, which can be used to specify that no value was
+ // requested, i.e. the DefaultValue will be assigned. The DefaultValue is
+ // usually None.
+ bool IsNone = false;
+ if (!outputting())
+ if (auto *Node = dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode()))
+ IsNone = Node->getRawValue() == "<none>";
+
+ if (IsNone)
+ Val = DefaultValue;
+ else
+ yamlize(*this, Val.getValue(), Required, Ctx);
+ this->postflightKey(SaveInfo);
+ } else {
+ if (UseDefault)
+ Val = DefaultValue;
+ }
+}
+
/// YAML I/O does conversion based on types. But often native data types
/// are just a typedef of built in intergral types (e.g. int). But the C++
/// type matching system sees through the typedef and all the typedefed types
--- /dev/null
+## We have a special "<none>" value for all keys that are implemented
+## as Optional<> in the code. Setting a key to "<none>" means no-op and
+## works in the same way as when a field was not specified at all.
+
+## Test a few keys for which the "<none>" value is supported.
+## We do not test all possible keys, because it would be too verbose.
+## It reasonable to test all keys for a section, because normally many
+## of them would conflict or intersect when specified together.
+# RUN: yaml2obj %s --docnum=1 -o %t-none
+# RUN: yaml2obj %s --docnum=2 -o %t-base
+# RUN: cmp %t-none %t-base
+
+## We do not use the TEST macro. It exists to
+## demonstrate the expected use case for the <none> word.
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .bar
+ Type: SHT_PROGBITS
+ Offset: [[TEST=<none>]]
+ Address: [[TEST=<none>]]
+ Content: [[TEST=<none>]]
+ Size: [[TEST=<none>]]
+ ContentArray: [[TEST=<none>]]
+ Info: [[TEST=<none>]]
+ EntSize: [[TEST=<none>]]
+ ShName: [[TEST=<none>]]
+ ShOffset: [[TEST=<none>]]
+ ShSize: [[TEST=<none>]]
+ ShFlags: [[TEST=<none>]]
+
+## The same document, but all fields that were set to <none> are removed.
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .bar
+ Type: SHT_PROGBITS