/*  -*- C++ -*-

    Copyright © 2020 Michal Schulz <michal.schulz@gmx.de>
    https://github.com/michalsc

    This Source Code Form is subject to the terms of the
    Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
    with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#ifndef _TINYSTD_VECTOR
#define _TINYSTD_VECTOR

#include <stdint.h>
#include <iterator>
#include <type_traits>
#include <stdexcept>
#include <initializer_list>
#include <tinystl/bits/support.h>
#include <tinystl/allocator>

namespace tinystd {

template < class T, class Alloc = allocator<T> >
class vector {
public:
    typedef T                       value_type;
    typedef Alloc                   allocator_type;
    typedef value_type&             reference;
    typedef const value_type&       const_reference;
    typedef value_type*             pointer;
    typedef const value_type*       const_pointer;
    typedef uintptr_t               size_type;
    typedef ptrdiff_t               difference_type;

    // Interators
    class const_iterator;
    // Bidirectional iterator for list
    class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
    {
        pointer n;

    public:
        iterator() : n(nullptr) {};
        iterator(pointer node) : n(node) {};
        iterator(const iterator &it) : n(it.n){};
        value_type& operator*() const { return *n; }

        iterator& operator+=(difference_type pos) { n += pos; return *this; }
        iterator& operator-=(difference_type pos) { n -= pos; return *this; }
        iterator operator+(difference_type pos) { iterator tmp(*this); tmp+=pos; return tmp; }
        iterator operator-(difference_type pos) { iterator tmp(*this); tmp-=pos; return tmp; }
        friend inline iterator operator+(const difference_type pos, const iterator& rhs) { iterator tmp(rhs); tmp+=pos; return tmp; }
        friend inline iterator operator-(const difference_type pos, const iterator& rhs) { iterator tmp(rhs); tmp-=pos; return tmp; }
        friend inline difference_type operator-(const iterator& rhs, const iterator& lhs) { return lhs.n - rhs.n; }
        difference_type operator-(const iterator& rhs) { return n - rhs.n; }
        bool operator<(const iterator &rhs) { return rhs.n > n; }
        bool operator<=(const iterator &rhs) { return rhs.n >= n; }
        bool operator>(const iterator &rhs) { return rhs.n < n; }
        bool operator>=(const iterator &rhs) { return rhs.n <= n; }
        value_type& operator[](difference_type pos) { return *(n+pos); }

        iterator &operator++() {
            n++;
            return *this;
        }
        iterator &operator--() {
            n--;
            return *this;
        }
        iterator operator++(int) {
            iterator tmp(*this);
            operator++();
            return tmp;
        }
        iterator operator--(int) {
            iterator tmp(*this);
            operator--();
            return tmp;
        }

        bool operator==(const iterator &rhs) const { return n == rhs.n; }
        bool operator!=(const iterator &rhs) const { return n != rhs.n; }

        friend class vector::const_iterator;
        friend class vector;
    };

    class const_iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
    {
        pointer n;

      public:
        const_iterator() : n(nullptr){};
        const_iterator(pointer node) : n(node){};
        const_iterator(const const_iterator &it) : n(it.n){};
        const_iterator(const typename vector<value_type, Alloc>::iterator &it) : n(it.n) {};
        value_type &operator*() const { return *n; }

        const_iterator& operator+=(difference_type pos) { n += pos; return *this; }
        const_iterator& operator-=(difference_type pos) { n -= pos; return *this; }
        const_iterator operator+(difference_type pos) { const_iterator tmp(*this); tmp+=pos; return tmp; }
        const_iterator operator-(difference_type pos) { const_iterator tmp(*this); tmp-=pos; return tmp; }
        friend inline const_iterator operator+(const difference_type pos, const const_iterator& rhs) { const_iterator tmp(rhs); tmp+=pos; return tmp; }
        friend inline const_iterator operator-(const difference_type pos, const const_iterator& rhs) { const_iterator tmp(rhs); tmp-=pos; return tmp; }
        friend inline difference_type operator-(const const_iterator& rhs, const const_iterator& lhs) { return lhs.n - rhs.n; }
        difference_type operator-(const const_iterator& rhs) { return n - rhs.n; }
        bool operator<(const iterator &rhs) { return rhs.n > n; }
        bool operator<=(const iterator &rhs) { return rhs.n >= n; }
        bool operator>(const iterator &rhs) { return rhs.n < n; }
        bool operator>=(const iterator &rhs) { return rhs.n <= n; }
        value_type& operator[](difference_type pos) const { return *(n+pos); }

        const_iterator &operator++() {
            n++;
            return *this;
        }
        const_iterator &operator--() {
            n--;
            return *this;
        }
        const_iterator operator++(int) {
            const_iterator tmp(*this);
            operator++();
            return tmp;
        }
        const_iterator operator--(int) {
            const_iterator tmp(*this);
            operator--();
            return tmp;
        }

        bool operator==(const const_iterator &rhs) const { return n == rhs.n; }
        bool operator!=(const const_iterator &rhs) const { return n != rhs.n; }

        friend class vector;
    };

    class const_reverse_iterator;
    // Bidirectional iterator for list
    class reverse_iterator : public std::iterator<std::random_access_iterator_tag, value_type>
    {
        pointer n;

    public:
        reverse_iterator() : n(nullptr) {};
        reverse_iterator(pointer node) : n(node) {};
        reverse_iterator(const reverse_iterator &it) : n(it.n){};
        value_type& operator*() { return *n; }

        reverse_iterator& operator+=(difference_type pos) { n -= pos; return *this; }
        reverse_iterator& operator-=(difference_type pos) { n += pos; return *this; }
        reverse_iterator operator+(difference_type pos) { reverse_iterator tmp(*this); tmp+=pos; return tmp; }
        reverse_iterator operator-(difference_type pos) { reverse_iterator tmp(*this); tmp-=pos; return tmp; }
        friend inline reverse_iterator operator+(const difference_type pos, const reverse_iterator& rhs) { reverse_iterator tmp(rhs); tmp+=pos; return tmp; }
        friend inline reverse_iterator operator-(const difference_type pos, const reverse_iterator& rhs) { reverse_iterator tmp(rhs); tmp-=pos; return tmp; }
        friend inline difference_type operator-(const reverse_iterator& rhs, const reverse_iterator& lhs) { return rhs.n - lhs.n; }
        difference_type operator-(const reverse_iterator& rhs) { return rhs.n - n; }
        bool operator<(const iterator &rhs) { return rhs.n < n; }
        bool operator<=(const iterator &rhs) { return rhs.n <= n; }
        bool operator>(const iterator &rhs) { return rhs.n > n; }
        bool operator>=(const iterator &rhs) { return rhs.n >= n; }
        value_type& operator[](difference_type pos) { return *(n-pos); }

        reverse_iterator &operator++() {
            n--;
            return *this;
        }
        reverse_iterator &operator--() {
            n++;
            return *this;
        }
        reverse_iterator operator++(int) {
            reverse_iterator tmp(*this);
            operator++();
            return tmp;
        }
        iterator operator--(int) {
            reverse_iterator tmp(*this);
            operator--();
            return tmp;
        }

        bool operator==(const reverse_iterator &rhs) const { return n == rhs.n; }
        bool operator!=(const reverse_iterator &rhs) const { return n != rhs.n; }

        friend class vector::const_reverse_iterator;
        friend class vector;
    };

    class const_reverse_iterator : public std::iterator<std::random_access_iterator_tag, value_type>
    {
        pointer n;

      public:
        const_reverse_iterator() : n(nullptr){};
        const_reverse_iterator(pointer node) : n(node){};
        const_reverse_iterator(const const_reverse_iterator &it) : n(it.n){};
        const_reverse_iterator(const typename vector<value_type, Alloc>::const_iterator &it) : n(it.n) {};
        value_type &operator*() const { return *n; }

        const_reverse_iterator& operator+=(difference_type pos) { n -= pos; return *this; }
        const_reverse_iterator& operator-=(difference_type pos) { n += pos; return *this; }
        const_reverse_iterator operator+(difference_type pos) { const_reverse_iterator tmp(*this); tmp+=pos; return tmp; }
        const_reverse_iterator operator-(difference_type pos) { const_reverse_iterator tmp(*this); tmp-=pos; return tmp; }
        friend inline const_reverse_iterator operator+(const difference_type pos, const const_reverse_iterator& rhs) { const_reverse_iterator tmp(rhs); tmp+=pos; return tmp; }
        friend inline const_reverse_iterator operator-(const difference_type pos, const const_reverse_iterator& rhs) { const_reverse_iterator tmp(rhs); tmp-=pos; return tmp; }
        friend inline difference_type operator-(const const_reverse_iterator& rhs, const const_reverse_iterator& lhs) { return rhs.n - lhs.n; }
        difference_type operator-(const const_reverse_iterator& rhs) { return rhs.n - n; }
        bool operator<(const iterator &rhs) { return rhs.n < n; }
        bool operator<=(const iterator &rhs) { return rhs.n <= n; }
        bool operator>(const iterator &rhs) { return rhs.n > n; }
        bool operator>=(const iterator &rhs) { return rhs.n >= n; }
        value_type& operator[](difference_type pos) const { return *(n-pos); }

        const_reverse_iterator &operator++() {
            n--;
            return *this;
        }
        const_reverse_iterator &operator--() {
            n--;
            return *this;
        }
        const_reverse_iterator operator++(int) {
            const_reverse_iterator tmp(*this);
            operator++();
            return tmp;
        }
        const_reverse_iterator operator--(int) {
            const_reverse_iterator tmp(*this);
            operator--();
            return tmp;
        }

        bool operator==(const const_reverse_iterator &rhs) const { return n == rhs.n; }
        bool operator!=(const const_reverse_iterator &rhs) const { return n != rhs.n; }

        friend class vector;
    };

    // Constructors
    explicit vector(const allocator_type& alloc = allocator_type())
        : _contents(nullptr), _count(0), _capacity(0), _alloc(alloc) { }
    vector(size_type count, const value_type& value, const allocator_type& alloc = allocator_type())
        : _count(count), _capacity(count), _alloc(alloc)
    {
        _contents = _alloc.allocate(count);
        for (int i=0; i < count; i++) {
            _alloc.construct(&_contents[i], value);
        }
    }
    explicit vector(size_type count, const allocator_type& alloc = allocator_type())
        : _count(count), _capacity(count), _alloc(alloc)
    {
        _contents = _alloc.allocate(count);
    }
    template< typename InputIt,
              typename = std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category, std::input_iterator_tag>::value>>
    vector( InputIt first, InputIt last, const allocator_type& alloc = allocator_type() ) : _alloc(alloc)
    {
        _count = std::distance(first, last);
        _capacity = _count;
        _contents = _alloc.allocate(_count);
        pointer p = _contents;
        for (InputIt it = first; it != last; ++it, ++p) {
            _alloc.construct(p, *it);
        }
    }
    vector(const vector& other)
        : _count(other._count), _capacity(other._count), _alloc(other.get_allocator())
    {
        if (_count > 0) {
            _contents = _alloc.allocate(_count);
            for (int i=0; i < _count; i++) {
                _contents[i] = value_type(other._contents[i]);
            }
        }
    }
    vector(const vector& other, const allocator_type & alloc)
        : _count(other._count), _capacity(other._count), _alloc(alloc)
    {
        if (_count > 0) {
            _contents = _alloc.allocate(_count);
            for (int i=0; i < _count; i++) {
                _contents[i] = value_type(other._contents[i]);
            }
        }
    }
    vector(vector&& other)
        : _count(other._count), _capacity(other._count), _alloc(other.get_allocator())
    {
        if (_count > 0) {
            _contents = other._contents;
        }
        other._contents = nullptr;
        other._capacity = 0;
        other._size = 0;
    }
    vector(vector&& other, const allocator_type& alloc)
        : _count(other._count), _capacity(other._capacity), _alloc(alloc)
    {
        if (_alloc == other._alloc) {
            if (_count > 0) {
                _contents = other._contents;
            }
            other._contents = nullptr;
            other._capacity = 0;
            other._size = 0;
        }
        else {
            if (_count > 0) {
                _contents = _alloc.allocate(_count);
                for (int i=0; i < _count; i++) {
                    _contents[i] = value_type(other._contents[i]);
                }
            }
        }
    }
    vector(std::initializer_list<value_type> init, const allocator_type& alloc = allocator_type())
        : _count(init.size()), _capacity(init.size()), _alloc(alloc)
    {
        if (_count > 0) {
            _contents = _alloc.allocate(_count);
            pointer p = _contents;
            for (auto it: init) {
                _alloc.construct(p++, it);
            }
        }
    }
    allocator_type get_allocator() const { return _alloc; }

    // Destructor
    ~vector()
    {
        if (_count > 0) {
            if (!std::is_pointer<value_type>::value) {
                for (size_type i=0; i < _count; i++) {
                    _alloc.destroy(&_contents[i]);
                }
            }
            _alloc.deallocate(_contents, _capacity);
        }
    }

    vector& operator=(const vector& other)
    {
        if (_capacity) {
            if (!std::is_pointer<value_type>::value) {
                for (size_type i=0; i < _count; i++) {
                    _alloc.destroy(&_contents[i]);
                }
            }
        }
        if (_alloc != other._alloc) {
            _alloc.deallocate(_contents, _capacity);
            _alloc = other.get_allocator();
            _contents = _alloc.allocate(other._count);
            _capacity = other._count;
        }
        if (_capacity < other._count) {
            _alloc.deallocate(_contents, _capacity);
            _contents = _alloc.allocate(other._count);
            _capacity = other._count;
        }
        pointer p = _contents;
        for (auto it: other) {
            _alloc.construct(p++, it);
        }
        _count = other._count;
        return *this;
    }
    vector& operator=(vector&& other)
    {
        if (_capacity) {
            if (!std::is_pointer<value_type>::value) {
                for (int i=0; i < _count; i++) {
                    _alloc.destroy(&_contents[i]);
                }
            }
            _alloc.deallocate(_contents, _capacity);
        }
        if (_alloc == other._alloc) {
            _contents = other._contents;
            _capacity = other._capacity;
            _count = other._count;
            other._contents = nullptr;
            other._capacity = 0;
            other._size = 0;
        }
        else {
            _capacity = other._count;
            _count = other._count;
            _contents = _alloc.allocate(_capacity);

            pointer p = _contents;
            for (auto it: other) {
                _alloc.construct(p++, it);
            }
        }
        return *this;
    }
    vector& operator=(std::initializer_list<value_type> ilist)
    {
        if (_capacity) {
            if (!std::is_pointer<value_type>::value) {
                for (int i=0; i < _count; i++) {
                    _alloc.destroy(&_contents[i]);
                }
            }
        }
        if (_capacity < ilist.size()) {
            _alloc.deallocate(_contents, _capacity);
            _capacity = ilist.size();
            _contents = _alloc.allocate(_capacity);
        }
        pointer p = _contents;
        _count = ilist.size();
        for (auto it: ilist) {
            _alloc.construct(p++, it);
        }
        return *this;
    }
    void assign(size_type count, const value_type& value)
    {
        if (_capacity) {
            if (!std::is_pointer<value_type>::value) {
                for (int i=0; i < _count; i++) {
                    _alloc.destroy(&_contents[i]);
                }
            }
        }
        if (_capacity < count) {
            _alloc.deallocate(_contents, _capacity);
            _capacity = count;
            _contents = _alloc.allocate(count);
        }
        for (int i=0; i < count; i++) {
            _alloc.construct(&_contents[i], value);
        }
        _count = count;
    }
    template < class InputIt,
               typename = std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category, std::input_iterator_tag>::value>>
    void assign( InputIt first, InputIt last )
    {
        if (_capacity) {
            if (!std::is_pointer<value_type>::value) {
                for (int i=0; i < _count; i++) {
                    _alloc.destroy(&_contents[i]);
                }
            }
            _alloc.deallocate(_contents, _capacity);
        }
        _count = std::distance(first, last);
        _capacity = _count;
        _contents = _alloc.allocate(_count);
        pointer p = _contents;
        for (InputIt it = first; it != last; ++it, ++p) {
            _alloc.construct(p, *it);
        }
    }
    void assign(std::initializer_list<value_type> ilist)
    {
        if (_capacity) {
            if (!std::is_pointer<value_type>::value) {
                for (int i=0; i < _count; i++) {
                    _alloc.destroy(&_contents[i]);
                }
            }
        }
        if (_capacity < ilist.size()) {
            _alloc.deallocate(_contents, _capacity);
            _contents = _alloc.allocate(ilist.size());
            _capacity = ilist.size();
        }
        pointer p = _contents;
        _count = ilist.size();
        for (auto it: ilist) {
            _alloc.construct(p++, it);
        }
    }

    // Element access
    reference at(size_type pos)
    {
        if (pos >= _count) {
#if NO_EXCEPTIONS
            return *(pointer)nullptr;
#else
            throw std::out_of_range("tinystd::vector::at() out of range");
#endif
        }
        else {
            return _contents[pos];
        }
    }
    const_reference at(size_type pos) const
    {
        if (pos >= _count) {
#if NO_EXCEPTIONS
            return *(pointer)nullptr;
#else
            throw std::out_of_range("tinystd::vector::at() out of range");
#endif
        }
        else {
            return _contents[pos];
        }
    }
    reference operator[](size_type pos) { return _contents[pos]; }
    const_reference operator[](size_type pos) const { return _contents[pos]; }
    reference front() { return _contents[0]; }
    const_reference front() const { return _contents[0]; }
    reference back() { return _contents[_count - 1]; }
    const_reference back() const { return _contents[_count - 1]; }
    const_pointer data() const noexcept { return _contents; }
    pointer data() noexcept { return _contents; }

    // Iterators
    iterator begin() noexcept { if (_count) return iterator(&_contents[0]); else return iterator(nullptr); }
    const_iterator begin() const noexcept { if (_count) return const_iterator(&_contents[0]); else return const_iterator(nullptr); }
    const_iterator cbegin() const noexcept { if (_count) return const_iterator(&_contents[0]); else return const_iterator(nullptr); }
    iterator end() noexcept { if (_count) return iterator(&_contents[_count]); else return iterator(nullptr); }
    const_iterator cend() const noexcept { if (_count) return const_iterator(&_contents[_count]); else return const_iterator(nullptr); }
    const_iterator end() const noexcept { if (_count) return const_iterator(&_contents[_count]); else return const_iterator(nullptr); }
    reverse_iterator rbegin() noexcept { if (_count) return reverse_iterator(&_contents[_count-1]); else return reverse_iterator(nullptr); }
    const_reverse_iterator crbegin() const noexcept { if (_count) return const_reverse_iterator(&_contents[_count-1]); else return const_reverse_iterator(nullptr); }
    const_reverse_iterator rbegin() const noexcept { if (_count) return const_reverse_iterator(&_contents[_count-1]); else return const_reverse_iterator(nullptr); }
    reverse_iterator rend() noexcept { if (_count) return reverse_iterator(&_contents[-1]); else return reverse_iterator(nullptr); }
    const_reverse_iterator crend() const noexcept { if (_count) return const_reverse_iterator(&_contents[-1]); else return const_reverse_iterator(nullptr); }
    const_reverse_iterator rend() const noexcept { if (_count) return const_reverse_iterator(&_contents[-1]); else return const_reverse_iterator(nullptr); }

    // Capacity
    bool empty() { return 0 == _count; }
    size_type size() { return _count; }
    size_type max_size() { return (uintptr_t)-1 / sizeof(value_type); }
    size_type capacity() { return _capacity; }
    void shrink_to_fit() {}
    void reserve(size_type required)
    {
        if (required < 4) {
            required = 4;
        }
        if (required > _capacity) {
#if !NO_EXCEPTIONS
            if (required > max_size()) {
                throw std::length_error("tinystd::vector::reserve() too large!");
            }
#endif
            size_type mask = (~size_type(0)) >> __builtin_clzl(required);
            required = (required + mask) & ~mask;
            pointer new_buffer = _alloc.allocate(required);
            if (new_buffer) {
                if (_contents != nullptr) {
                    memcpy(new_buffer, _contents, _count * sizeof(value_type));
                    _alloc.deallocate(_contents, _capacity);
                }
                _contents = new_buffer;
                _capacity = required;
            }
        }
    }

    // Modifiers
    void clear()
    {
        if (_count) {
            for (int i=0; i < _count; i++) {
                _alloc.destruct(&_contents[i]);
            }
            _count = 0;
        }
    }
    void swap(vector& other)
    {
        size_type tmp1;
        pointer tmp2 = _contents;
        _contents = other._contents;
        other._contents = tmp2;
        tmp1 = _count;
        _count = other._count;
        other._count = tmp1;
        tmp1 = _capacity;
        _capacity = other._capacity;
        other._capacity = tmp1;
    }

    void emplace_back(value_type&& value)
    {
        reserve(_count + 1);
        _contents[_count++] = std::forward<value_type>(value);
    }

    void push_back(value_type&& value)
    {
        emplace_back(std::move(value));
    }

    void push_back(value_type& value)
    {
        reserve(_count + 1);
        _alloc.construct(&_contents[_count++], value);
    }

    void pop_back()
    {
        if (_count > 0) {
            _alloc.destroy(&_contents[--_count]);
        }
    }

    void resize(size_type count)
    {
        if (count < _count) {
            for (size_type i=count; i < _count; i++) {
                _alloc.destroy(&_contents[i]);
            }
        }
        else if (count > _count) {
            reserve(count);
            for (size_type i=_count; i < _count; i++) {
                _alloc.construct(&_contents[i], value_type());
            }
        }

        _count = count;
    }

    void resize(size_type count, const value_type& value)
    {
        if (count < _count) {
            for (size_type i=count; i < _count; i++) {
                _alloc.destroy(&_contents[i]);
            }
        }
        else if (count > _count) {
            reserve(count);
            for (size_type i=_count; i < _count; i++) {
                _alloc.construct(&_contents[i], value_type(value));
            }
        }

        _count = count;
    }

    iterator insert(const_iterator pos, const value_type& value )
    {
        size_type position = pos.n - _contents;

        reserve(_count + 1);
        for(size_type p = _count; p > position; --p) {
            _contents[p] = std::move(_contents[p-1]);
        }
        _alloc.construct(&_contents[position], value_type(value));
        _count++;

        return iterator(&_contents[position]);
    }

    iterator insert(const_iterator pos, value_type&& value )
    {
        size_type position = pos.n - _contents;

        reserve(_count + 1);
        for(size_type p = _count; p > position; --p) {
            _contents[p] = std::move(_contents[p-1]);
        }
        _contents[position] = std::forward<value_type>(value);
        _count++;

        return iterator(&_contents[position]);
    }

    iterator insert( const_iterator pos, size_type count, const T& value )
    {
        if (count > 0) {
            size_type position = pos.n - _contents;

            reserve(_count + count);
            for(size_type p = _count + count - 1; p > position + count - 1; --p) {
                _contents[p] = std::move(_contents[p-count]);
            }
            for (int c=0; c < count; c++) {
                _alloc.construct(&_contents[position + c], value_type(value));
            }
            _count+=count;
            return iterator(&_contents[position]);
        } else {
            return iterator(pos.n);
        }
    }

    template < class InputIt,
               typename = std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category, std::input_iterator_tag>::value>>
    iterator insert(const_iterator pos, InputIt first, InputIt last)
    {
        size_type position = pos.n - _contents;
        size_type count = std::distance(first, last);
        if (count) {
            reserve(_count + count);
            for(size_type p = _count + count - 1; p > position + count - 1; --p) {
                _contents[p] = std::move(_contents[p-count]);
            }
            pointer p = &_contents[position];
            for (InputIt it = first; it != last; ++it, ++p) {
                _alloc.construct(p, *it);
            }
            _count+=count;
            return iterator(&_contents[position]);
        }
        else {
            return iterator(pos.n);
        }
    }

    iterator insert( const_iterator pos, std::initializer_list<T> ilist )
    {
        size_type position = pos.n - _contents;
        if (ilist.size()) {
            size_type count = ilist.size();
            reserve(_count + count);
            for(size_type p = _count + count - 1; p > position + count - 1; --p) {
                _contents[p] = std::move(_contents[p-count]);
            }
            pointer p = &_contents[position];
            for (auto it: ilist) {
                _alloc.construct(p++, it);
            }
            _count+=count;
            return iterator(&_contents[position]);
        } else {
            return iterator(pos.n);
        }
    }

    iterator erase(const_iterator pos)
    {
        if (_count) {
            size_type position = pos - begin();

            _alloc.destroy(&_contents[position]);
            for (size_type p=position; p < _count - 1; p++)
            {
                _contents[p] = std::move(_contents[p + 1]);
            }
            _count--;
            return iterator(&_contents[position]);
        }
        else {
            return iterator(nullptr);
        }
    }

    iterator erase(const_iterator first, const_iterator last)
    {
        if (first == last) {
            return iterator(first.n);
        }

        size_type position = first.n - _contents;
        size_type count = last - first;

        for (size_type p=position; p < count; p++) {
            _alloc.destroy(&_contents[p]);
        }

        if (last < end()) {
            size_type items_to_move = end() - last;
            for (size_type p = position; p < _count - 1; p++) {
                _contents[p] = std::move(_contents[p + count]);
            }
        }

        _count -= count;

        return iterator(&_contents[position]);
    }

//emplace is missing

private:
    pointer         _contents;
    size_type       _count;
    size_type       _capacity;
    allocator_type  _alloc;
};


template< class T, class Alloc >
bool operator==( const tinystd::vector<T,Alloc>& lhs,
                 const tinystd::vector<T,Alloc>& rhs )
{
    if (lhs.size() != rhs.size()) {
        return false;
    }

    for (int i=0; i < lhs.size(); i++) {
        if (lhs[i] != rhs[i]) {
            return false;
        }
    }

    return true;
}

template< class T, class Alloc >
bool operator!=( const tinystd::vector<T,Alloc>& lhs,
                 const tinystd::vector<T,Alloc>& rhs )
{
    if (lhs.size() != rhs.size()) {
        return true;
    }

    for (int i=0; i < lhs.size(); i++) {
        if (lhs[i] != rhs[i]) {
            return true;
        }
    }

    return false;
}

}

#endif // _TINYSTD_VECTOR
