Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
3
 * It is copyright by its individual contributors, as recorded in the
4
 * project's Git history.  See COPYING.txt at the top level for license
5
 * terms and a link to the Git history.
6
 */
7
#pragma once
8
 
9
#include <algorithm>
10
#include <cstddef>
11
#include <memory>
12
#include <stdexcept>
13
#include "dxxsconf.h"
14
#include <array>
15
 
16
template <typename T = unsigned>
17
class base_count_array_t
18
{
19
protected:
20
        typedef T size_type;
21
        void clear() { m_count = 0; }
22
        size_type m_count = 0;
23
public:
24
        size_type size() const { return m_count; }
25
        bool empty() const { return !m_count; }
26
};
27
 
28
template <typename T, std::size_t S>
29
class count_array_t : public base_count_array_t<>
30
{
31
public:
32
        using array_type = std::array<T, S>;
33
        typedef typename array_type::value_type value_type;
34
        typedef typename array_type::iterator iterator;
35
        typedef typename array_type::const_iterator const_iterator;
36
        typedef typename array_type::const_reference const_reference;
37
        static typename array_type::size_type max_size() { return S; }
38
        ~count_array_t() { clear(); }
39
        count_array_t &operator=(const count_array_t &rhs)
40
        {
41
                if (this != &rhs)
42
                {
43
                        iterator lb = begin();
44
                        iterator le = end();
45
                        const_iterator rb = rhs.begin();
46
                        const_iterator re = rhs.end();
47
                        for (; lb != le && rb != re; ++lb, ++rb)
48
                                *lb = *rb;
49
                        shrink(lb);
50
                        for (; rb != re; ++rb)
51
                                emplace_back(*rb);
52
                }
53
                return *this;
54
        }
55
        template <typename... Args>
56
        void emplace_back(Args&&... args)
57
        {
58
                if (m_count >= S)
59
                        throw std::length_error("too many elements");
60
                T *uninitialized = static_cast<T *>(&arrayref()[m_count]);
61
                new(static_cast<void *>(uninitialized)) T(std::forward<Args>(args)...);
62
                ++ m_count;
63
        }
64
        void clear()
65
        {
66
                shrink(begin());
67
        }
68
        // for std::back_insert_iterator
69
        void push_back(const T& t)
70
        {
71
                emplace_back(t);
72
        }
73
        void pop_back()
74
        {
75
                shrink(end() - 1);
76
        }
77
        iterator begin() { return arrayref().begin(); }
78
        iterator end() { return arrayref().begin() + m_count; }
79
        iterator find(const T &t) { return std::find(begin(), end(), t); }
80
        const_iterator find(const T &t) const { return std::find(begin(), end(), t); }
81
        const_reference operator[](size_type i) const
82
        {
83
                if (i >= m_count)
84
                        throw std::out_of_range("not enough elements");
85
                return arrayref()[i];
86
        }
87
        const_reference back() const { return (*this)[m_count - 1]; }
88
        bool contains(const T &t) const { return find(t) != end(); }
89
        void erase(iterator i)
90
        {
91
                shrink(i);
92
        }
93
        void erase(const T &t)
94
        {
95
                shrink(std::remove(begin(), end(), t));
96
        }
97
        template <typename F>
98
                void erase_if(F f)
99
                {
100
                        shrink(std::remove_if(begin(), end(), f));
101
                }
102
        void replace(const T &o, const T &n)
103
        {
104
                std::replace(begin(), end(), o, n);
105
        }
106
        const_iterator begin() const { return arrayref().begin(); }
107
        const_iterator end() const { return arrayref().begin() + m_count; }
108
private:
109
        void destroy(iterator b, iterator e)
110
        {
111
                for (; b != e; ++b)
112
                        b->~T();
113
        }
114
        void shrink(iterator b)
115
        {
116
                destroy(b, end());
117
                m_count = std::distance(begin(), b);
118
        }
119
private:
120
        union U {
121
                array_type m_data;
122
                U() {}
123
        } u;
124
        array_type &arrayref() { return u.m_data; }
125
        const array_type &arrayref() const { return u.m_data; }
126
};