instance_specific_extensions.cc revision 13514
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
27namespace tlm
28{
29
30template class tlm_array<tlm_utils::ispex_base *>;
31
32} // namespace tlm
33
34namespace tlm_utils
35{
36
37namespace
38{
39
40class ispex_registry // Copied from tlm_gp.cpp.
41{
42    typedef unsigned int key_type;
43    typedef std::map<sc_core::sc_type_index, key_type> type_map;
44
45  public:
46    static ispex_registry &
47    instance()
48    {
49        if (!instance_) {
50            // Don't cleanup registry.
51            instance_ = new ispex_registry();
52        }
53        return *instance_;
54    }
55
56    unsigned int
57    register_extension(sc_core::sc_type_index type)
58    {
59        type_map::const_iterator it = ids_.find(type);
60
61        if (it == ids_.end()) {
62            // New extension - generate/store ID.
63            type_map::value_type v(type, static_cast<key_type>(ids_.size()));
64            ids_.insert(v);
65            return v.second;
66        }
67        return it->second;
68    }
69
70    static unsigned int
71    max_num_extensions()
72    {
73        return (instance_) ? instance().ids_.size() : 0;
74    }
75
76  private:
77    static ispex_registry *instance_;
78    type_map ids_;
79    ispex_registry() {}
80};
81
82ispex_registry *ispex_registry::instance_ = nullptr;
83
84} //  anonymous namespace
85
86unsigned int
87ispex_base::register_private_extension(const std::type_info &type)
88{
89    return ispex_registry::instance().register_extension(type);
90}
91
92// Helper to do the numbering of private extension accessors.
93static unsigned int
94max_num_ispex_accessors(bool increment=false)
95{
96    static unsigned int max_num = 0;
97    if (increment)
98        ++max_num;
99    return max_num;
100}
101
102// ----------------------------------------------------------------------------
103
104// The pool for the container, plain as can be.
105class instance_specific_extension_container_pool
106{
107    instance_specific_extension_container_pool() : unused(nullptr) {}
108    ~instance_specific_extension_container_pool();
109
110  public:
111    static instance_specific_extension_container_pool &
112    instance()
113    {
114        static instance_specific_extension_container_pool inst;
115        return inst;
116    }
117
118    instance_specific_extension_container *create();
119    void free(instance_specific_extension_container *);
120
121  private:
122    instance_specific_extension_container *unused;
123};
124
125instance_specific_extension_container *
126instance_specific_extension_container_pool::create()
127{
128    if (!unused) {
129        unused = new instance_specific_extension_container();
130    }
131    instance_specific_extension_container *tmp = unused;
132    unused = unused->next;
133    return tmp;
134}
135
136void
137instance_specific_extension_container_pool::free(
138        instance_specific_extension_container *cont)
139{
140    cont->next = unused;
141    unused = cont;
142}
143
144instance_specific_extension_container_pool::
145    ~instance_specific_extension_container_pool()
146{
147    while (unused) {
148        instance_specific_extension_container *tmp = unused;
149        unused = unused->next;
150        delete tmp;
151    }
152}
153
154// ----------------------------------------------------------------------------
155
156instance_specific_extension_container *
157instance_specific_extension_container::create()
158{
159    return instance_specific_extension_container_pool::instance().create();
160}
161
162instance_specific_extension_container::
163    instance_specific_extension_container() :
164    use_count(0), m_txn(NULL), m_release_fn(NULL), m_carrier(NULL), next(NULL)
165{
166    resize();
167}
168
169void
170instance_specific_extension_container::
171    attach_carrier(instance_specific_extension_carrier *carrier,
172            void *txn, release_fn *rel_fn)
173{
174    m_txn = txn;
175    m_release_fn = rel_fn;
176    m_carrier = carrier;
177}
178
179void
180instance_specific_extension_container::resize()
181{
182    m_ispex_per_accessor.resize(max_num_ispex_accessors());
183
184    for (unsigned int i = 0; i < m_ispex_per_accessor.size(); ++i) {
185        m_ispex_per_accessor[i] =
186            new instance_specific_extensions_per_accessor(this);
187        m_ispex_per_accessor[i]->resize_extensions();
188    }
189}
190
191instance_specific_extension_container::
192    ~instance_specific_extension_container()
193{
194    for (unsigned int i = 0; i < m_ispex_per_accessor.size(); ++i)
195        delete m_ispex_per_accessor[i];
196}
197
198void
199instance_specific_extension_container::inc_use_count()
200{
201    use_count++;
202}
203
204void
205instance_specific_extension_container::dec_use_count()
206{
207    if ((--use_count) == 0) {
208        // If this container isn't used any more we release the carrier
209        // extension.
210        m_release_fn(m_carrier, m_txn);
211        // We send it back to our pool.
212        instance_specific_extension_container_pool::instance().free(this);
213    }
214}
215
216instance_specific_extensions_per_accessor *
217instance_specific_extension_container::get_accessor(unsigned int idx)
218{
219    return m_ispex_per_accessor[idx];
220}
221
222// ----------------------------------------------------------------------------
223
224// non-templatized version with manual index:
225ispex_base *
226instance_specific_extensions_per_accessor::set_extension(
227        unsigned int index, ispex_base *ext)
228{
229    resize_extensions();
230    ispex_base *tmp = m_extensions[index];
231    m_extensions[index] = ext;
232    if (!tmp && ext)
233        m_container->inc_use_count();
234    return tmp;
235}
236
237ispex_base *
238instance_specific_extensions_per_accessor::get_extension(
239        unsigned int index) const
240{
241    return (index < m_extensions.size()) ? m_extensions[index] : nullptr;
242}
243
244void
245instance_specific_extensions_per_accessor::clear_extension(unsigned int index)
246{
247    if (index < m_extensions.size()) {
248        if (m_extensions[index])
249            m_container->dec_use_count();
250        m_extensions[index] = static_cast<ispex_base *>(nullptr);
251    }
252}
253
254void
255instance_specific_extensions_per_accessor::resize_extensions()
256{
257    m_extensions.expand(ispex_registry::max_num_extensions());
258}
259
260// ----------------------------------------------------------------------------
261
262instance_specific_extension_accessor::instance_specific_extension_accessor() :
263    m_index(max_num_ispex_accessors(true) - 1)
264{}
265
266} // namespace tlm_utils
267