Skip to content

Commit

Permalink
Fix compilation error on gcc for StaticVector and support non-movable…
Browse files Browse the repository at this point in the history
… types
  • Loading branch information
Oipo committed Feb 22, 2024
1 parent 59d95e2 commit 08c18af
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 27 deletions.
4 changes: 2 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ while [[ $# -gt 0 ]]; do
esac
done

ccompilers=("clang-14" "clang-18" "gcc-11" "gcc")
cppcompilers=("clang++-14" "clang++-18" "g++-11" "g++")
ccompilers=("clang-15" "clang-18" "gcc-11" "gcc")
cppcompilers=("clang++-15" "clang++-18" "g++-11" "g++")

if [[ "$1" == "--dev" ]]; then
ccompilers=("clang" "gcc")
Expand Down
56 changes: 43 additions & 13 deletions include/ichor/stl/StaticVector.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,16 @@ namespace Ichor {
emplace_back();
}
}
constexpr StaticVector(storage_size_type n, value_type const & value) {
constexpr StaticVector(storage_size_type n, const_reference value) {
assert(n <= N);
for(storage_size_type i = 0; i < n; ++i) {
emplace_back(value);
push_back(value);
}
}
template <class InputIterator>
constexpr StaticVector(InputIterator first, InputIterator last) {
while(first != last) {
emplace_back(*first);
push_back(*first);
first++;
}
}
Expand All @@ -222,15 +222,19 @@ namespace Ichor {
} else {
auto pos = list.begin();
while (pos != list.end()) {
emplace_back(*pos);
if constexpr (std::is_move_constructible_v<T>) {
emplace_back(std::move(*pos));
} else {
push_back(*pos);
}
pos++;
}
}
}
constexpr StaticVector(StaticVector const & other) noexcept(std::is_nothrow_copy_constructible_v<value_type>) {
assert(other._size <= N);
for(auto const &t : other) {
emplace_back(t);
push_back(t);
}
}
constexpr StaticVector(StaticVector&& other) noexcept(std::is_nothrow_move_constructible_v<value_type>) {
Expand All @@ -245,7 +249,7 @@ namespace Ichor {
assert(other._size <= N);
clear();
for(auto const &t : other) {
emplace_back(t);
push_back(t);
}
return *this;
}
Expand Down Expand Up @@ -339,13 +343,21 @@ namespace Ichor {
if constexpr (Detail::is_sufficiently_trivial<T>) {
if(sz > _size) {
for(storage_size_type i = _size; i < sz; ++i) {
emplace_back(c);
if constexpr (std::is_move_constructible_v<T>) {
emplace_back(c);
} else {
push_back(c);
}
}
}
} else {
if(sz > _size) {
for(storage_size_type i = _size; i < sz; ++i) {
emplace_back(c);
if constexpr (std::is_move_constructible_v<T>) {
emplace_back(c);
} else {
push_back(c);
}
}
} else if(sz < _size) {
for(storage_size_type i = static_cast<storage_size_type>(sz); i < _size; ++i) {
Expand Down Expand Up @@ -392,8 +404,9 @@ namespace Ichor {
template <class... Args>
constexpr iterator emplace(const_iterator position, Args&&... args);
template <class... Args>
constexpr reference emplace_back(Args&&... args) {
constexpr reference emplace_back(Args&&... args) noexcept(Detail::is_sufficiently_trivial<T>) {
assert(_size < N);
//fmt::print("emplace_back {} {}\n", _size, (void*)(data() + size()));
std::construct_at(data() + size(), T{std::forward<Args>(args)...});
++_size;
return back();
Expand All @@ -405,37 +418,54 @@ namespace Ichor {
}
constexpr void push_back(value_type&& x) final {
assert(_size < N);
std::construct_at(data() + size(), std::forward<T>(x));
if constexpr (std::is_move_constructible_v<T>) {
std::construct_at(data() + size(), std::forward<T>(x));
} else {
std::terminate(); // should never be called because value_type&& is impossible for non-moveable types
}
++_size;
}

constexpr void pop_back() final {
assert(_size > 0);
if constexpr (!Detail::is_sufficiently_trivial<T>) {
//fmt::print("pop_back destroy_at {} {}\n", (void*)begin().operator->(), (void*)&back());
std::destroy_at(std::addressof(back()));
}
--_size;
}
constexpr iterator erase(const_iterator const_position) final {
auto position = iterator{const_cast<pointer>(const_position.operator->())};
if(position + 1 != end()) {
std::move(position + 1, end(), position);
if constexpr (std::is_move_constructible_v<T>) {
std::move(position + 1, end(), position);
} else {
std::copy(position + 1, end(), position);
}
}
//fmt::print("erase pop_back {} {}\n", (void*)begin().operator->(), (void*)position.operator->());
pop_back();
return position;
}
constexpr iterator erase(const_iterator const_first, const_iterator const_last) final {
auto first = iterator{const_cast<pointer>(const_first.operator->())};
if(const_first != const_last) {
auto last = iterator{const_cast<pointer>(const_last.operator->())};
auto position = std::move(last, end(), first);
SVIterator<T, false> position;

if constexpr (std::is_move_constructible_v<T>) {
position = std::move(last, end(), first);
} else {
position = std::copy(last, end(), first);
}

if constexpr (!Detail::is_sufficiently_trivial<T>) {
while(position != end()) {
std::destroy_at(position.operator->());
position++;
}
}
_size -= std::distance(first, last);
_size -= static_cast<storage_size_type>(std::distance(first, last));
}

return first;
Expand Down
1 change: 1 addition & 0 deletions src/ichor/event_queues/IOUringQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# pragma GCC diagnostic ignored "-Wsign-conversion"
# pragma GCC diagnostic ignored "-Wshadow"
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wpedantic"
# pragma GCC diagnostic ignored "-Wgnu-pointer-arith"
# pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
# pragma GCC diagnostic ignored "-Wgnu-statement-expression-from-macro-expansion"
Expand Down
78 changes: 66 additions & 12 deletions test/StlTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,34 @@ struct noncopyable final {
noncopyable& operator=(noncopyable&&) = default;
};

uint64_t destructed{};

struct sufficiently_non_trival {
sufficiently_non_trival() = default;
sufficiently_non_trival(int _i) : i(_i) {}
~sufficiently_non_trival() { destructed = true; }
sufficiently_non_trival(const sufficiently_non_trival&) = default;
sufficiently_non_trival(sufficiently_non_trival&&) = default;
sufficiently_non_trival& operator=(const sufficiently_non_trival&) = default;
sufficiently_non_trival& operator=(sufficiently_non_trival&&) = default;
sufficiently_non_trival(int _i) : i(_i) { }
~sufficiently_non_trival() { ++destructed; }
sufficiently_non_trival(const sufficiently_non_trival& o) = default;
sufficiently_non_trival(sufficiently_non_trival&& o) noexcept = default;
sufficiently_non_trival& operator=(const sufficiently_non_trival& o) = default;
sufficiently_non_trival& operator=(sufficiently_non_trival&& o) noexcept = default;

[[nodiscard]] constexpr bool operator==(int _i) const noexcept { return _i == i; }

int i{};
};

struct sufficiently_non_trival_non_moveable {
sufficiently_non_trival_non_moveable() = default;
sufficiently_non_trival_non_moveable(int _i) : i(_i) { }
~sufficiently_non_trival_non_moveable() { ++destructed; }
sufficiently_non_trival_non_moveable(const sufficiently_non_trival_non_moveable& o) = default;
sufficiently_non_trival_non_moveable(sufficiently_non_trival_non_moveable&& o) noexcept = delete;
sufficiently_non_trival_non_moveable& operator=(const sufficiently_non_trival_non_moveable& o) = default;
sufficiently_non_trival_non_moveable& operator=(sufficiently_non_trival_non_moveable&& o) noexcept = delete;

[[nodiscard]] constexpr bool operator==(int _i) const noexcept { return _i == i; }

int i{};
bool destructed{};
};

template <>
Expand Down Expand Up @@ -899,31 +914,70 @@ TEST_CASE("STL Tests") {
REQUIRE(eraseNTSv[3] == 4);
REQUIRE(eraseNTSv.size() == 4);

destructed = 0;
auto erasePos = eraseNTSv.erase(eraseNTSv.cbegin() + 1, eraseNTSv.cbegin() + 3);
REQUIRE(eraseNTSv.size() == 2);
REQUIRE(eraseNTSv[0] == 1);
REQUIRE(eraseNTSv[1] == 4);
REQUIRE(erasePos == eraseNTSv.begin() + 1);
REQUIRE(destructed == 2);

erasePos = eraseNTSv.erase(eraseNTSv.cbegin());
REQUIRE(eraseNTSv.size() == 1);
REQUIRE(eraseNTSv[0] == 4);
REQUIRE(erasePos == eraseNTSv.begin());
REQUIRE(destructed == 3);

sufficiently_non_trival *ptr = eraseNTSv.data();
REQUIRE(!ptr++->destructed);
REQUIRE(ptr++->destructed);
REQUIRE(ptr++->destructed);
REQUIRE(ptr->destructed);
eraseNTSv.pop_back();
REQUIRE(eraseNTSv.empty());
REQUIRE(destructed == 4);

eraseNTSv.assign((std::size_t)3, 3);
REQUIRE(eraseNTSv.size() == 3);
REQUIRE(eraseNTSv[0] == 3);
REQUIRE(eraseNTSv[1] == 3);
REQUIRE(eraseNTSv[2] == 3);
}

{
StaticVector<sufficiently_non_trival_non_moveable, 4> eraseNTSv{1, 2, 3, 4};
REQUIRE(!eraseNTSv.empty());
REQUIRE(eraseNTSv.size() == 4);
REQUIRE(eraseNTSv[0] == 1);
REQUIRE(eraseNTSv[1] == 2);
REQUIRE(eraseNTSv[2] == 3);
REQUIRE(eraseNTSv[3] == 4);
REQUIRE(eraseNTSv.size() == 4);

destructed = 0;
auto erasePos = eraseNTSv.erase(eraseNTSv.cbegin() + 1, eraseNTSv.cbegin() + 3);
REQUIRE(eraseNTSv.size() == 2);
REQUIRE(eraseNTSv[0] == 1);
REQUIRE(eraseNTSv[1] == 4);
REQUIRE(erasePos == eraseNTSv.begin() + 1);
REQUIRE(destructed == 2);

erasePos = eraseNTSv.erase(eraseNTSv.cbegin());
REQUIRE(eraseNTSv.size() == 1);
REQUIRE(eraseNTSv[0] == 4);
REQUIRE(erasePos == eraseNTSv.begin());
REQUIRE(destructed == 3);

eraseNTSv.pop_back();
REQUIRE(eraseNTSv.empty());
REQUIRE(destructed == 4);

eraseNTSv.assign((std::size_t)3, 3);
REQUIRE(eraseNTSv.size() == 3);
REQUIRE(eraseNTSv[0] == 3);
REQUIRE(eraseNTSv[1] == 3);
REQUIRE(eraseNTSv[2] == 3);

StaticVector<sufficiently_non_trival_non_moveable, 4> eraseNTSv2{eraseNTSv};
StaticVector<sufficiently_non_trival_non_moveable, 4> eraseNTSv3;
eraseNTSv3 = eraseNTSv2;
REQUIRE(eraseNTSv2.size() == 3);
REQUIRE(eraseNTSv3.size() == 3);
}

{
Expand Down

0 comments on commit 08c18af

Please sign in to comment.