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,137 @@ +//===-- 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; + + template OpaqueDataStore(Mods... Ms) { + add(std::move(Ms)...); + } + + /// 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())}; + } + + 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(ArgTs &&...Args) { + return *(DataT *)Storage + .insert(Storage.end(), + std::make_unique(std::forward(Args)...)) + ->get(); + } + + template void add(T D, Mods... Ms) { + add(std::move(D)); + add(std::move(Ms)...); + } + + /// Get an entry of the specified StoredData type, or insert a new default + /// constructed entry. + template DataT &add(DataT D) { + assert(!contains() && "adding arguments of the same type"); + return insert(std::move(D)); + } + + 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,35 @@ +//===- 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, AddData) { + 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); +}