#ifndef LLVM_SUPPORT_YAMLTRAITS_H
#define LLVM_SUPPORT_YAMLTRAITS_H
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
template <bool B> struct IsFlowSequenceBase {};
template <> struct IsFlowSequenceBase<true> { static const bool flow = true; };
-template <typename T, bool Flow>
-struct SequenceTraitsImpl : IsFlowSequenceBase<Flow> {
-private:
- using type = typename T::value_type;
+template <typename T, typename U = void>
+struct IsResizable : std::false_type {};
-public:
- static size_t size(IO &io, T &seq) { return seq.size(); }
+template <typename T>
+struct IsResizable<T, std::void_t<decltype(std::declval<T>().resize(0))>>
+ : public std::true_type {};
+
+template <typename T, bool B> struct IsResizableBase {
+ using type = typename T::value_type;
static type &element(IO &io, T &seq, size_t index) {
if (index >= seq.size())
}
};
+template <typename T> struct IsResizableBase<T, false> {
+ using type = typename T::value_type;
+
+ static type &element(IO &io, T &seq, size_t index) {
+ if (index >= seq.size()) {
+ io.setError(Twine("value sequence extends beyond static size (") +
+ Twine(seq.size()) + ")");
+ return seq[0];
+ }
+ return seq[index];
+ }
+};
+
+template <typename T, bool Flow>
+struct SequenceTraitsImpl
+ : IsFlowSequenceBase<Flow>, IsResizableBase<T, IsResizable<T>::value> {
+ static size_t size(IO &io, T &seq) { return seq.size(); }
+};
+
// Simple helper to check an expression can be used as a bool-valued template
// argument.
template <bool> struct CheckIsBool { static const bool value = true; };
SmallVectorImpl<T>,
std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
: SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {};
+template <typename T>
+struct SequenceTraits<
+ MutableArrayRef<T>,
+ std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
+ : SequenceTraitsImpl<MutableArrayRef<T>, SequenceElementTraits<T>::flow> {};
// Sequences of fundamental types use flow formatting.
template <typename T>
yin.setCurrentDocument();
EXPECT_TRUE(yin.error());
}
+
+struct FixedArray {
+ FixedArray() {
+ // Initialize to int max as a sentinel value.
+ for (auto &v : values)
+ v = std::numeric_limits<int>::max();
+ }
+ int values[4];
+};
+
+namespace llvm {
+namespace yaml {
+ template <>
+ struct MappingTraits<FixedArray> {
+ static void mapping(IO &io, FixedArray& st) {
+ MutableArrayRef<int> array = st.values;
+ io.mapRequired("Values", array);
+ }
+ };
+}
+}
+
+TEST(YAMLIO, FixedSizeArray) {
+ FixedArray faval;
+ Input yin("---\nValues: [ 1, 2, 3, 4 ]\n...\n");
+ yin >> faval;
+
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(faval.values[0], 1);
+ EXPECT_EQ(faval.values[1], 2);
+ EXPECT_EQ(faval.values[2], 3);
+ EXPECT_EQ(faval.values[3], 4);
+
+ std::string serialized;
+ {
+ llvm::raw_string_ostream os(serialized);
+ Output yout(os);
+ yout << faval;
+ }
+ auto expected = "---\n"
+ "Values: [ 1, 2, 3, 4 ]\n"
+ "...\n";
+ ASSERT_EQ(serialized, expected);
+}
+
+TEST(YAMLIO, FixedSizeArrayMismatch) {
+ {
+ FixedArray faval;
+ Input yin("---\nValues: [ 1, 2, 3 ]\n...\n");
+ yin >> faval;
+
+ // No error for too small, leaves the default initialized value
+ EXPECT_FALSE(yin.error());
+ EXPECT_EQ(faval.values[0], 1);
+ EXPECT_EQ(faval.values[1], 2);
+ EXPECT_EQ(faval.values[2], 3);
+ EXPECT_EQ(faval.values[3], std::numeric_limits<int>::max());
+ }
+
+ {
+ FixedArray faval;
+ Input yin("---\nValues: [ 1, 2, 3, 4, 5 ]\n...\n");
+ yin >> faval;
+
+ // Error for too many elements.
+ EXPECT_TRUE(!!yin.error());
+ }
+
+}