-
Notifications
You must be signed in to change notification settings - Fork 769
Implement a property set I/O library. #1357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
//==-- PropertySetIO.h -- models a sequence of property sets and their I/O -==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// Models a sequence of property sets and their input and output operations. | ||
// TODO use Yaml as I/O engine. | ||
// PropertyValue set format: | ||
// '['<PropertyValue set name>']' | ||
// <property name>=<property type>'|'<property value> | ||
// <property name>=<property type>'|'<property value> | ||
// ... | ||
// '['<PropertyValue set name>']' | ||
// <property name>=<property type>'|'<property value> | ||
// where | ||
// <PropertyValue set name>, <property name> are strings | ||
// <property type> - string representation of the property type | ||
// <property value> - string representation of the property value. | ||
// | ||
// For example: | ||
// [Staff/Ages] | ||
// person1=1|20 | ||
// person2=1|25 | ||
// [Staff/Experience] | ||
// person1=1|1 | ||
// person2=1|2 | ||
// person3=1|12 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_SUPPORT_PROPERTYSETIO_H | ||
#define LLVM_SUPPORT_PROPERTYSETIO_H | ||
|
||
#include "llvm/ADT/MapVector.h" | ||
#include "llvm/ADT/StringRef.h" | ||
#include "llvm/Support/Error.h" | ||
#include "llvm/Support/MemoryBuffer.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
||
#include <istream> | ||
#include <map> | ||
#include <memory> | ||
#include <string> | ||
|
||
namespace llvm { | ||
namespace util { | ||
|
||
// Represents a property value. PropertyValue name is stored in the encompassing | ||
// container. | ||
class PropertyValue { | ||
public: | ||
// Defines supported property types | ||
enum Type { first = 0, NONE = first, UINT32, last = UINT32 }; | ||
|
||
// Translates C++ type to the corresponding type tag. | ||
template <typename T> static Type getTypeTag(); | ||
|
||
// Casts from int value to a type tag. | ||
static Expected<Type> getTypeTag(int T) { | ||
if (T < first || T > last) | ||
return createStringError(std::error_code(), "bad property type " + T); | ||
return static_cast<Type>(T); | ||
} | ||
|
||
PropertyValue() = default; | ||
PropertyValue(Type T) : Ty(T) {} | ||
|
||
PropertyValue(uint32_t Val) : Ty(UINT32), Val({Val}) {} | ||
PropertyValue(const PropertyValue &P) = default; | ||
PropertyValue(PropertyValue &&P) = default; | ||
|
||
PropertyValue &operator=(PropertyValue &&P) = default; | ||
|
||
PropertyValue &operator=(const PropertyValue &P) = default; | ||
|
||
// get property value as unsigned 32-bit integer | ||
uint32_t asUint32() const { | ||
assert(Ty == UINT32); | ||
return Val.UInt32Val; | ||
} | ||
|
||
bool isValid() const { return getType() != NONE; } | ||
|
||
// set property value; the 'T' type must be convertible to a property type tag | ||
template <typename T> void set(T V) { | ||
assert(getTypeTag<T>() == Ty); | ||
getValueRef<T>() = V; | ||
} | ||
|
||
Type getType() const { return Ty; } | ||
|
||
size_t size() const { | ||
switch (Ty) { | ||
case UINT32: | ||
return sizeof(Val.UInt32Val); | ||
default: | ||
llvm_unreachable_internal("unsupported property type"); | ||
} | ||
} | ||
|
||
private: | ||
template <typename T> T &getValueRef(); | ||
|
||
Type Ty = NONE; | ||
union { | ||
uint32_t UInt32Val; | ||
} Val; | ||
}; | ||
|
||
std::ostream &operator<<(std::ostream &Out, const PropertyValue &V); | ||
|
||
// A property set. Preserves insertion order when iterating elements. | ||
using PropertySet = MapVector<StringRef, PropertyValue>; | ||
|
||
// A "registry" of multiple property sets. Maps a property set name to its | ||
// contents. Can be read/written. | ||
class PropertySetRegistry { | ||
public: | ||
using MapTy = MapVector<StringRef, PropertySet>; | ||
|
||
// Specific property category names used by tools. | ||
static constexpr char SYCL_SPECIALIZATION_CONSTANTS[] = | ||
"SYCL/specialization constants"; | ||
kbobrovs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Function for bulk addition of an entire property set under given category | ||
// (property set name). | ||
template <typename T> | ||
void add(StringRef Category, const std::map<StringRef, T> &Props) { | ||
assert(PropSetMap.find(Category) == PropSetMap.end() && | ||
"category already added"); | ||
auto &PropSet = PropSetMap[Category]; | ||
|
||
for (const auto &Prop : Props) | ||
PropSet.insert(std::make_pair(Prop.first, PropertyValue(Prop.second))); | ||
} | ||
|
||
// Parses and creates a property set registry. | ||
static Expected<std::unique_ptr<PropertySetRegistry>> | ||
read(const MemoryBuffer *Buf); | ||
|
||
// Dumps a property set registry to a stream. | ||
void write(raw_ostream &Out) const; | ||
|
||
// Start iterator of all preperty sets in the registry. | ||
MapTy::const_iterator begin() const { return PropSetMap.begin(); } | ||
// End iterator of all preperty sets in the registry. | ||
MapTy::const_iterator end() const { return PropSetMap.end(); } | ||
|
||
// Retrieves a property set with given name. | ||
PropertySet &operator[](StringRef Name) { return PropSetMap[Name]; } | ||
// Constant access to the underlying map. | ||
const MapTy &getPropSets() const { return PropSetMap; } | ||
|
||
private: | ||
MapTy PropSetMap; | ||
}; | ||
|
||
} // namespace util | ||
} // namespace llvm | ||
|
||
#endif // #define LLVM_SUPPORT_PROPERTYSETIO_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
//==- PropertySetIO.cpp - models a sequence of property sets and their I/O -==// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "llvm/Support/PropertySetIO.h" | ||
|
||
#include "llvm/ADT/APInt.h" | ||
#include "llvm/Support/Error.h" | ||
#include "llvm/Support/LineIterator.h" | ||
|
||
using namespace llvm::util; | ||
using namespace llvm; | ||
|
||
Expected<std::unique_ptr<PropertySetRegistry>> | ||
PropertySetRegistry::read(const MemoryBuffer *Buf) { | ||
auto Res = std::make_unique<PropertySetRegistry>(); | ||
PropertySet *CurPropSet = nullptr; | ||
std::error_code EC; | ||
|
||
for (line_iterator LI(*Buf); !LI.is_at_end(); LI++) { | ||
// see if this line starts a new property set | ||
if (LI->startswith("[")) { | ||
// yes - parse the category (property name) | ||
auto EndPos = LI->rfind(']'); | ||
if (EndPos == StringRef::npos) | ||
return createStringError(EC, "invalid line: " + *LI); | ||
StringRef Category = LI->substr(1, EndPos - 1); | ||
CurPropSet = &(*Res)[Category]; | ||
continue; | ||
} | ||
if (!CurPropSet) | ||
return createStringError(EC, "property category missing"); | ||
// parse name and type+value | ||
auto Parts = LI->split('='); | ||
|
||
if (Parts.first.empty() || Parts.second.empty()) | ||
return createStringError(EC, "invalid property line: " + *LI); | ||
auto TypeVal = Parts.second.split('|'); | ||
|
||
if (TypeVal.first.empty() || TypeVal.second.empty()) | ||
return createStringError(EC, "invalid property value: " + Parts.second); | ||
APInt Tint; | ||
|
||
// parse type | ||
if (TypeVal.first.getAsInteger(10, Tint)) | ||
return createStringError(EC, "invalid property type: " + TypeVal.first); | ||
Expected<PropertyValue::Type> Ttag = | ||
PropertyValue::getTypeTag(static_cast<int>(Tint.getSExtValue())); | ||
StringRef Val = TypeVal.second; | ||
|
||
if (!Ttag) | ||
return Ttag.takeError(); | ||
PropertyValue Prop(Ttag.get()); | ||
|
||
// parse value depending on its type | ||
switch (Ttag.get()) { | ||
case PropertyValue::Type::UINT32: { | ||
APInt ValV; | ||
if (Val.getAsInteger(10, ValV)) | ||
return createStringError(EC, "invalid property value: " + Val); | ||
Prop.set(static_cast<uint32_t>(ValV.getZExtValue())); | ||
break; | ||
} | ||
default: | ||
return createStringError(EC, "unsupported property type: " + Ttag.get()); | ||
} | ||
(*CurPropSet)[Parts.first] = Prop; | ||
} | ||
if (!CurPropSet) | ||
return createStringError(EC, "invalid property set registry"); | ||
|
||
return Expected<std::unique_ptr<PropertySetRegistry>>(std::move(Res)); | ||
} | ||
|
||
namespace llvm { | ||
// output a property to a stream | ||
raw_ostream &operator<<(raw_ostream &Out, const PropertyValue &Prop) { | ||
Out << static_cast<int>(Prop.getType()) << "|"; | ||
switch (Prop.getType()) { | ||
case PropertyValue::Type::UINT32: | ||
Out << Prop.asUint32(); | ||
break; | ||
default: | ||
llvm_unreachable_internal("unsupported property type: " + Prop.getType()); | ||
} | ||
return Out; | ||
} | ||
} // namespace llvm | ||
|
||
void PropertySetRegistry::write(raw_ostream &Out) const { | ||
for (const auto &PropSet : PropSetMap) { | ||
Out << "[" << PropSet.first << "]\n"; | ||
|
||
for (const auto &Props : PropSet.second) { | ||
Out << std::string(Props.first) << "=" << Props.second << "\n"; | ||
} | ||
} | ||
} | ||
|
||
namespace llvm { | ||
namespace util { | ||
|
||
template <> uint32_t &PropertyValue::getValueRef<uint32_t>() { | ||
return Val.UInt32Val; | ||
} | ||
template <> PropertyValue::Type PropertyValue::getTypeTag<uint32_t>() { | ||
return UINT32; | ||
} | ||
|
||
constexpr char PropertySetRegistry::SYCL_SPECIALIZATION_CONSTANTS[]; | ||
} // namespace util | ||
} // namespace llvm |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
//===- llvm/unittest/Support/PropertySetIO.cpp - Property set I/O tests ---===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "llvm/Support/PropertySetIO.h" | ||
#include "llvm/Support/MemoryBuffer.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
||
#include "gtest/gtest.h" | ||
|
||
using namespace llvm; | ||
using namespace llvm::util; | ||
|
||
namespace { | ||
|
||
TEST(PropertySet, IntValuesIO) { | ||
// '1' in '1|20' means 'integer property' | ||
auto Content = "[Staff/Ages]\n" | ||
"person1=1|20\n" | ||
"person2=1|25\n" | ||
"[Staff/Experience]\n" | ||
"person1=1|1\n" | ||
"person2=1|2\n" | ||
"person3=1|12\n"; | ||
auto MemBuf = MemoryBuffer::getMemBuffer(Content); | ||
// Parse a property set registry | ||
auto PropSetsPtr = PropertySetRegistry::read(MemBuf.get()); | ||
|
||
if (!PropSetsPtr) | ||
FAIL() << "PropertySetRegistry::read failed\n"; | ||
|
||
std::string Serialized; | ||
{ | ||
llvm::raw_string_ostream OS(Serialized); | ||
// Serialize | ||
PropSetsPtr->get()->write(OS); | ||
} | ||
// Check that the original and the serialized version are equal | ||
ASSERT_EQ(Serialized, Content); | ||
} | ||
} // namespace |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such as https://llvm.org/docs/YamlIO.html ?
That sounds like a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, exactly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just do it. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, in TODO list.