[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