فهرست منبع

Initial commit

Ivan Arkhipov 6 سال پیش
کامیت
31391a9ab5
3فایلهای تغییر یافته به همراه562 افزوده شده و 0 حذف شده
  1. 99 0
      StackAllocator.h
  2. 382 0
      XorList.h
  3. 81 0
      main.cpp

+ 99 - 0
StackAllocator.h

@@ -0,0 +1,99 @@
+//
+// Created by Ivan Arkhipov on 29.04.2018.
+//
+
+#ifndef XOR_LIST_STACKALLOCATOR_H
+#define XOR_LIST_STACKALLOCATOR_H
+
+#include <c++/cstddef>
+#include <c++/new>
+#include <memory.h>
+
+template<typename T, int elements_in_block = 100>
+class StackAllocator {
+
+public:
+    typedef size_t size_type;
+    typedef ptrdiff_t difference_type;
+    typedef T *pointer;
+    typedef const T *const_pointer;
+    typedef T &reference;
+    typedef const T &const_reference;
+    typedef T value_type;
+
+    template<typename T1>
+    struct rebind {
+        typedef StackAllocator<T1> other;
+    };
+
+    StackAllocator() : last_block_(nullptr) {}
+
+    StackAllocator(const StackAllocator &other) : last_block_(nullptr) {};
+
+    StackAllocator(StackAllocator &&other) noexcept : last_block_(nullptr) {
+        other.last_block_ = nullptr;
+    }
+
+    ~StackAllocator() {
+        for (Block *block = last_block_; block != nullptr;) {
+            Block *prev_block = block->prev_block_;
+            delete block;
+            block = prev_block;
+        }
+    }
+
+    pointer allocate(size_type n, const void * = nullptr) {
+        if (n > elements_in_block) {
+            throw std::bad_alloc();
+        }
+
+        if (!last_block_ || last_block_->end_ + n >= last_block_->block_end_) {
+            last_block_ = new Block(last_block_);
+        }
+        pointer result = last_block_->end_;
+        last_block_->end_ += n;
+        return result;
+    }
+
+    void deallocate(pointer p, size_type n) {
+        // does nothing
+    }
+
+    template<class U, class... Args>
+    void construct(U *p, Args &&... args) {
+        ::new((void *) p) U(std::forward<Args>(args)...);
+    };
+
+    template<class U>
+    void destroy(U *p) {
+        p->~U();
+    }
+
+private:
+    struct Block {
+    private:
+        Block() {}
+
+    public:
+        explicit Block(Block *prev_block = nullptr) {
+            begin_ = reinterpret_cast<pointer>(::operator new(sizeof(value_type) * elements_in_block));
+            end_ = begin_;
+            block_end_ = begin_ + elements_in_block;
+            prev_block_ = prev_block;
+        }
+
+        ~Block() {
+            delete[] begin_;
+        }
+
+        pointer begin_;
+        pointer end_;
+        pointer block_end_;
+
+        Block *prev_block_;
+    };
+
+    Block *last_block_;
+};
+
+#endif //XOR_LIST_STACKALLOCATOR_H

+ 382 - 0
XorList.h

@@ -0,0 +1,382 @@
+//
+// Created by kikab on 06.05.2018.
+//
+
+#ifndef XOR_LIST_XORLIST_H
+#define XOR_LIST_XORLIST_H
+
+#include <forward_list>
+#include <bits/allocator.h>
+#include <ext/alloc_traits.h>
+#include <vector>
+#include <list>
+#include <memory>
+#include <utility>
+
+template<typename T>
+struct XorListNode {
+public:
+    XorListNode() = delete;
+
+    XorListNode(const T &val) {
+        val_ = val;
+    }
+
+    XorListNode(const T &&val) {
+        val_ = std::forward<XorListNode<T> >(val);
+    }
+
+    XorListNode *right(const XorListNode *left) const {
+        return reinterpret_cast<XorListNode *>(xor_ptr_ ^ reinterpret_cast<uintptr_t>(left));
+    }
+
+    XorListNode *left(const XorListNode *right) const {
+        return reinterpret_cast<XorListNode *>(xor_ptr_ ^ reinterpret_cast<uintptr_t>(right));
+    }
+
+    void assign_leftright(const XorListNode *left, const XorListNode *right) {
+        xor_ptr_ = (reinterpret_cast<uintptr_t>(left) ^ reinterpret_cast<uintptr_t>(right));
+    }
+
+    T val_;
+private:
+    uintptr_t xor_ptr_;
+};
+
+template<typename T>
+struct FwdXorListIterator {
+    typedef FwdXorListIterator<T> Self;
+    typedef XorListNode<T> Node;
+
+    typedef ptrdiff_t difference_type;
+    typedef std::bidirectional_iterator_tag iterator_category;
+    typedef T value_type;
+    typedef T *pointer;
+    typedef T &reference;
+
+
+    FwdXorListIterator() = delete;
+
+    FwdXorListIterator(Node *x, Node *prev) : node_(x), left_(prev) {}
+
+    // Must downcast from _List_node_base to _List_node to get to value.
+    reference operator*() const {
+        return node_->val_;
+    }
+
+    pointer operator->() const {
+        return &node_->val_;
+    }
+
+    Self &operator++() {
+        Node *future_left_ = node_;
+        node_ = node_->right(left_);
+        left_ = future_left_;
+        return *this;
+    }
+
+    Self operator++(int) {
+        Self __tmp = *this;
+        Node *future_left_ = node_;
+        node_ = node_->right(left_);
+        left_ = future_left_;
+        return __tmp;
+    }
+
+    Self &operator--() {
+        Node *future_right = node_;
+        node_ = node_->left(node_->right(left_));
+        left_ = node_->left(future_right);
+        return *this;
+    }
+
+    Self operator--(int) {
+        Self __tmp = *this;
+        Node *future_right = node_;
+        node_ = node_->left(node_->right(left_));
+        left_ = node_->left(future_right);
+        return __tmp;
+    }
+
+    bool operator==(const Self &x) const {
+        return left_ == x.left_;
+    }
+
+    bool operator!=(const Self &x) const {
+        return left_ != x.left_;
+    }
+
+    Node *node_;
+    Node *left_;
+};
+
+
+template<typename T, typename Allocator = std::allocator<T> >
+class XorList {
+
+private:
+    typedef typename Allocator::template rebind<XorListNode<T>>::other allocator_type;
+    typedef __gnu_cxx::__alloc_traits<allocator_type> Allocator_traits;
+
+public:
+    // types:
+    typedef T value_type;
+    typedef typename Allocator_traits::pointer pointer;
+    typedef typename Allocator_traits::const_pointer const_pointer;
+    typedef value_type& reference;
+    typedef const value_type& const_reference;
+
+    typedef FwdXorListIterator<T> iterator;
+    typedef std::reverse_iterator<iterator> reverse_iterator;
+    typedef std::size_t size_type;
+    typedef std::ptrdiff_t difference_type;
+    //typedef Allocator                                  allocator_type;
+
+    explicit XorList(const Allocator &alloc = Allocator())
+            : front_(nullptr), back_(nullptr), size_(0), allocator_(allocator_type()) {}
+
+    XorList(size_type count, const_reference value = T(), const Allocator &alloc = Allocator())
+            : front_(nullptr), back_(nullptr), size_(0), allocator_(allocator_type()) {
+        for (size_type i = 0; i < count; i++)
+            push_back(value);
+    }
+
+    XorList(const XorList &other) {
+        *this = other;
+    }
+
+    XorList(const XorList &&other) noexcept {
+        *this = other;
+    }
+
+    ~XorList() {
+        XorListNode<T> *xleft = nullptr;
+        XorListNode<T> *x = front_;
+        while (x != back_) {
+            XorListNode<T> *xnext = x->right(xleft);
+            if (xnext) {
+                allocator_.destroy(xleft);
+                allocator_.deallocate(xleft, 1);
+            }
+            xleft = x;
+            x = xnext;
+        }
+
+        if (xleft) {
+            allocator_.destroy(xleft);
+            allocator_.deallocate(xleft, 1);
+        }
+        if (x) {
+            allocator_.destroy(x);
+            allocator_.deallocate(x, 1);
+        }
+    }
+
+    XorList &operator=(const XorList &other) {
+        if (this == &other)
+            return *this;
+
+        this->~XorList();
+        this->front_ = other.front_;
+        this->back_ = other.back_;
+        this->size_ = other.size_;
+        this->allocator_ = other.allocator_;
+    }
+
+    XorList &operator=(const XorList &&other) noexcept {
+        if (this == &other)
+            return *this;
+
+        this->~XorList();
+        this->front_ = other.front_;
+        this->back_ = other.back_;
+        this->size_ = other.size_;
+        this->allocator_ = other.allocator_;
+    }
+
+    value_type front() {
+        return front_->val_;
+    }
+
+    value_type back() {
+        return back_->val_;
+    }
+
+    iterator begin() {
+        return iterator(front_, nullptr);
+    }
+
+    iterator end() {
+        if (!back_)
+            return iterator(nullptr, nullptr);
+        return ++iterator(back_, back_->left(nullptr));
+    }
+
+    reverse_iterator rbegin() {
+        return reverse_iterator(front_, nullptr);
+    }
+
+    reverse_iterator rend() {
+        return ++reverse_iterator(back_, back_->left(nullptr));
+    }
+
+    size_type size() {
+        return size_;
+    }
+
+    void push_back(const value_type &val) {
+        XorListNode<T> *past_back = back_;
+        back_ = reinterpret_cast<XorListNode<T> *>(allocator_.allocate(1));
+        allocator_.construct(back_, std::forward<XorListNode<T> >(val));
+        back_->assign_leftright(past_back, nullptr);
+        if (past_back)
+            past_back->assign_leftright(past_back->left(nullptr), back_);
+        if (!front_)
+            front_ = back_;
+        size_++;
+    }
+
+    void push_back(const value_type &&val) {
+        XorListNode<value_type> *past_back = back_;
+        back_ = reinterpret_cast<XorListNode<T> *>(allocator_.allocate(1));
+        allocator_.construct(back_, XorListNode<T>(std::forward<XorListNode<T> >(val)));
+        back_->assign_leftright(past_back, nullptr);
+        if (past_back)
+            past_back->assign_leftright(past_back->left(nullptr), back_);
+        if (!front_)
+            front_ = back_;
+        size_++;
+    }
+
+    void push_front(const value_type &val) {
+        XorListNode<value_type> *past_front = front_;
+        front_ = reinterpret_cast<XorListNode<T> *>(allocator_.allocate(1));
+        allocator_.construct(front_, std::forward<XorListNode<T> >(val));
+        front_->assign_leftright(nullptr, past_front);
+        if (past_front)
+            past_front->assign_leftright(front_, past_front->right(nullptr));
+        if (!back_)
+            back_ = front_;
+        size_++;
+    }
+
+    void push_front(const value_type &&val) {
+        XorListNode<value_type> *past_front = front_;
+        front_ = reinterpret_cast<XorListNode<T> *>(allocator_.allocate(1));
+        allocator_.construct(front_, std::forward<XorListNode<T> >(val));
+        front_->assign_leftright(nullptr, past_front);
+        if (past_front)
+            past_front->assign_leftright(front_,  past_front->right(nullptr));
+        if (!back_)
+            back_ = front_;
+        size_++;
+    }
+
+    void pop_back() {
+        XorListNode<T> *past_back = back_;
+        back_ = back_->left(nullptr);
+        back_->assign_leftright(back_->left(past_back), nullptr);
+        allocator_.destroy(past_back);
+        allocator_.deallocate(past_back, 1);
+    }
+
+    void pop_front() {
+        XorListNode<T> *past_front = front_;
+        front_ = front_->right(nullptr);
+        front_->assign_leftright(nullptr, front_->right(past_front));
+        allocator_.destroy(past_front);
+        allocator_.deallocate(past_front, 1);
+    }
+
+    void insert_before(iterator it, T &val) {
+        XorListNode<T> *cur = *it;
+        XorListNode<T> *prev = it.left_;
+        XorListNode<T> *past = it.node_->right(prev);
+
+        XorListNode<T> *new_node = reinterpret_cast<XorListNode<T> *>(allocator_.allocate(1));
+        allocator_.construct(new_node, std::forward<XorListNode<T> >(val));
+        new_node->assign_leftright(prev, cur);
+
+        if (cur)
+            cur->assign_leftright(new_node, past);
+
+        if (prev)
+            prev->assign_leftright(prev->left(cur), new_node);
+    }
+
+    void insert_before(iterator it, T &&val) {
+        XorListNode<T> *cur = *it;
+        XorListNode<T> *prev = it.left_;
+        XorListNode<T> *past = it.node_->right(prev);
+
+        XorListNode<T> *new_node = allocator_.allocate(1);
+        allocator_.construct(new_node, std::forward<XorListNode<T> >(val));
+        new_node->assign_leftright(prev, cur);
+
+        if (cur)
+            cur->assign_leftright(new_node, past);
+
+        if (prev)
+            prev->assign_leftright(prev->left(cur), new_node);
+    }
+
+    void insert_after(iterator it, T &val) {
+        XorListNode<T> *cur = *it;
+        XorListNode<T> *prev = it.left_;
+        XorListNode<T> *past = it.node_->right(prev);
+
+        XorListNode<T> *new_node = allocator_.allocate(1);
+        allocator_.construct(new_node, std::forward<XorListNode<T> >(val));
+        new_node->assign_leftright(cur, past);
+
+        if (cur)
+            cur->assign_leftright(prev, new_node);
+
+        if (past)
+            past->assign_leftright(new_node, past->right(cur));
+    }
+
+    void insert_after(iterator it, T &&val) {
+        XorListNode<T> *cur = *it;
+        XorListNode<T> *prev = it.left_;
+        XorListNode<T> *past = it.node_->right(prev);
+
+        XorListNode<T> *new_node = allocator_.allocate(1);
+        allocator_.construct(new_node, std::forward<XorListNode<T> >(val));
+        new_node->assign_leftright(cur, past);
+
+        if (cur)
+            cur->assign_leftright(prev, new_node);
+
+        if (past)
+            past->assign_leftright(new_node, past->right(cur));
+    }
+
+    void erase(iterator it) {
+        XorListNode<T> *prev = it.left_;
+        XorListNode<T> *cur = it.operator->();
+        XorListNode<T> *past = it.node_->right(prev);
+
+        if (prev)
+            prev->assign_leftright(prev->left(cur), past);
+
+        if (past)
+            past->assign_leftright(prev, past->right(cur));
+
+        if (cur)
+            size_--;
+
+        allocator_.destroy(cur);
+        allocator_.deallocate(cur, 1);
+    }
+
+private:
+    XorListNode<T> *front_;
+    XorListNode<T> *back_; // Pointer to the LAST element
+
+    size_type size_;
+    allocator_type allocator_;
+
+};
+
+#endif //XOR_LIST_XORLIST_H

+ 81 - 0
main.cpp

@@ -0,0 +1,81 @@
+#include <iostream>
+#include <list>
+#include <memory>
+
+#include <ctime>
+#include <random>
+#include <cassert>
+
+#include "StackAllocator.h"
+#include "XorList.h"
+
+const int NUM_CONTENT = 10000000;
+int random_nums[NUM_CONTENT * 2];
+
+int main() {
+    std::random_device rd;
+    std::mt19937 mt(rd());
+    std::uniform_int_distribution<int> random_gen(-128256512, 128256512);
+
+    for (int i = 0; i < NUM_CONTENT * 2; i++) {
+        random_nums[i] = random_gen(mt);
+    }
+
+//    for (const auto &i : random_nums)
+//        std::cout << i << " ";
+//    std::cout << "\n\n";
+
+    {
+        std::list<int> b;
+        std::clock_t start_std_allocator = std::clock();
+        for (int i = 0; i < NUM_CONTENT * 2; i += 2) {
+            b.push_front(random_nums[i]);
+            if (b.front() != random_nums[i]) {
+                std::cout << "AAAAAAAAAAAAAAAA: front is  " << b.front() << ", expected: " << random_nums[i]
+                          << std::endl;
+            }
+
+            b.push_back(random_nums[i + 1]);
+            if (b.back() != random_nums[i + 1]) {
+                std::cout << "BBBBBBBBBBBBBBBB: back is  " << b.back() << ", expected: " << random_nums[i + 1]
+                          << std::endl;
+            }
+        }
+        std::clock_t end_std_allocator = std::clock();
+        std::cout << "Time for std::list with std::allocator is "
+                  << (end_std_allocator - start_std_allocator) / (double) (CLOCKS_PER_SEC / 1000) << "ms" << std::endl;
+//
+//        std::cout << "=============DATA BEGIN===========\n";
+//        for (auto k = b.begin(); k != b.end(); ++k)
+//            std::cout << *k << " ";
+//        std::cout << "\n==============DATA END============\n\n";
+    }
+
+    {
+        XorList<int, StackAllocator<int>> a;
+        std::clock_t start_stack_allocator = std::clock();
+        for (int i = 0; i < NUM_CONTENT * 2; i += 2) {
+            a.push_front(random_nums[i]);
+            if (a.front() != random_nums[i]) {
+                std::cout << "AAAAAAAAAAAAAAAA: front is  " << a.front() << ", expected: " << random_nums[i]
+                          << std::endl;
+            }
+
+            a.push_back(random_nums[i + 1]);
+            if (a.back() != random_nums[i + 1]) {
+                std::cout << "BBBBBBBBBBBBBBBB: back is  " << a.back() << ", expected: " << random_nums[i + 1]
+                          << std::endl;
+            }
+        }
+        std::clock_t end_stack_allocator = std::clock();
+        std::cout << "Time for XorList with StackAllocator is "
+                  << (end_stack_allocator - start_stack_allocator) / (double) (CLOCKS_PER_SEC / 1000) << "ms"
+                  << std::endl;
+//
+//        std::cout << "=============DATA BEGIN===========\n";
+//        for (auto k = a.begin(); k != a.end(); ++k)
+//            std::cout << *k << " ";
+//        std::cout << "\n==============DATA END============\n\n";
+    }
+    return 0;
+}