instance_specific_extensions.cc revision 13523:de27641700bb
1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20#include <tlm_utils/instance_specific_extensions_int.h>
21
22#include <iostream>
23#include <map>
24#include <systemc>
25#include <tlm>
26#include <typeindex>
27
28namespace tlm
29{
30
31template class tlm_array<tlm_utils::ispex_base *>;
32
33} // namespace tlm
34
35namespace tlm_utils
36{
37
38namespace
39{
40
41class ispex_registry // Copied from tlm_gp.cpp.
42{
43    typedef unsigned int key_type;
44    typedef std::map<std::type_index, key_type> type_map;
45
46  public:
47    static ispex_registry &
48    instance()
49    {
50        if (!instance_) {
51            // Don't cleanup registry.
52            instance_ = new ispex_registry();
53        }
54        return *instance_;
55    }
56
57    unsigned int
58    register_extension(std::type_index type)
59    {
60        type_map::const_iterator it = ids_.find(type);
61
62        if (it == ids_.end()) {
63            // New extension - generate/store ID.
64            type_map::value_type v(type, static_cast<key_type>(ids_.size()));
65            ids_.insert(v);
66            return v.second;
67        }
68        return it->second;
69    }
70
71    static unsigned int
72    max_num_extensions()
73    {
74        return (instance_) ? instance().ids_.size() : 0;
75    }
76
77  private:
78    static ispex_registry *instance_;
79    type_map ids_;
80    ispex_registry() {}
81};
82
83ispex_registry *ispex_registry::instance_ = nullptr;
84
85} //  anonymous namespace
86
87unsigned int
88ispex_base::register_private_extension(const std::type_info &type)
89{
90    return ispex_registry::instance().register_extension(type);
91}
92
93// Helper to do the numbering of private extension accessors.
94static unsigned int
95max_num_ispex_accessors(bool increment=false)
96{
97    static unsigned int max_num = 0;
98    if (increment)
99        ++max_num;
100    return max_num;
101}
102
103// ----------------------------------------------------------------------------
104
105// The pool for the container, plain as can be.
106class instance_specific_extension_container_pool
107{
108    instance_specific_extension_container_pool() : unused(nullptr) {}
109    ~instance_specific_extension_container_pool();
110
111  public:
112    static instance_specific_extension_container_pool &
113    instance()
114    {
115        static instance_specific_extension_container_pool inst;
116        return inst;
117    }
118
119    instance_specific_extension_container *create();
120    void free(instance_specific_extension_container *);
121
122  private:
123    instance_specific_extension_container *unused;
124};
125
126instance_specific_extension_container *
127instance_specific_extension_container_pool::create()
128{
129    if (!unused) {
130        unused = new instance_specific_extension_container();
131    }
132    instance_specific_extension_container *tmp = unused;
133    unused = unused->next;
134    return tmp;
135}
136
137void
138instance_specific_extension_container_pool::free(
139        instance_specific_extension_container *cont)
140{
141    cont->next = unused;
142    unused = cont;
143}
144
145instance_specific_extension_container_pool::
146    ~instance_specific_extension_container_pool()
147{
148    while (unused) {
149        instance_specific_extension_container *tmp = unused;
150        unused = unused->next;
151        delete tmp;
152    }
153}
154
155// ----------------------------------------------------------------------------
156
157instance_specific_extension_container *
158instance_specific_extension_container::create()
159{
160    return instance_specific_extension_container_pool::instance().create();
161}
162
163instance_specific_extension_container::
164    instance_specific_extension_container() :
165    use_count(0), m_txn(NULL), m_release_fn(NULL), m_carrier(NULL), next(NULL)
166{
167    resize();
168}
169
170void
171instance_specific_extension_container::
172    attach_carrier(instance_specific_extension_carrier *carrier,
173            void *txn, release_fn *rel_fn)
174{
175    m_txn = txn;
176    m_release_fn = rel_fn;
177    m_carrier = carrier;
178}
179
180void
181instance_specific_extension_container::resize()
182{
183    m_ispex_per_accessor.resize(max_num_ispex_accessors());
184
185    for (unsigned int i = 0; i < m_ispex_per_accessor.size(); ++i) {
186        m_ispex_per_accessor[i] =
187            new instance_specific_extensions_per_accessor(this);
188        m_ispex_per_accessor[i]->resize_extensions();
189    }
190}
191
192instance_specific_extension_container::
193    ~instance_specific_extension_container()
194{
195    for (unsigned int i = 0; i < m_ispex_per_accessor.size(); ++i)
196        delete m_ispex_per_accessor[i];
197}
198
199void
200instance_specific_extension_container::inc_use_count()
201{
202    use_count++;
203}
204
205void
206instance_specific_extension_container::dec_use_count()
207{
208    if ((--use_count) == 0) {
209        // If this container isn't used any more we release the carrier
210        // extension.
211        m_release_fn(m_carrier, m_txn);
212        // We send it back to our pool.
213        instance_specific_extension_container_pool::instance().free(this);
214    }
215}
216
217instance_specific_extensions_per_accessor *
218instance_specific_extension_container::get_accessor(unsigned int idx)
219{
220    return m_ispex_per_accessor[idx];
221}
222
223// ----------------------------------------------------------------------------
224
225// non-templatized version with manual index:
226ispex_base *
227instance_specific_extensions_per_accessor::set_extension(
228        unsigned int index, ispex_base *ext)
229{
230    resize_extensions();
231    ispex_base *tmp = m_extensions[index];
232    m_extensions[index] = ext;
233    if (!tmp && ext)
234        m_container->inc_use_count();
235    return tmp;
236}
237
238ispex_base *
239instance_specific_extensions_per_accessor::get_extension(
240        unsigned int index) const
241{
242    return (index < m_extensions.size()) ? m_extensions[index] : nullptr;
243}
244
245void
246instance_specific_extensions_per_accessor::clear_extension(unsigned int index)
247{
248    if (index < m_extensions.size()) {
249        if (m_extensions[index])
250            m_container->dec_use_count();
251        m_extensions[index] = static_cast<ispex_base *>(nullptr);
252    }
253}
254
255void
256instance_specific_extensions_per_accessor::resize_extensions()
257{
258    m_extensions.expand(ispex_registry::max_num_extensions());
259}
260
261// ----------------------------------------------------------------------------
262
263instance_specific_extension_accessor::instance_specific_extension_accessor() :
264    m_index(max_num_ispex_accessors(true) - 1)
265{}
266
267} // namespace tlm_utils
268