summaryrefslogtreecommitdiff
path: root/client/glz_decoder_window.h
blob: 831f2d56f96822a587367b4f9aff2072aad33edf (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
/*
   Copyright (C) 2009 Red Hat, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _H_GLZ_DECODER_WINDOW
#define _H_GLZ_DECODER_WINDOW

#include "glz_decoder_config.h"
#include "glz_decoded_image.h"

#include <list>

#include "read_write_mutex.h"

typedef int DecodedImageWinId;

/*
    The class represents the lz window of images, which is shared among the glz decoders
*/

class GlzDecoderWindow {
public:
    GlzDecoderWindow(int pixels_capacity, GlzDecoderDebug &debug_calls);
    virtual ~GlzDecoderWindow();

    DecodedImageWinId pre_decode(uint64_t image_id, uint64_t relative_head_id);

    void post_decode(GlzDecodedImage *image);

    /* NOTE - get_ref_pixel should be called only after pre_decode was called and
       before post decode was called */
    uint8_t *get_ref_pixel(DecodedImageWinId decoded_image_win_id, int dist_from_ref_image,
                           int pixel_offset);

    void abort();

    /* NOTE - clear mustn't be called if the window is currently used by a decoder*/
    void clear();

    void set_pixels_capacity(int pixels_capacity);

private:
    void wait_for_image(int index);
    void add_image(GlzDecodedImage *image);
    uint8_t* get_pixel_after_image_entered(int image_index, int pixel_offset);

    bool will_overflow(uint64_t image_id, uint64_t relative_head_id);
    bool is_empty();

    DecodedImageWinId pre_decode_update_window(uint64_t image_id, uint64_t relative_head_id);
    void pre_decode_finalize();
    void post_decode_intialize();
    void post_decode_update_window(GlzDecodedImage *image);
    void add_pre_decoded_image(uint64_t image_id);
    void add_decoded_image(GlzDecodedImage *image);
    void narrow_window(GlzDecodedImage *last_added);
    void remove_head(uint64_t new_head_image_id);
    int  calc_image_win_idx(uint64_t image_id);
    int  calc_realloc_size(uint64_t new_tail_image_id);
    void realloc(int size);
    void init();
    void release_images();

private:
    int _pixels_capacity;
    GlzDecodedImage **_images; // cyclic window
    int _head_idx;            // index in images array (not image id)
    uint64_t _tail_image_id;
    int _images_capacity;
    int _n_images;            // _n_images counts all the images in
                              // the window, including the missing ones
    uint64_t _n_pixels;

    std::list<uint64_t> _missing_list;

    Mutex _win_modifiers_mutex;
    ReadWriteMutex _win_alloc_rw_mutex;
    Mutex _new_image_mutex;

    Condition _new_image_cond;          // when get_pixel_ref waits for an image
    Condition _release_image_cond;      // when waiting for the window to narrow.
    Condition _win_alloc_cond;

    bool _aborting;

    GlzDecoderDebug &_debug_calls;
};

inline uint8_t* GlzDecoderWindow::get_pixel_after_image_entered(int image_index,
                                                                int pixel_offset)
{
    return _images[image_index]->get_pixel_ref(pixel_offset);
}

/* should be called only between pre and post (when realloc mutex is write-locked).
   Note that it can't use calc_image_win_idx, since the window is not locked for changes
   (that are not reallocation) during decoding.*/
inline uint8_t *GlzDecoderWindow::get_ref_pixel(DecodedImageWinId decoded_image_win_id,
                                                int dist_from_ref_image, int pixel_offset)
{
    int ref_image_index = (dist_from_ref_image <= decoded_image_win_id) ?
        (decoded_image_win_id - dist_from_ref_image) :
        _images_capacity + (decoded_image_win_id - dist_from_ref_image);

    if (_images[ref_image_index] == NULL) { // reading image is atomic
        wait_for_image(ref_image_index);
    }

    // after image entered - it won't leave the window till no decoder needs it
    return get_pixel_after_image_entered(ref_image_index, pixel_offset);
}

#endif // _H_GLZ_DECODER_WINDOW