Skip to content

Commit d6b00ff

Browse files
committed
Add noexceptions support
1 parent b8aabf6 commit d6b00ff

File tree

3 files changed

+117
-23
lines changed

3 files changed

+117
-23
lines changed

include/beman/inplace_vector/inplace_vector.hpp

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,27 @@
1010
#include <cstddef> // for size_t
1111
#include <cstdint> // for fixed-width integer types
1212
#include <cstdio> // for assertion diagnostics
13-
#include <cstdlib> // for abort
1413
#include <functional> // for less and equal_to
1514
#include <iterator> // for reverse_iterator and iterator traits
1615
#include <limits> // for numeric_limits
1716
#include <memory> // for destroy
1817
#include <new> // for operator new
1918
#include <ranges>
20-
#include <stdexcept> // for length_error
2119
#include <type_traits> // for aligned_storage and all meta-functions
2220

2321
// Artifact from previous implementation, can be used as hints for optimizer
2422
#define IV_EXPECT(EXPR)
2523

24+
#if !defined(__cpp_exceptions) || __cpp_exceptions < 199711L
25+
#ifndef BEMAN_IV_THROW
26+
#include <cstdlib> // for abort
27+
#define BEMAN_IV_THROW(x) abort()
28+
#endif
29+
#else
30+
#include <stdexcept> // for length_error
31+
#define BEMAN_IV_THROW(x) throw x
32+
#endif
33+
2634
// beman::from_range_t
2735
namespace beman {
2836
struct from_range_t {};
@@ -260,8 +268,9 @@ struct inplace_vector
260268
static constexpr size_type max_size() noexcept { return N; }
261269
static constexpr size_type capacity() noexcept { return N; }
262270
constexpr void reserve(size_type n) {
263-
if (n > N) [[unlikely]]
264-
throw std::bad_alloc();
271+
if (n > N) [[unlikely]] {
272+
BEMAN_IV_THROW(std::bad_alloc());
273+
}
265274
}
266275
constexpr void shrink_to_fit() {}
267276

@@ -351,8 +360,9 @@ struct inplace_vector
351360
constexpr T &emplace_back(Args &&...args)
352361
requires(std::constructible_from<T, Args...>)
353362
{
354-
if (!try_emplace_back(std::forward<Args>(args)...)) [[unlikely]]
355-
throw std::bad_alloc();
363+
if (!try_emplace_back(std::forward<Args>(args)...)) [[unlikely]] {
364+
BEMAN_IV_THROW(std::bad_alloc());
365+
}
356366
return back();
357367
}
358368
constexpr T &push_back(const T &x)
@@ -395,12 +405,14 @@ struct inplace_vector
395405
requires(std::constructible_from<T, std::ranges::range_reference_t<R>>)
396406
{
397407
if constexpr (std::ranges::sized_range<R>) {
398-
if (size() + std::ranges::size(rg) > capacity()) [[unlikely]]
399-
throw std::bad_alloc();
408+
if (size() + std::ranges::size(rg) > capacity()) [[unlikely]] {
409+
BEMAN_IV_THROW(std::bad_alloc());
410+
}
400411
}
401412
for (auto &&e : rg) {
402-
if (size() == capacity()) [[unlikely]]
403-
throw std::bad_alloc();
413+
if (size() == capacity()) [[unlikely]] {
414+
BEMAN_IV_THROW(std::bad_alloc());
415+
}
404416
emplace_back(std::forward<decltype(e)>(e));
405417
}
406418
}
@@ -426,8 +438,9 @@ struct inplace_vector
426438
assert_iterator_in_range(position);
427439
if constexpr (std::random_access_iterator<InputIterator>) {
428440
if (size() + static_cast<size_type>(std::distance(first, last)) >
429-
capacity()) [[unlikely]]
430-
throw std::bad_alloc{};
441+
capacity()) [[unlikely]] {
442+
BEMAN_IV_THROW(std::bad_alloc());
443+
}
431444
}
432445
auto b = end();
433446
for (; first != last; ++first)
@@ -543,9 +556,9 @@ struct inplace_vector
543556
{
544557
if (sz == size())
545558
return;
546-
else if (sz > N) [[unlikely]]
547-
throw std::bad_alloc{};
548-
else if (sz > size())
559+
else if (sz > N) [[unlikely]] {
560+
BEMAN_IV_THROW(std::bad_alloc());
561+
} else if (sz > size())
549562
insert(end(), sz - size(), c);
550563
else {
551564
unsafe_destroy(begin() + sz, end());
@@ -557,25 +570,27 @@ struct inplace_vector
557570
{
558571
if (sz == size())
559572
return;
560-
else if (sz > N) [[unlikely]]
561-
throw std::bad_alloc{};
562-
else if (sz > size())
573+
else if (sz > N) [[unlikely]] {
574+
BEMAN_IV_THROW(std::bad_alloc());
575+
} else if (sz > size()) {
563576
while (size() != sz)
564577
emplace_back(T{});
565-
else {
578+
} else {
566579
unsafe_destroy(begin() + sz, end());
567580
unsafe_set_size(sz);
568581
}
569582
}
570583

571584
constexpr reference at(size_type pos) {
572-
if (pos >= size()) [[unlikely]]
573-
throw std::out_of_range("inplace_vector::at");
585+
if (pos >= size()) [[unlikely]] {
586+
BEMAN_IV_THROW(std::out_of_range("inplace_vector::at"));
587+
}
574588
return details::inplace_vector::index(*this, pos);
575589
}
576590
constexpr const_reference at(size_type pos) const {
577-
if (pos >= size()) [[unlikely]]
578-
throw std::out_of_range("inplace_vector::at");
591+
if (pos >= size()) [[unlikely]] {
592+
BEMAN_IV_THROW(std::out_of_range("inplace_vector::at"));
593+
}
579594
return details::inplace_vector::index(*this, pos);
580595
}
581596

tests/beman/inplace_vector/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ add_gtest(constructors)
4242
add_gtest(size_n_data)
4343
add_gtest(erasure)
4444

45+
if(
46+
CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
47+
OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
48+
)
49+
add_gtest(noexceptions)
50+
target_compile_options(
51+
beman.inplace_vector.tests.noexceptions
52+
PRIVATE -fno-exceptions
53+
)
54+
endif()
55+
4556
# constexpr test
4657
add_executable(beman.inplace_vector.tests.constexpr constexpr.test.cpp)
4758
target_link_libraries(
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include <array>
2+
3+
bool abort_called = false;
4+
#define BEMAN_IV_THROW(x) abort_called = true;
5+
6+
#include "gtest_setup.hpp"
7+
8+
namespace {
9+
template <typename Param> class NoExceptions : public IVBasicTest<Param> {};
10+
TYPED_TEST_SUITE(NoExceptions, IVAllTypes);
11+
12+
TYPED_TEST(NoExceptions, NonThrowing) {
13+
14+
using IV = TestFixture::IV;
15+
using T = TestFixture::T;
16+
17+
const auto reference = this->unique();
18+
19+
IV device;
20+
abort_called = false;
21+
22+
device.assign(reference.begin(), reference.end());
23+
EXPECT_EQ(device, reference);
24+
device.clear();
25+
26+
EXPECT_EQ(abort_called, false);
27+
}
28+
29+
TYPED_TEST(NoExceptions, Throwing) {
30+
31+
using IV = TestFixture::IV;
32+
using T = TestFixture::T;
33+
34+
const auto reference = this->unique();
35+
auto range = std::array<T, IV::capacity() + 1>{};
36+
37+
IV device;
38+
device.assign(reference.begin(), reference.end());
39+
40+
abort_called = false;
41+
device.emplace_back(T{});
42+
EXPECT_EQ(abort_called, true);
43+
44+
abort_called = false;
45+
device.resize(IV::capacity() + 1);
46+
EXPECT_EQ(abort_called, true);
47+
48+
abort_called = false;
49+
device.resize(IV::capacity() + 1, T{});
50+
EXPECT_EQ(abort_called, true);
51+
52+
abort_called = false;
53+
device.reserve(IV::capacity() + 1);
54+
EXPECT_EQ(abort_called, true);
55+
56+
abort_called = false;
57+
device.append_range(range);
58+
EXPECT_EQ(abort_called, true);
59+
60+
abort_called = false;
61+
device.insert(device.end(), range.begin(), range.end());
62+
EXPECT_EQ(abort_called, true);
63+
64+
abort_called = false;
65+
device.at(IV::capacity() + 1);
66+
EXPECT_EQ(abort_called, true);
67+
}
68+
} // namespace

0 commit comments

Comments
 (0)