| /***************************************************************************** |
| |
| Licensed to Accellera Systems Initiative Inc. (Accellera) under one or |
| more contributor license agreements. See the NOTICE file distributed |
| with this work for additional information regarding copyright ownership. |
| Accellera licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with the |
| License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| implied. See the License for the specific language governing |
| permissions and limitations under the License. |
| |
| *****************************************************************************/ |
| |
| #include <tlm_utils/instance_specific_extensions_int.h> |
| |
| #include <iostream> |
| #include <map> |
| #include <typeindex> |
| |
| namespace tlm |
| { |
| |
| template class tlm_array<tlm_utils::ispex_base *>; |
| |
| } // namespace tlm |
| |
| namespace tlm_utils |
| { |
| |
| namespace |
| { |
| |
| class ispex_registry // Copied from tlm_gp.cpp. |
| { |
| typedef unsigned int key_type; |
| typedef std::map<std::type_index, key_type> type_map; |
| |
| public: |
| static ispex_registry & |
| instance() |
| { |
| if (!instance_) { |
| // Don't cleanup registry. |
| instance_ = new ispex_registry(); |
| } |
| return *instance_; |
| } |
| |
| unsigned int |
| register_extension(std::type_index type) |
| { |
| type_map::const_iterator it = ids_.find(type); |
| |
| if (it == ids_.end()) { |
| // New extension - generate/store ID. |
| type_map::value_type v(type, static_cast<key_type>(ids_.size())); |
| ids_.insert(v); |
| return v.second; |
| } |
| return it->second; |
| } |
| |
| static unsigned int |
| max_num_extensions() |
| { |
| return (instance_) ? instance().ids_.size() : 0; |
| } |
| |
| private: |
| static ispex_registry *instance_; |
| type_map ids_; |
| ispex_registry() {} |
| }; |
| |
| ispex_registry *ispex_registry::instance_ = nullptr; |
| |
| } // anonymous namespace |
| |
| unsigned int |
| ispex_base::register_private_extension(const std::type_info &type) |
| { |
| return ispex_registry::instance().register_extension(type); |
| } |
| |
| // Helper to do the numbering of private extension accessors. |
| static unsigned int |
| max_num_ispex_accessors(bool increment=false) |
| { |
| static unsigned int max_num = 0; |
| if (increment) |
| ++max_num; |
| return max_num; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| // The pool for the container, plain as can be. |
| class instance_specific_extension_container_pool |
| { |
| instance_specific_extension_container_pool() : unused(nullptr) {} |
| ~instance_specific_extension_container_pool(); |
| |
| public: |
| static instance_specific_extension_container_pool & |
| instance() |
| { |
| static instance_specific_extension_container_pool inst; |
| return inst; |
| } |
| |
| instance_specific_extension_container *create(); |
| void free(instance_specific_extension_container *); |
| |
| private: |
| instance_specific_extension_container *unused; |
| }; |
| |
| instance_specific_extension_container * |
| instance_specific_extension_container_pool::create() |
| { |
| if (!unused) { |
| unused = new instance_specific_extension_container(); |
| } |
| instance_specific_extension_container *tmp = unused; |
| unused = unused->next; |
| return tmp; |
| } |
| |
| void |
| instance_specific_extension_container_pool::free( |
| instance_specific_extension_container *cont) |
| { |
| cont->next = unused; |
| unused = cont; |
| } |
| |
| instance_specific_extension_container_pool:: |
| ~instance_specific_extension_container_pool() |
| { |
| while (unused) { |
| instance_specific_extension_container *tmp = unused; |
| unused = unused->next; |
| delete tmp; |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| instance_specific_extension_container * |
| instance_specific_extension_container::create() |
| { |
| return instance_specific_extension_container_pool::instance().create(); |
| } |
| |
| instance_specific_extension_container:: |
| instance_specific_extension_container() : |
| use_count(0), m_txn(NULL), m_release_fn(NULL), m_carrier(NULL), next(NULL) |
| { |
| resize(); |
| } |
| |
| void |
| instance_specific_extension_container:: |
| attach_carrier(instance_specific_extension_carrier *carrier, |
| void *txn, release_fn *rel_fn) |
| { |
| m_txn = txn; |
| m_release_fn = rel_fn; |
| m_carrier = carrier; |
| } |
| |
| void |
| instance_specific_extension_container::resize() |
| { |
| m_ispex_per_accessor.resize(max_num_ispex_accessors()); |
| |
| for (unsigned int i = 0; i < m_ispex_per_accessor.size(); ++i) { |
| m_ispex_per_accessor[i] = |
| new instance_specific_extensions_per_accessor(this); |
| m_ispex_per_accessor[i]->resize_extensions(); |
| } |
| } |
| |
| instance_specific_extension_container:: |
| ~instance_specific_extension_container() |
| { |
| for (unsigned int i = 0; i < m_ispex_per_accessor.size(); ++i) |
| delete m_ispex_per_accessor[i]; |
| } |
| |
| void |
| instance_specific_extension_container::inc_use_count() |
| { |
| use_count++; |
| } |
| |
| void |
| instance_specific_extension_container::dec_use_count() |
| { |
| if ((--use_count) == 0) { |
| // If this container isn't used any more we release the carrier |
| // extension. |
| m_release_fn(m_carrier, m_txn); |
| // We send it back to our pool. |
| instance_specific_extension_container_pool::instance().free(this); |
| } |
| } |
| |
| instance_specific_extensions_per_accessor * |
| instance_specific_extension_container::get_accessor(unsigned int idx) |
| { |
| return m_ispex_per_accessor[idx]; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| // non-templatized version with manual index: |
| ispex_base * |
| instance_specific_extensions_per_accessor::set_extension( |
| unsigned int index, ispex_base *ext) |
| { |
| resize_extensions(); |
| ispex_base *tmp = m_extensions[index]; |
| m_extensions[index] = ext; |
| if (!tmp && ext) |
| m_container->inc_use_count(); |
| return tmp; |
| } |
| |
| ispex_base * |
| instance_specific_extensions_per_accessor::get_extension( |
| unsigned int index) const |
| { |
| return (index < m_extensions.size()) ? m_extensions[index] : nullptr; |
| } |
| |
| void |
| instance_specific_extensions_per_accessor::clear_extension(unsigned int index) |
| { |
| if (index < m_extensions.size()) { |
| if (m_extensions[index]) |
| m_container->dec_use_count(); |
| m_extensions[index] = static_cast<ispex_base *>(nullptr); |
| } |
| } |
| |
| void |
| instance_specific_extensions_per_accessor::resize_extensions() |
| { |
| m_extensions.expand(ispex_registry::max_num_extensions()); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| instance_specific_extension_accessor::instance_specific_extension_accessor() : |
| m_index(max_num_ispex_accessors(true) - 1) |
| {} |
| |
| } // namespace tlm_utils |