bool AliasIdSet::checkInvariants() const { if (isBigInteger()) { // Must use bitset mode for single integers below BitsetMax. return m_bits > BitsetMax && m_bits < Max; } return true; }
uint32_t AliasIdSet::size() const { if (isBigInteger()) return 1; if (hasUpperRange()) return Max; // MSB is always set in bitset mode; it doesn't count. return folly::popcount(m_bits) - 1; }
bool AliasIdSet::hasSingleValue() const { if (isBigInteger()) return true; if (hasUpperRange()) return false; auto const x = m_bits & (m_bits - 1); // popcount(x) = popcount(m_bits) - 1. return x == Empty; }
void AliasIdSet::unset(uint32_t id) { if (isBigInteger()) { // Empty is represented in bitset mode. if (m_bits == id) m_bits = Empty; return; } // cannot safely unset upper range. if (id > BitsetMax) return; m_bits &= ~(1ull << id); }
std::string AliasIdSet::toString() const { assertx(checkInvariants()); if (isBigInteger()) { return folly::to<std::string>(m_bits); } if (empty()) return "None"; if (isAny()) return "Any"; std::string result; // Try to print the slots by grouping them, expect output like // '0~4,9,10,50~...' auto first = true; // whether to avoid priting the separator int32_t begin = -1; // starting bit of the consecutive range. // Append slots [begin, end) to result string. auto const appendRange = [&] (uint32_t end) { assertx(end > begin); result += folly::to<std::string>(begin); if (end == begin + 1) return; if (end == begin + 2) { result += folly::to<std::string>(",", begin + 1); } else { result += folly::to<std::string>("~", end - 1); } }; for (uint32_t i = 0; i <= BitsetMax; ++i) { if (test(i)) { if (begin < 0) begin = static_cast<int32_t>(i); else continue; } else { if (begin < 0) continue; if (!first) result += ","; appendRange(i); begin = -1; first = false; } } if (hasUpperRange()) { if (!first) result += ","; if (begin < 0) begin = BitsetMax + 1; result += folly::to<std::string>(begin, "~..."); } else if (begin >= 0) { // Append [begin, BitsetMax]. appendRange(BitsetMax + 1); } return result; }
bool AliasIdSet::isSubsetOf(const AliasIdSet rhs) const { if (*this == rhs || empty()) return true; if (isBigInteger()) { // If `rhs' is a big integer, the following will return false. We know // they cannot be the same integer. return rhs.hasUpperRange(); } // nonempty bitset. if (rhs.isBigInteger()) return false; // Both are bitsets. return !(m_bits & (~rhs.m_bits)); }
bool AliasIdSet::maybe(const AliasIdSet other) const { if (isBigInteger()) { if (m_bits == other.m_bits) return true; // If `other' is a big integer, the following will return false. return other.hasUpperRange(); } if (other.isBigInteger()) { return hasUpperRange(); } // Both are bitsets, including cases when one is empty. auto r = m_bits & other.m_bits; // Does r have a bit set other than MSB? return r & (r - 1); }
AliasIdSet AliasIdSet::operator|=(const AliasIdSet rhs) { if (*this == rhs || rhs.empty()) return *this; if (empty()) { m_bits = rhs.m_bits; return *this; } if (isBigInteger() || rhs.isBigInteger()) { // Result contains a big integer, as well as one other integer, so we // must use bitset mode. setUpperRange(); } if (rhs.isBitset()) { // Both are bitsets. m_bits |= rhs.m_bits; } assertx(checkInvariants()); return *this; }
std::string CborValue::inspect() const { if( isNull() ) { static std::string null = "(null)"; return null; } else if( isUndefined() ) { static std::string undefined = "(undefined)"; return undefined; } else if( isBool() ) { return boost::lexical_cast<std::string>(toBool()); } else if( isPositiveInteger() ) { return boost::lexical_cast<std::string>(toPositiveInteger()); } else if( isNegativeInteger() ) { std::string result = "-"; const char specialValue[] = "18446744073709551616"; // 0x10000000000000000 uint64_t value = toNegativeInteger(); if( value == 0 ) result += specialValue; else result += boost::lexical_cast<std::string>(value); return result; } else if( isDouble() ) { return boost::lexical_cast<std::string>(toDouble()); } else if( isString() ) { return toString(); } else if( isByteString() ) { std::vector<char> byteString = toByteString(); std::string result = "(0x"; static const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; for(size_t i = 0; i < byteString.size(); ++i) { unsigned char c = static_cast<unsigned char>(byteString[i]); result += hex[c / sizeof(hex)]; result += hex[c % sizeof(hex)]; } result += ')'; return result; } else if( isArray() ) { std::vector<CborValue> values = toArray(); std::string result = "["; if( values.empty() == false ) { for(size_t i = 0; i < values.size(); ++i) { result += values[i].inspect(); result += ", "; } result.resize(result.size() - 1); result[result.size() - 1] = ']'; } else { result += ']'; } return result; } else if( isMap() ) { std::map<CborValue, CborValue> values = toMap(); std::string result = "{"; if( values.empty() == false ) { std::map<CborValue, CborValue>::iterator it = values.begin(); std::map<CborValue, CborValue>::iterator end = values.end(); for(; it != end; ++it) { result += it->first.inspect(); result += ": "; result += it->second.inspect(); result += ", "; } result.resize(result.size() - 1); result[result.size() - 1] = '}'; } else { result += '}'; } return result; } else if( isBigInteger() ) { BigInteger bigInteger = toBigInteger(); std::string result; if( bigInteger.positive ) result = "(big integer: 0x"; else result = "(negative big integer: 0x"; static const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; if( bigInteger.bigint.empty() == false ) { for(size_t i = 0; i < bigInteger.bigint.size(); ++i) { unsigned char c = static_cast<unsigned char >(bigInteger.bigint[i]); result += hex[c / sizeof(hex)]; result += hex[c % sizeof(hex)]; } result.resize(result.size() - 1); result[result.size() - 1] = ')'; } else { result += ')'; } return result; } assert(false); std::string invalidType = "(invalid type)"; return invalidType; }