Skip to content

Commit

Permalink
Merge pull request #22 from wusatosi/c++17
Browse files Browse the repository at this point in the history
Lower lowest supported version to C++17.
  • Loading branch information
wusatosi authored Nov 19, 2024
2 parents 7c62d04 + 8fa4168 commit 9573915
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 22 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/ci_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
c: gcc
- cpp: clang++
c: clang
cpp_version: [20, 23, 26]
cpp_version: [17, 20, 23, 26]
cmake_args:
- description: "Default"
args: ""
Expand All @@ -46,6 +46,8 @@ jobs:
- description: "ASan"
args: "-DCMAKE_CXX_FLAGS=-fsanitize=address -fsanitize=undefined"
include:
# Needs C++ 20 as C++17 selectivly disables ranges and concepts
# related functionalities
- platform: ubuntu-latest
compiler:
cpp: g++
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ which dynamic memory allocations are undesired.

### Compiler support

Building this repository requires **C++20** or later.
Building this repository requires **C++17** or later.

### Dependencies

Expand Down
76 changes: 56 additions & 20 deletions include/beman/inplace_vector/inplace_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,29 @@

#include <algorithm>
#include <cassert>
#include <compare>
#include <concepts>
#include <exception>
#include <iterator>
#include <limits>
#include <memory>
#include <new>
#include <ranges>
#include <stdexcept>
#include <type_traits>
#include <utility>

#ifdef __cpp_concepts
#include <concepts>
#endif

#ifdef __cpp_lib_containers_ranges
#include <ranges>
#endif

#ifdef __cpp_lib_three_way_comparison
#include <compare>
#endif

namespace beman::inplace_vector {
#ifdef __cpp_concepts
namespace detail {
// Exposition-only container-compatible-range
template <typename T>
Expand All @@ -29,6 +40,7 @@ concept container_compatible_range_impl = requires(T &&t) {
template <typename T>
constexpr bool container_compatible_range =
detail::container_compatible_range_impl<T>;
#endif

template <bool Condition, typename TrueType, typename FalseType>
using If = typename std::conditional<Condition, TrueType, FalseType>::type;
Expand Down Expand Up @@ -99,12 +111,12 @@ struct inplace_vector_base : public inplace_vector_destruct_base<T, Capacity> {
inplace_vector_base(const inplace_vector_base &other) noexcept(
std::is_nothrow_copy_constructible_v<T>)
: inplace_vector_destruct_base<T, Capacity>(other.size) {
std::ranges::copy(other.begin(), other.end(), begin());
std::copy(other.begin(), other.end(), begin());
}
inplace_vector_base(inplace_vector_base &&other) noexcept(
Capacity == 0 || std::is_nothrow_move_constructible_v<T>)
: inplace_vector_destruct_base<T, Capacity>(other.size) {
std::ranges::copy(other.begin(), other.end(), begin());
std::copy(other.begin(), other.end(), begin());
std::destroy(other.begin(), other.end());
other.size = 0;
}
Expand All @@ -114,17 +126,16 @@ struct inplace_vector_base : public inplace_vector_destruct_base<T, Capacity> {
const auto diff = static_cast<std::ptrdiff_t>(other.size() - size());
// other.size is less than size
if (diff < 0) {
const auto new_end =
std::ranges::copy(other.begin(), other.end(), begin());
const auto new_end = std::copy(other.begin(), other.end(), begin());
// destroy unnecessary memory
std::destroy(new_end, end());
}
// other.size is greater than size
else {
// copy other vector into the current vector until it runs ouf of size
std::ranges::copy(other.begin(), other.begin() + size(), begin());
std::copy(other.begin(), other.begin() + size(), begin());
// copy the other half after the end of the current vector
std::ranges::copy(other.begin() + size(), other.end(), end());
std::copy(other.begin() + size(), other.end(), end());
}
this->size_ = other.size();
return *this;
Expand Down Expand Up @@ -200,7 +211,7 @@ struct inplace_vector_base : public inplace_vector_destruct_base<T, Capacity> {
template <typename Iter>
static constexpr void uninitialized_copy(Iter first, Iter last,
iterator dest) noexcept {
std::ranges::copy(first, last, dest);
std::copy(first, last, dest);
}

template <typename Iter>
Expand Down Expand Up @@ -244,13 +255,15 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
base::uninitialized_fill(this->begin(), this->end(), value);
}

#ifdef __cpp_concepts
template <class InputIterator>
requires std::input_iterator<T>
constexpr inplace_vector(InputIterator first, InputIterator last) : base() {
for (; first != last; ++first) {
emplace_back(*first);
}
}

template <class InputIterator>
requires std::forward_iterator<T>
constexpr inplace_vector(InputIterator first, InputIterator last)
Expand All @@ -259,15 +272,22 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
base::uninitialized_copy(first, last, this->begin());
}
}
#ifdef __cpp_lib_containers_ranges
#else
template <class Itr> constexpr inplace_vector(Itr first, Itr last) : base() {
for (; first != last; ++first) {
emplace_back(*first);
}
}
#endif

#if defined(__cpp_lib_containers_ranges) && defined(__cpp_concepts)
template <typename R>
requires container_compatible_range<R>
constexpr inplace_vector(std::from_range_t, R &&rg) {
for (auto &&value : rg) {
emplace_back(std::forward<decltype(value)>(value));
}
}
#else
#endif
constexpr inplace_vector(std::initializer_list<T> il) : base(il.size()) {
if (il.size() != 0) {
Expand All @@ -282,14 +302,13 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
// The current size is greater
if (diff < 0) {
// if other.size is less than just copy normally
const iterator new_end =
std::ranges::copy(il.begin(), il.end(), this->begin());
const iterator new_end = std::copy(il.begin(), il.end(), this->begin());
// destroy the wasted memory
std::destroy(new_end, this->end());
// The other size is greater than size
} else {
// copy other vector into the current vector until it runs ouf of size
std::ranges::copy(il.begin(), il.begin() + this->size(), this->begin());
std::copy(il.begin(), il.begin() + this->size(), this->begin());
// copy the other half after the end of the current vector
base::uninitialized_copy(il.begin() + this->size(), il.end(),
this->end());
Expand Down Expand Up @@ -318,6 +337,7 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
}
}; // freestanding-deleted

#if defined(__cpp_lib_containers_ranges) and defined(__cpp_concepts)
template <typename R>
requires container_compatible_range<R>
constexpr void assign_range(R &&rg) {
Expand All @@ -340,6 +360,8 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
emplace_back(*first);
}
}; // freestanding-deleted
#endif

constexpr void assign(size_type n, const T &u) {
if (Capacity == 0) {
assert(size() == 0 &&
Expand All @@ -366,13 +388,12 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
// other size is less than size
if (diff < 0) {
// if other.size is less than just copy normally
const iterator new_end =
std::ranges::copy(il.begin(), il.end(), this->begin());
const iterator new_end = std::copy(il.begin(), il.end(), this->begin());
std::destroy(new_end, this->end);
// other.size is greater than size
} else {
// copy other vector into the current vector until it runs ouf of size
std::ranges::copy(il.begin(), il.begin() + this->size(), this->begin());
std::copy(il.begin(), il.begin() + this->size(), this->begin());
// copy the other half after the end of the current vector
base::uninitialized_copy(il.begin() + this->size(), il.end(),
this->end());
Expand Down Expand Up @@ -491,6 +512,8 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
}
return this->unchecked_emplace_back(std::move(x));
}; // freestanding-deleted

#if defined(__cpp_lib_containers_ranges) and defined(__cpp_concepts)
template <typename R>
requires container_compatible_range<T>
constexpr void append_range(R &&rg) {
Expand All @@ -500,6 +523,8 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
emplace_back(*first);
}
}; // freestanding-deleted
#endif

constexpr void pop_back() {
if (!empty()) {
const auto end = this->end();
Expand Down Expand Up @@ -546,7 +571,13 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {

template <class... Args>
constexpr reference unchecked_emplace_back(Args &&...args) {
#ifdef __cpp_constexpr_dynamic_alloc
auto final = std::construct_at(end(), std::forward<Args>(args)...);
#else
// Note: placement-new may not be constexpr friendly
// Avoiding placement-new may allow inplace_vector to be constexpr friendly
auto final = ::new (end()) T(std::forward<Args>(args)...);
#endif
this->change_size(1);
return *final;
};
Expand Down Expand Up @@ -644,13 +675,14 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
InputIterator imiddle = std::next(first, to_copy);
base::uninitialized_copy(imiddle, last, end);
base::uninitialized_move(pos, end, middle);
std::ranges::copy(first, imiddle, pos);
std::copy(first, imiddle, pos);
} else {
base::uninitialized_move(end - count, end, end);
std::move_backward(pos, end - count, end);
std::ranges::copy(first, last, pos);
std::copy(first, last, pos);
}
} // freestanding-deleted
#if defined(__cpp_lib_containers_ranges) and defined(__cpp_concepts)
template <typename R>
requires container_compatible_range<R>
constexpr iterator insert_range(const_iterator position, R &&rg) {
Expand All @@ -665,6 +697,7 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
std::rotate(pos, old_end, this->end());
return pos;
} // freestanding-deleted
#endif
constexpr iterator insert(const_iterator position,
std::initializer_list<T> il) {
const iterator pos = position;
Expand Down Expand Up @@ -744,10 +777,13 @@ class inplace_vector : public inplace_vector_base<T, Capacity> {
return std::equal(x.begin(), x.end(), y.begin(), y.end());
}

#ifdef __cpp_lib_three_way_comparison
constexpr friend std::compare_three_way_result<T>
operator<=>(const inplace_vector &x, const inplace_vector &y) {
return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
};
#endif

constexpr friend void swap(inplace_vector &x, inplace_vector &y) noexcept(
Capacity == 0 || (std::is_nothrow_swappable_v<T> &&
std::is_nothrow_move_constructible_v<T>)) {
Expand Down

0 comments on commit 9573915

Please sign in to comment.