addr_range_map.hh revision 12777
14484Sbinkertn@umich.edu/*
24484Sbinkertn@umich.edu * Copyright (c) 2012, 2018 ARM Limited
34484Sbinkertn@umich.edu * All rights reserved
44484Sbinkertn@umich.edu *
54484Sbinkertn@umich.edu * The license below extends only to copyright in the software and shall
64484Sbinkertn@umich.edu * not be construed as granting a license to any other intellectual
74484Sbinkertn@umich.edu * property including but not limited to intellectual property relating
84484Sbinkertn@umich.edu * to a hardware implementation of the functionality of the software
94484Sbinkertn@umich.edu * licensed hereunder.  You may use the software subject to the license
104484Sbinkertn@umich.edu * terms below provided that you ensure that this notice is replicated
114484Sbinkertn@umich.edu * unmodified and in its entirety in all distributions of the software,
124484Sbinkertn@umich.edu * modified or unmodified, in source code or in binary form.
134484Sbinkertn@umich.edu *
144484Sbinkertn@umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
154484Sbinkertn@umich.edu * All rights reserved.
164484Sbinkertn@umich.edu *
174484Sbinkertn@umich.edu * Redistribution and use in source and binary forms, with or without
184484Sbinkertn@umich.edu * modification, are permitted provided that the following conditions are
194484Sbinkertn@umich.edu * met: redistributions of source code must retain the above copyright
204484Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer;
214484Sbinkertn@umich.edu * redistributions in binary form must reproduce the above copyright
224484Sbinkertn@umich.edu * notice, this list of conditions and the following disclaimer in the
234484Sbinkertn@umich.edu * documentation and/or other materials provided with the distribution;
244484Sbinkertn@umich.edu * neither the name of the copyright holders nor the names of its
254484Sbinkertn@umich.edu * contributors may be used to endorse or promote products derived from
264484Sbinkertn@umich.edu * this software without specific prior written permission.
274484Sbinkertn@umich.edu *
284484Sbinkertn@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
294484Sbinkertn@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
304484Sbinkertn@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
314484Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
324484Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
334484Sbinkertn@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
344484Sbinkertn@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
354484Sbinkertn@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
364484Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
374484Sbinkertn@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
384484Sbinkertn@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
394484Sbinkertn@umich.edu *
404484Sbinkertn@umich.edu * Authors: Ali Saidi
414484Sbinkertn@umich.edu *          Andreas Hansson
424484Sbinkertn@umich.edu */
434484Sbinkertn@umich.edu
444484Sbinkertn@umich.edu#ifndef __BASE_ADDR_RANGE_MAP_HH__
454484Sbinkertn@umich.edu#define __BASE_ADDR_RANGE_MAP_HH__
464484Sbinkertn@umich.edu
474484Sbinkertn@umich.edu#include <map>
484484Sbinkertn@umich.edu#include <utility>
494484Sbinkertn@umich.edu
504484Sbinkertn@umich.edu#include "base/addr_range.hh"
514484Sbinkertn@umich.edu
524484Sbinkertn@umich.edu/**
534484Sbinkertn@umich.edu * The AddrRangeMap uses an STL map to implement an interval tree for
544484Sbinkertn@umich.edu * address decoding. The value stored is a template type and can be
554484Sbinkertn@umich.edu * e.g. a port identifier, or a pointer.
564484Sbinkertn@umich.edu */
574484Sbinkertn@umich.edutemplate <typename V, int max_cache_size=0>
584484Sbinkertn@umich.educlass AddrRangeMap
594484Sbinkertn@umich.edu{
604484Sbinkertn@umich.edu  private:
614484Sbinkertn@umich.edu    typedef std::map<AddrRange, V> RangeMap;
624484Sbinkertn@umich.edu
634484Sbinkertn@umich.edu  public:
644484Sbinkertn@umich.edu    typedef typename RangeMap::iterator iterator;
654484Sbinkertn@umich.edu    typedef typename RangeMap::const_iterator const_iterator;
664484Sbinkertn@umich.edu
674484Sbinkertn@umich.edu    /**
684484Sbinkertn@umich.edu     * Find entry that contains the given address range
694484Sbinkertn@umich.edu     *
704484Sbinkertn@umich.edu     * Searches through the ranges in the address map and returns an
714484Sbinkertn@umich.edu     * iterator to the entry which range is a superset of the input
724484Sbinkertn@umich.edu     * address range. Returns end() if none found.
734484Sbinkertn@umich.edu     *
744484Sbinkertn@umich.edu     * @param r An input address range
754484Sbinkertn@umich.edu     * @return An iterator that contains the input address range
764484Sbinkertn@umich.edu     */
774484Sbinkertn@umich.edu    const_iterator
784484Sbinkertn@umich.edu    contains(const AddrRange &r) const
794484Sbinkertn@umich.edu    {
804484Sbinkertn@umich.edu        return find(r, [r](const AddrRange r1) { return r.isSubset(r1); });
814484Sbinkertn@umich.edu    }
824484Sbinkertn@umich.edu
834484Sbinkertn@umich.edu    /**
844484Sbinkertn@umich.edu     * Find entry that contains the given address
854484Sbinkertn@umich.edu     *
864484Sbinkertn@umich.edu     * Searches through the ranges in the address map and returns an
874484Sbinkertn@umich.edu     * iterator to the entry which range is a superset of the input
884484Sbinkertn@umich.edu     * address. Returns end() if none found.
894484Sbinkertn@umich.edu     *
904484Sbinkertn@umich.edu     * @param r An input address
914484Sbinkertn@umich.edu     * @return An iterator that contains the input address
924484Sbinkertn@umich.edu     */
934484Sbinkertn@umich.edu    const_iterator
944484Sbinkertn@umich.edu    contains(Addr r) const
954484Sbinkertn@umich.edu    {
964484Sbinkertn@umich.edu        return contains(RangeSize(r, 1));
974484Sbinkertn@umich.edu    }
984484Sbinkertn@umich.edu
994484Sbinkertn@umich.edu    /**
1004484Sbinkertn@umich.edu     * Find entry that intersects with the given address range
1014484Sbinkertn@umich.edu     *
1024484Sbinkertn@umich.edu     * Searches through the ranges in the address map and returns an
1034484Sbinkertn@umich.edu     * iterator to the first entry which range intersects with the
1044484Sbinkertn@umich.edu     * input address.
1054484Sbinkertn@umich.edu     *
1064484Sbinkertn@umich.edu     * @param r An input address
1074484Sbinkertn@umich.edu     * @return An iterator that intersects with the input address range
1084484Sbinkertn@umich.edu     */
1094484Sbinkertn@umich.edu    const_iterator
1104484Sbinkertn@umich.edu    intersects(const AddrRange &r) const
1114484Sbinkertn@umich.edu    {
1124484Sbinkertn@umich.edu        return find(r, [r](const AddrRange r1) { return r.intersects(r1); });
1134484Sbinkertn@umich.edu    }
1144484Sbinkertn@umich.edu
1154484Sbinkertn@umich.edu    const_iterator
1164484Sbinkertn@umich.edu    insert(const AddrRange &r, const V& d)
1174484Sbinkertn@umich.edu    {
1184484Sbinkertn@umich.edu        if (intersects(r) != end())
1194484Sbinkertn@umich.edu            return tree.end();
1204484Sbinkertn@umich.edu
1214484Sbinkertn@umich.edu        return tree.insert(std::make_pair(r, d)).first;
1224484Sbinkertn@umich.edu    }
1234484Sbinkertn@umich.edu
1244484Sbinkertn@umich.edu    void
1254484Sbinkertn@umich.edu    erase(iterator p)
1264484Sbinkertn@umich.edu    {
1274484Sbinkertn@umich.edu        cache.remove(p);
1284484Sbinkertn@umich.edu        tree.erase(p);
1294484Sbinkertn@umich.edu    }
1304484Sbinkertn@umich.edu
1314484Sbinkertn@umich.edu    void
1324484Sbinkertn@umich.edu    erase(iterator p, iterator q)
1334484Sbinkertn@umich.edu    {
1344484Sbinkertn@umich.edu        for (auto it = p; it != q; it++) {
1354484Sbinkertn@umich.edu            cache.remove(p);
1364484Sbinkertn@umich.edu        }
1374484Sbinkertn@umich.edu        tree.erase(p,q);
1384484Sbinkertn@umich.edu    }
1394484Sbinkertn@umich.edu
1404484Sbinkertn@umich.edu    void
1414484Sbinkertn@umich.edu    clear()
142    {
143        cache.erase(cache.begin(), cache.end());
144        tree.erase(tree.begin(), tree.end());
145    }
146
147    const_iterator
148    begin() const
149    {
150        return tree.begin();
151    }
152
153    iterator
154    begin()
155    {
156        return tree.begin();
157    }
158
159    const_iterator
160    end() const
161    {
162        return tree.end();
163    }
164
165    iterator
166    end()
167    {
168        return tree.end();
169    }
170
171    std::size_t
172    size() const
173    {
174        return tree.size();
175    }
176
177    bool
178    empty() const
179    {
180        return tree.empty();
181    }
182
183  private:
184    /**
185     * Add an address range map entry to the cache.
186     *
187     * @param it Iterator to the entry in the address range map
188     */
189    void
190    addNewEntryToCache(const_iterator it) const
191    {
192        if (max_cache_size != 0) {
193            // If there's a cache, add this element to it.
194            if (cache.size() >= max_cache_size) {
195                // If the cache is full, move the last element to the
196                // front and overwrite it with the new value. This
197                // avoids creating or destroying elements of the list.
198                auto last = cache.end();
199                last--;
200                *last = it;
201                if (max_cache_size > 1)
202                    cache.splice(cache.begin(), cache, last);
203            } else {
204                cache.push_front(it);
205            }
206        }
207    }
208
209    /**
210     * Find entry that satisfies a condition on an address range
211     *
212     * Searches through the ranges in the address map and returns an
213     * iterator to the entry that satisfies the input conidition on
214     * the input address range. Returns end() if none found.
215     *
216     * @param r An input address range
217     * @param f A condition on an address range
218     * @return An iterator that contains the input address range
219     */
220    const_iterator
221    find(const AddrRange &r, std::function<bool(const AddrRange)> cond) const
222    {
223        // Check the cache first
224        for (auto c = cache.begin(); c != cache.end(); c++) {
225            auto it = *c;
226            if (cond(it->first)) {
227                // If this entry matches, promote it to the front
228                // of the cache and return it.
229                cache.splice(cache.begin(), cache, c);
230                return it;
231            }
232        }
233
234        const_iterator next = tree.upper_bound(r);
235        if (next != end() && cond(next->first)) {
236            addNewEntryToCache(next);
237            return next;
238        }
239        if (next == begin())
240            return end();
241        next--;
242
243        const_iterator i;
244        do {
245            i = next;
246            if (cond(i->first)) {
247                addNewEntryToCache(i);
248                return i;
249            }
250            // Keep looking if the next range merges with the current one.
251        } while (next != begin() &&
252                 (--next)->first.mergesWith(i->first));
253
254        return end();
255    }
256
257    RangeMap tree;
258
259    /**
260     * A list of iterator that correspond to the max_cache_size most
261     * recently used entries in the address range map. This mainly
262     * used to optimize lookups. The elements in the list should
263     * always be valid iterators of the tree.
264     */
265    mutable std::list<const_iterator> cache;
266};
267
268#endif //__BASE_ADDR_RANGE_MAP_HH__
269