diff --git a/llvm/include/llvm/Support/OpaqueDataStore.h b/llvm/include/llvm/Support/OpaqueDataStore.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Support/OpaqueDataStore.h @@ -0,0 +1,120 @@ +//===-- llvm/Support/OpaqueDataStore.h --------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_OPAQUEDATASTORE_H +#define LLVM_SUPPORT_OPAQUEDATASTORE_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" + +#include + +namespace llvm { +class raw_ostream; + +/// Base class for StoredData. +class StoredDataBase { +public: + /// Must have a virtual destructor because it is used polymorphically. + virtual ~StoredDataBase() = default; + + // Returns the class ID for this type. + static const void *classID() { return &ID; } + + // Check whether this instance is a subclass of the class identified by + // ClassID. + virtual bool isA(const void *const ClassID) const { + return ClassID == classID(); + } + +private: + virtual void anchor(); + + static char ID; +}; + +/// Template base helper for StoredData types +template +class StoredDataInfo : public ParentDataT { +public: + using ParentDataT::ParentDataT; // inherit constructors + + /// Return the class ID for the metadata type. + static const void *classID() { return &ThisDataT::ID; } + + /// Implement isA for this type and check the parent type as well. + bool isA(const void *const ClassID) const override { + return ClassID == classID() || ParentDataT::isA(ClassID); + } +}; + +/// Class for storing opaque type-safe data +class OpaqueDataStore { +public: + OpaqueDataStore() = default; + + /// Get an entry of the specified DataStore type, or insert a new default + /// constructed entry. + template DataT &get() { + auto It = llvm::find_if(Storage, + [](const std::unique_ptr &Entry) { + return Entry->isA(DataT::classID()); + }); + if (It == Storage.end()) + return insert(); + return *(DataT *)It->get(); + } + + /// Get an entry of the specified OpaqueDataStore type if it is stored. Unlike + /// get, this method does not construct an entry if it does not already exist, + /// but will return an empty optional instead. + template llvm::Optional find() const { + auto It = llvm::find_if(Storage, + [](const std::unique_ptr &Entry) { + return Entry->isA(DataT::classID()); + }); + if (It == Storage.end()) + return {}; + return {reinterpret_cast(It->get())}; + } + + /// Get an entry of the specified OpaqueDataStore type if it is stored. Unlike + /// get, this method does not construct an entry if it does not already exist, + /// but will return an empty optional instead. + template llvm::Optional find() { + auto It = llvm::find_if(Storage, + [](const std::unique_ptr &Entry) { + return Entry->isA(DataT::classID()); + }); + if (It == Storage.end()) + return {}; + return {reinterpret_cast(It->get())}; + } + + /// returns true of the collection contains an element of the specified type. + template bool contains() const { + return (bool)find(); + } + + /// Returns the size of the OpaqueDataStore collection. + size_t size() const { return Storage.size(); } + +private: + /// Insert a new StoredData entry into this collection, and only called via + /// get() + template DataT &insert() { + return *(DataT *)Storage.insert(Storage.end(), std::make_unique()) + ->get(); + } + + SmallVector, 8> Storage; +}; + +} // namespace llvm + +#endif // LLVM_SUPPORT_OPAQUEDATASTORE_H diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -188,6 +188,7 @@ MSP430Attributes.cpp MSP430AttributeParser.cpp NativeFormatting.cpp + OpaqueDataStore.cpp OptimizedStructLayout.cpp Optional.cpp Parallel.cpp diff --git a/llvm/lib/Support/OpaqueDataStore.cpp b/llvm/lib/Support/OpaqueDataStore.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/OpaqueDataStore.cpp @@ -0,0 +1,15 @@ +//===-- lib/Support/OpaqueDataStore.cpp -------------------------*- C++ -*-===// +// +// 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/OpaqueDataStore.h" + +using namespace llvm; + +void StoredDataBase::anchor() {} + +char StoredDataBase::ID = 0; diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -61,6 +61,7 @@ MemoryBufferTest.cpp MemoryTest.cpp NativeFormatTests.cpp + OpaqueDataStoreTests.cpp OptimizedStructLayoutTest.cpp ParallelTest.cpp Path.cpp diff --git a/llvm/unittests/Support/OpaqueDataStoreTests.cpp b/llvm/unittests/Support/OpaqueDataStoreTests.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Support/OpaqueDataStoreTests.cpp @@ -0,0 +1,64 @@ +//===- llvm/unittest/Support/DataStoreTests.cpp ---------------------------===// +// +// 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/OpaqueDataStore.h" + +#include "gtest/gtest.h" + +using namespace llvm; + +class DummyData : public StoredDataInfo { +public: + DummyData() {} + static char ID; + uint32_t Value; +}; +char DummyData::ID = 0; + +TEST(DataStoreTests, GetData) { + OpaqueDataStore Data; + EXPECT_FALSE(Data.contains()); + + DummyData &V1 = Data.get(); + EXPECT_TRUE(Data.contains()); + + DummyData &V2 = Data.get(); + EXPECT_EQ(Data.size(), 1ull); + + V1.Value = 0xFEEDFACE; + EXPECT_EQ(V2.Value, 0xFEEDFACE); +} +class DummyData2 : public StoredDataInfo { +public: + DummyData2() {} + static char ID; + uint32_t Value; +}; +char DummyData2::ID = 0; + +TEST(DataStoreTests, MultipleEntries) { + OpaqueDataStore Data; + EXPECT_FALSE(Data.contains()); + + { + DummyData &V1 = Data.get(); + EXPECT_TRUE(Data.contains()); + + DummyData2 &V2 = Data.get(); + EXPECT_EQ(Data.size(), 2ull); + + V1.Value = 0xFEEDFACE; + V2.Value = 0xFACEFEED; + } + { + DummyData &V1 = Data.get(); + DummyData2 &V2 = Data.get(); + EXPECT_EQ(V1.Value, 0xFEEDFACE); + EXPECT_EQ(V2.Value, 0xFACEFEED); + } +}