Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef STDLIB_ARRAY_HPP
- #define STDLIB_ARRAY_HPP
- #include <algorithm>
- #include <cstddef>
- #include <initializer_list>
- #include <iterator>
- #include <stdexcept>
- #include <type_traits>
- #include <utility>
- namespace stdlib {
- using std::size_t;
- namespace details {
- using std::swap; // for array_traits::is_nothrow_swappable_v
- template<typename ValueType, size_t Size>
- struct array_traits {
- using type = ValueType[Size];
- using iterator = ValueType*;
- using const_iterator = const ValueType*;
- static constexpr bool is_nothrow_swappable_v =
- noexcept(swap(std::declval<ValueType&>(), std::declval<ValueType&>()));
- static constexpr iterator begin(type& array) noexcept {
- return array;
- }
- static constexpr const_iterator begin(const type& array) noexcept {
- return array;
- }
- static constexpr iterator end(type& array) noexcept {
- return array + Size;
- }
- static constexpr const_iterator end(const type& array) noexcept {
- return array + Size;
- }
- };
- template<typename ValueType>
- struct array_traits<ValueType, 0> {
- using type = struct { };
- using iterator = ValueType*;
- using const_iterator = const ValueType*;
- static constexpr bool is_nothrow_swappable_v = true;
- static constexpr iterator begin(type&) noexcept {
- return nullptr;
- }
- static constexpr const_iterator begin(const type&) noexcept {
- return nullptr;
- }
- static constexpr iterator end(type&) noexcept {
- return nullptr;
- }
- static constexpr const_iterator end(const type&) noexcept {
- return nullptr;
- }
- };
- }
- template<typename ValueType, size_t Size>
- struct array {
- private:
- using array_traits = ::stdlib::details::array_traits<ValueType, Size>;
- public:
- using value_type = ValueType;
- using reference = value_type&;
- using const_reference = const value_type&;
- using pointer = value_type*;
- using const_pointer = const value_type*;
- using iterator = typename array_traits::iterator;
- using const_iterator = typename array_traits::const_iterator;
- static_assert(std::is_same<iterator, pointer>::value &&
- std::is_same<const_iterator, const_pointer>::value,
- "array::iterator and array::pointer shall be same type");
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- using size_type = size_t;
- using difference_type = std::ptrdiff_t;
- void fill(const ValueType& value) {
- std::fill(begin(), end(), value);
- }
- void swap(array& other) noexcept(array_traits::is_nothrow_swappable_v) {
- std::swap_ranges(begin(), end(), other.begin());
- }
- iterator begin() noexcept {
- return array_traits::begin(underlying_array);
- }
- constexpr const_iterator begin() const noexcept {
- return array_traits::begin(underlying_array);
- }
- iterator end() noexcept {
- return array_traits::end(underlying_array);
- }
- constexpr const_iterator end() const noexcept {
- return array_traits::end(underlying_array);
- }
- reverse_iterator rbegin() noexcept {
- return reverse_iterator{end()};
- }
- constexpr const_reverse_iterator rbegin() const noexcept {
- return const_reverse_iterator{end()};
- }
- reverse_iterator rend() noexcept {
- return reverse_iterator{begin()};
- }
- constexpr const_reverse_iterator rend() const noexcept {
- return const_reverse_iterator{begin()};
- }
- constexpr const_iterator cbegin() const noexcept {
- return begin();
- }
- constexpr const_iterator cend() const noexcept {
- return begin();
- }
- constexpr const_reverse_iterator crbegin() const noexcept {
- return rbegin();
- }
- constexpr const_reverse_iterator crend() const noexcept {
- return rend();
- }
- constexpr bool empty() const noexcept {
- return size() == 0;
- }
- constexpr size_type size() const noexcept {
- return Size;
- }
- constexpr size_type max_size() const noexcept {
- return size();
- }
- reference operator[](size_type index) {
- return begin()[index];
- }
- constexpr const_reference operator[](size_type index) const {
- return begin()[index];
- }
- reference at(size_type index) {
- if(index >= size()) {
- throw std::out_of_range{"index is out of bounds"};
- }
- return begin()[index];
- }
- constexpr const_reference at(size_type index) const {
- if(index >= size()) {
- throw std::out_of_range{"index is out of bounds"};
- }
- return begin()[index];
- }
- reference front() {
- return begin()[0];
- }
- constexpr const_reference front() const {
- return begin()[0];
- }
- reference back() {
- return begin()[size() - 1];
- }
- const_reference back() const {
- return begin()[size() - 1];
- }
- ValueType* data() noexcept {
- return begin();
- }
- constexpr const ValueType* data() const noexcept {
- return begin();
- }
- typename array_traits::type underlying_array;
- };
- template<typename ValueType, size_t Size>
- bool operator==(const array<ValueType, Size>& lhs, const array<ValueType, Size>& rhs) {
- return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
- }
- template<typename ValueType, size_t Size>
- bool operator!=(const array<ValueType, Size>& lhs, const array<ValueType, Size>& rhs) {
- return !(lhs == rhs);
- }
- template<typename ValueType, size_t Size>
- bool operator<(const array<ValueType, Size>& lhs, const array<ValueType, Size>& rhs) {
- return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
- }
- template<typename ValueType, size_t Size>
- bool operator>(const array<ValueType, Size>& lhs, const array<ValueType, Size>& rhs) {
- return rhs < lhs;
- }
- template<typename ValueType, size_t Size>
- bool operator<=(const array<ValueType, Size>& lhs, const array<ValueType, Size>& rhs) {
- return !(rhs < lhs);
- }
- template<typename ValueType, size_t Size>
- bool operator>=(const array<ValueType, Size>& lhs, const array<ValueType, Size>& rhs) {
- return !(lhs < rhs);
- }
- template<typename ValueType, size_t Size>
- void swap(array<ValueType, Size>& lhs, array<ValueType, Size>& rhs) noexcept(noexcept(lhs.swap(rhs)));
- template<typename>
- struct tuple_size;
- template<size_t, typename>
- struct tuple_element;
- template<typename ValueType, size_t Size>
- struct tuple_size<array<ValueType, Size>> : std::integral_constant<size_t, Size> { };
- template<size_t Index, typename ValueType, size_t Size>
- struct tuple_element<Index, array<ValueType, Size>> {
- static_assert(Index < Size, "invalid index (Index >= Size)");
- using type = ValueType;
- };
- template<size_t Index, typename ValueType, size_t Size>
- ValueType& get(array<ValueType, Size>& arr) noexcept {
- static_assert(Index < Size, "invalid index (Index >= Size)");
- return arr[Index];
- }
- template<size_t Index, typename ValueType, size_t Size>
- ValueType&& get(array<ValueType, Size>&& arr) noexcept {
- static_assert(Index < Size, "invalid index (Index >= Size)");
- return std::move(arr[Index]);
- }
- template<size_t Index, typename ValueType, size_t Size>
- constexpr const ValueType& get(const array<ValueType, Size>& arr) noexcept {
- static_assert(Index < Size, "invalid index (Index >= Size)");
- return arr[Index];
- }
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement