summaryrefslogtreecommitdiff
path: root/include/o3tl/enumarray.hxx
blob: 4fd5cab3155f0272705ba4454570495894c13803 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * 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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_O3TL_ENUMARRAY_HXX
#define INCLUDED_O3TL_ENUMARRAY_HXX

#include <iterator>
#include <type_traits>
#include <utility>
#include <array>
#include <cassert>

namespace o3tl {

template<typename EA>
class enumarray_iterator;
template<typename EA>
class enumarray_const_iterator;

///
/// This is a container convenience class for arrays indexed by enum values.
///
/// This assumes that the 'enum class' definition
///  - starts at zero
///  - has no holes in its sequence of values
///  - defines a value called LAST which refers to the greatest constant.
///
/// \param E the 'enum class' type.
/// \param V the value type to be stored in the array
template<typename E, typename V>
class enumarray final
{
public:
    typedef enumarray<E, V> self_type;
    typedef enumarray_iterator<self_type> iterator;
    typedef enumarray_const_iterator<self_type> const_iterator;

    typedef V             value_type;
    typedef E             key_type;
    typedef size_t        size_type;

    static const size_type max_index = static_cast<size_type>(E::LAST);

    // If this ctor only had the args parameter pack, it would erroneously get picked as a better
    // choice than the (implicit) copy ctor (taking a const lvalue reference) when a copy is made
    // from a non-const lvalue enumarray; the easiest way to avoid that is the additional arg
    // parameter; and to keep things simple that parameter is always passed by const lvalue
    // reference for now even if there could be cases where passing it by rvalue reference might be
    // beneficial or even necessary if V is a move-only type:
    template<typename... T> constexpr enumarray(V const & arg, T && ...args):
        detail_values{arg, std::forward<T>(args)...}
    {
        static_assert(sizeof... (T) == max_index);
    }

    // coverity[uninit_ctor] - by design:
    enumarray() {}

    const V& operator[](E index) const
    {
        assert(index>=static_cast<E>(0) && index<=E::LAST);
        return detail_values[static_cast<size_type>(index)];
    }

    V& operator[](E index)
    {
        assert(index>=static_cast<E>(0) && index<=E::LAST);
        return detail_values[static_cast<size_type>(index)];
    }

    void fill(V val)
    { for (size_type i=0; i<=max_index; ++i) detail_values[i] = val; }

    static size_type size()        { return max_index + 1; }
    iterator         begin()       { return iterator(*this, 0); }
    iterator         end()         { return iterator(*this, size()); }
    const_iterator   begin() const { return const_iterator(*this, 0); }
    const_iterator   end() const   { return const_iterator(*this, size()); }

    V*               data()       { return detail_values.data(); }

private:
    std::array<V, max_index + 1> detail_values;
};


template<typename EA>
class enumarray_iterator {
    EA*         m_buf;
    size_t      m_pos;
public:
    typedef enumarray_iterator<EA>  self_type;
    typedef typename EA::value_type value_type;
    typedef typename EA::key_type   key_type;
    typedef std::bidirectional_iterator_tag iterator_category; //should be random access, but that would require define subtraction operators on the enums
    typedef
        typename std::make_signed<
            typename std::underlying_type<typename EA::key_type>::type>::type
        difference_type;
    typedef typename EA::value_type*   pointer;
    typedef typename EA::value_type&   reference;

    enumarray_iterator(EA& b, size_t start_pos)
         : m_buf(&b), m_pos(start_pos) {}
    value_type& operator*()  const { return (*m_buf)[static_cast<key_type>(m_pos)]; }
    value_type* operator->() const { return &(operator*()); }
    self_type&  operator++() { ++m_pos; return *this; }
    bool        operator!=(self_type const & other) const { return m_buf != other.m_buf || m_pos != other.m_pos; }
    bool        operator==(self_type const & other) const { return m_buf == other.m_buf && m_pos == other.m_pos; }
};

template<typename EA>
class enumarray_const_iterator {
    EA const *  m_buf;
    size_t      m_pos;
public:
    typedef enumarray_const_iterator<EA>    self_type;
    typedef typename EA::value_type const   value_type;
    typedef typename EA::key_type           key_type;
    typedef std::bidirectional_iterator_tag iterator_category; //should be random access, but that would require define subtraction operators on the enums
    typedef
        typename std::make_signed<
            typename std::underlying_type<typename EA::key_type>::type>::type
                                            difference_type;
    typedef typename EA::value_type const * pointer;
    typedef typename EA::value_type const & reference;

    enumarray_const_iterator(EA const & b, size_t start_pos)
         : m_buf(&b), m_pos(start_pos) {}
    value_type& operator*()  const { return (*m_buf)[static_cast<key_type>(m_pos)]; }
    value_type* operator->() const { return &(operator*()); }
    self_type&  operator++() { ++m_pos; return *this; }
    bool        operator!=(self_type const & other) const { return m_buf != other.m_buf || m_pos != other.m_pos; }
    bool        operator==(self_type const & other) const { return m_buf == other.m_buf && m_pos == other.m_pos; }
};

}; // namespace o3tl

#endif /* INCLUDED_O3TL_ENUMARRAY_HXX */

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */