diff --git a/src/base/SConscript b/src/base/SConscript index 4a6b65fa72..29f106a0b2 100644 --- a/src/base/SConscript +++ b/src/base/SConscript @@ -90,6 +90,7 @@ GTest('bitunion.test', 'bitunion.test.cc') GTest('channel_addr.test', 'channel_addr.test.cc', 'channel_addr.cc') GTest('circlebuf.test', 'circlebuf.test.cc') GTest('circular_queue.test', 'circular_queue.test.cc') +GTest('extensible.test', 'extensible.test.cc') GTest('sat_counter.test', 'sat_counter.test.cc') GTest('refcnt.test','refcnt.test.cc') GTest('condcodes.test', 'condcodes.test.cc') diff --git a/src/base/extensible.hh b/src/base/extensible.hh new file mode 100644 index 0000000000..eb79c71be3 --- /dev/null +++ b/src/base/extensible.hh @@ -0,0 +1,187 @@ +/* + * Copyright 2023 Google, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* @file + * Extensible Object Base Class Declaration + */ + +#ifndef __BASE_EXTENSIBLE_HH__ +#define __BASE_EXTENSIBLE_HH__ + +#include +#include +#include + +namespace gem5 +{ + +/** + * This is base of every extension. + */ +class ExtensionBase +{ + public: + explicit ExtensionBase(const unsigned int id) + : extID(id) {} + + virtual ~ExtensionBase() = default; + + virtual std::unique_ptr clone() const = 0; + + static unsigned int + maxNumExtensions() + { + static unsigned int max_num = 0; + return ++max_num; + } + + unsigned int getExtensionID() const { return extID; } + + private: + const unsigned int extID; +}; + +/** + * This is the extension for carrying additional information. + * Each type of extension will have a unique extensionID. + * This extensionID will assign to base class for comparsion. + */ +template +class Extension : public ExtensionBase +{ + public: + Extension() : ExtensionBase(extensionID) {} + + const static unsigned int extensionID; +}; + +template +const unsigned int Extension::extensionID = + ExtensionBase::maxNumExtensions() - 1; + +template +class Extensible +{ + public: + Extensible() = default; + Extensible(const Extensible& other) + { + // Clone every extension from other. + for (auto& ext : other.extensions) { + extensions.emplace_back(ext->clone()); + } + } + virtual ~Extensible() = default; + + /** + * Set a new extension to the packet and replace the old one, if there + * already exists the same type of extension in this packet. This new + * extension will be deleted automatically with the shared_ptr<>. + * + * @param ext Extension to set + */ + template + void + setExtension(std::shared_ptr ext) + { + static_assert(std::is_base_of::value, + "Extension should inherit from ExtensionBase."); + assert(ext.get() != nullptr); + + auto it = findExtension(); + + if (it != extensions.end()) { + // There exists the same type of extension in the list. + // Replace it to the new one. + *it = std::move(ext); + } else { + // Add ext into the linked list. + extensions.emplace_back(std::move(ext)); + } + } + + /** + * Remove the extension based on its type. + * + * @param ext Extension to remove + */ + template + void + removeExtension(void) + { + static_assert(std::is_base_of::value, + "Extension should inherit from ExtensionBase."); + + auto it = findExtension(); + if (it != extensions.end()) + extensions.erase(it); + } + + /** + * Get the extension pointer by linear search with the extensionID. + */ + template + std::shared_ptr + getExtension() + { + static_assert(std::is_base_of::value, + "Extension should inherit from ExtensionBase."); + auto it = findExtension(); + if (it == extensions.end()) + return nullptr; + return std::static_pointer_cast(*it); + } + + protected: + + /** + * Go through the extension list and return the iterator to the instance of + * the type of extension. If there is no such an extension, return the end + * iterator of the list. + * + * @return The iterator to the extension type T if there exists. + */ + template + std::list>::iterator + findExtension() + { + auto it = extensions.begin(); + while (it != extensions.end()) { + if ((*it)->getExtensionID() == T::extensionID) + break; + it++; + } + return it; + } + + // Linked list of extensions. + std::list> extensions; +}; + +} // namespace gem5 + +#endif //__BASE_EXTENSIBLE_HH__ diff --git a/src/base/extensible.test.cc b/src/base/extensible.test.cc new file mode 100644 index 0000000000..66cbbda527 --- /dev/null +++ b/src/base/extensible.test.cc @@ -0,0 +1,111 @@ +/* + * Copyright 2023 Google, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +#include "base/extensible.hh" + +using namespace gem5; + +namespace { + +class TestTarget : public Extensible +{ +}; + +class IntegerExtension : public Extension +{ + public: + explicit IntegerExtension(uint32_t data) + : data_(data) {} + + std::unique_ptr clone() const override + { + return std::unique_ptr(new IntegerExtension(data_)); + } + + uint32_t getData() const { return data_; } + + private: + uint32_t data_; +}; + +class BoolExtension : public Extension +{ + public: + explicit BoolExtension(bool data) + : data_(data) {} + + std::unique_ptr clone() const override + { + return std::unique_ptr(new BoolExtension(data_)); + } + + bool getData() const { return data_; } + + private: + bool data_; +}; + +} // namespace + +TEST(ExtensibleTest, ExtensionID) +{ + std::shared_ptr ext1(new IntegerExtension(0xabcd)); + EXPECT_EQ(0, ext1->getExtensionID()); + + std::shared_ptr ext2(new BoolExtension(true)); + EXPECT_EQ(1, ext2->getExtensionID()); +} + +TEST(ExtensibleTest, SetAndRemoveExtension) +{ + const uint32_t data = 0xbeef; + std::shared_ptr ext(new IntegerExtension(data)); + std::unique_ptr target(new TestTarget); + target->setExtension(ext); + EXPECT_EQ(data, target->getExtension()->getData()); + + target->removeExtension(); + EXPECT_EQ(nullptr, target->getExtension()); +} + +TEST(ExtensibleTest, ReplaceExtension) +{ + const uint32_t data = 0xbeef; + std::shared_ptr ext(new IntegerExtension(data)); + std::unique_ptr target(new TestTarget); + target->setExtension(ext); + EXPECT_EQ(data, target->getExtension()->getData()); + + const uint32_t new_data = 0xa5a5; + std::shared_ptr new_ext(new IntegerExtension(new_data)); + target->setExtension(new_ext); + EXPECT_EQ(new_data, target->getExtension()->getData()); +}