forked from y-scope/clp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core: Add
Array
template class to abstract a fixed-size contiguous …
…buffer whose size is determined at runtime. (y-scope#513)
- Loading branch information
1 parent
1b67fdb
commit 86299ca
Showing
3 changed files
with
170 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#ifndef CLP_ARRAY_HPP | ||
#define CLP_ARRAY_HPP | ||
|
||
#include <concepts> | ||
#include <cstddef> | ||
#include <cstring> | ||
#include <memory> | ||
#include <stdexcept> | ||
#include <type_traits> | ||
|
||
namespace clp { | ||
/** | ||
* Class for a runtime fix-sized array. | ||
* @tparam T The type of elements in the array. The type must be default initializable so that this | ||
* class doesn't need to implement a constructor which takes an initializer list. | ||
*/ | ||
template <typename T> | ||
requires(std::is_fundamental_v<T> || std::default_initializable<T>) | ||
class Array { | ||
public: | ||
// Types | ||
using Iterator = T*; | ||
using ConstIterator = T const*; | ||
|
||
// Constructors | ||
// NOLINTNEXTLINE(*-avoid-c-arrays) | ||
explicit Array(size_t size) : m_data{std::make_unique<T[]>(size)}, m_size{size} { | ||
if constexpr (std::is_fundamental_v<T>) { | ||
memset(m_data.get(), 0, m_size * sizeof(T)); | ||
} | ||
} | ||
|
||
// Disable copy constructor and assignment operator | ||
Array(Array const&) = delete; | ||
auto operator=(Array const&) -> Array& = delete; | ||
|
||
// Default move constructor and assignment operator | ||
Array(Array&&) = default; | ||
auto operator=(Array&&) -> Array& = default; | ||
|
||
// Destructor | ||
~Array() = default; | ||
|
||
// Methods | ||
/** | ||
* @return Whether the array is empty. | ||
*/ | ||
[[nodiscard]] auto empty() const -> bool { return 0 == size(); } | ||
|
||
/** | ||
* @return The size of the array. | ||
*/ | ||
[[nodiscard]] auto size() const -> size_t { return m_size; } | ||
|
||
/** | ||
* @return A pointer to the underlying data buffer. | ||
*/ | ||
[[nodiscard]] auto data() -> T* { return m_data.get(); } | ||
|
||
/** | ||
* @return A pointer to the underlying data buffer. | ||
*/ | ||
[[nodiscard]] auto data() const -> T const* { return m_data.get(); } | ||
|
||
/** | ||
* @param idx | ||
* @return The element at the given index. | ||
* @throw `OperationFailed` if the given index is out of bound. | ||
*/ | ||
[[nodiscard]] auto at(size_t idx) -> T& { | ||
assert_is_in_range(idx); | ||
return m_data[idx]; | ||
} | ||
|
||
/** | ||
* @param idx | ||
* @return The element at the given index. | ||
* @throw `OperationFailed` if the given index is out of bound. | ||
*/ | ||
[[nodiscard]] auto at(size_t idx) const -> T const& { | ||
assert_is_in_range(idx); | ||
return m_data[idx]; | ||
} | ||
|
||
[[nodiscard]] auto begin() -> Iterator { return m_data.get(); } | ||
|
||
[[nodiscard]] auto end() -> Iterator { return m_data.get() + m_size; } | ||
|
||
[[nodiscard]] auto begin() const -> ConstIterator { return m_data.get(); } | ||
|
||
[[nodiscard]] auto end() const -> ConstIterator { return m_data.get() + m_size; } | ||
|
||
private: | ||
/** | ||
* @param idx | ||
* @throw `std::out_of_range` if the given index is out of bound. | ||
*/ | ||
auto assert_is_in_range(size_t idx) -> void { | ||
if (idx >= m_size) { | ||
throw std::out_of_range("clp::Array out-of-range access."); | ||
} | ||
} | ||
|
||
// Variables | ||
// NOLINTNEXTLINE(*-avoid-c-arrays) | ||
std::unique_ptr<T[]> m_data; | ||
size_t m_size; | ||
}; | ||
} // namespace clp | ||
|
||
#endif // CLP_ARRAY_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#include <algorithm> | ||
#include <cstddef> | ||
#include <string> | ||
#include <vector> | ||
|
||
#include <Catch2/single_include/catch2/catch.hpp> | ||
|
||
#include "../src/clp/Array.hpp" | ||
|
||
using clp::Array; | ||
using std::vector; | ||
|
||
// NOLINTNEXTLINE(readability-function-cognitive-complexity) | ||
TEST_CASE("array_fundamental", "[clp::Array]") { | ||
Array<int> clp_array_empty{0}; | ||
REQUIRE(clp_array_empty.empty()); | ||
// NOLINTNEXTLINE(readability-container-size-empty) | ||
REQUIRE((0 == clp_array_empty.size())); | ||
REQUIRE((clp_array_empty.begin() == clp_array_empty.end())); | ||
|
||
constexpr size_t cBufferSize{1024}; | ||
|
||
vector<int> std_vector; | ||
for (int i{0}; i < cBufferSize; ++i) { | ||
std_vector.push_back(i); | ||
} | ||
|
||
Array<int> clp_array{cBufferSize}; | ||
auto const& clp_array_const_ref = clp_array; | ||
std::for_each(clp_array_const_ref.begin(), clp_array_const_ref.end(), [](int i) -> void { | ||
REQUIRE((0 == i)); | ||
}); | ||
|
||
std::copy(std_vector.cbegin(), std_vector.cend(), clp_array.begin()); | ||
|
||
size_t idx{0}; | ||
for (auto const val : clp_array) { | ||
REQUIRE((val == clp_array.at(idx))); | ||
REQUIRE((val == std_vector.at(idx))); | ||
++idx; | ||
} | ||
REQUIRE((cBufferSize == idx)); | ||
REQUIRE_THROWS(clp_array.at(idx)); | ||
} | ||
|
||
TEST_CASE("array_default_initializable", "[clp::Array]") { | ||
Array<std::string> clp_array_empty{0}; | ||
REQUIRE(clp_array_empty.empty()); | ||
// NOLINTNEXTLINE(readability-container-size-empty) | ||
REQUIRE((0 == clp_array_empty.size())); | ||
REQUIRE((clp_array_empty.begin() == clp_array_empty.end())); | ||
|
||
vector<std::string> const std_vector{"yscope", "clp", "clp::Array", "default_initializable"}; | ||
Array<std::string> clp_array{std_vector.size()}; | ||
std::copy(std_vector.cbegin(), std_vector.cend(), clp_array.begin()); | ||
REQUIRE(std::equal(std_vector.begin(), std_vector.end(), clp_array.begin(), clp_array.end())); | ||
} |