113514Sgabeblack@google.com/*****************************************************************************
213514Sgabeblack@google.com
313514Sgabeblack@google.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
413514Sgabeblack@google.com  more contributor license agreements.  See the NOTICE file distributed
513514Sgabeblack@google.com  with this work for additional information regarding copyright ownership.
613514Sgabeblack@google.com  Accellera licenses this file to you under the Apache License, Version 2.0
713514Sgabeblack@google.com  (the "License"); you may not use this file except in compliance with the
813514Sgabeblack@google.com  License.  You may obtain a copy of the License at
913514Sgabeblack@google.com
1013514Sgabeblack@google.com    http://www.apache.org/licenses/LICENSE-2.0
1113514Sgabeblack@google.com
1213514Sgabeblack@google.com  Unless required by applicable law or agreed to in writing, software
1313514Sgabeblack@google.com  distributed under the License is distributed on an "AS IS" BASIS,
1413514Sgabeblack@google.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1513514Sgabeblack@google.com  implied.  See the License for the specific language governing
1613514Sgabeblack@google.com  permissions and limitations under the License.
1713514Sgabeblack@google.com
1813514Sgabeblack@google.com *****************************************************************************/
1913514Sgabeblack@google.com
2013514Sgabeblack@google.com#include <tlm_utils/instance_specific_extensions_int.h>
2113514Sgabeblack@google.com
2213514Sgabeblack@google.com#include <iostream>
2313514Sgabeblack@google.com#include <map>
2413523Sgabeblack@google.com#include <typeindex>
2513514Sgabeblack@google.com
2613514Sgabeblack@google.comnamespace tlm
2713514Sgabeblack@google.com{
2813514Sgabeblack@google.com
2913514Sgabeblack@google.comtemplate class tlm_array<tlm_utils::ispex_base *>;
3013514Sgabeblack@google.com
3113514Sgabeblack@google.com} // namespace tlm
3213514Sgabeblack@google.com
3313514Sgabeblack@google.comnamespace tlm_utils
3413514Sgabeblack@google.com{
3513514Sgabeblack@google.com
3613514Sgabeblack@google.comnamespace
3713514Sgabeblack@google.com{
3813514Sgabeblack@google.com
3913514Sgabeblack@google.comclass ispex_registry // Copied from tlm_gp.cpp.
4013514Sgabeblack@google.com{
4113514Sgabeblack@google.com    typedef unsigned int key_type;
4213523Sgabeblack@google.com    typedef std::map<std::type_index, key_type> type_map;
4313514Sgabeblack@google.com
4413514Sgabeblack@google.com  public:
4513514Sgabeblack@google.com    static ispex_registry &
4613514Sgabeblack@google.com    instance()
4713514Sgabeblack@google.com    {
4813514Sgabeblack@google.com        if (!instance_) {
4913514Sgabeblack@google.com            // Don't cleanup registry.
5013514Sgabeblack@google.com            instance_ = new ispex_registry();
5113514Sgabeblack@google.com        }
5213514Sgabeblack@google.com        return *instance_;
5313514Sgabeblack@google.com    }
5413514Sgabeblack@google.com
5513514Sgabeblack@google.com    unsigned int
5613523Sgabeblack@google.com    register_extension(std::type_index type)
5713514Sgabeblack@google.com    {
5813514Sgabeblack@google.com        type_map::const_iterator it = ids_.find(type);
5913514Sgabeblack@google.com
6013514Sgabeblack@google.com        if (it == ids_.end()) {
6113514Sgabeblack@google.com            // New extension - generate/store ID.
6213514Sgabeblack@google.com            type_map::value_type v(type, static_cast<key_type>(ids_.size()));
6313514Sgabeblack@google.com            ids_.insert(v);
6413514Sgabeblack@google.com            return v.second;
6513514Sgabeblack@google.com        }
6613514Sgabeblack@google.com        return it->second;
6713514Sgabeblack@google.com    }
6813514Sgabeblack@google.com
6913514Sgabeblack@google.com    static unsigned int
7013514Sgabeblack@google.com    max_num_extensions()
7113514Sgabeblack@google.com    {
7213514Sgabeblack@google.com        return (instance_) ? instance().ids_.size() : 0;
7313514Sgabeblack@google.com    }
7413514Sgabeblack@google.com
7513514Sgabeblack@google.com  private:
7613514Sgabeblack@google.com    static ispex_registry *instance_;
7713514Sgabeblack@google.com    type_map ids_;
7813514Sgabeblack@google.com    ispex_registry() {}
7913514Sgabeblack@google.com};
8013514Sgabeblack@google.com
8113514Sgabeblack@google.comispex_registry *ispex_registry::instance_ = nullptr;
8213514Sgabeblack@google.com
8313514Sgabeblack@google.com} //  anonymous namespace
8413514Sgabeblack@google.com
8513514Sgabeblack@google.comunsigned int
8613514Sgabeblack@google.comispex_base::register_private_extension(const std::type_info &type)
8713514Sgabeblack@google.com{
8813514Sgabeblack@google.com    return ispex_registry::instance().register_extension(type);
8913514Sgabeblack@google.com}
9013514Sgabeblack@google.com
9113514Sgabeblack@google.com// Helper to do the numbering of private extension accessors.
9213514Sgabeblack@google.comstatic unsigned int
9313514Sgabeblack@google.commax_num_ispex_accessors(bool increment=false)
9413514Sgabeblack@google.com{
9513514Sgabeblack@google.com    static unsigned int max_num = 0;
9613514Sgabeblack@google.com    if (increment)
9713514Sgabeblack@google.com        ++max_num;
9813514Sgabeblack@google.com    return max_num;
9913514Sgabeblack@google.com}
10013514Sgabeblack@google.com
10113514Sgabeblack@google.com// ----------------------------------------------------------------------------
10213514Sgabeblack@google.com
10313514Sgabeblack@google.com// The pool for the container, plain as can be.
10413514Sgabeblack@google.comclass instance_specific_extension_container_pool
10513514Sgabeblack@google.com{
10613514Sgabeblack@google.com    instance_specific_extension_container_pool() : unused(nullptr) {}
10713514Sgabeblack@google.com    ~instance_specific_extension_container_pool();
10813514Sgabeblack@google.com
10913514Sgabeblack@google.com  public:
11013514Sgabeblack@google.com    static instance_specific_extension_container_pool &
11113514Sgabeblack@google.com    instance()
11213514Sgabeblack@google.com    {
11313514Sgabeblack@google.com        static instance_specific_extension_container_pool inst;
11413514Sgabeblack@google.com        return inst;
11513514Sgabeblack@google.com    }
11613514Sgabeblack@google.com
11713514Sgabeblack@google.com    instance_specific_extension_container *create();
11813514Sgabeblack@google.com    void free(instance_specific_extension_container *);
11913514Sgabeblack@google.com
12013514Sgabeblack@google.com  private:
12113514Sgabeblack@google.com    instance_specific_extension_container *unused;
12213514Sgabeblack@google.com};
12313514Sgabeblack@google.com
12413514Sgabeblack@google.cominstance_specific_extension_container *
12513514Sgabeblack@google.cominstance_specific_extension_container_pool::create()
12613514Sgabeblack@google.com{
12713514Sgabeblack@google.com    if (!unused) {
12813514Sgabeblack@google.com        unused = new instance_specific_extension_container();
12913514Sgabeblack@google.com    }
13013514Sgabeblack@google.com    instance_specific_extension_container *tmp = unused;
13113514Sgabeblack@google.com    unused = unused->next;
13213514Sgabeblack@google.com    return tmp;
13313514Sgabeblack@google.com}
13413514Sgabeblack@google.com
13513514Sgabeblack@google.comvoid
13613514Sgabeblack@google.cominstance_specific_extension_container_pool::free(
13713514Sgabeblack@google.com        instance_specific_extension_container *cont)
13813514Sgabeblack@google.com{
13913514Sgabeblack@google.com    cont->next = unused;
14013514Sgabeblack@google.com    unused = cont;
14113514Sgabeblack@google.com}
14213514Sgabeblack@google.com
14313514Sgabeblack@google.cominstance_specific_extension_container_pool::
14413514Sgabeblack@google.com    ~instance_specific_extension_container_pool()
14513514Sgabeblack@google.com{
14613514Sgabeblack@google.com    while (unused) {
14713514Sgabeblack@google.com        instance_specific_extension_container *tmp = unused;
14813514Sgabeblack@google.com        unused = unused->next;
14913514Sgabeblack@google.com        delete tmp;
15013514Sgabeblack@google.com    }
15113514Sgabeblack@google.com}
15213514Sgabeblack@google.com
15313514Sgabeblack@google.com// ----------------------------------------------------------------------------
15413514Sgabeblack@google.com
15513514Sgabeblack@google.cominstance_specific_extension_container *
15613514Sgabeblack@google.cominstance_specific_extension_container::create()
15713514Sgabeblack@google.com{
15813514Sgabeblack@google.com    return instance_specific_extension_container_pool::instance().create();
15913514Sgabeblack@google.com}
16013514Sgabeblack@google.com
16113514Sgabeblack@google.cominstance_specific_extension_container::
16213514Sgabeblack@google.com    instance_specific_extension_container() :
16313514Sgabeblack@google.com    use_count(0), m_txn(NULL), m_release_fn(NULL), m_carrier(NULL), next(NULL)
16413514Sgabeblack@google.com{
16513514Sgabeblack@google.com    resize();
16613514Sgabeblack@google.com}
16713514Sgabeblack@google.com
16813514Sgabeblack@google.comvoid
16913514Sgabeblack@google.cominstance_specific_extension_container::
17013514Sgabeblack@google.com    attach_carrier(instance_specific_extension_carrier *carrier,
17113514Sgabeblack@google.com            void *txn, release_fn *rel_fn)
17213514Sgabeblack@google.com{
17313514Sgabeblack@google.com    m_txn = txn;
17413514Sgabeblack@google.com    m_release_fn = rel_fn;
17513514Sgabeblack@google.com    m_carrier = carrier;
17613514Sgabeblack@google.com}
17713514Sgabeblack@google.com
17813514Sgabeblack@google.comvoid
17913514Sgabeblack@google.cominstance_specific_extension_container::resize()
18013514Sgabeblack@google.com{
18113514Sgabeblack@google.com    m_ispex_per_accessor.resize(max_num_ispex_accessors());
18213514Sgabeblack@google.com
18313514Sgabeblack@google.com    for (unsigned int i = 0; i < m_ispex_per_accessor.size(); ++i) {
18413514Sgabeblack@google.com        m_ispex_per_accessor[i] =
18513514Sgabeblack@google.com            new instance_specific_extensions_per_accessor(this);
18613514Sgabeblack@google.com        m_ispex_per_accessor[i]->resize_extensions();
18713514Sgabeblack@google.com    }
18813514Sgabeblack@google.com}
18913514Sgabeblack@google.com
19013514Sgabeblack@google.cominstance_specific_extension_container::
19113514Sgabeblack@google.com    ~instance_specific_extension_container()
19213514Sgabeblack@google.com{
19313514Sgabeblack@google.com    for (unsigned int i = 0; i < m_ispex_per_accessor.size(); ++i)
19413514Sgabeblack@google.com        delete m_ispex_per_accessor[i];
19513514Sgabeblack@google.com}
19613514Sgabeblack@google.com
19713514Sgabeblack@google.comvoid
19813514Sgabeblack@google.cominstance_specific_extension_container::inc_use_count()
19913514Sgabeblack@google.com{
20013514Sgabeblack@google.com    use_count++;
20113514Sgabeblack@google.com}
20213514Sgabeblack@google.com
20313514Sgabeblack@google.comvoid
20413514Sgabeblack@google.cominstance_specific_extension_container::dec_use_count()
20513514Sgabeblack@google.com{
20613514Sgabeblack@google.com    if ((--use_count) == 0) {
20713514Sgabeblack@google.com        // If this container isn't used any more we release the carrier
20813514Sgabeblack@google.com        // extension.
20913514Sgabeblack@google.com        m_release_fn(m_carrier, m_txn);
21013514Sgabeblack@google.com        // We send it back to our pool.
21113514Sgabeblack@google.com        instance_specific_extension_container_pool::instance().free(this);
21213514Sgabeblack@google.com    }
21313514Sgabeblack@google.com}
21413514Sgabeblack@google.com
21513514Sgabeblack@google.cominstance_specific_extensions_per_accessor *
21613514Sgabeblack@google.cominstance_specific_extension_container::get_accessor(unsigned int idx)
21713514Sgabeblack@google.com{
21813514Sgabeblack@google.com    return m_ispex_per_accessor[idx];
21913514Sgabeblack@google.com}
22013514Sgabeblack@google.com
22113514Sgabeblack@google.com// ----------------------------------------------------------------------------
22213514Sgabeblack@google.com
22313514Sgabeblack@google.com// non-templatized version with manual index:
22413514Sgabeblack@google.comispex_base *
22513514Sgabeblack@google.cominstance_specific_extensions_per_accessor::set_extension(
22613514Sgabeblack@google.com        unsigned int index, ispex_base *ext)
22713514Sgabeblack@google.com{
22813514Sgabeblack@google.com    resize_extensions();
22913514Sgabeblack@google.com    ispex_base *tmp = m_extensions[index];
23013514Sgabeblack@google.com    m_extensions[index] = ext;
23113514Sgabeblack@google.com    if (!tmp && ext)
23213514Sgabeblack@google.com        m_container->inc_use_count();
23313514Sgabeblack@google.com    return tmp;
23413514Sgabeblack@google.com}
23513514Sgabeblack@google.com
23613514Sgabeblack@google.comispex_base *
23713514Sgabeblack@google.cominstance_specific_extensions_per_accessor::get_extension(
23813514Sgabeblack@google.com        unsigned int index) const
23913514Sgabeblack@google.com{
24013514Sgabeblack@google.com    return (index < m_extensions.size()) ? m_extensions[index] : nullptr;
24113514Sgabeblack@google.com}
24213514Sgabeblack@google.com
24313514Sgabeblack@google.comvoid
24413514Sgabeblack@google.cominstance_specific_extensions_per_accessor::clear_extension(unsigned int index)
24513514Sgabeblack@google.com{
24613514Sgabeblack@google.com    if (index < m_extensions.size()) {
24713514Sgabeblack@google.com        if (m_extensions[index])
24813514Sgabeblack@google.com            m_container->dec_use_count();
24913514Sgabeblack@google.com        m_extensions[index] = static_cast<ispex_base *>(nullptr);
25013514Sgabeblack@google.com    }
25113514Sgabeblack@google.com}
25213514Sgabeblack@google.com
25313514Sgabeblack@google.comvoid
25413514Sgabeblack@google.cominstance_specific_extensions_per_accessor::resize_extensions()
25513514Sgabeblack@google.com{
25613514Sgabeblack@google.com    m_extensions.expand(ispex_registry::max_num_extensions());
25713514Sgabeblack@google.com}
25813514Sgabeblack@google.com
25913514Sgabeblack@google.com// ----------------------------------------------------------------------------
26013514Sgabeblack@google.com
26113514Sgabeblack@google.cominstance_specific_extension_accessor::instance_specific_extension_accessor() :
26213514Sgabeblack@google.com    m_index(max_num_ispex_accessors(true) - 1)
26313514Sgabeblack@google.com{}
26413514Sgabeblack@google.com
26513514Sgabeblack@google.com} // namespace tlm_utils
266