| /* | |
| * Copyright (C) 2015 The Android Open Source Project | |
| * | |
| * 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. | |
| */ | |
| #ifndef ART_LIBARTBASE_BASE_DCHECKED_VECTOR_H_ | |
| #define ART_LIBARTBASE_BASE_DCHECKED_VECTOR_H_ | |
| #include <algorithm> | |
| #include <type_traits> | |
| #include <vector> | |
| #include <android-base/logging.h> | |
| namespace art { | |
| // Template class serving as a replacement for std::vector<> but adding | |
| // DCHECK()s for the subscript operator, front(), back(), pop_back(), | |
| // and for insert()/emplace()/erase() positions. | |
| // | |
| // Note: The element accessor at() is specified as throwing std::out_of_range | |
| // but we do not use exceptions, so this accessor is deliberately hidden. | |
| // Note: The common pattern &v[0] used to retrieve pointer to the data is not | |
| // valid for an empty dchecked_vector<>. Use data() to avoid checking empty(). | |
| template <typename T, typename Alloc = std::allocator<T>> | |
| class dchecked_vector : private std::vector<T, Alloc> { | |
| private: | |
| // std::vector<> has a slightly different specialization for bool. We don't provide that. | |
| static_assert(!std::is_same_v<T, bool>, "Not implemented for bool."); | |
| using Base = std::vector<T, Alloc>; | |
| public: | |
| using typename Base::value_type; | |
| using typename Base::allocator_type; | |
| using typename Base::reference; | |
| using typename Base::const_reference; | |
| using typename Base::pointer; | |
| using typename Base::const_pointer; | |
| using typename Base::iterator; | |
| using typename Base::const_iterator; | |
| using typename Base::reverse_iterator; | |
| using typename Base::const_reverse_iterator; | |
| using typename Base::size_type; | |
| using typename Base::difference_type; | |
| // Construct/copy/destroy. | |
| dchecked_vector() | |
| : Base() { } | |
| explicit dchecked_vector(const allocator_type& alloc) | |
| : Base(alloc) { } | |
| explicit dchecked_vector(size_type n, const allocator_type& alloc = allocator_type()) | |
| : Base(n, alloc) { } | |
| dchecked_vector(size_type n, | |
| const value_type& value, | |
| const allocator_type& alloc = allocator_type()) | |
| : Base(n, value, alloc) { } | |
| template <typename InputIterator> | |
| dchecked_vector(InputIterator first, | |
| InputIterator last, | |
| const allocator_type& alloc = allocator_type()) | |
| : Base(first, last, alloc) { } | |
| dchecked_vector(const dchecked_vector& src) | |
| : Base(src) { } | |
| dchecked_vector(const dchecked_vector& src, const allocator_type& alloc) | |
| : Base(src, alloc) { } | |
| dchecked_vector(dchecked_vector&& src) noexcept | |
| : Base(std::move(src)) { } | |
| dchecked_vector(dchecked_vector&& src, const allocator_type& alloc) noexcept | |
| : Base(std::move(src), alloc) { } | |
| dchecked_vector(std::initializer_list<value_type> il, | |
| const allocator_type& alloc = allocator_type()) | |
| : Base(il, alloc) { } | |
| ~dchecked_vector() = default; | |
| dchecked_vector& operator=(const dchecked_vector& src) { | |
| Base::operator=(src); | |
| return *this; | |
| } | |
| dchecked_vector& operator=(dchecked_vector&& src) noexcept { | |
| Base::operator=(std::move(src)); | |
| return *this; | |
| } | |
| dchecked_vector& operator=(std::initializer_list<value_type> il) { | |
| Base::operator=(il); | |
| return *this; | |
| } | |
| // Iterators. | |
| using Base::begin; | |
| using Base::end; | |
| using Base::rbegin; | |
| using Base::rend; | |
| using Base::cbegin; | |
| using Base::cend; | |
| using Base::crbegin; | |
| using Base::crend; | |
| // Capacity. | |
| using Base::size; | |
| using Base::max_size; | |
| using Base::resize; | |
| using Base::capacity; | |
| using Base::empty; | |
| using Base::reserve; | |
| using Base::shrink_to_fit; | |
| // Element access: inherited. | |
| // Note: Deliberately not providing at(). | |
| using Base::data; | |
| // Element access: subscript operator. Check index. | |
| reference operator[](size_type n) { | |
| DCHECK_LT(n, size()); | |
| return Base::operator[](n); | |
| } | |
| const_reference operator[](size_type n) const { | |
| DCHECK_LT(n, size()); | |
| return Base::operator[](n); | |
| } | |
| // Element access: front(), back(). Check not empty. | |
| reference front() { DCHECK(!empty()); return Base::front(); } | |
| const_reference front() const { DCHECK(!empty()); return Base::front(); } | |
| reference back() { DCHECK(!empty()); return Base::back(); } | |
| const_reference back() const { DCHECK(!empty()); return Base::back(); } | |
| // Modifiers: inherited. | |
| using Base::assign; | |
| using Base::push_back; | |
| using Base::clear; | |
| using Base::emplace_back; | |
| // Modifiers: pop_back(). Check not empty. | |
| void pop_back() { DCHECK(!empty()); Base::pop_back(); } | |
| // Modifiers: swap(). Swap only with another dchecked_vector instead of a plain vector. | |
| void swap(dchecked_vector& other) { Base::swap(other); } | |
| // Modifiers: insert(). Check position. | |
| iterator insert(const_iterator position, const value_type& value) { | |
| DCHECK(cbegin() <= position && position <= cend()); | |
| return Base::insert(position, value); | |
| } | |
| iterator insert(const_iterator position, size_type n, const value_type& value) { | |
| DCHECK(cbegin() <= position && position <= cend()); | |
| return Base::insert(position, n, value); | |
| } | |
| template <typename InputIterator> | |
| iterator insert(const_iterator position, InputIterator first, InputIterator last) { | |
| DCHECK(cbegin() <= position && position <= cend()); | |
| return Base::insert(position, first, last); | |
| } | |
| iterator insert(const_iterator position, value_type&& value) { | |
| DCHECK(cbegin() <= position && position <= cend()); | |
| return Base::insert(position, std::move(value)); | |
| } | |
| iterator insert(const_iterator position, std::initializer_list<value_type> il) { | |
| DCHECK(cbegin() <= position && position <= cend()); | |
| return Base::insert(position, il); | |
| } | |
| // Modifiers: erase(). Check position. | |
| iterator erase(const_iterator position) { | |
| DCHECK(cbegin() <= position && position < cend()); | |
| return Base::erase(position); | |
| } | |
| iterator erase(const_iterator first, const_iterator last) { | |
| DCHECK(cbegin() <= first && first <= cend()); | |
| DCHECK(first <= last && last <= cend()); | |
| return Base::erase(first, last); | |
| } | |
| // Modifiers: emplace(). Check position. | |
| template <typename... Args> | |
| iterator emplace(const_iterator position, Args&&... args) { | |
| DCHECK(cbegin() <= position && position <= cend()); | |
| Base::emplace(position, std::forward(args...)); | |
| } | |
| // Allocator. | |
| using Base::get_allocator; | |
| }; | |
| // Non-member swap(), found by argument-dependent lookup for an unqualified call. | |
| template <typename T, typename Alloc> | |
| void swap(dchecked_vector<T, Alloc>& lhs, dchecked_vector<T, Alloc>& rhs) { | |
| lhs.swap(rhs); | |
| } | |
| // Non-member relational operators. | |
| template <typename T, typename Alloc> | |
| bool operator==(const dchecked_vector<T, Alloc>& lhs, const dchecked_vector<T, Alloc>& rhs) { | |
| return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); | |
| } | |
| template <typename T, typename Alloc> | |
| bool operator!=(const dchecked_vector<T, Alloc>& lhs, const dchecked_vector<T, Alloc>& rhs) { | |
| return !(lhs == rhs); | |
| } | |
| template <typename T, typename Alloc> | |
| bool operator<(const dchecked_vector<T, Alloc>& lhs, const dchecked_vector<T, Alloc>& rhs) { | |
| return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); | |
| } | |
| template <typename T, typename Alloc> | |
| bool operator<=(const dchecked_vector<T, Alloc>& lhs, const dchecked_vector<T, Alloc>& rhs) { | |
| return !(rhs < lhs); | |
| } | |
| template <typename T, typename Alloc> | |
| bool operator>(const dchecked_vector<T, Alloc>& lhs, const dchecked_vector<T, Alloc>& rhs) { | |
| return rhs < lhs; | |
| } | |
| template <typename T, typename Alloc> | |
| bool operator>=(const dchecked_vector<T, Alloc>& lhs, const dchecked_vector<T, Alloc>& rhs) { | |
| return !(lhs < rhs); | |
| } | |
| } // namespace art | |
| #endif // ART_LIBARTBASE_BASE_DCHECKED_VECTOR_H_ |