/***************************************************************************** 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 #include #include #include #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 struct enable_if {}; template struct enable_if { typedef T type; }; template struct remove_const { typedef T type; }; template struct remove_const { typedef T type; }; template struct is_same { static const bool value = false; }; template struct is_same { static const bool value = true; }; template struct is_const { static const bool value = false; }; template struct is_const { static const bool value = true; }; #endif template struct is_more_const { static const bool value = is_same::type, typename remove_const::type>::value && is_const::value >= is_const::value; }; struct special_result {}; template struct remove_special_fptr {}; template struct remove_special_fptr { 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::type * = NULL } // namespace sc_gem5 namespace sc_core { template class sc_vector_assembly; template class sc_vector; template sc_vector_assembly sc_assemble_vector( sc_vector &, 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 &get_elements() const; protected: std::vector objs; // What's returned by get_elements, which really returns the elemenets // which are also objects. mutable std::vector 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 class sc_direct_access { public: typedef Element ElementType; typedef ElementType Type; typedef typename sc_gem5::remove_const::type PlainType; typedef sc_direct_access Policy; typedef sc_direct_access NonConstPolicy; typedef sc_direct_access ConstPolicy; sc_direct_access() {} sc_direct_access(const NonConstPolicy &) {} template 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 class sc_member_access { public: template friend class sc_member_access; typedef Element ElementType; typedef Access AccessType; typedef AccessType (ElementType::*MemberType); typedef AccessType Type; typedef typename sc_gem5::remove_const::type PlainType; typedef typename sc_gem5::remove_const::type PlainElemType; typedef sc_member_access Policy; typedef sc_member_access NonConstPolicy; typedef sc_member_access 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 > class sc_vector_iter : public std::iterator, 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::type PlainType; typedef const PlainType ConstPlainType; typedef typename sc_direct_access::ConstPolicy ConstDirectPolicy; friend class sc_vector; template friend class sc_vector_assembly; template friend class sc_vector_iter; typedef std::iterator BaseType; typedef sc_vector_iter ThisType; typedef sc_vector VectorType; typedef std::vector StorageType; template struct SelectIter { typedef typename std::vector::iterator type; }; template struct SelectIter { typedef typename std::vector::const_iterator type; }; typedef typename SelectIter::type RawIterator; typedef sc_vector_iter ConstIterator; typedef sc_vector_iter 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 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((void *)*it_)); } pointer operator -> () const { return Policy::get(static_cast((void *)*it_)); } reference operator [] (difference_type n) const { return *Policy::get(static_cast((void *)it_[n])); } difference_type operator - (ConstDirectIterator const &other) const { return it_ - other.it_; } }; template class sc_vector : public sc_vector_base { public: using sc_vector_base::size_type; typedef sc_vector_iter iterator; typedef sc_vector_iter 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 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::create_element); } static T * create_element(const char *_name, size_type index) { return new T(_name); } template 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(objs[index]); } const T & operator [] (size_type index) const { return *static_cast(objs[index]); } T & at(size_type index) { this->checkIndex(index); return *static_cast(objs[index]); } const T & at(size_type index) const { this->checkIndex(index); return *static_cast(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 iterator bind(sc_vector_assembly c) { return bind(c.begin(), c.end()); } template iterator bind(BindableContainer &c) { return bind(c.begin(), c.end()); } template iterator bind(BindableIterator first, BindableIterator last) { return bind(first, last, this->begin()); } template 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 iterator operator () (sc_vector_assembly c) { return (*this)(c.begin(), c.end()); } template iterator operator () (ArgumentContainer &c) { return (*this)(c.begin(), c.end()); } template iterator operator () (ArgumentIterator first, ArgumentIterator last) { return (*this)(first, last, this->begin()); } template 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_base() {} sc_vector &operator = (const sc_vector &) { return *this; } void clear() { for (auto obj: objs) delete static_cast(obj); } template friend class sc_vector_assembly; sc_object * objectCast(void *ptr) const { return implicitCast(static_cast(ptr)); } }; template class sc_vector_assembly { public: friend sc_vector_assembly sc_assemble_vector<>( sc_vector &, MT (T::*)); typedef size_t size_type; typedef sc_vector_iter > iterator; typedef sc_vector_iter< const T, sc_member_access > 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 get_elements() const { std::vector ret; for (const_iterator it = begin(); it != end(); it++) { sc_object *obj_ptr = vec_->objectCast(const_cast(&*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 iterator bind(sc_vector_assembly c) { return bind(c.begin(), c.end()); } template iterator bind(BindableContainer &c) { return bind(c.begin(), c.end()); } template iterator bind(BindableIterator first, BindableIterator last) { return bind(first, last, this->begin()); } template 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 iterator bind(BindableIterator first, BindableIterator last, typename sc_vector::iterator from) { return bind(first, last, iterator(from.it_, ptr_)); } template iterator operator () (sc_vector_assembly c) { return (*this)(c.begin(), c.end()); } template iterator operator () (ArgumentContainer &c) { return (*this)(c.begin(), c.end()); } template iterator operator () (ArgumentIterator first, ArgumentIterator last) { return (*this)(first, last, this->begin()); } template 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 iterator operator () (ArgumentIterator first, ArgumentIterator last, typename sc_vector::iterator from) { return (*this)(first, last, iterator(from.it_, ptr_)); } private: sc_vector_assembly(sc_vector &v, MemberType ptr) : vec_(&v), ptr_(ptr) {} sc_vector *vec_; MemberType ptr_; }; template sc_vector_assembly sc_assemble_vector(sc_vector &v, MT (T::*ptr)) { return sc_vector_assembly(v, ptr); } } // namespace sc_core #endif //__SYSTEMC_EXT_UTIL_SC_VECTOR_HH__