Repository: duckdb/duckdb
File: src/common/types/bit.cpp (C++)

Code before:
#include "duckdb/common/assert.hpp"
#include "duckdb/common/numeric_utils.hpp"
#include "duckdb/common/operator/cast_operators.hpp"
#include "duckdb/common/typedefs.hpp"
#include "duckdb/common/types/bit.hpp"
#include "duckdb/common/types/string_type.hpp"

namespace duckdb {

namespace {

char GetByteFromHex(data_t byte_1, data_t byte_2) {
	static constexpr data_t lookup[103] = {
	    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	    255, 255, 255, 255, 255, 255, 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   255, 255, 255, 255, 255,
	    255, 255, 10,  11,  12,  13,  14,  15,  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 10,  11,  12,  13,  14,  15};
	return UnsafeNumericCast<char>((lookup[byte_1] << 4) | lookup[byte_2]);
}

bool IsValidHexChar(data_t c) {
	return (c >= 48 && c <= 57) || (c >= 65 && c <= 70) || (c >= 97 && c <= 102);
}

} // namespace

// **** helper functions ****
static char ComputePadding(idx_t len) {
	return UnsafeNumericCast<char>((8 - (len % 8)) % 8);
}

idx_t Bit::ComputeBitstringLen(idx_t len) {
	idx_t result = len / 8;
	if (len % 8 != 0) {
		result++;
	}
	// additional first byte to store info on zero padding
	result++;
	return result;
}

static inline idx_t GetBitPadding(const bitstring_t &bit_string) {
	auto data = const_data_ptr_cast(bit_string.GetData());
	D_ASSERT(idx_t(data[0]) < 8);
	return data[0];
}

Review comment (suggestion):
These already exist in `StringUtil` (`CharacterIsHex` and `GetHexValue`) - maybe we can unify these? e.g. we can use the lookup table in `StringUtil::GetHexValue` and use `lookup[byte] == 255` to figure out if a byte is invalid

Code after:
#include "duckdb/common/assert.hpp"
#include "duckdb/common/exception/conversion_exception.hpp"
#include "duckdb/common/numeric_utils.hpp"
#include "duckdb/common/operator/cast_operators.hpp"
#include "duckdb/common/typedefs.hpp"
#include "duckdb/common/types/bit.hpp"
#include "duckdb/common/types/string_type.hpp"
#include "duckdb/common/string_util.hpp"
#include <cstdint>

namespace duckdb {

namespace {

// **** helper functions ****
char ComputePadding(idx_t len) {
	return UnsafeNumericCast<char>((8 - (len % 8)) % 8);
}

idx_t GetBitPadding(const bitstring_t &bit_string) {
	auto data = const_data_ptr_cast(bit_string.GetData());
	D_ASSERT(idx_t(data[0]) < 8);
	return data[0];
}

idx_t GetBitSize(const string_t &str) {
	string error_message;
	idx_t str_len;
	if (!Bit::TryGetBitStringSize(str, str_len, &error_message)) {
		throw ConversionException(error_message);
	}
	return str_len;
}

void ToBitThrow(string_t str, bitstring_t &output_str) {
	string error_message;
	if (!Bit::ToBit(str, output_str, &error_message)) {
		throw ConversionException(error_message);
	}
}

void AssignInvalidCharacterError(char c, string *error_message) {
	auto error = StringUtil::Format("Invalid character encountered in string -> bit conversion: '%s'", string(1, c));
	HandleCastError::AssignError(error, error_message);
}

bool GetByteFromHex(char char_1, char char_2, data_t &output, string *error_message) {