/* * 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 #include #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. * * Example usage: * * class MyTarget : Extensible {}; * * class MyExtension : public Extension * { * public: * MyExtension(); * std::unique_ptr clone() const override; * uint32_t getData(); * * private: * uint32_t data_;; * }; * * std::unique_ptr mytarget(new MyTarget); * std::shared_ptr myext(new MyExtension); * mytarget->setExtension(myext); * * std::shared_ptr ext = mytarget->getExtension(); * uint32_t data = ext->getData(); * mytarget->removeExtension(); * * 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 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__