1 /* Quorum 2 * Copyright (C) 2012 Genome group at University of Maryland. 3 * 4 * This program is free software: you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation, either version 3 of the 7 * License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef __JELLYFISH_ATOMIC_BITS_ARRAY_HPP__ 19 #define __JELLYFISH_ATOMIC_BITS_ARRAY_HPP__ 20 21 #include <stdexcept> 22 #include <iterator> 23 24 #include <jellyfish/allocators_mmap.hpp> 25 #include <jellyfish/atomic_gcc.hpp> 26 #include <jellyfish/divisor.hpp> 27 28 namespace jellyfish { 29 template<typename Value, typename T, typename Derived> 30 class atomic_bits_array_base { 31 static const int w_ = sizeof(T) * 8; 32 const int bits_; 33 const size_t size_; 34 const T mask_; 35 const jflib::divisor64 d_; 36 size_t size_bytes_; 37 T* data_; 38 static atomic::gcc atomic_; 39 40 friend class iterator; 41 class iterator : public std::iterator<std::input_iterator_tag, Value> { 42 friend class atomic_bits_array_base; 43 const atomic_bits_array_base& ary_; 44 T* word_; 45 T mask_; 46 int off_; 47 iterator(const atomic_bits_array_base & a,T * w,T m,int o)48 iterator(const atomic_bits_array_base& a, T* w, T m, int o) : ary_(a), word_(w), mask_(m), off_(o) { } 49 public: operator ==(const iterator & rhs) const50 bool operator==(const iterator& rhs) const { return word_ == rhs.word_ && off_ == rhs.off_; } operator !=(const iterator & rhs) const51 bool operator!=(const iterator& rhs) const { return word_ != rhs.word_ || off_ != rhs.off_; } operator *() const52 Value operator*() const { return static_cast<Value>((*word_ & mask_) >> off_); } operator ->() const53 Value* operator->() const { return 0; } operator ++()54 iterator& operator++() { 55 off_ += ary_.bits_; 56 if(off_ + ary_.bits_ < w_) { 57 mask_ <<= ary_.bits_; 58 } else { 59 ++word_; 60 mask_ = ary_.mask_; 61 off_ = 0; 62 } 63 return *this; 64 } operator ++(int)65 iterator operator++(int) { 66 iterator res(*this); 67 ++*this; 68 return res; 69 } 70 }; 71 72 class element_proxy { 73 T* word_; 74 const T mask_; 75 const int off_; 76 T prev_word_; 77 get_val(T v) const78 Value get_val(T v) const { 79 return static_cast<Value>((v & mask_) >> off_); 80 } 81 82 public: element_proxy(T * word,T mask,int off)83 element_proxy(T* word, T mask, int off) : 84 word_(word), mask_(mask), off_(off) 85 { } 86 operator Value() const87 operator Value() const { return get_val(*word_); } get()88 Value get() { 89 prev_word_ = *word_; 90 return get_val(prev_word_); 91 } 92 set(Value & nval)93 bool set(Value& nval) { 94 Value pval; 95 Value cval = get_val(prev_word_); 96 do { 97 pval = cval; 98 const T new_word = (prev_word_ & ~mask_) | ((static_cast<T>(nval) << off_) & mask_); 99 const T actual_word = atomic_.cas(word_, prev_word_, new_word); 100 if(__builtin_expect(actual_word == prev_word_, 1)) 101 return true; 102 prev_word_ = actual_word; 103 cval = get_val(prev_word_); 104 } while(pval == cval); 105 nval = cval; 106 return false; 107 } 108 }; 109 110 public: atomic_bits_array_base(int bits,size_t size)111 atomic_bits_array_base(int bits, // Number of bits per entry 112 size_t size) : // Number of entries 113 bits_(bits), 114 size_(size), 115 mask_((T)-1 >> (w_ - bits)), // mask of one entry at the LSB of a word 116 d_(w_ / bits), // divisor of the number of entries per word 117 size_bytes_((size / d_ + (size % d_ != 0)) * sizeof(T)), 118 data_(static_cast<Derived*>(this)->alloc_data(size_bytes_)) 119 { 120 static_assert(sizeof(T) >= sizeof(Value), "Container type T must have at least as many bits as value type"); 121 if((size_t)bits > sizeof(Value) * 8) 122 throw std::runtime_error("The number of bits per entry must be less than the number of bits in the value type"); 123 if(!data_) 124 throw std::runtime_error("Can't allocate memory for atomic_bits_array"); 125 } 126 127 // Return the element at position pos. No check for out of bounds. operator [](size_t pos)128 element_proxy operator[](size_t pos) { 129 uint64_t q, r; 130 d_.division(pos, q, r); 131 const int off = r * bits_; 132 return element_proxy(data_ + q, mask_ << off, off); 133 } operator [](size_t pos) const134 const element_proxy operator[](size_t pos) const { 135 uint64_t q, r; 136 d_.division(pos, q, r); 137 const int off = r * bits_; 138 return element_proxy(data_ + q, mask_ << off, off); 139 } write(std::ostream & os) const140 void write(std::ostream& os) const { 141 os.write((const char*)data_, size_bytes_); 142 } size_bytes() const143 size_t size_bytes() const { return size_bytes_; } bits() const144 int bits() const { return bits_; } 145 begin() const146 iterator begin() const { return iterator(*this, data_, mask_, 0); } end() const147 iterator end() const { 148 uint64_t q, r; 149 d_.division(size_, q, r); 150 const int off = r * bits_; 151 return iterator(*this, data_ + q, mask_ << off, off); 152 } 153 }; 154 155 template<typename Value, typename T = uint64_t> 156 class atomic_bits_array : 157 protected allocators::mmap, 158 public atomic_bits_array_base<Value, T, atomic_bits_array<Value, T> > 159 { 160 typedef atomic_bits_array_base<Value, T, atomic_bits_array<Value, T> > super; 161 friend class atomic_bits_array_base<Value, T, atomic_bits_array<Value, T> >; 162 public: atomic_bits_array(int bits,size_t size)163 atomic_bits_array(int bits, size_t size) : 164 allocators::mmap(), 165 super(bits, size) 166 { } 167 168 protected: alloc_data(size_t s)169 T* alloc_data(size_t s) { 170 allocators::mmap::realloc(s); 171 return (T*)allocators::mmap::get_ptr(); 172 } 173 }; 174 175 struct mem_info { 176 void* ptr_; 177 size_t bytes_; mem_infojellyfish::mem_info178 mem_info(void* ptr, size_t bytes) : ptr_(ptr), bytes_(bytes) { } 179 }; 180 template<typename Value, typename T = uint64_t> 181 class atomic_bits_array_raw : 182 protected mem_info, 183 public atomic_bits_array_base<Value, T, atomic_bits_array_raw<Value, T> > 184 { 185 typedef atomic_bits_array_base<Value, T, atomic_bits_array_raw<Value, T> > super; 186 friend class atomic_bits_array_base<Value, T, atomic_bits_array_raw<Value, T> >; 187 public: atomic_bits_array_raw(void * ptr,size_t bytes,int bits,size_t size)188 atomic_bits_array_raw(void* ptr, size_t bytes, int bits, size_t size) : 189 mem_info(ptr, bytes), 190 super(bits, size) 191 { } 192 193 protected: alloc_data(size_t s)194 T* alloc_data(size_t s) { 195 assert(bytes_ == s); 196 return (T*)ptr_; 197 } 198 }; 199 200 } // namespace jellyfish 201 202 #endif /* __JELLYFISH_ATOMIC_BITS_ARRAY_HPP__ */ 203