/* * Copyright 2008-2012 NVIDIA Corporation * * Licensed 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. */ /*! \file vector_base.inl * \brief Inline file for vector_base.h. */ #include #include #include #include #include #include #include #include #include #include #include namespace thrust { namespace detail { template vector_base ::vector_base(void) :m_storage(), m_size(0) { ; } // end vector_base::vector_base() template vector_base ::vector_base(size_type n) :m_storage(), m_size(0) { default_init(n); } // end vector_base::vector_base() template vector_base ::vector_base(size_type n, const value_type &value) :m_storage(), m_size(0) { fill_init(n,value); } // end vector_base::vector_base() template vector_base ::vector_base(const vector_base &v) :m_storage(), m_size(0) { range_init(v.begin(), v.end()); } // end vector_base::vector_base() template vector_base & vector_base ::operator=(const vector_base &v) { if(this != &v) { assign(v.begin(), v.end()); } // end if return *this; } // end vector_base::operator=() template template vector_base ::vector_base(const vector_base &v) :m_storage(), m_size(0) { range_init(v.begin(), v.end()); } // end vector_base::vector_base() template template vector_base & vector_base ::operator=(const vector_base &v) { assign(v.begin(), v.end()); return *this; } // end vector_base::operator=() template template vector_base ::vector_base(const std::vector &v) :m_storage(), m_size(0) { range_init(v.begin(), v.end()); } // end vector_base::vector_base() template template vector_base & vector_base ::operator=(const std::vector &v) { assign(v.begin(), v.end()); return *this; } // end vector_base::operator=() template template void vector_base ::init_dispatch(IteratorOrIntegralType n, IteratorOrIntegralType value, true_type) { fill_init(n,value); } // end vector_base::init_dispatch() template void vector_base ::default_init(size_type n) { if(n > 0) { m_storage.allocate(n); m_size = n; m_storage.default_construct_n(begin(), size()); } // end if } // end vector_base::default_init() template void vector_base ::fill_init(size_type n, const T &x) { if(n > 0) { m_storage.allocate(n); m_size = n; m_storage.uninitialized_fill_n(begin(), size(), x); } // end if } // end vector_base::fill_init() template template void vector_base ::init_dispatch(InputIterator first, InputIterator last, false_type) { range_init(first, last); } // end vector_base::init_dispatch() template template void vector_base ::range_init(InputIterator first, InputIterator last) { range_init(first, last, typename thrust::iterator_traversal::type()); } // end vector_base::range_init() template template void vector_base ::range_init(InputIterator first, InputIterator last, thrust::incrementable_traversal_tag) { for(; first != last; ++first) push_back(*first); } // end vector_base::range_init() template template void vector_base ::range_init(ForwardIterator first, ForwardIterator last, thrust::random_access_traversal_tag) { size_type new_size = thrust::distance(first, last); allocate_and_copy(new_size, first, last, m_storage); m_size = new_size; } // end vector_base::range_init() template template vector_base ::vector_base(InputIterator first, InputIterator last) :m_storage(), m_size(0) { // check the type of InputIterator: if it's an integral type, // we need to interpret this call as (size_type, value_type) typedef thrust::detail::is_integral Integer; init_dispatch(first, last, Integer()); } // end vector_basee::vector_base() template void vector_base ::resize(size_type new_size) { if(new_size < size()) { iterator new_end = begin(); thrust::advance(new_end, new_size); erase(new_end, end()); } // end if else { append(new_size - size()); } // end else } // end vector_base::resize() template void vector_base ::resize(size_type new_size, const value_type &x) { if(new_size < size()) { iterator new_end = begin(); thrust::advance(new_end, new_size); erase(new_end, end()); } // end if else { insert(end(), new_size - size(), x); } // end else } // end vector_base::resize() template typename vector_base::size_type vector_base ::size(void) const { return m_size; } // end vector_base::size() template typename vector_base::size_type vector_base ::max_size(void) const { return m_storage.max_size(); } // end vector_base::max_size() template void vector_base ::reserve(size_type n) { if(n > capacity()) { allocate_and_copy(n, begin(), end(), m_storage); } // end if } // end vector_base::reserve() template typename vector_base::size_type vector_base ::capacity(void) const { return m_storage.size(); } // end vector_base::capacity() template void vector_base ::shrink_to_fit(void) { // use the swap trick vector_base(*this).swap(*this); } // end vector_base::shrink_to_fit() template typename vector_base::reference vector_base ::operator[](const size_type n) { return m_storage[n]; } // end vector_base::operator[] template typename vector_base::const_reference vector_base ::operator[](const size_type n) const { return m_storage[n]; } // end vector_base::operator[] template typename vector_base::iterator vector_base ::begin(void) { return m_storage.begin(); } // end vector_base::begin() template typename vector_base::const_iterator vector_base ::begin(void) const { return m_storage.begin(); } // end vector_base::begin() template typename vector_base::const_iterator vector_base ::cbegin(void) const { return begin(); } // end vector_base::cbegin() template typename vector_base::reverse_iterator vector_base ::rbegin(void) { return reverse_iterator(end()); } // end vector_base::rbegin() template typename vector_base::const_reverse_iterator vector_base ::rbegin(void) const { return const_reverse_iterator(end()); } // end vector_base::rbegin() template typename vector_base::const_reverse_iterator vector_base ::crbegin(void) const { return rbegin(); } // end vector_base::crbegin() template typename vector_base::iterator vector_base ::end(void) { iterator result = begin(); thrust::advance(result, size()); return result; } // end vector_base::end() template typename vector_base::const_iterator vector_base ::end(void) const { const_iterator result = begin(); thrust::advance(result, size()); return result; } // end vector_base::end() template typename vector_base::const_iterator vector_base ::cend(void) const { return end(); } // end vector_base::cend() template typename vector_base::reverse_iterator vector_base ::rend(void) { return reverse_iterator(begin()); } // end vector_base::rend() template typename vector_base::const_reverse_iterator vector_base ::rend(void) const { return const_reverse_iterator(begin()); } // end vector_base::rend() template typename vector_base::const_reverse_iterator vector_base ::crend(void) const { return rend(); } // end vector_base::crend() template typename vector_base::const_reference vector_base ::front(void) const { return *begin(); } // end vector_base::front() template typename vector_base::reference vector_base ::front(void) { return *begin(); } // end vector_base::front() template typename vector_base::const_reference vector_base ::back(void) const { const_iterator ptr_to_back = end(); --ptr_to_back; return *ptr_to_back; } // end vector_base::vector_base template typename vector_base::reference vector_base ::back(void) { iterator ptr_to_back = end(); --ptr_to_back; return *ptr_to_back; } // end vector_base::vector_base template typename vector_base::pointer vector_base ::data(void) { return &front(); } // end vector_base::data() template typename vector_base::const_pointer vector_base ::data(void) const { return &front(); } // end vector_base::data() template vector_base ::~vector_base(void) { // destroy every living thing m_storage.destroy(begin(),end()); } // end vector_base::~vector_base() template void vector_base ::clear(void) { resize(0); } // end vector_base::~vector_dev() template bool vector_base ::empty(void) const { return size() == 0; } // end vector_base::empty(); template void vector_base ::push_back(const value_type &x) { insert(end(), x); } // end vector_base::push_back() template void vector_base ::pop_back(void) { iterator e = end(); iterator ptr_to_back = e; --ptr_to_back; m_storage.destroy(ptr_to_back, e); --m_size; } // end vector_base::pop_back() template typename vector_base::iterator vector_base ::erase(iterator pos) { iterator end = pos; ++end; return erase(pos,end); } // end vector_base::erase() template typename vector_base::iterator vector_base ::erase(iterator first, iterator last) { // overlap copy the range [last,end()) to first // XXX this copy only potentially overlaps iterator i = thrust::detail::overlapped_copy(last, end(), first); // destroy everything after i m_storage.destroy(i, end()); // modify our size m_size -= (last - first); // return an iterator pointing to the position of the first element // following the erased range return first; } // end vector_base::erase() template void vector_base ::swap(vector_base &v) { thrust::swap(m_storage, v.m_storage); thrust::swap(m_size, v.m_size); } // end vector_base::swap() template void vector_base ::assign(size_type n, const T &x) { fill_assign(n, x); } // end vector_base::assign() template template void vector_base ::assign(InputIterator first, InputIterator last) { // we could have received assign(n, x), so disambiguate on the // type of InputIterator typedef typename thrust::detail::is_integral integral; assign_dispatch(first, last, integral()); } // end vector_base::assign() template typename vector_base::allocator_type vector_base ::get_allocator(void) const { return m_storage.get_allocator(); } // end vector_base::get_allocator() template typename vector_base::iterator vector_base ::insert(iterator position, const T &x) { // find the index of the insertion size_type index = thrust::distance(begin(), position); // make the insertion insert(position, 1, x); // return an iterator pointing back to position iterator result = begin(); thrust::advance(result, index); return result; } // end vector_base::insert() template void vector_base ::insert(iterator position, size_type n, const T &x) { fill_insert(position, n, x); } // end vector_base::insert() template template void vector_base ::insert(iterator position, InputIterator first, InputIterator last) { // we could have received insert(position, n, x), so disambiguate on the // type of InputIterator typedef typename thrust::detail::is_integral integral; insert_dispatch(position, first, last, integral()); } // end vector_base::insert() template template void vector_base ::assign_dispatch(InputIterator first, InputIterator last, false_type) { range_assign(first, last); } // end vector_base::assign_dispatch() template template void vector_base ::assign_dispatch(Integral n, Integral x, true_type) { fill_assign(n, x); } // end vector_base::assign_dispatch() template template void vector_base ::insert_dispatch(iterator position, InputIterator first, InputIterator last, false_type) { copy_insert(position, first, last); } // end vector_base::insert_dispatch() template template void vector_base ::insert_dispatch(iterator position, Integral n, Integral x, true_type) { fill_insert(position, n, x); } // end vector_base::insert_dispatch() template template void vector_base ::copy_insert(iterator position, ForwardIterator first, ForwardIterator last) { if(first != last) { // how many new elements will we create? const size_type num_new_elements = thrust::distance(first, last); if(capacity() - size() >= num_new_elements) { // we've got room for all of them // how many existing elements will we displace? const size_type num_displaced_elements = end() - position; iterator old_end = end(); if(num_displaced_elements > num_new_elements) { // construct copy n displaced elements to new elements // following the insertion m_storage.uninitialized_copy(end() - num_new_elements, end(), end()); // extend the size m_size += num_new_elements; // copy num_displaced_elements - num_new_elements elements to existing elements // this copy overlaps const size_type copy_length = (old_end - num_new_elements) - position; thrust::detail::overlapped_copy(position, old_end - num_new_elements, old_end - copy_length); // finally, copy the range to the insertion point thrust::copy(first, last, position); } // end if else { ForwardIterator mid = first; thrust::advance(mid, num_displaced_elements); // construct copy new elements at the end of the vector m_storage.uninitialized_copy(mid, last, end()); // extend the size m_size += num_new_elements - num_displaced_elements; // construct copy the displaced elements m_storage.uninitialized_copy(position, old_end, end()); // extend the size m_size += num_displaced_elements; // copy to elements which already existed thrust::copy(first, mid, position); } // end else } // end if else { const size_type old_size = size(); // compute the new capacity after the allocation size_type new_capacity = old_size + thrust::max THRUST_PREVENT_MACRO_SUBSTITUTION (old_size, num_new_elements); // allocate exponentially larger new storage new_capacity = thrust::max THRUST_PREVENT_MACRO_SUBSTITUTION (new_capacity, 2 * capacity()); // do not exceed maximum storage new_capacity = thrust::min THRUST_PREVENT_MACRO_SUBSTITUTION (new_capacity, max_size()); if(new_capacity > max_size()) { throw std::length_error("insert(): insertion exceeds max_size()."); } // end if storage_type new_storage(new_capacity); // record how many constructors we invoke in the try block below iterator new_end = new_storage.begin(); try { // construct copy elements before the insertion to the beginning of the newly // allocated storage new_end = m_storage.uninitialized_copy(begin(), position, new_storage.begin()); // construct copy elements to insert new_end = m_storage.uninitialized_copy(first, last, new_end); // construct copy displaced elements from the old storage to the new storage // remember [position, end()) refers to the old storage new_end = m_storage.uninitialized_copy(position, end(), new_end); } // end try catch(...) { // something went wrong, so destroy & deallocate the new storage m_storage.destroy(new_storage.begin(), new_end); new_storage.deallocate(); // rethrow throw; } // end catch // call destructors on the elements in the old storage m_storage.destroy(begin(), end()); // record the vector's new state m_storage.swap(new_storage); m_size = old_size + num_new_elements; } // end else } // end if } // end vector_base::copy_insert() template void vector_base ::append(size_type n) { if(n != 0) { if(capacity() - size() >= n) { // we've got room for all of them // default construct new elements at the end of the vector m_storage.default_construct_n(end(), n); // extend the size m_size += n; } // end if else { const size_type old_size = size(); // compute the new capacity after the allocation size_type new_capacity = old_size + thrust::max THRUST_PREVENT_MACRO_SUBSTITUTION (old_size, n); // allocate exponentially larger new storage new_capacity = thrust::max THRUST_PREVENT_MACRO_SUBSTITUTION (new_capacity, 2 * capacity()); // do not exceed maximum storage new_capacity = thrust::min THRUST_PREVENT_MACRO_SUBSTITUTION (new_capacity, max_size()); // create new storage storage_type new_storage(new_capacity); // record how many constructors we invoke in the try block below iterator new_end = new_storage.begin(); try { // construct copy all elements into the newly allocated storage new_end = m_storage.uninitialized_copy(begin(), end(), new_storage.begin()); // construct new elements to insert m_storage.default_construct_n(new_end, n); new_end += n; } // end try catch(...) { // something went wrong, so destroy & deallocate the new storage m_storage.destroy(new_storage.begin(), new_end); new_storage.deallocate(); // rethrow throw; } // end catch // call destructors on the elements in the old storage m_storage.destroy(begin(), end()); // record the vector's new state m_storage.swap(new_storage); m_size = old_size + n; } // end else } // end if } // end vector_base::append() template void vector_base ::fill_insert(iterator position, size_type n, const T &x) { if(n != 0) { if(capacity() - size() >= n) { // we've got room for all of them // how many existing elements will we displace? const size_type num_displaced_elements = end() - position; iterator old_end = end(); if(num_displaced_elements > n) { // construct copy n displaced elements to new elements // following the insertion m_storage.uninitialized_copy(end() - n, end(), end()); // extend the size m_size += n; // copy num_displaced_elements - n elements to existing elements // this copy overlaps const size_type copy_length = (old_end - n) - position; thrust::detail::overlapped_copy(position, old_end - n, old_end - copy_length); // finally, fill the range to the insertion point thrust::fill_n(position, n, x); } // end if else { // construct new elements at the end of the vector m_storage.uninitialized_fill_n(end(), n - num_displaced_elements, x); // extend the size m_size += n - num_displaced_elements; // construct copy the displaced elements m_storage.uninitialized_copy(position, old_end, end()); // extend the size m_size += num_displaced_elements; // fill to elements which already existed thrust::fill(position, old_end, x); } // end else } // end if else { const size_type old_size = size(); // compute the new capacity after the allocation size_type new_capacity = old_size + thrust::max THRUST_PREVENT_MACRO_SUBSTITUTION (old_size, n); // allocate exponentially larger new storage new_capacity = thrust::max THRUST_PREVENT_MACRO_SUBSTITUTION (new_capacity, 2 * capacity()); // do not exceed maximum storage new_capacity = thrust::min THRUST_PREVENT_MACRO_SUBSTITUTION (new_capacity, max_size()); if(new_capacity > max_size()) { throw std::length_error("insert(): insertion exceeds max_size()."); } // end if storage_type new_storage(new_capacity); // record how many constructors we invoke in the try block below iterator new_end = new_storage.begin(); try { // construct copy elements before the insertion to the beginning of the newly // allocated storage new_end = m_storage.uninitialized_copy(begin(), position, new_storage.begin()); // construct new elements to insert m_storage.uninitialized_fill_n(new_end, n, x); new_end += n; // construct copy displaced elements from the old storage to the new storage // remember [position, end()) refers to the old storage new_end = m_storage.uninitialized_copy(position, end(), new_end); } // end try catch(...) { // something went wrong, so destroy & deallocate the new storage m_storage.destroy(new_storage.begin(), new_end); new_storage.deallocate(); // rethrow throw; } // end catch // call destructors on the elements in the old storage m_storage.destroy(begin(), end()); // record the vector's new state m_storage.swap(new_storage); m_size = old_size + n; } // end else } // end if } // end vector_base::fill_insert() template template void vector_base ::range_assign(InputIterator first, InputIterator last) { // dispatch on traversal range_assign(first, last, typename thrust::iterator_traversal::type()); } // end range_assign() template template void vector_base ::range_assign(InputIterator first, InputIterator last, thrust::incrementable_traversal_tag) { iterator current(begin()); // assign to elements which already exist for(; first != last && current != end(); ++current, ++first) { *current = *first; } // end for // either just the input was exhausted or both // the input and vector elements were exhausted if(first == last) { // if we exhausted the input, erase leftover elements erase(current, end()); } // end if else { // insert the rest of the input at the end of the vector insert(end(), first, last); } // end else } // end vector_base::range_assign() template template void vector_base ::range_assign(RandomAccessIterator first, RandomAccessIterator last, thrust::random_access_traversal_tag) { const size_type n = thrust::distance(first, last); if(n > capacity()) { storage_type new_storage; allocate_and_copy(n, first, last, new_storage); // call destructors on the elements in the old storage m_storage.destroy(begin(), end()); // record the vector's new state m_storage.swap(new_storage); m_size = n; } // end if else if(size() >= n) { // we can already accomodate the new range iterator new_end = thrust::copy(first, last, begin()); // destroy the elements we don't need m_storage.destroy(new_end, end()); // update size m_size = n; } // end else if else { // range fits inside allocated storage, but some elements // have not been constructed yet // XXX TODO we could possibly implement this with one call // to transform rather than copy + uninitialized_copy // copy to elements which already exist RandomAccessIterator mid = first; thrust::advance(mid, size()); thrust::copy(first, mid, begin()); // uninitialize_copy to elements which must be constructed m_storage.uninitialized_copy(mid, last, end()); // update size m_size = n; } // end else } // end vector_base::assign() template void vector_base ::fill_assign(size_type n, const T &x) { if(n > capacity()) { // XXX we should also include a copy of the allocator: // vector_base temp(n, x, get_allocator()); vector_base temp(n, x); temp.swap(*this); } // end if else if(n > size()) { // fill to existing elements thrust::fill(begin(), end(), x); // construct uninitialized elements m_storage.uninitialized_fill_n(end(), n - size(), x); // adjust size m_size += (n - size()); } // end else if else { // fill to existing elements iterator new_end = thrust::fill_n(begin(), n, x); // erase the elements after the fill erase(new_end, end()); } // end else } // end vector_base::fill_assign() template template void vector_base ::allocate_and_copy(size_type requested_size, ForwardIterator first, ForwardIterator last, storage_type &new_storage) { if(requested_size == 0) { new_storage.deallocate(); return; } // end if // allocate exponentially larger new storage size_type allocated_size = thrust::max(requested_size, 2 * capacity()); // do not exceed maximum storage allocated_size = thrust::min(allocated_size, max_size()); if(requested_size > allocated_size) { throw std::length_error("assignment exceeds max_size()."); } // end if new_storage.allocate(allocated_size); try { // construct the range to the newly allocated storage m_storage.uninitialized_copy(first, last, new_storage.begin()); } // end try catch(...) { // something went wrong, so destroy & deallocate the new storage // XXX seems like this destroys too many elements -- should just be last - first instead of requested_size iterator new_storage_end = new_storage.begin(); thrust::advance(new_storage_end, requested_size); m_storage.destroy(new_storage.begin(), new_storage_end); new_storage.deallocate(); // rethrow throw; } // end catch } // end vector_base::allocate_and_copy() } // end detail template void swap(detail::vector_base &a, detail::vector_base &b) { a.swap(b); } // end swap() namespace detail { // iterator tags match template bool vector_equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, thrust::detail::true_type) { return thrust::equal(first1, last1, first2); } // iterator tags differ template bool vector_equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, thrust::detail::false_type) { typename thrust::iterator_difference::type n = thrust::distance(first1,last1); typedef typename thrust::iterator_system::type FromSystem1; typedef typename thrust::iterator_system::type FromSystem2; // bring both ranges to the host system // note that these copies are no-ops if the range is already convertible to the host system FromSystem1 from_system1; FromSystem2 from_system2; thrust::host_system_tag to_system; thrust::detail::move_to_system rng1(from_system1, to_system, first1, last1); thrust::detail::move_to_system rng2(from_system2, to_system, first2, first2 + n); return thrust::equal(rng1.begin(), rng1.end(), rng2.begin()); } template bool vector_equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2) { typedef typename thrust::iterator_system::type system1; typedef typename thrust::iterator_system::type system2; // dispatch on the sameness of the two systems return vector_equal(first1, last1, first2, thrust::detail::is_same()); } } // end namespace detail template bool operator==(const detail::vector_base& lhs, const detail::vector_base& rhs) { return lhs.size() == rhs.size() && detail::vector_equal(lhs.begin(), lhs.end(), rhs.begin()); } template bool operator==(const detail::vector_base& lhs, const std::vector& rhs) { return lhs.size() == rhs.size() && detail::vector_equal(lhs.begin(), lhs.end(), rhs.begin()); } template bool operator==(const std::vector& lhs, const detail::vector_base& rhs) { return lhs.size() == rhs.size() && detail::vector_equal(lhs.begin(), lhs.end(), rhs.begin()); } template bool operator!=(const detail::vector_base& lhs, const detail::vector_base& rhs) { return !(lhs == rhs); } template bool operator!=(const detail::vector_base& lhs, const std::vector& rhs) { return !(lhs == rhs); } template bool operator!=(const std::vector& lhs, const detail::vector_base& rhs) { return !(lhs == rhs); } } // end thrust