20 #include <initializer_list> 27 #include <type_traits> 31 #include <hilti/rt/extension-points.h> 32 #include <hilti/rt/fmt.h> 33 #include <hilti/rt/iterator.h> 34 #include <hilti/rt/types/vector_fwd.h> 35 #include <hilti/rt/util.h> 47 template<
class T, T Default_>
52 value_type* allocate(std::size_t n) {
return static_cast<value_type*
>(::operator
new(n *
sizeof(value_type))); }
54 void deallocate(value_type* p, std::size_t) noexcept { ::operator
delete(p); }
57 void construct(U* p) noexcept(std::is_nothrow_default_constructible<U>::value) {
58 ::new (static_cast<void*>(p)) U(Default_);
61 template<
typename U,
typename... Args>
62 void construct(U* p, Args&&... args) {
63 ::new (p) U(std::forward<Args>(args)...);
72 template<
class T, T D1,
class U, U D2>
77 template<
class T, T D1,
class U, U D2>
82 template<
typename T,
typename Allocator>
86 std::weak_ptr<V*> _control;
87 typename V::size_type _index = 0;
90 using difference_type =
typename V::V::iterator::difference_type;
91 using value_type =
typename V::V::iterator::value_type;
92 using pointer =
typename V::V::iterator::pointer;
93 using reference =
typename V::V::iterator::reference;
94 using const_reference =
typename V::V::const_reference;
95 using iterator_category =
typename V::V::iterator::iterator_category;
98 Iterator(
typename V::size_type&& index,
const typename V::C& control)
99 : _control(control), _index(std::move(index)) {}
101 reference operator*();
102 const_reference operator*()
const;
116 if ( a._control.lock() != b._control.lock() )
117 throw InvalidArgument(
"cannot compare iterators into different vectors");
118 return a._index == b._index;
121 friend bool operator!=(
const Iterator& a,
const Iterator& b) {
return ! (a == b); }
124 if ( a._control.lock() != b._control.lock() )
125 throw InvalidArgument(
"cannot compare iterators into different vectors");
126 return a._index < b._index;
130 if ( a._control.lock() != b._control.lock() )
131 throw InvalidArgument(
"cannot compare iterators into different vectors");
132 return a._index <= b._index;
136 if ( a._control.lock() != b._control.lock() )
137 throw InvalidArgument(
"cannot compare iterators into different vectors");
138 return a._index > b._index;
142 if ( a._control.lock() != b._control.lock() )
143 throw InvalidArgument(
"cannot compare iterators into different vectors");
144 return a._index >= b._index;
148 if ( a._control.lock() != b._control.lock() )
149 throw InvalidArgument(
"cannot perform arithmetic with iterators into different vectors");
150 return a._index - b._index;
156 std::optional<std::reference_wrapper<V>> _container()
const;
159 template<
typename T,
typename Allocator>
163 std::weak_ptr<Vector<T, Allocator>*> _control;
164 typename V::size_type _index = 0;
167 using difference_type =
typename V::V::const_iterator::difference_type;
168 using value_type =
typename V::V::const_iterator::value_type;
169 using pointer =
typename V::V::const_iterator::pointer;
170 using reference =
typename V::V::const_iterator::reference;
171 using const_reference =
typename V::V::iterator::reference;
172 using iterator_category =
typename V::V::const_iterator::iterator_category;
175 ConstIterator(
typename V::size_type&& index,
const typename V::C& control)
176 : _control(control), _index(std::move(index)) {}
178 const_reference operator*()
const;
192 if ( a._control.lock() != b._control.lock() )
193 throw InvalidArgument(
"cannot compare iterators into different vectors");
194 return a._index == b._index;
200 if ( a._control.lock() != b._control.lock() )
201 throw InvalidArgument(
"cannot compare iterators into different vectors");
202 return a._index < b._index;
206 if ( a._control.lock() != b._control.lock() )
207 throw InvalidArgument(
"cannot compare iterators into different vectors");
208 return a._index <= b._index;
212 if ( a._control.lock() != b._control.lock() )
213 throw InvalidArgument(
"cannot compare iterators into different vectors");
214 return a._index > b._index;
218 if ( a._control.lock() != b._control.lock() )
219 throw InvalidArgument(
"cannot compare iterators into different vectors");
220 return a._index >= b._index;
224 if ( a._control.lock() != b._control.lock() )
225 throw InvalidArgument(
"cannot perform arithmetic with iterators into different vectors");
226 return a._index - b._index;
232 std::optional<std::reference_wrapper<V>> _container()
const;
248 template<
typename T,
typename Allocator>
249 class Vector :
protected std::vector<T, Allocator> {
252 static_assert(! std::is_same_v<T, bool>,
"'Vector' cannot be used with naked booleans, use 'Bool'");
254 using V = std::vector<T, Allocator>;
256 using size_type = uint64_t;
257 using reference = T&;
258 using const_reference =
const T&;
262 using C = std::shared_ptr<Vector*>;
263 C _control = std::make_shared<Vector<T, Allocator>*>(
this);
269 Vector(
Vector&& other) noexcept : V(std::move(other)) {}
271 Vector(std::initializer_list<T>
init,
const Allocator& alloc = Allocator()) : V(std::move(init), alloc) {}
282 throw IndexError(
"vector is empty");
294 throw IndexError(
"vector is empty");
306 throw IndexError(
"vector is empty");
318 if ( i >= V::size() )
319 throw IndexError(
fmt(
"vector index %" PRIu64
" out of range", i));
332 if ( end <= start || start >= V::size() )
335 if ( end >= V::size() )
339 std::copy(V::begin() + start, V::begin() + end, std::back_inserter(v));
350 if ( end >= V::size() )
354 std::copy(V::begin(), V::begin() + end, std::back_inserter(v));
367 static_cast<V&
>(*this) =
static_cast<const V&
>(other);
380 static_cast<V&
>(*this) =
static_cast<V&&
>(std::move(other));
391 if ( i >= V::size() )
392 throw IndexError(
fmt(
"vector index %" PRIu64
" out of range", i));
404 if ( i >= V::size() )
405 throw IndexError(
fmt(
"vector index %" PRIu64
" out of range", i));
417 if ( i >= V::size() )
418 throw IndexError(
fmt(
"vector index %" PRIu64
" out of range", i));
431 void assign(uint64_t i, T x) {
432 if ( i >= V::size() )
435 V::data()[i] = std::move(x);
455 V::insert(V::end(), other.V::begin(), other.V::end());
459 auto begin() {
return iterator(0u, _control); }
460 auto end() {
return iterator(size(), _control); }
468 size_t size()
const {
return V::size(); }
471 using typename V::value_type;
474 using V::emplace_back;
481 friend bool operator==(
const Vector& a,
const Vector& b) {
482 return static_cast<const V&
>(a) == static_cast<const V&>(b);
489 auto begin()
const& {
return this; }
490 auto end()
const& {
return this; }
491 auto empty()
const {
return true; }
492 auto size()
const {
return 0u; }
495 template<
typename T,
typename Allocator>
499 template<
typename T,
typename Allocator>
503 template<
typename T,
typename Allocator>
507 template<
typename T,
typename Allocator>
512 template<
typename Allocator,
typename I,
typename O,
typename C>
515 for (
auto&& i : input )
516 output.emplace_back(func(i));
521 template<
typename Allocator,
typename I,
typename O,
typename C>
522 Vector<O, Allocator> make(
const C& input, std::function<O(I)> func, std::function<
bool(I)> pred) {
524 for (
auto&& i : input )
526 output.emplace_back(func(i));
533 namespace detail::adl {
534 template<
typename T,
typename Allocator>
536 using detail::adl::to_string;
542 template<
typename T,
typename Allocator>
544 return "<vector iterator>";
547 template<
typename T,
typename Allocator>
549 return "<const vector iterator>";
553 template<
typename T,
typename Allocator>
554 inline std::ostream& operator<<(std::ostream& out, const Vector<T, Allocator>& x) {
559 inline std::ostream& operator<<(std::ostream& out,
const vector::Empty& x) {
564 template<
typename T,
typename Allocator>
569 template<
typename T,
typename Allocator>
571 if (
auto&& c = _container() ) {
572 auto&& data = c->get();
574 if ( _index >= data.size() ) {
575 throw InvalidIterator(
fmt(
"index %s out of bounds", _index));
581 throw InvalidIterator(
"bound object has expired");
584 template<
typename T,
typename Allocator>
586 if (
auto&& c = _container() ) {
587 auto&& data = c->get();
589 if ( _index >= data.size() ) {
590 throw InvalidIterator(
fmt(
"index %s out of bounds", _index));
596 throw InvalidIterator(
"bound object has expired");
601 template<
typename T,
typename Allocator>
602 inline std::ostream& operator<<(std::ostream& out, const vector::Iterator<T, Allocator>& ) {
603 return out <<
"<vector iterator>";
606 template<
typename T,
typename Allocator>
607 inline std::ostream& operator<<(std::ostream& out, const vector::ConstIterator<T, Allocator>& ) {
608 return out <<
"<const vector iterator>";
613 template<
typename T,
typename Allocator>
615 if (
auto l = _control.lock() ) {
616 return {std::ref(**l)};
622 template<
typename T,
typename Allocator>
624 if (
auto&& c = _container() ) {
625 auto&& data = c->get();
627 if ( _index >= data.size() ) {
628 throw InvalidIterator(
fmt(
"index %s out of bounds", _index));
634 throw InvalidIterator(
"bound object has expired");
637 template<
typename T,
typename Allocator>
639 if (
auto l = _control.lock() ) {
640 return {std::ref(**l)};
Vector< T > sub(uint64_t start, uint64_t end) const
Definition: vector.h:331
std::string to_string(T &&x)
Definition: extension-points.h:26
void init()
Definition: init.cc:19
Vector< T > sub(uint64_t end) const
Definition: vector.h:349
const_iterator iteratorAt(uint64_t i) const
Definition: vector.h:317
Vector & operator=(const Vector &other)
Definition: vector.h:366
auto transform(const std::vector< X > &x, F f)
Definition: util.h:299
void pop_back()
Definition: vector.h:304
T operator[](uint64_t i) &&
Definition: vector.h:403
Vector operator+(const Vector &other) const
Definition: vector.h:443
const T & back() const
Definition: vector.h:292
const T & front() const
Definition: vector.h:280
const T & operator[](uint64_t i) const &
Definition: vector.h:390
Vector & operator+=(const Vector &other)
Definition: vector.h:454
Vector & operator=(Vector &&other) noexcept
Definition: vector.h:379
std::string join(const T &l, const std::string &delim="")
Definition: util.h:281
T & operator[](uint64_t i) &
Definition: vector.h:416
std::string fmt(const char *fmt, const Args &... args)
Definition: fmt.h:13