| /* | |
| * 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 | |
| * | |
| * This class can be used to add an "extension" field to packet/request which | |
| * will be passed along with the original packet/request pointer. This allows | |
| * developers to extend packet/request without modifying the original class. | |
| */ | |
| #ifndef __BASE_EXTENSIBLE_HH__ | |
| #define __BASE_EXTENSIBLE_HH__ | |
| #include <cassert> | |
| #include <list> | |
| #include <memory> | |
| #include <type_traits> | |
| #include <utility> | |
| 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<ExtensionBase> 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. | |
| * | |
| * Example usage: | |
| * | |
| * class MyTarget : Extensible<MyTarget> {}; | |
| * | |
| * class MyExtension : public Extension<MyTarget, MyExtension> | |
| * { | |
| * public: | |
| * MyExtension(); | |
| * std::unique_ptr<ExtensionBase> clone() const override; | |
| * uint32_t getData(); | |
| * | |
| * private: | |
| * uint32_t data_;; | |
| * }; | |
| * | |
| * std::unique_ptr<MyTarget> mytarget(new MyTarget); | |
| * std::shared_ptr<MyExtension> myext(new MyExtension); | |
| * mytarget->setExtension(myext); | |
| * | |
| * std::shared_ptr<MyExtension> ext = mytarget->getExtension<MyExtension>(); | |
| * uint32_t data = ext->getData(); | |
| * mytarget->removeExtension<MyExtension>(); | |
| * | |
| * In the example above, MyTarget can carry an extension named MyExtension, | |
| * which contains an additional data field. This could be applicated to any | |
| * debug information or any data field in any protocol. | |
| */ | |
| template <typename Target, typename T> | |
| class Extension : public ExtensionBase | |
| { | |
| public: | |
| Extension() : ExtensionBase(extensionID) {} | |
| const static unsigned int extensionID; | |
| }; | |
| template <typename Target, typename T> | |
| const unsigned int Extension<Target, T>::extensionID = | |
| ExtensionBase::maxNumExtensions() - 1; | |
| template <typename Target> | |
| 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 <typename T> | |
| void | |
| setExtension(std::shared_ptr<T> ext) | |
| { | |
| static_assert(std::is_base_of<ExtensionBase, T>::value, | |
| "Extension should inherit from ExtensionBase."); | |
| assert(ext.get() != nullptr); | |
| auto it = findExtension<T>(); | |
| 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 <typename T> | |
| void | |
| removeExtension(void) | |
| { | |
| static_assert(std::is_base_of<ExtensionBase, T>::value, | |
| "Extension should inherit from ExtensionBase."); | |
| auto it = findExtension<T>(); | |
| if (it != extensions.end()) | |
| extensions.erase(it); | |
| } | |
| /** | |
| * Get the extension pointer by linear search with the extensionID. | |
| */ | |
| template <typename T> | |
| std::shared_ptr<T> | |
| getExtension() | |
| { | |
| static_assert(std::is_base_of<ExtensionBase, T>::value, | |
| "Extension should inherit from ExtensionBase."); | |
| auto it = findExtension<T>(); | |
| if (it == extensions.end()) | |
| return nullptr; | |
| return std::static_pointer_cast<T>(*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 <typename T> | |
| std::list<std::shared_ptr<ExtensionBase>>::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<std::shared_ptr<ExtensionBase>> extensions; | |
| }; | |
| } // namespace gem5 | |
| #endif //__BASE_EXTENSIBLE_HH__ |