Skip to content

Commit

Permalink
Add insert, emplace, erase, push_back and pop_back (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex-PLACET authored May 23, 2024
1 parent 11957f8 commit 6a725bf
Show file tree
Hide file tree
Showing 2 changed files with 708 additions and 29 deletions.
195 changes: 182 additions & 13 deletions include/sparrow/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

#include <algorithm>
#include <concepts>
#include <cstdint>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <type_traits>

#include "sparrow/contracts.hpp"
#include "sparrow/allocator.hpp"
#include "sparrow/contracts.hpp"
#include "sparrow/iterator.hpp"
#include "sparrow/mp_utils.hpp"

namespace sparrow
{
Expand Down Expand Up @@ -69,7 +69,7 @@ namespace sparrow

~buffer_base();

buffer_base(buffer_base&&) = default;
buffer_base(buffer_base&&) noexcept = default;

template <allocator A>
constexpr buffer_base(buffer_base&& rhs, const A& a);
Expand Down Expand Up @@ -156,14 +156,14 @@ namespace sparrow
template <allocator A>
buffer(const buffer& rhs, const A& a);

buffer(buffer&& rhs) = default;
buffer(buffer&& rhs) noexcept = default;

template <allocator A>
buffer(buffer&& rhs, const A& a);

buffer& operator=(const buffer& rhs);
buffer& operator=(buffer&& rhs);
buffer& operator=(std::initializer_list<value_type> init);
constexpr buffer& operator=(const buffer& rhs);
constexpr buffer& operator=(buffer&& rhs);
constexpr buffer& operator=(std::initializer_list<value_type> init);

// Element access

Expand Down Expand Up @@ -216,9 +216,28 @@ namespace sparrow
// Modifiers

constexpr void clear();

constexpr iterator insert(const_iterator pos, const T& value);
constexpr iterator insert(const_iterator pos, T&& value);
constexpr iterator insert(const_iterator pos, size_type count, const T& value);
template <class InputIt>
constexpr iterator insert(const_iterator pos, InputIt first, InputIt last);
constexpr iterator insert(const_iterator pos, std::initializer_list<T> ilist);

template <class... Args>
constexpr iterator emplace(const_iterator pos, Args&&... args);

constexpr iterator erase(const_iterator pos);
constexpr iterator erase(const_iterator first, const_iterator last);

constexpr void push_back(const T& value);
constexpr void push_back(T&& value);

constexpr void pop_back();

constexpr void resize(size_type new_size);
constexpr void resize(size_type new_size, const value_type& value);
constexpr void swap(buffer& rhs);
constexpr void swap(buffer& rhs) noexcept;

private:

Expand Down Expand Up @@ -458,7 +477,7 @@ namespace sparrow
}

template <class T>
buffer<T>& buffer<T>::operator=(const buffer& rhs)
constexpr buffer<T>& buffer<T>::operator=(const buffer& rhs)
{
if (std::addressof(rhs) != this)
{
Expand All @@ -469,7 +488,7 @@ namespace sparrow
}

template <class T>
buffer<T>& buffer<T>::operator=(buffer&& rhs)
constexpr buffer<T>& buffer<T>::operator=(buffer&& rhs)
{
if (get_allocator() == rhs.get_allocator())
{
Expand All @@ -488,7 +507,7 @@ namespace sparrow
}

template <class T>
buffer<T>& buffer<T>::operator=(std::initializer_list<value_type> init)
constexpr buffer<T>& buffer<T>::operator=(std::initializer_list<value_type> init)
{
assign_range_impl(
std::make_move_iterator(init.begin()),
Expand Down Expand Up @@ -686,6 +705,156 @@ namespace sparrow
erase_at_end(get_data().p_begin);
}

template <class T>
constexpr auto buffer<T>::insert(const_iterator pos, const T& value) -> iterator
{
SPARROW_ASSERT_TRUE(cbegin() <= pos);
SPARROW_ASSERT_TRUE(pos <= cend());
return emplace(pos, value);
}

template <class T>
constexpr auto buffer<T>::insert(const_iterator pos, T&& value) -> iterator
{
SPARROW_ASSERT_TRUE(cbegin() <= pos);
SPARROW_ASSERT_TRUE(pos <= cend());
return emplace(pos, std::move(value));
}

template <class T>
constexpr auto buffer<T>::insert(const_iterator pos, size_type count, const T& value) -> iterator
{
SPARROW_ASSERT_TRUE(cbegin() <= pos);
SPARROW_ASSERT_TRUE(pos <= cend());

const difference_type offset = std::distance(cbegin(), pos);
pointer ptr = get_data().p_begin + offset;
if (count != 0)
{
const size_type sz = size();
const size_type offset = std::distance(get_data().p_begin, ptr);
reserve(sz + count);

auto& data = get_data();
const auto new_ptr = data.p_begin + offset;
std::move_backward(new_ptr, data.p_end, data.p_end + count);
std::fill_n(new_ptr, count, value);
data.p_end += count;
}
return std::next(begin(), offset);
}

template <typename T>
struct is_move_iterator : std::false_type
{
};

template <typename Iterator>
struct is_move_iterator<std::move_iterator<Iterator>> : std::true_type
{
};

template <typename T>
constexpr bool is_move_iterator_v = is_move_iterator<T>::value;

template <class T>
template <class InputIt>
constexpr auto buffer<T>::insert(const_iterator pos, InputIt first, InputIt last) -> iterator
{
SPARROW_ASSERT_TRUE(cbegin() <= pos && pos <= cend());
const size_type num_elements = std::distance(first, last);
const size_type new_size = size() + num_elements;
const size_type offset = std::distance(cbegin(), pos);
const size_type old_size = size();
resize(new_size);
auto& data = get_data();
const pointer p = data.p_begin + offset;
const iterator p_it = iterator(p);
const iterator end_it = std::next(begin(), old_size);
std::move_backward(p_it, end_it, end());
if constexpr (is_move_iterator_v<InputIt>)
{
std::uninitialized_move(first, last, p_it);
}
else
{
std::uninitialized_copy(first, last, p_it);
}
return p_it;
}

template <class T>
constexpr auto buffer<T>::insert(const_iterator pos, std::initializer_list<T> ilist) -> iterator
{
SPARROW_ASSERT_TRUE(cbegin() <= pos);
SPARROW_ASSERT_TRUE(pos <= cend());
return insert(pos, ilist.begin(), ilist.end());
}

template <class T>
template <class... Args>
constexpr buffer<T>::iterator buffer<T>::emplace(const_iterator pos, Args&&... args)
{
SPARROW_ASSERT_TRUE(cbegin() <= pos);
SPARROW_ASSERT_TRUE(pos <= cend());
const size_type offset = std::distance(cbegin(), pos);
reserve(size() + 1);
pointer p = get_data().p_begin + offset;
if (p != get_data().p_end)
{
alloc_traits::construct(get_allocator(), get_data().p_end, std::move(*(get_data().p_end - 1)));
std::move_backward(p, get_data().p_end - 1, get_data().p_end);
alloc_traits::construct(get_allocator(), p, std::forward<Args>(args)...);
}
else
{
alloc_traits::construct(get_allocator(), get_data().p_end, std::forward<Args>(args)...);
}
++get_data().p_end;
return iterator(p);
}

template <class T>
constexpr auto buffer<T>::erase(const_iterator pos) -> iterator
{
SPARROW_ASSERT_TRUE(cbegin() <= pos);
SPARROW_ASSERT_TRUE(pos < cend());
return erase(pos, pos + 1);
}

template <class T>
constexpr auto buffer<T>::erase(const_iterator first, const_iterator last) -> iterator
{
SPARROW_ASSERT_TRUE(first < last);
SPARROW_ASSERT_TRUE(cbegin() <= first);
SPARROW_ASSERT_TRUE(last <= cend());
const size_type offset = std::distance(cbegin(), first);
const size_type len = std::distance(first, last);
pointer p = get_data().p_begin + offset;
erase_at_end(std::move(p + len, get_data().p_end, p));
return iterator(p);
}

template <class T>
constexpr void buffer<T>::push_back(const T& value)
{
emplace(cend(), value);
}

template <class T>
constexpr void buffer<T>::push_back(T&& value)
{
emplace(cend(), std::move(value));
}

template <class T>
constexpr void buffer<T>::pop_back()
{
SPARROW_ASSERT_FALSE(empty());
destroy(get_allocator(), get_data().p_end - 1);
--get_data().p_end;
}

template <class T>
constexpr void buffer<T>::resize(size_type new_size)
{
Expand All @@ -711,7 +880,7 @@ namespace sparrow
}

template <class T>
constexpr void buffer<T>::swap(buffer& rhs)
constexpr void buffer<T>::swap(buffer& rhs) noexcept
{
std::swap(this->get_data(), rhs.get_data());
}
Expand Down
Loading

0 comments on commit 6a725bf

Please sign in to comment.