ulfben icon

Container 2020 day 2 (refactoring)

ulfben | PRO | 11/20/20 02:59:09 PM UTC (Edited) | 0 ⭐ | 1577 👁️ | Never ⏰ | []
C++ |

5.74 KB

|

None

|

0 👍

/

0 👎

#pragma once
#include <algorithm>
#include <numeric>
#include <cassert>
#include <stdexcept>
namespace API
{
    template<typename T>
    class Container
    {
    public:
        using pointer = T*;
        using const_pointer = const T*;
        using iterator = T*; //aliases for generic code
        using const_iterator = const T*; 
        using value_type = T;
        using size_type = size_t;
        using reference = T&;
        using const_reference = const T&;           
 
        Container() = default;
        ~Container() { delete[] _data;  } //WARNING: may invoke double-delete, if we've manually called destructors on our Ts.
        explicit Container(size_type count) : _data(new T[count]), _count(count), _capacity(count){
            //STL behavior is to fill with defaulted-Ts. 
                //std::fill(begin(), end(), T());   
            //I'm ignoring this to let me delegate to this constructor efficiently.             
        };
 
        //range construction
        Container(const_iterator begin, const_iterator end) : Container(static_cast<size_type>(std::distance(begin, end))) {
            assert(begin <= end && "Container(iter, iter): begin & end iterators are reversed");
            std::copy(begin, end, begin());
        }
        
        //copy ctor, delegating to range
        explicit Container(const Container& that) : Container(that.begin(), that.end()){}
        
        //list construction, delegating to range. 
        Container(std::initializer_list<T> list) : Container(std::begin(list), std::end(list)) {}
 
        Container(Container&& that) noexcept {          
            _count = std::exchange(that._count, 0);
            _capacity = std::exchange(that._capacity, 0);           
            _data = std::exchange(that._data, nullptr);         
        }
 
        //by value assignment idiom. deals with both copy- and move assignment
        Container& operator=(Container that) noexcept {
            swap(that); //we take all in that, and give that all of us. that is destroyed at the return of this function. 
            return *this;
        }
 
        void swap(Container& that) noexcept {
            using std::swap;
            swap(_data, that._data);
            swap(_count, that._count);
            swap(_capacity, that._capacity);
        }
 
        //ADL overload. See Arthur O'Dwyer: https://youtu.be/7Qgd9B1KuMQ?t=2597
        friend void swap(Container<T>& a, Container<T>& b) noexcept {
            a.swap(b);
        }           
        
        void clear() noexcept {
            //TODO: could be erase(begin(), end()). 
            while (!empty()) {
                pop_back();
            }
        }
 
        void pop_back() noexcept {
            assert(!empty() && "pop_back() on empty container is undefined!");
            back().~T(); //WARNING: will lead do double delete when we call delete[] on _data
            --_count;
        }
 
        void reserve(size_type newCapacity) {
            if (newCapacity <= _capacity) { return;  } //never decrease the allocation
            pointer newBuffer = new T[newCapacity];
            std::move(begin(), end(), newBuffer);
            delete[] _data;
            _data = newBuffer;
            _capacity = newCapacity;
        }
        
        void push_back(const T& value) {
            if (_capacity == 0) {
                reserve(2);
            }
            else if (_count == _capacity) {
                reserve(2 * _capacity);
            }
            _data[_count] = value;
            _count++;
        }
 
        reference at(size_type index) {
            if (index >= size()) {
                throw std::out_of_range("Container at() index is out of range!");
            }
            return _data[index];
        }
        const_reference at(size_type index) const {
            if (index >= size()) {
                throw std::out_of_range("Container at() index is out of range!");
            }
            return _data[index];
        }
 
        reference operator[](size_type index) noexcept{
            assert(index < size() && "Container operator[] index is out of range!");
            return _data[index];
        }
        const_reference operator[](size_type index) const noexcept {
            assert(index < size() && "Container operator[] index is out of range!");
            return _data[index];
        }
 
        reference front() noexcept {
            assert(!empty() && "front() on empty container is UB");
            return _data[0];
        }
        const_reference front() const noexcept {
            assert(!empty() && "front() on empty container is UB");
            return _data[0];
        }
 
        const_reference back() const noexcept {
            assert(!empty() && "back() on empty container is UB");
            return _data[size() - 1];
        }
        reference back() noexcept {
            assert(!empty() && "back() on empty container is UB");
            return _data[size() - 1];
        }
        
        [[nodiscard]] constexpr bool empty() const noexcept {
            return size() == 0;
        }
 
        size_type capacity() const noexcept {
            return _capacity;
        }
        size_type size() const noexcept {
            return _count;
        }
 
        //TODO: make free functions of these
        const_iterator begin() const noexcept { return _data; }     
        const_iterator cbegin() const noexcept { return _data; }
        iterator begin() noexcept { return _data; }
 
        const_iterator end() const noexcept { return _data + _count; }
        const_iterator cend() const noexcept { return _data + _count; }     
        iterator end() noexcept { return _data + _count; }
 
    private:
        T* _data = nullptr;
        size_type _count = 0;
        size_type _capacity = 0;
    };
    
    template<typename T>
    bool operator==(const Container<T>& lhs, const Container<T>& rhs) noexcept {
        if (std::size(lhs) != std::size(rhs)) { return false; }
        return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
    }
    template<typename T>
    bool operator<(const Container<T>& lhs, const Container<T>& rhs) noexcept {
        return std::lexicographical_compare(lhs.begin(), lhs.end(),
            rhs.begin(), rhs.end());
    }
 
    template<typename T>
    bool operator!=(const Container<T>& lhs, const Container<T>& rhs) noexcept {
        return not(lhs == rhs);
    }
    template<typename T>
    bool operator>(const Container<T>& lhs, const Container<T>& rhs) noexcept {
        return rhs < lhs;
    }
    template<typename T>
    bool operator<=(const Container<T>& lhs, const Container<T>& rhs) noexcept {
        !(lhs > rhs);
    }
    template<typename T>
    bool operator>=(const Container<T>& lhs, const Container<T>& rhs) noexcept {
        !(lhs < rhs);
    }
}

Comments

  • Yuizcko icon
    05/18/26 12:59:32 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400