Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions include/camp/array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,134 @@ struct array {
value_type elements[N];
};

template <class T>
struct array<T, 0> {
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using iterator = pointer;
using const_iterator = const_pointer;

constexpr reference at(size_type)
{
throw std::out_of_range{"camp::array::at detected out of range access"};
}

constexpr const_reference at(size_type) const
{
throw std::out_of_range{"camp::array::at detected out of range access"};
}

CAMP_HOST_DEVICE constexpr reference operator[](size_type) noexcept
{
return *data();
}

CAMP_HOST_DEVICE constexpr const_reference operator[](
size_type) const noexcept
{
return *data();
}

reference front() = delete;
const_reference front() const = delete;
reference back() = delete;
const_reference back() const = delete;

CAMP_HOST_DEVICE constexpr pointer data() noexcept { return nullptr; }

CAMP_HOST_DEVICE constexpr const_pointer data() const noexcept
{
return nullptr;
}

CAMP_HOST_DEVICE constexpr iterator begin() noexcept
{
return iterator(data());
}

CAMP_HOST_DEVICE constexpr const_iterator begin() const noexcept
{
return const_iterator(data());
}

CAMP_HOST_DEVICE constexpr const_iterator cbegin() const noexcept
{
return const_iterator(data());
}

CAMP_HOST_DEVICE constexpr iterator end() noexcept
{
return iterator(data());
}

CAMP_HOST_DEVICE constexpr const_iterator end() const noexcept
{
return const_iterator(data());
}

CAMP_HOST_DEVICE constexpr const_iterator cend() const noexcept
{
return const_iterator(data());
}

CAMP_HOST_DEVICE constexpr bool empty() const noexcept { return true; }

CAMP_HOST_DEVICE constexpr size_type size() const noexcept { return 0; }

CAMP_HOST_DEVICE constexpr size_type max_size() const noexcept { return 0; }

CAMP_HOST_DEVICE constexpr void fill(const T&) {}

CAMP_HOST_DEVICE constexpr void swap(array&) noexcept {}
};

template <class T>
CAMP_HOST_DEVICE inline constexpr bool operator==(const array<T, 0>&,
const array<T, 0>&)
{
return true;
}

template <class T>
CAMP_HOST_DEVICE inline constexpr bool operator!=(const array<T, 0>&,
const array<T, 0>&)
{
return false;
}

template <class T>
CAMP_HOST_DEVICE inline constexpr bool operator<(const array<T, 0>&,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: C++20 replaces most of these comparison operators with the three-way comparison <=> operator

const array<T, 0>&)
{
return false;
}

template <class T>
CAMP_HOST_DEVICE inline constexpr bool operator<=(const array<T, 0>&,
const array<T, 0>&)
{
return true;
}

template <class T>
CAMP_HOST_DEVICE inline constexpr bool operator>(const array<T, 0>&,
const array<T, 0>&)
{
return false;
}

template <class T>
CAMP_HOST_DEVICE inline constexpr bool operator>=(const array<T, 0>&,
const array<T, 0>&)
{
return true;
}

template <class T, std::size_t N>
CAMP_HOST_DEVICE inline constexpr bool operator==(const array<T, N>& lhs,
const array<T, N>& rhs)
Expand Down
51 changes: 51 additions & 0 deletions test/array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,48 @@ CAMP_TEST_BEGIN(array, copy_assignment)
}
CAMP_TEST_END(array, copy_assignment)

CAMP_TEST_BEGIN(array, zero_sized_capacity)
{
camp::array<int, 0> a{};
const camp::array<int, 0>& c = a;

return a.empty() && c.empty() && a.size() == 0 && c.size() == 0
&& a.max_size() == 0 && c.max_size() == 0;
}
CAMP_TEST_END(array, zero_sized_capacity)

CAMP_TEST_BEGIN(array, zero_sized_data)
{
camp::array<int, 0> a{};
const camp::array<int, 0>& c = a;

return a.data() == nullptr && c.data() == nullptr && a.begin() == a.end()
&& c.begin() == c.end() && a.cbegin() == a.cend()
&& c.cbegin() == c.cend();
}
CAMP_TEST_END(array, zero_sized_data)

CAMP_TEST_BEGIN(array, zero_sized_modifiers)
{
camp::array<int, 0> a{};
camp::array<int, 0> b = {};

a.fill(3);
camp::swap(a, b);

return a.empty() && b.empty() && a.size() == 0 && b.size() == 0;
}
CAMP_TEST_END(array, zero_sized_modifiers)

CAMP_TEST_BEGIN(array, zero_sized_comparisons)
{
camp::array<int, 0> a{};
camp::array<int, 0> b = {};

return a == b && !(a != b) && !(a < b) && a <= b && !(a > b) && a >= b;
}
CAMP_TEST_END(array, zero_sized_comparisons)

// Not portable as currently implemented
TEST(host_array, at)
{
Expand Down Expand Up @@ -77,6 +119,15 @@ TEST(host_array, at)
EXPECT_TRUE(exception);
}

TEST(host_array, zero_sized_at)
{
camp::array<int, 0> a{};
const camp::array<int, 0>& b = a;

EXPECT_THROW(a.at(0), std::out_of_range);
EXPECT_THROW(b.at(0), std::out_of_range);
}

CAMP_TEST_BEGIN(array, subscript)
{
camp::array<int, 2> a = {1, 8};
Expand Down
Loading