Skip to content

Commit 5034c10

Browse files
committed
Implement a property set I/O library.
A simple library which allows to construct and serialize/deserialize a sequence of typed property sets, where each property is a <name,typed value> pair. To be used in offload tools. Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent ce53521 commit 5034c10

File tree

5 files changed

+326
-0
lines changed

5 files changed

+326
-0
lines changed
+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
//==-- PropertySetIO.h -- models a sequence of property sets and their I/O -==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
// Models a sequence of property sets and their input and output operations.
9+
// TODO use Yaml as I/O engine.
10+
// PropertyValue set format:
11+
// '['<PropertyValue set name>']'
12+
// <property name>=<property type>'|'<property value>
13+
// <property name>=<property type>'|'<property value>
14+
// ...
15+
// '['<PropertyValue set name>']'
16+
// <property name>=<property type>'|'<property value>
17+
// where
18+
// <PropertyValue set name>, <property name> are strings
19+
// <property type> - string representation of the property type
20+
// <property value> - string representation of the property value.
21+
//
22+
// For example:
23+
// [Staff/Ages]
24+
// person1=1|20
25+
// person2=1|25
26+
// [Staff/Experience]
27+
// person1=1|1
28+
// person2=1|2
29+
// person3=1|12
30+
//
31+
//===----------------------------------------------------------------------===//
32+
33+
#ifndef LLVM_SUPPORT_PROPERTYSETIO_H
34+
#define LLVM_SUPPORT_PROPERTYSETIO_H
35+
36+
#include "llvm/ADT/MapVector.h"
37+
#include "llvm/ADT/StringRef.h"
38+
#include "llvm/Support/Error.h"
39+
#include "llvm/Support/MemoryBuffer.h"
40+
#include "llvm/Support/raw_ostream.h"
41+
42+
#include <istream>
43+
#include <map>
44+
#include <memory>
45+
#include <string>
46+
47+
namespace llvm {
48+
namespace util {
49+
50+
// Represents a property value. PropertyValue name is stored in the encompassing
51+
// container.
52+
class PropertyValue {
53+
public:
54+
// Defines supported property types
55+
enum Type { first = 0, NONE = first, UINT32, last = UINT32 };
56+
57+
// Translates C++ type to the corresponding type tag.
58+
template <typename T> static Type getTypeTag();
59+
60+
// Casts from int value to a type tag.
61+
static Expected<Type> getTypeTag(int T) {
62+
if (T < first || T > last)
63+
return createStringError(std::error_code(), "bad property type " + T);
64+
return static_cast<Type>(T);
65+
}
66+
67+
PropertyValue() = default;
68+
PropertyValue(Type T) : Ty(T) {}
69+
70+
PropertyValue(uint32_t Val) : Ty(UINT32), Val({Val}) {}
71+
PropertyValue(const PropertyValue &P) = default;
72+
PropertyValue(PropertyValue &&P) = default;
73+
74+
PropertyValue &operator=(PropertyValue &&P) = default;
75+
76+
PropertyValue &operator=(const PropertyValue &P) = default;
77+
78+
// get property value as unsigned 32-bit integer
79+
uint32_t asUint32() const {
80+
assert(Ty == UINT32);
81+
return Val.UInt32Val;
82+
}
83+
84+
bool isValid() const { return getType() != NONE; }
85+
86+
// set property value; the 'T' type must be convertible to a property type tag
87+
template <typename T> void set(T V) {
88+
assert(getTypeTag<T>() == Ty);
89+
getValueRef<T>() = V;
90+
}
91+
92+
Type getType() const { return Ty; }
93+
94+
size_t size() const {
95+
switch (Ty) {
96+
case UINT32:
97+
return sizeof(Val.UInt32Val);
98+
default:
99+
llvm_unreachable_internal("unsupported property type");
100+
}
101+
}
102+
103+
private:
104+
template <typename T> T &getValueRef();
105+
106+
Type Ty = NONE;
107+
union {
108+
uint32_t UInt32Val;
109+
} Val;
110+
};
111+
112+
std::ostream &operator<<(std::ostream &Out, const PropertyValue &V);
113+
114+
// A property set. Preserves insertion order when iterating elements.
115+
using PropertySet = MapVector<StringRef, PropertyValue>;
116+
117+
// A "registry" of multiple property sets. Maps a property set name to its
118+
// contents. Can be read/written.
119+
class PropertySetRegistry {
120+
public:
121+
using MapTy = MapVector<StringRef, PropertySet>;
122+
123+
// Specific property category names used by tools.
124+
static constexpr char SYCL_SPECIALIZATION_CONSTANTS[] =
125+
"SYCL/specialization constants";
126+
127+
// Function for bulk addition of an entire property set under given category
128+
// (property set name).
129+
template <typename T>
130+
void add(StringRef Category, const std::map<StringRef, T> &Props) {
131+
assert(PropSetMap.find(Category) == PropSetMap.end() &&
132+
"category already added");
133+
auto &PropSet = PropSetMap[Category];
134+
135+
for (const auto &Prop : Props)
136+
PropSet.insert(std::make_pair(Prop.first, PropertyValue(Prop.second)));
137+
}
138+
139+
// Parses and creates a property set registry.
140+
static Expected<std::unique_ptr<PropertySetRegistry>>
141+
read(const MemoryBuffer *Buf);
142+
143+
// Dumps a property set registry to a stream.
144+
void write(raw_ostream &Out) const;
145+
146+
// Start iterator of all preperty sets in the registry.
147+
MapTy::const_iterator begin() const { return PropSetMap.begin(); }
148+
// End iterator of all preperty sets in the registry.
149+
MapTy::const_iterator end() const { return PropSetMap.end(); }
150+
151+
// Retrieves a property set with given name.
152+
PropertySet &operator[](StringRef Name) { return PropSetMap[Name]; }
153+
// Constant access to the underlying map.
154+
const MapTy &getPropSets() const { return PropSetMap; }
155+
156+
private:
157+
MapTy PropSetMap;
158+
};
159+
160+
} // namespace util
161+
} // namespace llvm
162+
163+
#endif // #define LLVM_SUPPORT_PROPERTYSETIO_H

llvm/lib/Support/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ add_llvm_component_library(LLVMSupport
119119
Parallel.cpp
120120
PluginLoader.cpp
121121
PrettyStackTrace.cpp
122+
PropertySetIO.cpp
122123
RandomNumberGenerator.cpp
123124
Regex.cpp
124125
ScaledNumber.cpp

llvm/lib/Support/PropertySetIO.cpp

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//==- PropertySetIO.cpp - models a sequence of property sets and their I/O -==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/Support/PropertySetIO.h"
10+
11+
#include "llvm/ADT/APInt.h"
12+
#include "llvm/Support/Error.h"
13+
#include "llvm/Support/LineIterator.h"
14+
15+
using namespace llvm::util;
16+
using namespace llvm;
17+
18+
Expected<std::unique_ptr<PropertySetRegistry>>
19+
PropertySetRegistry::read(const MemoryBuffer *Buf) {
20+
auto Res = std::make_unique<PropertySetRegistry>();
21+
PropertySet *CurPropSet = nullptr;
22+
std::error_code EC;
23+
24+
for (line_iterator LI(*Buf); !LI.is_at_end(); LI++) {
25+
// see if this line starts a new property set
26+
if (LI->startswith("[")) {
27+
// yes - parse the category (property name)
28+
auto EndPos = LI->rfind(']');
29+
if (EndPos == StringRef::npos)
30+
return createStringError(EC, "invalid line: " + *LI);
31+
StringRef Category = LI->substr(1, EndPos - 1);
32+
CurPropSet = &(*Res)[Category];
33+
continue;
34+
}
35+
if (!CurPropSet)
36+
return createStringError(EC, "property category missing");
37+
// parse name and type+value
38+
auto Parts = LI->split('=');
39+
40+
if (Parts.first.empty() || Parts.second.empty())
41+
return createStringError(EC, "invalid property line: " + *LI);
42+
auto TypeVal = Parts.second.split('|');
43+
44+
if (TypeVal.first.empty() || TypeVal.second.empty())
45+
return createStringError(EC, "invalid property value: " + Parts.second);
46+
APInt Tint;
47+
48+
// parse type
49+
if (TypeVal.first.getAsInteger(10, Tint))
50+
return createStringError(EC, "invalid property type: " + TypeVal.first);
51+
Expected<PropertyValue::Type> Ttag =
52+
PropertyValue::getTypeTag(static_cast<int>(Tint.getSExtValue()));
53+
StringRef Val = TypeVal.second;
54+
55+
if (!Ttag)
56+
return Ttag.takeError();
57+
PropertyValue Prop(Ttag.get());
58+
59+
// parse value depending on its type
60+
switch (Ttag.get()) {
61+
case PropertyValue::Type::UINT32: {
62+
APInt ValV;
63+
if (Val.getAsInteger(10, ValV))
64+
return createStringError(EC, "invalid property value: " + Val);
65+
Prop.set(static_cast<uint32_t>(ValV.getZExtValue()));
66+
break;
67+
}
68+
default:
69+
return createStringError(EC, "unsupported property type: " + Ttag.get());
70+
}
71+
(*CurPropSet)[Parts.first] = Prop;
72+
}
73+
if (!CurPropSet)
74+
return createStringError(EC, "invalid property set registry");
75+
76+
return Expected<std::unique_ptr<PropertySetRegistry>>(std::move(Res));
77+
}
78+
79+
namespace llvm {
80+
// output a property to a stream
81+
raw_ostream &operator<<(raw_ostream &Out, const PropertyValue &Prop) {
82+
Out << static_cast<int>(Prop.getType()) << "|";
83+
switch (Prop.getType()) {
84+
case PropertyValue::Type::UINT32:
85+
Out << Prop.asUint32();
86+
break;
87+
default:
88+
llvm_unreachable_internal("unsupported property type: " + Prop.getType());
89+
}
90+
return Out;
91+
}
92+
} // namespace llvm
93+
94+
void PropertySetRegistry::write(raw_ostream &Out) const {
95+
for (const auto &PropSet : PropSetMap) {
96+
Out << "[" << PropSet.first << "]\n";
97+
98+
for (const auto &Props : PropSet.second) {
99+
Out << std::string(Props.first) << "=" << Props.second << "\n";
100+
}
101+
}
102+
}
103+
104+
namespace llvm {
105+
namespace util {
106+
107+
template <> uint32_t &PropertyValue::getValueRef<uint32_t>() {
108+
return Val.UInt32Val;
109+
}
110+
template <> PropertyValue::Type PropertyValue::getTypeTag<uint32_t>() {
111+
return UINT32;
112+
}
113+
114+
constexpr char PropertySetRegistry::SYCL_SPECIALIZATION_CONSTANTS[];
115+
} // namespace util
116+
} // namespace llvm

llvm/unittests/Support/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ add_llvm_unittest(SupportTests
5555
Path.cpp
5656
ProcessTest.cpp
5757
ProgramTest.cpp
58+
PropertySetIOTest.cpp
5859
RegexTest.cpp
5960
ReverseIterationTest.cpp
6061
ReplaceFileTest.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===- llvm/unittest/Support/PropertySetIO.cpp - Property set I/O tests ---===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/Support/PropertySetIO.h"
10+
#include "llvm/Support/MemoryBuffer.h"
11+
#include "llvm/Support/raw_ostream.h"
12+
13+
#include "gtest/gtest.h"
14+
15+
using namespace llvm;
16+
using namespace llvm::util;
17+
18+
namespace {
19+
20+
TEST(PropertySet, IntValuesIO) {
21+
// '1' in '1|20' means 'integer property'
22+
auto Content = "[Staff/Ages]\n"
23+
"person1=1|20\n"
24+
"person2=1|25\n"
25+
"[Staff/Experience]\n"
26+
"person1=1|1\n"
27+
"person2=1|2\n"
28+
"person3=1|12\n";
29+
auto MemBuf = MemoryBuffer::getMemBuffer(Content);
30+
// Parse a property set registry
31+
auto PropSetsPtr = PropertySetRegistry::read(MemBuf.get());
32+
33+
if (!PropSetsPtr)
34+
FAIL() << "PropertySetRegistry::read failed\n";
35+
36+
std::string Serialized;
37+
{
38+
llvm::raw_string_ostream OS(Serialized);
39+
// Serialize
40+
PropSetsPtr->get()->write(OS);
41+
}
42+
// Check that the original and the serialized version are equal
43+
ASSERT_EQ(Serialized, Content);
44+
}
45+
} // namespace

0 commit comments

Comments
 (0)