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