HOME

Sample

#include "stdafx.h"
#include <iostream>
#include "polymorphic_list.h"
#include <cassert>

using namespace std;

struct Box
{
    int i;
    Box(int x) : i(x)
    {
    }

    void Draw()
    {
        cout << "I am Box class" << endl;
    }
};

struct Circle
{
    int radius;
    Circle(int r) : radius(r)
    {
    }

    void Draw()
    {
        cout << "I am Circle class" << endl;
    }
};



void Sample1()
{
    polymorphic_list list;
    
    emplace_back<Box>(list, 2);
    emplace_back<Circle>(list, 1);
    
    //Option 1
    for (auto& item : list)
    {
        switch (is_index<Box, Circle>(item))
        {
        case 1:
            ref<Box>(item).Draw();
            break;
        case 2:
            ref<Circle>(item).Draw();
            break;
        default:
            assert(false);
        }
    }

    //Option 2
    for (auto& item : list)
    {
        if (auto p = is_ptr<Box>(item))
        {
            p->Draw();
        }
        else if (auto p = is_ptr<Circle>(item))
        {
            p->Draw();
        }
        else
        {
            assert(false);
        }
    }
}

int main()
{
    Sample1();
    return 0;
}

Code

#pragma once
#include <algorithm>
#include <cassert>
#include <memory>

template<class T>
static size_t type_id()
{
    static size_t id = sizeof(T);
    return (size_t) &id;
}

class type_pointer
{
    size_t m_id = 0;
    void * m_pObject = nullptr;
    const type_info * m_ti;
protected:

    template<class T>
    void set_pointer(T* p)
    {
        m_ti = &typeid(T);
        m_pObject = p;
        m_id = type_id<T>();
    }

public:

    friend size_t id(const type_pointer& tp)
    {
        return tp.m_id;
    }

    friend void* ptr(const type_pointer& tp)
    {
        return tp.m_pObject;
    }
};

template<class T>
T* ptr(const type_pointer& tp)
{
    assert(is<T>(tp));
    return (T*) ptr(tp);
}

template<class T>
T& ref(const type_pointer& tp)
{
    assert(is<T>(tp));
    return *((T*) ptr(tp));
}

template<class T>
T* is_ptr(const type_pointer& tp)
{
    return is<T>(tp) ? ptr<T>(tp) : nullptr;
}

template<class T>
bool is(const type_pointer& tp)
{
    return id(tp) == type_id<T>();
}

template<int N>
int is_index_imp(const type_pointer&)
{
    return -1;
}

template<int N, class T1, typename... TN>
int is_index_imp(const type_pointer& tp)
{
    if (is<T1>(tp))
    {
        return N;
    }

    return is_index_imp<N + 1, TN...>(tp);
}

template<typename... TN>
int is_index(const type_pointer& tp)
{
    return is_index_imp<1, TN...>(tp);
}

struct polymorphic_list_node_base : public type_pointer
{
    polymorphic_list_node_base* m_next;
    polymorphic_list_node_base* m_prev;
    polymorphic_list_node_base(polymorphic_list_node_base* p,
        polymorphic_list_node_base* n)
        : m_next(n)
        , m_prev(p)
    {
    }

    friend polymorphic_list_node_base* next(polymorphic_list_node_base& node)
    {
        return node.m_next;
    }

    friend polymorphic_list_node_base* prev(polymorphic_list_node_base& node)
    {
        return node.m_prev;
    }
};

template<class T>
struct polymorphic_list_node : public polymorphic_list_node_base
{
    T m_data;
    template<class... Args>
    polymorphic_list_node(polymorphic_list_node_base* p,
        polymorphic_list_node_base* n,
        Args&&... args)
        : polymorphic_list_node_base(p, n)
        , m_data(args...)

    {
        set_pointer<T>(&m_data);
    }
};

struct polymorphic_list_iterator
{
    typedef polymorphic_list_iterator iterator;
    typedef polymorphic_list_iterator const_iterator;
    typedef type_pointer              value_type;
    typedef value_type*               pointer;
    typedef value_type&               reference;
    typedef size_t                    size_type;
    typedef ptrdiff_t                 difference_type;

    polymorphic_list_node_base* m_pNode;

    polymorphic_list_iterator(polymorphic_list_node_base* x) : m_pNode(x)
    {
    }

    polymorphic_list_iterator(const iterator& x)
        : m_pNode(x.m_pNode)
    {
    }

    polymorphic_list_iterator()
    {
    }

    void Increment()
    {
        m_pNode = next(*m_pNode);
    }

    void Decrement()
    {
        m_pNode = prev(*m_pNode);
    }

    bool operator==(const polymorphic_list_iterator& x) const
    {
        return m_pNode == x.m_pNode;
    }

    bool operator!=(const polymorphic_list_iterator& x) const
    {
        return m_pNode != x.m_pNode;
    }

    reference operator*() const
    {
        return *(m_pNode);
    }

    pointer operator->() const
    {
        return &(operator*());
    }

    polymorphic_list_iterator& operator++()
    {
        this->Increment();
        return *this;
    }

    polymorphic_list_iterator operator++(int)
    {
        auto tmp = *this;
        this->Increment();
        return tmp;
    }

    polymorphic_list_iterator& operator--()
    {
        this->Decrement();
        return *this;
    }

    polymorphic_list_iterator operator--(int)
    {
        auto tmp = *this;
        this->Decrement();
        return tmp;
    }
};

class polymorphic_list
{
public:
    typedef type_pointer              value_type;
    typedef value_type*               pointer;
    typedef const value_type*         const_pointer;
    typedef value_type&               reference;
    typedef const value_type&         const_reference;
    typedef size_t                    size_type;
    typedef ptrdiff_t                 difference_type;
    typedef polymorphic_list_iterator iterator;
    typedef polymorphic_list_iterator const_iterator;

    explicit polymorphic_list()
    {
        m_pNode = new polymorphic_list_node<Empty>(nullptr, nullptr);
        m_pNode->m_next = m_pNode;
        m_pNode->m_prev = m_pNode;
    }

    ~polymorphic_list()
    {
        clear();
    }

private:
    polymorphic_list_node_base* m_pNode;

    struct Empty
    {
    };

    iterator insert_node(iterator position, polymorphic_list_node_base* tmp)
    {
        tmp->m_next = position.m_pNode;
        tmp->m_prev = prev(*position.m_pNode);
        position.m_pNode->m_prev->m_next = tmp;
        position.m_pNode->m_prev = tmp;
        return tmp;
    }

    std::unique_ptr<polymorphic_list_node_base> remove(iterator position)
    {
        auto* next_node = next(*position.m_pNode);
        auto* prev_node = prev(*position.m_pNode);
        auto* n = position.m_pNode;
        prev_node->m_next = next_node;
        next_node->m_prev = prev_node;

        n->m_next = nullptr;
        n->m_prev = nullptr;
        return std::unique_ptr<polymorphic_list_node_base>(n);
    }

    polymorphic_list& operator=(const polymorphic_list& x) = delete;
    polymorphic_list(polymorphic_list&) = delete;

    void clear()
    {
        auto* cur = next(*m_pNode);
        while (cur != m_pNode)
        {
            auto* tmp = cur;
            cur = next(*cur);
            delete tmp;
        }
        m_pNode->m_next = m_pNode;
        m_pNode->m_prev = m_pNode;
    }

    friend iterator begin(polymorphic_list& lst)
    {
        return next(*lst.m_pNode);
    }

    friend const_iterator cbegin(const polymorphic_list& lst)
    {
        return next(*lst.m_pNode);
    }

    friend iterator end(polymorphic_list& lst)
    {
        return lst.m_pNode;
    }

    friend const_iterator cend(const polymorphic_list& lst)
    {
        return lst.m_pNode;
    }

    friend bool empty(const polymorphic_list& lst)
    {
        return next(*lst.m_pNode) == lst.m_pNode;
    }

    friend void swap(polymorphic_list& a, polymorphic_list& b)
    {
        std::swap(a.m_pNode, b.m_pNode);
    }

    template<class T, class... Args>
    friend iterator emplace_insert(polymorphic_list& list, iterator position, Args&&... args)
    {
        auto* tmp = new polymorphic_list_node<T>(nullptr,
            nullptr,
            std::forward<Args>(args)...);
        return list.insert_node(position, tmp);
    }

    friend void move_to(polymorphic_list& from, iterator position, polymorphic_list& into)
    {
        auto sp = from.remove(position);
        into.insert_node(end(into), sp.release());
    }

    friend polymorphic_list::iterator erase(polymorphic_list& list, polymorphic_list::iterator position)
    {
        auto* next_node = next(*position.m_pNode);
        auto* prev_node = prev(*position.m_pNode);
        auto* n = position.m_pNode;
        prev_node->m_next = next_node;
        next_node->m_prev = prev_node;
        delete n;
        return iterator(next_node);
    }

    friend void clear(polymorphic_list& list)
    {
        list.clear();
    }
};

template<class T, class... Args>
void emplace_back(polymorphic_list& list, Args&&... args)
{
    emplace_insert<T>(list, end(list), std::forward<Args>(args)...);
}

inline polymorphic_list::iterator erase(polymorphic_list& list,
    polymorphic_list::iterator first,
    polymorphic_list::iterator last)
{
    while (first != last)
        erase(list, first++);
    return last;
}

inline polymorphic_list::reference front(polymorphic_list& lst)
{
    return *begin(lst);
}

inline polymorphic_list::const_reference  cfront(const polymorphic_list& lst)
{
    return *cbegin(lst);
}

inline void pop_front(polymorphic_list& list)
{
    erase(list, begin(list));
}

inline void pop_back(polymorphic_list& list)
{
    auto tmp = end(list);
    erase(list, --tmp);
}

inline polymorphic_list::reference back(polymorphic_list& lst)
{
    return *(--end(lst));
}

inline polymorphic_list::const_reference cback(const polymorphic_list& lst)
{
    return *(--cend(lst));
}