[llvm] a95717e - [YAML] Support serializing MutableArrayRef

Chris Bieneman via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 3 10:29:25 PST 2023


Author: Chris Bieneman
Date: 2023-01-03T12:29:11-06:00
New Revision: a95717ef71975dca4583944b3b8380284f346129

URL: https://github.com/llvm/llvm-project/commit/a95717ef71975dca4583944b3b8380284f346129
DIFF: https://github.com/llvm/llvm-project/commit/a95717ef71975dca4583944b3b8380284f346129.diff

LOG: [YAML] Support serializing MutableArrayRef

While the YAML format itself doesn't support fixed-sized arrays, some
of the data structures we encode in and out of YAML (specifically in
ObjectYAML) are actually fixed-sized arrays which we end up expressing
as resizable arrays.

Enabling the YAML tooling to support reading and writing from
fixed-sized arrays using MutableArrayRef can simplify some of the error
reporting and use logic for cases where the sizes of arrays are defined
by the target format.

Note: my SFINAE-foo isn't the best, so if there is a cleaner way to
implement the traits please advise.

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D140427

Added: 
    

Modified: 
    llvm/include/llvm/Support/YAMLTraits.h
    llvm/unittests/Support/YAMLIOTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h
index 4eff55f07ed7b..e46442d4736f0 100644
--- a/llvm/include/llvm/Support/YAMLTraits.h
+++ b/llvm/include/llvm/Support/YAMLTraits.h
@@ -9,6 +9,7 @@
 #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"
@@ -1945,13 +1946,15 @@ operator<<(Output &yout, T &seq) {
 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())
@@ -1960,6 +1963,25 @@ struct SequenceTraitsImpl : IsFlowSequenceBase<Flow> {
   }
 };
 
+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; };
@@ -1981,6 +2003,11 @@ struct SequenceTraits<
     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>

diff  --git a/llvm/unittests/Support/YAMLIOTest.cpp b/llvm/unittests/Support/YAMLIOTest.cpp
index ae676c73970e8..2ed79cae31edc 100644
--- a/llvm/unittests/Support/YAMLIOTest.cpp
+++ b/llvm/unittests/Support/YAMLIOTest.cpp
@@ -3266,3 +3266,72 @@ TEST(YAMLIO, TestScannerNoNullScanPlainScalarInFlow) {
   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());
+  }
+
+}


        


More information about the llvm-commits mailing list