aboutsummaryrefslogtreecommitdiffstats
path: root/staging_vespalib/src/vespa/vespalib/util/polymorphicarrays.h
blob: 696c55f9ae39c1cd4e2c6ba875985e6d2dd29751 (plain) (blame)
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
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
//
#pragma once

#include <vespa/vespalib/util/memory.h>

namespace vespalib {

/**
 * Describes an interface an array of polymorphic types.
 * The intention is to allow efficient implementations when that is possible
 * while still enjoying the flexibility of the polymorph interface.
 * It is not a full feldged Array implementation as std::vector. It contains just
 * the minimum required to allow for efficient implementations for document::ArrayFieldValue.
 *
 * You specify the base type the interface shall provide. This base type must define
 * virtual void assign(const B & rhs);
 * For use with ComplexArrayT your type also need
 * virtual T * clone() const;
 */
template<typename B>
class IArrayT
{
public:
    class iterator {
    public:
        iterator(IArrayT & a, size_t i) : _a(&a), _i(i) { }
        iterator operator+(size_t diff) const { return iterator(*_a, _i + diff); }
        iterator& operator++() { ++_i; return *this; }
        iterator operator++(int) { iterator other(*this); ++_i; return other; }
        bool operator==(const iterator & other) const { return (_a == other._a) && (_i == other._i); }
        bool operator!=(const iterator & other) const { return (_i != other._i) || (_a != other._a); }
        B & operator*() { return (*_a)[_i]; }
        B * operator->() { return &(*_a)[_i]; }
        friend ssize_t operator - (const iterator & a, const iterator & b) { return a._i - b._i; }
    private:
        IArrayT * _a;
        size_t  _i;
    };
    class const_iterator {
    public:
        const_iterator(const IArrayT & a, size_t i) : _a(&a), _i(i) { }
        const_iterator operator+(size_t diff) const { return const_iterator(*_a, _i + diff); }
        const_iterator& operator++() { ++_i; return *this; }
        const_iterator operator++(int) { const_iterator other(*this); ++_i; return other; }
        bool operator==(const const_iterator & other) const { return (_a == other._a) && (_i == other._i); }
        bool operator!=(const const_iterator & other) const { return (_i != other._i) || (_a != other._a); }
        const B & operator*() const { return (*_a)[_i]; }
        const B * operator->() const { return &(*_a)[_i]; }
        size_t operator - (const const_iterator & b) const { return _i - b._i; }
    private:
        const IArrayT * _a;
        size_t  _i;
    };
    typedef std::unique_ptr<IArrayT> UP;

    virtual ~IArrayT() { }
    virtual const B & operator [] (size_t i) const = 0;
    virtual B & operator [] (size_t i) = 0;
    virtual void resize(size_t sz) = 0;
    virtual void reserve(size_t sz) = 0;
    virtual void clear() = 0;
    virtual IArrayT * clone() const = 0;
    virtual size_t size() const = 0;
    virtual iterator erase(iterator it) = 0;
    virtual const_iterator begin() const { return const_iterator(*this, 0); }
    virtual const_iterator end() const { return const_iterator(*this, size()); }
    virtual iterator begin() { return iterator(*this, 0); }
    virtual iterator end() { return iterator(*this, size()); }
    bool empty() const { return size() == 0; }
    virtual void push_back(const B & v) = 0;
};

template <typename T, typename B>
class PrimitiveArrayT : public IArrayT<B>
{
    using typename IArrayT<B>::iterator;
public:
    PrimitiveArrayT() : _array() { }
    virtual ~PrimitiveArrayT() { }
    virtual const T & operator [] (size_t i) const { return _array[i]; }
    virtual T & operator [] (size_t i) { return _array[i]; }
    virtual void resize(size_t sz) { _array.resize(sz); }
    virtual void reserve(size_t sz) { _array.reserve(sz); }
    virtual void clear() { _array.clear(); }
    virtual IArrayT<B> * clone() const { return new PrimitiveArrayT<T, B>(*this); }
    virtual size_t size() const { return _array.size(); }
    virtual iterator erase(iterator it)  { _array.erase(_array.begin() + (it - this->begin())); return it; }
    virtual void push_back(const B & v) {
        size_t sz(_array.size());
        _array.resize(sz + 1);
        _array[sz].assign(v);
    }
private:
    std::vector<T> _array;
};

template <typename B>
class ComplexArrayT : public IArrayT<B>
{
    using typename IArrayT<B>::iterator;
public:
    class Factory {
    public:
        typedef std::unique_ptr<Factory> UP;
        typedef vespalib::CloneablePtr<Factory> CP;
        virtual B * create() = 0;
        virtual Factory * clone() const = 0;
        virtual ~Factory() { }
    };
    explicit ComplexArrayT(typename Factory::UP factory) : _array(), _factory(factory.release()) { }
    ~ComplexArrayT() { }
    const B & operator [] (size_t i) const override { return *_array[i]; }
    B & operator [] (size_t i) override { return *_array[i]; }
    void resize(size_t sz) override {
        _array.resize(sz);
        for (auto & cp : _array) {
            if ( cp.get() == nullptr) {
               cp.reset(_factory->create());
            }
        }
    }
    void reserve(size_t sz) override { _array.reserve(sz); }
    void clear() override { _array.clear(); }
    IArrayT<B> * clone() const override { return new ComplexArrayT<B>(*this); }
    size_t size() const override { return _array.size(); }
    iterator erase(iterator it) override  { _array.erase(_array.begin() + (it - this->begin())); return it; }
    void push_back(const B & v) override { _array.push_back(v.clone()); }
private:
    typedef vespalib::CloneablePtr<B> CP;
    std::vector<CP> _array;
    typename Factory::CP _factory;
};

}