1 // 1D array views; these classes are nested within zfp::array1
2 
3 // abstract view of 1D array (base class)
4 class preview {
5 public:
6   // rate in bits per value
rate()7   double rate() const { return array->rate(); }
8 
9   // dimensions of (sub)array
size()10   size_t size() const { return size_t(nx); }
11 
12   // local to global array index
global_x(uint i)13   uint global_x(uint i) const { return x + i; }
14 
15 protected:
16   // construction and assignment--perform shallow copy of (sub)array
preview(array1 * array)17   explicit preview(array1* array) : array(array), x(0), nx(array->nx) {}
preview(array1 * array,uint x,uint nx)18   explicit preview(array1* array, uint x, uint nx) : array(array), x(x), nx(nx) {}
19   preview& operator=(array1* a)
20   {
21     array = a;
22     x = 0;
23     nx = a->nx;
24     return *this;
25   }
26 
27   array1* array; // underlying container
28   uint x;        // offset into array
29   uint nx;       // dimensions of subarray
30 };
31 
32 // generic read-only view into a rectangular subset of a 1D array
33 class const_view : public preview {
34 protected:
35   using preview::array;
36   using preview::x;
37   using preview::nx;
38 public:
39   // construction--perform shallow copy of (sub)array
const_view(array1 * array)40   const_view(array1* array) : preview(array) {}
const_view(array1 * array,uint x,uint nx)41   const_view(array1* array, uint x, uint nx) : preview(array, x, nx) {}
42 
43   // dimensions of (sub)array
size_x()44   uint size_x() const { return nx; }
45 
46   // [i] accessor
47   Scalar operator[](uint index) const { return array->get(x + index); }
48 
49   // (i) accessor
operator()50   Scalar operator()(uint i) const { return array->get(x + i); }
51 };
52 
53 // generic read-write view into a rectangular subset of a 1D array
54 class view : public const_view {
55 protected:
56   using preview::array;
57   using preview::x;
58   using preview::nx;
59 public:
60   // construction--perform shallow copy of (sub)array
view(array1 * array)61   view(array1* array) : const_view(array) {}
view(array1 * array,uint x,uint nx)62   view(array1* array, uint x, uint nx) : const_view(array, x, nx) {}
63 
64   // [i] accessor from base class
65   using const_view::operator[];
66 
67   // (i) accessor from base class
68   using const_view::operator();
69 
70   // [i] mutator
71   reference operator[](uint index) { return reference(array, x + index); }
72 
73   // (i) mutator
operator()74   reference operator()(uint i) { return reference(array, x + i); }
75 };
76 
77 // thread-safe read-only view of 1D (sub)array with private cache
78 class private_const_view : public preview {
79 protected:
80   using preview::array;
81   using preview::x;
82   using preview::nx;
83 public:
84   // construction--perform shallow copy of (sub)array
private_const_view(array1 * array)85   private_const_view(array1* array) :
86     preview(array),
87     cache(array->cache.size())
88   {
89     init();
90   }
private_const_view(array1 * array,uint x,uint nx)91   private_const_view(array1* array, uint x, uint nx) :
92     preview(array, x, nx),
93     cache(array->cache.size())
94   {
95     init();
96   }
97 
98   // destructor
~private_const_view()99   ~private_const_view()
100   {
101     stream_close(zfp->stream);
102     zfp_stream_close(zfp);
103   }
104 
105   // dimensions of (sub)array
size_x()106   uint size_x() const { return nx; }
107 
108   // cache size in number of bytes
cache_size()109   size_t cache_size() const { return cache.size() * sizeof(CacheLine); }
110 
111   // set minimum cache size in bytes (array dimensions must be known)
set_cache_size(size_t csize)112   void set_cache_size(size_t csize)
113   {
114     cache.resize(array->lines(csize, nx));
115   }
116 
117   // empty cache without compressing modified cached blocks
clear_cache()118   void clear_cache() const { cache.clear(); }
119 
120   // (i) accessor
operator()121   Scalar operator()(uint i) const { return get(x + i); }
122 
123 protected:
124   // cache line representing one block of decompressed values
125   class CacheLine {
126   public:
operator()127     const Scalar& operator()(uint i) const { return a[index(i)]; }
operator()128     Scalar& operator()(uint i) { return a[index(i)]; }
data()129     const Scalar* data() const { return a; }
data()130     Scalar* data() { return a; }
131   protected:
index(uint i)132     static uint index(uint i) { return i & 3u; }
133     Scalar a[4];
134   };
135 
136   // copy private data
init()137   void init()
138   {
139     // copy compressed stream
140     zfp = zfp_stream_open(0);
141     *zfp = *array->zfp;
142     // copy bit stream
143     zfp->stream = stream_clone(array->zfp->stream);
144   }
145 
146   // inspector
get(uint i)147   const Scalar& get(uint i) const
148   {
149     const CacheLine* p = line(i);
150     return (*p)(i);
151   }
152 
153   // return cache line for i; may require write-back and fetch
line(uint i)154   CacheLine* line(uint i) const
155   {
156     CacheLine* p = 0;
157     uint b = array->block(i);
158     typename Cache<CacheLine>::Tag t = cache.access(p, b + 1, false);
159     uint c = t.index() - 1;
160     // fetch cache line; no writeback possible since view is read-only
161     if (c != b)
162       decode(b, p->data());
163     return p;
164   }
165 
166   // decode block with given index
decode(uint index,Scalar * block)167   void decode(uint index, Scalar* block) const
168   {
169     stream_rseek(zfp->stream, index * array->blkbits);
170     Codec::decode_block_1(zfp, block, array->shape ? array->shape[index] : 0);
171   }
172 
173   zfp_stream* zfp;                // stream of compressed blocks
174   mutable Cache<CacheLine> cache; // cache of decompressed blocks
175 };
176 
177 // thread-safe read-write view of private 1D (sub)array
178 class private_view : public private_const_view {
179 protected:
180   using preview::array;
181   using preview::x;
182   using preview::nx;
183   using private_const_view::zfp;
184   using private_const_view::cache;
185   using private_const_view::init;
186   using private_const_view::decode;
187   class view_reference;
188   typedef typename private_const_view::CacheLine CacheLine;
189 public:
190   // construction--perform shallow copy of (sub)array
private_view(array1 * array)191   private_view(array1* array) : private_const_view(array) {}
private_view(array1 * array,uint x,uint nx)192   private_view(array1* array, uint x, uint nx) : private_const_view(array, x, nx) {}
193 
194   // partition view into count block-aligned pieces, with 0 <= index < count
partition(uint index,uint count)195   void partition(uint index, uint count)
196   {
197     partition(x, nx, index, count);
198   }
199 
200   // flush cache by compressing all modified cached blocks
flush_cache()201   void flush_cache() const
202   {
203     for (typename Cache<CacheLine>::const_iterator p = cache.first(); p; p++) {
204       if (p->tag.dirty()) {
205         uint b = p->tag.index() - 1;
206         encode(b, p->line->data());
207       }
208       cache.flush(p->line);
209     }
210   }
211 
212   // (i) accessor from base class
213   using private_const_view::operator();
214 
215   // (i) mutator
operator()216   view_reference operator()(uint i) { return view_reference(this, x + i); }
217 
218 protected:
219   class view_reference {
220   public:
Scalar()221     operator Scalar() const { return view->get(i); }
222     view_reference operator=(const view_reference& r) { view->set(i, r.operator Scalar()); return *this; }
223     view_reference operator=(Scalar val) { view->set(i, val); return *this; }
224     view_reference operator+=(Scalar val) { view->add(i, val); return *this; }
225     view_reference operator-=(Scalar val) { view->sub(i, val); return *this; }
226     view_reference operator*=(Scalar val) { view->mul(i, val); return *this; }
227     view_reference operator/=(Scalar val) { view->div(i, val); return *this; }
228     // swap two array elements via proxy references
swap(view_reference a,view_reference b)229     friend void swap(view_reference a, view_reference b)
230     {
231       Scalar x = a.operator Scalar();
232       Scalar y = b.operator Scalar();
233       b.operator=(x);
234       a.operator=(y);
235     }
236 
237   protected:
238     friend class private_view;
view_reference(private_view * view,uint i)239     explicit view_reference(private_view* view, uint i) : view(view), i(i) {}
240     private_view* view;
241     uint i;
242   };
243 
244   // block-aligned partition of [offset, offset + size): index out of count
partition(uint & offset,uint & size,uint index,uint count)245   static void partition(uint& offset, uint& size, uint index, uint count)
246   {
247     uint bmin = offset / 4;
248     uint bmax = (offset + size + 3) / 4;
249     uint xmin = std::max(offset +    0, 4 * (bmin + (bmax - bmin) * (index + 0) / count));
250     uint xmax = std::min(offset + size, 4 * (bmin + (bmax - bmin) * (index + 1) / count));
251     offset = xmin;
252     size = xmax - xmin;
253   }
254 
255   // mutator
set(uint i,Scalar val)256   void set(uint i, Scalar val)
257   {
258     CacheLine* p = line(i, true);
259     (*p)(i) = val;
260   }
261 
262   // in-place updates
add(uint i,Scalar val)263   void add(uint i, Scalar val) { (*line(i, true))(i) += val; }
sub(uint i,Scalar val)264   void sub(uint i, Scalar val) { (*line(i, true))(i) -= val; }
mul(uint i,Scalar val)265   void mul(uint i, Scalar val) { (*line(i, true))(i) *= val; }
div(uint i,Scalar val)266   void div(uint i, Scalar val) { (*line(i, true))(i) /= val; }
267 
268   // return cache line for i; may require write-back and fetch
line(uint i,bool write)269   CacheLine* line(uint i, bool write) const
270   {
271     CacheLine* p = 0;
272     uint b = array->block(i);
273     typename Cache<CacheLine>::Tag t = cache.access(p, b + 1, write);
274     uint c = t.index() - 1;
275     if (c != b) {
276       // write back occupied cache line if it is dirty
277       if (t.dirty())
278         encode(c, p->data());
279       decode(b, p->data());
280     }
281     return p;
282   }
283 
284   // encode block with given index
encode(uint index,const Scalar * block)285   void encode(uint index, const Scalar* block) const
286   {
287     stream_wseek(zfp->stream, index * array->blkbits);
288     Codec::encode_block_1(zfp, block, array->shape ? array->shape[index] : 0);
289     stream_flush(zfp->stream);
290   }
291 };
292