source: trunk/GDE/SINA/builddir/src/idset.h

Last change on this file was 19170, checked in by westram, 2 years ago
  • sina source
    • unpack + remove tarball
    • no longer ignore sina builddir.
File size: 11.4 KB
Line 
1/*
2Copyright (c) 2006-2018 Elmar Pruesse <elmar.pruesse@ucdenver.edu>
3
4This file is part of SINA.
5SINA is free software: you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free
7Software Foundation, either version 3 of the License, or (at your
8option) any later version.
9
10SINA is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or
12FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13for more details.
14
15You should have received a copy of the GNU General Public License
16along with SINA.  If not, see <http://www.gnu.org/licenses/>.
17
18Additional permission under GNU GPL version 3 section 7
19
20If you modify SINA, or any covered work, by linking or combining it
21with components of ARB (or a modified version of that software),
22containing parts covered by the terms of the
23ARB-public-library-license, the licensors of SINA grant you additional
24permission to convey the resulting work. Corresponding Source for a
25non-source form of such a combination shall include the source code
26for the parts of ARB used as well as that of the covered work.
27*/
28
29#include <cstdint>
30#include <cstddef>
31#include <cassert>
32#include <vector>
33#include <iostream>
34
35#include "helpers.h"
36
37/** Abstract base class for container of ids
38 *
39 */
40class idset {
41public:
42    using value_type = uint32_t;
43    using inc_t = std::vector<int16_t>;
44    using data_t = std::vector<uint8_t>;
45
46    /* virtual destructor */
47    virtual ~idset() = default;
48
49    size_t size() const {
50        return _size;
51    }
52
53    /* add id to container; MUST be monotonically rising! */
54    virtual void push_back(value_type n) = 0;
55   
56    /* increment vector at offsets included in set */
57    virtual int increment(inc_t& data) const = 0;
58
59    ///// for unit testing: ////
60
61    /* create a new instance */
62    virtual idset* make_new(value_type size) const = 0;
63
64    void shrink_to_fit() { data.shrink_to_fit(); }
65
66    virtual std::ostream& write(std::ostream& o) const {return o;}
67
68protected:
69    mutable data_t data;
70    size_t _size{0};
71};
72
73
74/** idset implementation as bitmap **/
75class bitmap : public idset {
76public:
77    using block_type = typename data_t::value_type;
78    const size_t bits_per_block = sizeof(block_type) * 8;
79
80    explicit bitmap(value_type maxid) : idset() {
81        int blocks_needed = (maxid + bits_per_block - 1 )/ bits_per_block;
82        data.resize(blocks_needed, 0);
83    }
84
85    size_t block_index(value_type id) const {
86        return id / bits_per_block;
87    }
88
89    size_t block_offset(value_type id) const {
90        return id % bits_per_block;
91    }
92
93    /* set bit at @id */
94    void set(value_type id) const {
95        data[block_index(id)] |= 1 << (block_offset(id));
96    }
97
98    /* get value of bit at @id */
99    bool get(value_type id) const {
100        return (data[block_index(id)] & (1 << (block_offset(id)))) != 0;
101    }
102
103    /* count total number of set bits */
104    value_type count() const {
105        value_type total = 0;
106        for (const auto& block : data) {
107            total += __builtin_popcount(block);
108        }
109        return total;
110    }
111
112    idset* make_new(value_type size) const override {
113        return new bitmap(size);
114    }
115   
116    void push_back(value_type id) override {
117        if (!get(id)) ++_size;
118        set(id);
119    }
120
121    int increment(inc_t& t) const override {
122        for (value_type i=0; i < data.size(); i++) {
123            block_type block = data[i];
124            while (block != 0) {
125                auto j = __builtin_ctz(block);
126                ++t[i*bits_per_block+j];
127                block ^= 1<<j;
128            }
129        }
130        return 0;
131    }
132};
133
134
135
136/* idset implementation using plain integers
137 */
138class imap_abs : public idset {
139public:
140    explicit imap_abs(int /*unused*/) : idset() {};
141
142    /* once-forward iterator over contents */
143    class const_iterator {
144        data_t::const_iterator _it;
145    public:
146        explicit const_iterator(const data_t::const_iterator& it) : _it(it) {}
147        value_type operator*() const {
148            return *(value_type*)(&*_it);
149        }
150        const_iterator& operator++() {
151            _it += sizeof(value_type);
152            return *this;
153        }
154        bool operator!=(const const_iterator& rhs) const {
155            return _it != rhs._it;
156        }
157    };
158
159    const_iterator begin() const {
160        return const_iterator(data.begin());
161    }
162
163    const_iterator end() const {
164        return const_iterator(data.end());
165    }
166
167    idset* make_new(value_type size) const override {
168        return new imap_abs(size);
169    }
170
171    void push_back(value_type n) override {
172        size_t offset = data.size();
173        data.resize(data.size() + sizeof(value_type));
174        *(value_type*)(data.data() + offset) = n;
175        ++_size;
176    }
177
178    int increment(inc_t& t) const override {
179        for (idset::value_type it : *this) {
180            ++t[it];
181        }
182        return 0;
183    }
184};
185
186
187
188/* idset implementation using variable length integers
189 * (encoded using most significant bit to indicate need for another byte)
190 */
191class vlimap_abs : public idset {
192public:
193    explicit vlimap_abs(int /*maxsize*/=0) : idset() {}
194
195    /* once-forward iterator over contents */
196    class const_iterator {
197        data_t::const_iterator _it;
198    public:
199        data_t::const_iterator iter() {
200            return _it;
201        }
202
203        explicit const_iterator(const data_t::const_iterator& it) : _it(it) {}
204        inline value_type operator*()  __attribute__((always_inline)) { // DO NOT CALL TWICE
205            value_type val;
206            // first byte
207            uint8_t byte = *_it;
208//#define SINA_UNROLL
209#ifdef SINA_UNROLL
210            if ((byte & 0x80) == 0) {
211                return byte;
212            }
213            // second byte
214            val = byte - 0x80;
215            byte = *(++_it);
216            val += byte << 7;
217            if ((byte & 0x80) == 0) {
218                return val;
219            }
220            // third byte
221            val -= 0x80 << 7;
222            byte = *(++_it);
223            val += byte << 14;
224            if ((byte & 0x80) == 0) {
225                return val;
226            }
227            // fourth byte
228            val -= 0x80 << 14;
229            byte = *(++_it);
230            val += byte << 21;
231            if ((byte & 0x80) == 0) {
232                return val;
233            }
234            // fifth byte
235            val -= 0x80 << 21;
236            byte = *(++_it);
237            val += byte << 28;
238            //if (unlikely(byte & 0x80)) {
239            //    throw something
240            //}
241
242            return val;
243#else // SINA_UNROLL undefined
244            if (likely(byte < 128)) {
245                val = byte;
246            } else {
247                val = byte & 0x7f;
248                unsigned int shift = 7;
249                do {
250                    byte = *(++_it);
251                    val |= value_type(byte & 0x7f) << shift;
252                    shift += 7;
253                } while (byte >= 128);
254            }
255            return val;
256#endif // SINA_UNROLL
257        }
258        inline const_iterator& operator++()  __attribute__((always_inline))  {
259            ++_it; // step to next encoded value
260            return *this;
261        }
262        inline bool operator!=(const const_iterator& rhs) const  __attribute__((always_inline))  {
263            return _it != rhs._it;
264        }
265    };
266   
267    const_iterator begin() const {
268        return const_iterator(data.begin());
269    }
270   
271    const_iterator end() const {
272        return const_iterator(data.end());
273    }
274   
275    idset* make_new(value_type size) const override {
276        return new vlimap_abs(size);
277    }
278   
279    void push_back(value_type n) override {
280        while (n > 127) {
281            data.push_back(n | 0x80);
282            n >>= 7;
283        }
284        data.push_back(n);
285        ++_size;
286    }
287   
288    int increment(inc_t& t) const override {
289        for (idset::value_type it : *this) {
290            ++t[it];
291        }
292        return 0;
293    }
294};
295
296/* idset implementation using variable length integer on distances */
297class vlimap final : public vlimap_abs {
298public:
299    vlimap(value_type maxsize, inc_t::value_type inc=1)
300        : vlimap_abs(maxsize),
301          _inc(inc),
302          _last(0),
303          _maxsize(maxsize)
304    {}
305   
306    idset* make_new(value_type maxsize) const override {
307        return new vlimap(maxsize);
308    }
309   
310    void push_back(value_type n) override {
311        vlimap_abs::push_back(n-_last);
312        _last = n;
313    }
314
315    inline int increment(inc_t& t) const override {
316        auto it = data.begin();
317        auto end = data.end();
318        value_type last = 0;
319        while (it != end) {
320            uint8_t byte = *it;
321            if (likely(byte < 128)) {
322                last += byte;
323            } else {
324                value_type val = byte & 0x7f;
325                unsigned int shift = 7;
326                do {
327                    byte = *(++it);
328                    val |= value_type(byte & 0x7f) << shift;
329                    shift += 7;
330                } while (byte >= 128);
331                last += val;
332            }
333            t[last] += _inc;
334            ++it;
335        }
336        return 1-(_inc+1)/2;
337    }
338
339    /* append contents of another vlimap
340     * - largest value in LHS must be smaller than smallest in RHS
341     * - invertion status must be equal
342     */
343    void append(const vlimap& other) {
344        if (other.data.size() == 0) {
345            return;
346        }
347        if (data.size() == 0) {
348            data = other.data;
349            _last = other._last;
350            return;
351        }
352
353        auto it = other.begin();
354        auto val = *it;
355        push_back(val);
356
357        data_t::const_iterator data_it = (++it).iter();
358        data_t::const_iterator end = other.data.end();
359        data.insert(data.end(), data_it, end);
360        _last = other._last;
361    }
362
363    /* invert map
364     * replaces "in map" with "not in map"
365     * increment() on inverted object will actually decrement and return 1 instead of 0
366     */
367    void invert() {
368        vlimap res(0, -1);
369        value_type next = 0, last = 0;
370        for (auto inc : *this) {
371            next += inc;
372            while (last < next) {
373                res.push_back(last++);
374            }
375            ++last;
376        }
377        while (last < _maxsize) {
378            res.push_back(last++);
379        }
380        std::swap(data, res.data);
381        std::swap(_inc, res._inc);
382        std::swap(_last, res._last);
383        std::swap(_maxsize, res._maxsize);
384    }
385
386    struct file_header {
387        uint32_t inc, last, bytesize, size;
388    };
389
390    std::ostream& write(std::ostream& out) const override {
391        file_header head;
392        head.inc = _inc;
393        head.last = _last;
394        head.bytesize = data.size();
395        head.size = size();
396        out.write((char*)&head, sizeof(file_header));
397        out.write((char*)data.data(), sizeof(data_t::value_type) * data.size());
398        return out;
399    }
400
401    std::istream& read(std::istream& in) {
402        file_header head;
403        in.read((char*)&head, sizeof(file_header));
404        _inc = head.inc;
405        _last = head.last;
406        _size = head.size;
407        data.resize(head.bytesize);
408        in.read((char*)data.data(), sizeof(data_t::value_type) * data.size());
409        return in;
410    }
411private:
412    inc_t::value_type _inc{1};
413    value_type _last, _maxsize;
414};
415
416/*
417  Local Variables:
418  mode:c++
419  c-file-style:"stroustrup"
420  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
421  indent-tabs-mode:nil
422  fill-column:99
423  End:
424*/
425// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
Note: See TracBrowser for help on using the repository browser.