| … | … | @@ -166,6 +166,72 @@ bool BoolValue::operator==(const Value& other) const |
| 166 | 166 | // and even then, storing super-long bitstrings should probably |
| 167 | 167 | // be done in some way that is more efficient. For now, this is |
| 168 | 168 | // a stop-gap for experimentation. As always ... |
| 169 | std::string BoolValue::raw_hex_string() const |
| 170 | { |
| 171 | // Print in hexadecimal |
| 172 | std::string rv = " #x"; |
| 173 | |
| 174 | // The native storage format used above is big endian, in that |
| 175 | // bit zero is the left-most bit, bit one is to the right of that, |
| 176 | // and so on. This is easier to print than little-endian (which |
| 177 | // would force us to bit swap) but still presents some challenge. |
| 178 | size_t word_count = words_needed(_bit_count); |
| 179 | |
| 180 | // Print full 16 hex digits if we're lucky. |
| 181 | int bit_align = _bit_count % 64; |
| 182 | if (0 == bit_align) |
| 183 | { |
| 184 | for (size_t w = 0; w < word_count; w++) { |
| 185 | uint64_t word = _packed_bits[w]; |
| 186 | char buf[17]; |
| 187 | snprintf(buf, sizeof(buf), "%016lx", word); |
| 188 | rv += buf; |
| 189 | } |
| 190 | rv += ")"; |
| 191 | return rv; |
| 192 | } |
| 193 | |
| 194 | // First word to be padded by zeros, as needed. |
| 195 | uint64_t word = _packed_bits[0]; |
| 196 | uint64_t mask = (1ULL << (64 - bit_align)) - 1; |
| 197 | uint64_t carry = (word & mask) << bit_align; |
| 198 | word >>= (64 - bit_align); |
| 199 | int width = (bit_align + 3) >> 2; |
| 200 | char buf[17]; |
| 201 | snprintf(buf, sizeof(buf), "%0*lx", width, word); |
| 202 | rv += buf; |
| 203 | |
| 204 | // Are we done yet? |
| 205 | if (1 == word_count) |
| 206 | { |
| 207 | rv += ")"; |
| 208 | return rv; |
| 209 | } |
| 210 | |
| 211 | // Middle words are spliced from low bits of previous |
| 212 | // and high bits of current. |
| 213 | for (size_t w = 1; w < word_count - 1; w++) |
| 214 | { |
| 215 | uint64_t word = _packed_bits[w]; |
| 216 | uint64_t mask = (1ULL << (64 - bit_align)) - 1; |
| 217 | uint64_t rbits = (word & mask) << bit_align; |
| 218 | word >>= (64 - bit_align); |
| 219 | word = word | carry; |
| 220 | carry = rbits; |
| 221 | snprintf(buf, sizeof(buf), "%016lx", word); |
| 222 | rv += buf; |
| 223 | } |
| 224 | |
| 225 | // Last word handling |
| 226 | word = _packed_bits[word_count - 1]; |
| 227 | word >>= (64 - bit_align); |
| 228 | word = word | carry; |
| 229 | snprintf(buf, sizeof(buf), "%lx", word); |
| 230 | rv += buf; |
| 231 | |
| 232 | return rv; |
| 233 | } |
| 234 | |
| 169 | 235 | std::string BoolValue::to_string(const std::string& indent, Type t) const |
| 170 | 236 | { |
| 171 | 237 | std::string rv = indent + "(" + nameserver().getTypeName(t); |
| … | … | @@ -179,76 +245,25 @@ std::string BoolValue::to_string(const std::string& indent, Type t) const |
| 179 | 245 | if (get_bit(i)) rv += " 1"; |
| 180 | 246 | else rv += " 0"; |
| 181 | 247 | } |
| 182 | | rv += ")"; |
| 183 | | return rv; |
| 184 | 248 | } |
| 185 | | |
| 186 | | // For longer bitstrings, print in hexadecimal |
| 187 | | rv += " #x"; |
| 188 | | |
| 189 | | // The native storage format used above is big endian, in that |
| 190 | | // bit zero is the left-most bit, bit one is to the right of that, |
| 191 | | // and so on. This is easier to print than little-endian (which |
| 192 | | // would force us to bit swap) but still presents some challenge. |
| 193 | | size_t word_count = words_needed(_bit_count); |
| 194 | | |
| 195 | | // Print full 16 hex digits if we're lucky. |
| 196 | | int bit_align = _bit_count % 64; |
| 197 | | if (0 == bit_align) |
| 198 | | { |
| 199 | | for (size_t w = 0; w < word_count; w++) { |
| 200 | | uint64_t word = _packed_bits[w]; |
| 201 | | char buf[17]; |
| 202 | | snprintf(buf, sizeof(buf), "%016lx", word); |
| 203 | | rv += buf; |
| 204 | | } |
| 205 | | rv += ")"; |
| 206 | | return rv; |
| 207 | | } |
| 208 | | |
| 209 | | // First word to be padded by zeros, as needed. |
| 210 | | uint64_t word = _packed_bits[0]; |
| 211 | | uint64_t mask = (1ULL << (64 - bit_align)) - 1; |
| 212 | | uint64_t carry = (word & mask) << bit_align; |
| 213 | | word >>= (64 - bit_align); |
| 214 | | int width = (bit_align + 3) >> 2; |
| 215 | | char buf[17]; |
| 216 | | snprintf(buf, sizeof(buf), "%0*lx", width, word); |
| 217 | | rv += buf; |
| 218 | | |
| 219 | | // Are we done yet? |
| 220 | | if (1 == word_count) |
| 221 | | { |
| 222 | | rv += ")"; |
| 223 | | return rv; |
| 224 | | } |
| 225 | | |
| 226 | | // Middle words are spliced from low bits of previous |
| 227 | | // and high bits of current. |
| 228 | | for (size_t w = 1; w < word_count - 1; w++) |
| 229 | | { |
| 230 | | uint64_t word = _packed_bits[w]; |
| 231 | | uint64_t mask = (1ULL << (64 - bit_align)) - 1; |
| 232 | | uint64_t rbits = (word & mask) << bit_align; |
| 233 | | word >>= (64 - bit_align); |
| 234 | | word = word | carry; |
| 235 | | carry = rbits; |
| 236 | | snprintf(buf, sizeof(buf), "%016lx", word); |
| 237 | | rv += buf; |
| 238 | | } |
| 239 | | |
| 240 | | // Last word handling |
| 241 | | word = _packed_bits[word_count - 1]; |
| 242 | | word >>= (64 - bit_align); |
| 243 | | word = word | carry; |
| 244 | | snprintf(buf, sizeof(buf), "%lx", word); |
| 245 | | rv += buf; |
| 249 | else |
| 250 | rv += raw_hex_string(); |
| 246 | 251 | }); |
| 247 | 252 | |
| 248 | 253 | rv += ")"; |
| 249 | 254 | return rv; |
| 250 | 255 | } |
| 251 | 256 | |
| 257 | std::string BoolValue::hex_string() const |
| 258 | { |
| 259 | std::string rv; |
| 260 | SAFE_UPDATE(rv, |
| 261 | { |
| 262 | rv = raw_hex_string(); |
| 263 | }); |
| 264 | return rv; |
| 265 | } |
| 266 | |
| 252 | 267 | // ============================================================== |
| 253 | 268 | // Optimized packed boolean operations (static/internal use only) |
| 254 | 269 | |