| /***************************************************************************** |
| |
| 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. |
| |
| *****************************************************************************/ |
| |
| /* |
| * Copyright 2018 Google, Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Authors: Gabe Black |
| */ |
| |
| #ifndef __SYSTEMC_EXT_UTIL_SC_VECTOR_HH__ |
| #define __SYSTEMC_EXT_UTIL_SC_VECTOR_HH__ |
| |
| #include <stdint.h> |
| |
| #include <exception> |
| #include <iterator> |
| #include <vector> |
| |
| #include "../core/sc_module.hh" |
| #include "../core/sc_object.hh" |
| #include "messages.hh" |
| |
| namespace sc_gem5 |
| { |
| |
| // Goop for supporting sc_vector_iter, simplified from the Accellera version. |
| |
| #if __cplusplus >= 201103L |
| |
| using std::enable_if; |
| using std::remove_const; |
| using std::is_same; |
| using std::is_const; |
| |
| #else |
| |
| template<bool Cond, typename T=void> |
| struct enable_if |
| {}; |
| |
| template<typename T> |
| struct enable_if<true, T> |
| { |
| typedef T type; |
| }; |
| |
| template <typename T> |
| struct remove_const |
| { |
| typedef T type; |
| }; |
| template <typename T> |
| struct remove_const<const T> |
| { |
| typedef T type; |
| }; |
| |
| template <typename T, typename U> |
| struct is_same |
| { |
| static const bool value = false; |
| }; |
| template <typename T> |
| struct is_same<T, T> |
| { |
| static const bool value = true; |
| }; |
| |
| template <typename T> |
| struct is_const |
| { |
| static const bool value = false; |
| }; |
| template <typename T> |
| struct is_const<const T> |
| { |
| static const bool value = true; |
| }; |
| |
| #endif |
| |
| template <typename CT, typename T> |
| struct is_more_const |
| { |
| static const bool value = |
| is_same<typename remove_const<CT>::type, |
| typename remove_const<T>::type>::value && |
| is_const<CT>::value >= is_const<T>::value; |
| }; |
| |
| struct special_result |
| {}; |
| |
| template <typename T> |
| struct remove_special_fptr |
| {}; |
| |
| template <typename T> |
| struct remove_special_fptr<special_result & (*)(T)> |
| { |
| typedef T type; |
| }; |
| |
| #define SC_RPTYPE_(Type) \ |
| ::sc_gem5::remove_special_fptr< \ |
| ::sc_gem5::special_result & (*) Type>::type::value |
| |
| #define SC_ENABLE_IF_(Cond) \ |
| typename ::sc_gem5::enable_if<SC_RPTYPE_(Cond)>::type * = NULL |
| |
| } // namespace sc_gem5 |
| |
| namespace sc_core |
| { |
| |
| template <typename T, typename MT> |
| class sc_vector_assembly; |
| |
| template <typename T> |
| class sc_vector; |
| |
| template <typename T, typename MT> |
| sc_vector_assembly<T, MT> sc_assemble_vector( |
| sc_vector<T> &, MT(T::* member_ptr)); |
| |
| class sc_vector_base : public sc_object |
| { |
| public: |
| typedef size_t size_type; |
| |
| sc_vector_base(const char *_name) : sc_object(_name) {} |
| |
| virtual const char *kind() const { return "sc_vector"; } |
| size_type size() const; |
| const std::vector<sc_object *> &get_elements() const; |
| |
| protected: |
| std::vector<void *> objs; |
| |
| // What's returned by get_elements, which really returns the elemenets |
| // which are also objects. |
| mutable std::vector<sc_object *> elements; |
| |
| sc_object *implicitCast(sc_object *p) const { return p; } |
| sc_object *implicitCast(...) const |
| { |
| SC_REPORT_ERROR(SC_ID_VECTOR_NONOBJECT_ELEMENTS_, name()); |
| return nullptr; |
| } |
| virtual sc_object *objectCast(void *) const = 0; |
| |
| void checkIndex(size_type index) const; |
| void forceParent() const; |
| void unforceParent() const; |
| |
| void reportEmpty(const char *kind_, bool empty_dest) const; |
| }; |
| |
| |
| /* |
| * Non-standard iterator access adapters. Without using these, the classes as |
| * defined in the standard won't compile because of redundant bind() overloads. |
| */ |
| |
| template <typename Element> |
| class sc_direct_access |
| { |
| public: |
| typedef Element ElementType; |
| typedef ElementType Type; |
| typedef typename sc_gem5::remove_const<ElementType>::type PlainType; |
| |
| typedef sc_direct_access<ElementType> Policy; |
| typedef sc_direct_access<PlainType> NonConstPolicy; |
| typedef sc_direct_access<const PlainType> ConstPolicy; |
| |
| sc_direct_access() {} |
| sc_direct_access(const NonConstPolicy &) {} |
| |
| template <typename U> |
| sc_direct_access(const U &, |
| SC_ENABLE_IF_(( |
| sc_gem5::is_more_const< |
| ElementType, typename U::Policy::ElementType> |
| )) |
| ) |
| {} |
| |
| ElementType * |
| get(ElementType *this_) const |
| { |
| return this_; |
| } |
| }; |
| |
| template <typename Element, typename Access> |
| class sc_member_access |
| { |
| public: |
| template <typename, typename> |
| friend class sc_member_access; |
| |
| typedef Element ElementType; |
| typedef Access AccessType; |
| typedef AccessType (ElementType::*MemberType); |
| typedef AccessType Type; |
| typedef typename sc_gem5::remove_const<AccessType>::type PlainType; |
| typedef typename sc_gem5::remove_const<ElementType>::type PlainElemType; |
| |
| typedef sc_member_access<ElementType, AccessType> Policy; |
| typedef sc_member_access<PlainElemType, PlainType> NonConstPolicy; |
| typedef sc_member_access<const PlainElemType, const PlainType> ConstPolicy; |
| |
| sc_member_access(MemberType ptr) : ptr_(ptr) {} |
| sc_member_access(const NonConstPolicy &other) : ptr_(other.ptr_) {} |
| |
| AccessType *get(ElementType *this_) const { return &(this_->*ptr_); } |
| |
| private: |
| MemberType ptr_; |
| }; |
| |
| template <typename Element, |
| typename AccessPolicy=sc_direct_access<Element> > |
| class sc_vector_iter : |
| public std::iterator<std::random_access_iterator_tag, |
| typename AccessPolicy::Type>, |
| private AccessPolicy |
| { |
| private: |
| typedef Element ElementType; |
| typedef typename AccessPolicy::Policy Policy; |
| typedef typename AccessPolicy::NonConstPolicy NonConstPolicy; |
| typedef typename AccessPolicy::ConstPolicy ConstPolicy; |
| typedef typename Policy::Type AccessType; |
| |
| typedef typename sc_gem5::remove_const<ElementType>::type PlainType; |
| typedef const PlainType ConstPlainType; |
| typedef typename sc_direct_access<PlainType>::ConstPolicy |
| ConstDirectPolicy; |
| |
| friend class sc_vector<PlainType>; |
| template <typename, typename> |
| friend class sc_vector_assembly; |
| template <typename, typename> |
| friend class sc_vector_iter; |
| |
| typedef std::iterator<std::random_access_iterator_tag, AccessType> |
| BaseType; |
| typedef sc_vector_iter ThisType; |
| typedef sc_vector<PlainType> VectorType; |
| typedef std::vector<void *> StorageType; |
| |
| template <typename U> |
| struct SelectIter |
| { |
| typedef typename std::vector<void *>::iterator type; |
| }; |
| template <typename U> |
| struct SelectIter<const U> |
| { |
| typedef typename std::vector<void *>::const_iterator type; |
| }; |
| typedef typename SelectIter<ElementType>::type RawIterator; |
| typedef sc_vector_iter<ConstPlainType, ConstPolicy> ConstIterator; |
| typedef sc_vector_iter<ConstPlainType, ConstDirectPolicy> |
| ConstDirectIterator; |
| |
| RawIterator it_; |
| |
| sc_vector_iter(RawIterator it, Policy acc=Policy()) : |
| Policy(acc), it_(it) |
| {} |
| |
| Policy const &get_policy() const { return *this; } |
| |
| public: |
| // Conforms to Random Access Iterator category. |
| // See ISO/IEC 14882:2003(E), 24.1 [lib.iterator.requirements] |
| |
| typedef typename BaseType::difference_type difference_type; |
| typedef typename BaseType::reference reference; |
| typedef typename BaseType::pointer pointer; |
| |
| sc_vector_iter() : Policy(), it_() {} |
| |
| template <typename It> |
| sc_vector_iter(const It &it, |
| SC_ENABLE_IF_(( |
| sc_gem5::is_more_const< |
| ElementType, typename It::Policy::ElementType> |
| )) |
| ) : Policy(it.get_policy()), it_(it.it_) |
| {} |
| |
| ThisType & |
| operator ++ () |
| { |
| ++it_; |
| return *this; |
| } |
| ThisType & |
| operator -- () |
| { |
| --it_; |
| return *this; |
| } |
| ThisType |
| operator ++ (int) |
| { |
| ThisType old(*this); |
| ++it_; |
| return old; |
| } |
| ThisType |
| operator -- (int) |
| { |
| ThisType old(*this); |
| --it_; |
| return old; |
| } |
| |
| ThisType |
| operator + (difference_type n) const |
| { |
| return ThisType(it_ + n, get_policy()); |
| } |
| ThisType |
| operator - (difference_type n) const |
| { |
| return ThisType(it_ - n, get_policy()); |
| } |
| |
| ThisType & |
| operator += (difference_type n) |
| { |
| it_ += n; |
| return *this; |
| } |
| |
| ThisType & |
| operator -= (difference_type n) |
| { |
| it_ -= n; |
| return *this; |
| } |
| |
| bool |
| operator == (const ConstDirectIterator &other) const |
| { |
| return it_ == other.it_; |
| } |
| bool |
| operator != (const ConstDirectIterator &other) const |
| { |
| return it_ != other.it_; |
| } |
| bool |
| operator <= (const ConstDirectIterator &other) const |
| { |
| return it_ <= other.it_; |
| } |
| bool |
| operator >= (const ConstDirectIterator &other) const |
| { |
| return it_ >= other.it_; |
| } |
| bool |
| operator < (const ConstDirectIterator &other) const |
| { |
| return it_ < other.it_; |
| } |
| bool |
| operator > (const ConstDirectIterator &other) const |
| { |
| return it_ > other.it_; |
| } |
| |
| reference |
| operator * () const |
| { |
| return *Policy::get(static_cast<ElementType *>((void *)*it_)); |
| } |
| pointer |
| operator -> () const |
| { |
| return Policy::get(static_cast<ElementType *>((void *)*it_)); |
| } |
| reference |
| operator [] (difference_type n) const |
| { |
| return *Policy::get(static_cast<ElementType *>((void *)it_[n])); |
| } |
| |
| difference_type |
| operator - (ConstDirectIterator const &other) const |
| { |
| return it_ - other.it_; |
| } |
| }; |
| |
| template <typename T> |
| class sc_vector : public sc_vector_base |
| { |
| public: |
| using sc_vector_base::size_type; |
| typedef sc_vector_iter<T> iterator; |
| typedef sc_vector_iter<const T> const_iterator; |
| |
| sc_vector() : sc_vector_base(::sc_core::sc_gen_unique_name("vector")) {} |
| explicit sc_vector(const char *_name) : sc_vector_base(_name) {} |
| sc_vector(const char *_name, size_type _size) : sc_vector_base(_name) |
| { |
| init(_size); |
| } |
| template <typename Creator> |
| sc_vector(const char *_name, size_type _size, Creator creator) : |
| sc_vector_base(_name) |
| { |
| init(_size, creator); |
| } |
| virtual ~sc_vector() { clear(); } |
| |
| void |
| init(size_type _size) |
| { |
| init(_size, &sc_vector<T>::create_element); |
| } |
| static T * |
| create_element(const char *_name, size_type index) |
| { |
| return new T(_name); |
| } |
| |
| template <typename Creator> |
| void |
| init(size_type _size, Creator creator) |
| { |
| forceParent(); |
| try { |
| for (size_type i = 0; i < _size; i++) { |
| // XXX The name and scope of these objects needs to be handled |
| // specially. |
| T *p = creator(sc_gen_unique_name(basename()), i); |
| objs.push_back(p); |
| } |
| } catch (...) { |
| unforceParent(); |
| clear(); |
| throw; |
| } |
| unforceParent(); |
| } |
| |
| T &operator [] (size_type index) { return *static_cast<T *>(objs[index]); } |
| const T & |
| operator [] (size_type index) const |
| { |
| return *static_cast<const T *>(objs[index]); |
| } |
| |
| T & |
| at(size_type index) |
| { |
| this->checkIndex(index); |
| return *static_cast<T *>(objs[index]); |
| } |
| const T & |
| at(size_type index) const |
| { |
| this->checkIndex(index); |
| return *static_cast<const T *>(objs[index]); |
| } |
| |
| iterator begin() { return objs.begin(); } |
| iterator end() { return objs.end(); } |
| const_iterator begin() const { return objs.begin(); } |
| const_iterator end() const { return objs.end(); } |
| const_iterator cbegin() const { return objs.begin(); } |
| const_iterator cend() const { return objs.end(); } |
| |
| template <typename ContainerType, typename ArgumentType> |
| iterator |
| bind(sc_vector_assembly<ContainerType, ArgumentType> c) |
| { |
| return bind(c.begin(), c.end()); |
| } |
| |
| template <typename BindableContainer> |
| iterator |
| bind(BindableContainer &c) |
| { |
| return bind(c.begin(), c.end()); |
| } |
| |
| template <typename BindableIterator> |
| iterator |
| bind(BindableIterator first, BindableIterator last) |
| { |
| return bind(first, last, this->begin()); |
| } |
| |
| template <typename BindableIterator> |
| iterator |
| bind(BindableIterator first, BindableIterator last, iterator from) |
| { |
| if (!size() || from == end() || first == last) |
| reportEmpty(kind(), from == end()); |
| |
| while (from != end() && first != last) |
| (*from++).bind(*first++); |
| return from; |
| } |
| |
| template <typename ContainerType, typename ArgumentType> |
| iterator |
| operator () (sc_vector_assembly<ContainerType, ArgumentType> c) |
| { |
| return (*this)(c.begin(), c.end()); |
| } |
| |
| template <typename ArgumentContainer> |
| iterator |
| operator () (ArgumentContainer &c) |
| { |
| return (*this)(c.begin(), c.end()); |
| } |
| |
| template <typename ArgumentIterator> |
| iterator |
| operator () (ArgumentIterator first, ArgumentIterator last) |
| { |
| return (*this)(first, last, this->begin()); |
| } |
| |
| template <typename ArgumentIterator> |
| iterator |
| operator () (ArgumentIterator first, ArgumentIterator last, iterator from) |
| { |
| if (!size() || from == end() || first == last) |
| reportEmpty(kind(), from == end()); |
| |
| while (from != end() && first != last) |
| (*from++)(*first++); |
| return from; |
| } |
| |
| private: |
| // Disabled |
| sc_vector(const sc_vector &); |
| sc_vector &operator = (const sc_vector &); |
| |
| void |
| clear() |
| { |
| for (auto obj: objs) |
| delete static_cast<T *>(obj); |
| } |
| |
| template <typename, typename> |
| friend class sc_vector_assembly; |
| |
| sc_object * |
| objectCast(void *ptr) const |
| { |
| return implicitCast(static_cast<T *>(ptr)); |
| } |
| }; |
| |
| template <typename T, typename MT> |
| class sc_vector_assembly |
| { |
| public: |
| friend sc_vector_assembly<T, MT> sc_assemble_vector<>( |
| sc_vector<T> &, MT (T::*)); |
| |
| typedef size_t size_type; |
| typedef sc_vector_iter<T, sc_member_access<T, MT> > iterator; |
| typedef sc_vector_iter< |
| const T, sc_member_access<const T, const MT> > const_iterator; |
| typedef MT (T::*MemberType); |
| |
| sc_vector_assembly(const sc_vector_assembly &other) : |
| vec_(other.vec_), ptr_(other.ptr_) |
| {} |
| |
| iterator begin() { return iterator(vec_->begin().it_, ptr_); } |
| iterator end() { return iterator(vec_->end().it_, ptr_); } |
| |
| const_iterator |
| cbegin() const |
| { |
| return const_iterator(vec_->begin().it_, ptr_); |
| } |
| const_iterator |
| cend() const |
| { |
| return const_iterator(vec_->end().it_, ptr_); |
| } |
| |
| const_iterator |
| begin() const |
| { |
| return const_iterator(vec_->begin().it_, ptr_); |
| } |
| const_iterator |
| end() const |
| { |
| return const_iterator(vec_->end().it_, ptr_); |
| } |
| |
| size_type size() const { return vec_->size(); } |
| |
| std::vector<sc_object *> |
| get_elements() const |
| { |
| std::vector<sc_object *> ret; |
| for (const_iterator it = begin(); it != end(); it++) { |
| sc_object *obj_ptr = vec_->objectCast(const_cast<MT *>(&*it)); |
| |
| if (obj_ptr) |
| ret.push_back(obj_ptr); |
| } |
| return ret; |
| } |
| |
| typename iterator::reference |
| operator [] (size_type i) |
| { |
| return (*vec_)[i].*ptr_; |
| } |
| typename const_iterator::reference |
| operator [] (size_type i) const |
| { |
| return (*vec_)[i].*ptr_; |
| } |
| |
| typename iterator::reference |
| at(size_type i) |
| { |
| return vec_->at(i).*ptr_; |
| } |
| typename const_iterator::reference |
| at(size_type i) const |
| { |
| return vec_->at(i).*ptr_; |
| } |
| |
| template <typename ContainerType, typename ArgumentType> |
| iterator |
| bind(sc_vector_assembly<ContainerType, ArgumentType> c) |
| { |
| return bind(c.begin(), c.end()); |
| } |
| |
| template <typename BindableContainer> |
| iterator |
| bind(BindableContainer &c) |
| { |
| return bind(c.begin(), c.end()); |
| } |
| |
| template <typename BindableIterator> |
| iterator |
| bind(BindableIterator first, BindableIterator last) |
| { |
| return bind(first, last, this->begin()); |
| } |
| |
| template <typename BindableIterator> |
| iterator |
| bind(BindableIterator first, BindableIterator last, iterator from) |
| { |
| if (!size() || from == end() || first == last) |
| vec_->reportEmpty("sc_vector_assembly", from == end()); |
| |
| while (from != end() && first != last) |
| (*from++).bind(*first++); |
| return from; |
| } |
| |
| template <typename BindableIterator> |
| iterator |
| bind(BindableIterator first, BindableIterator last, |
| typename sc_vector<T>::iterator from) |
| { |
| return bind(first, last, iterator(from.it_, ptr_)); |
| } |
| |
| template <typename ContainerType, typename ArgumentType> |
| iterator |
| operator () (sc_vector_assembly<ContainerType, ArgumentType> c) |
| { |
| return (*this)(c.begin(), c.end()); |
| } |
| |
| template <typename ArgumentContainer> |
| iterator |
| operator () (ArgumentContainer &c) |
| { |
| return (*this)(c.begin(), c.end()); |
| } |
| |
| template <typename ArgumentIterator> |
| iterator |
| operator () (ArgumentIterator first, ArgumentIterator last) |
| { |
| return (*this)(first, last, this->begin()); |
| } |
| |
| template <typename ArgumentIterator> |
| iterator |
| operator () (ArgumentIterator first, ArgumentIterator last, iterator from) |
| { |
| if (!size() || from == end() || first == last) |
| vec_->reportEmpty("sc_vector_assembly", from == end()); |
| |
| while (from != end() && first != last) |
| (*from++)(*first++); |
| return from; |
| } |
| |
| template <typename ArgumentIterator> |
| iterator |
| operator () (ArgumentIterator first, ArgumentIterator last, |
| typename sc_vector<T>::iterator from) |
| { |
| return (*this)(first, last, iterator(from.it_, ptr_)); |
| } |
| |
| private: |
| sc_vector_assembly(sc_vector<T> &v, MemberType ptr) : |
| vec_(&v), ptr_(ptr) |
| {} |
| |
| sc_vector<T> *vec_; |
| MemberType ptr_; |
| }; |
| |
| template <typename T, typename MT> |
| sc_vector_assembly<T, MT> |
| sc_assemble_vector(sc_vector<T> &v, MT (T::*ptr)) |
| { |
| return sc_vector_assembly<T, MT>(v, ptr); |
| } |
| |
| } // namespace sc_core |
| |
| #endif //__SYSTEMC_EXT_UTIL_SC_VECTOR_HH__ |