Unindent contents of anonymous namespace

This commit is contained in:
Francisco Javier Jurado Moreno 2024-05-27 11:42:27 +02:00
parent 6d710d06a6
commit 6db2a42d19

View File

@ -23,216 +23,216 @@ namespace ErrorCodes
namespace namespace
{ {
const std::unordered_map<std::string_view, UInt64> size_unit_to_bytes = const std::unordered_map<std::string_view, UInt64> size_unit_to_bytes =
{
{"b", 1},
// ISO/IEC 80000-13 binary units
{"kib", 1024}, // 1024
{"mib", 1048576}, // 1024 * 1024
{"gib", 1073741824}, // 1024 * 1024 * 1024
{"tib", 1099511627776}, // 1024 * 1024 * 1024 * 1024
{"pib", 1125899906842624}, // 1024 * 1024 * 1024 * 1024 * 1024
{"eib", 1152921504606846976}, // 1024 * 1024 * 1024 * 1024 * 1024 * 1024
// SI units
{"kb", 1000}, // 10e3
{"mb", 1000000}, // 10e6
{"gb", 1000000000}, // 10e9
{"tb", 1000000000000}, // 10e12
{"pb", 1000000000000000}, // 10e15
{"eb", 1000000000000000000}, // 10e18
};
constexpr UInt64 MAX_UINT64 = std::numeric_limits<UInt64>::max();
class FunctionFromReadableSize : public IFunction
{
public:
static constexpr auto name = "fromReadableSize";
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionFromReadableSize>(); }
String getName() const override { return name; }
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
size_t getNumberOfArguments() const override { return 1; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
{"b", 1}, if (arguments.empty())
// ISO/IEC 80000-13 binary units throw Exception(
{"kib", 1024}, // 1024 ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION,
{"mib", 1048576}, // 1024 * 1024 "Number of arguments for function {} doesn't match: passed {}, should be 1.",
{"gib", 1073741824}, // 1024 * 1024 * 1024 getName(),
{"tib", 1099511627776}, // 1024 * 1024 * 1024 * 1024 arguments.size());
{"pib", 1125899906842624}, // 1024 * 1024 * 1024 * 1024 * 1024
{"eib", 1152921504606846976}, // 1024 * 1024 * 1024 * 1024 * 1024 * 1024
// SI units if (arguments.size() > 1)
{"kb", 1000}, // 10e3 throw Exception(
{"mb", 1000000}, // 10e6 ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION,
{"gb", 1000000000}, // 10e9 "Number of arguments for function {} doesn't match: passed {}, should be 1.",
{"tb", 1000000000000}, // 10e12 getName(),
{"pb", 1000000000000000}, // 10e15 arguments.size());
{"eb", 1000000000000000000}, // 10e18
};
constexpr UInt64 MAX_UINT64 = std::numeric_limits<UInt64>::max();
class FunctionFromReadableSize : public IFunction const IDataType & type = *arguments[0];
if (!isString(type))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot format {} as time string.", type.getName());
return std::make_shared<DataTypeUInt64>();
}
bool useDefaultImplementationForConstants() const override { return true; }
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{ {
public: auto col_to = ColumnUInt64::create();
static constexpr auto name = "fromReadableSize"; auto & res_data = col_to->getData();
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionFromReadableSize>(); }
String getName() const override { return name; } for (size_t i = 0; i < input_rows_count; ++i)
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
size_t getNumberOfArguments() const override { return 1; }
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
{ {
if (arguments.empty()) std::string_view str{arguments[0].column->getDataAt(i)};
throw Exception( Int64 token_tail = 0;
ErrorCodes::TOO_FEW_ARGUMENTS_FOR_FUNCTION, Int64 token_front = 0;
"Number of arguments for function {} doesn't match: passed {}, should be 1.", Int64 last_pos = str.length() - 1;
getName(), UInt64 result = 0;
arguments.size());
if (arguments.size() > 1) /// ignore '.' and ' ' at the end of string
throw Exception( while (last_pos >= 0 && (str[last_pos] == ' ' || str[last_pos] == '.'))
ErrorCodes::TOO_MANY_ARGUMENTS_FOR_FUNCTION, --last_pos;
"Number of arguments for function {} doesn't match: passed {}, should be 1.",
getName(),
arguments.size());
const IDataType & type = *arguments[0]; /// no valid characters
if (last_pos < 0)
if (!isString(type))
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "Cannot format {} as time string.", type.getName());
return std::make_shared<DataTypeUInt64>();
}
bool useDefaultImplementationForConstants() const override { return true; }
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
auto col_to = ColumnUInt64::create();
auto & res_data = col_to->getData();
for (size_t i = 0; i < input_rows_count; ++i)
{ {
std::string_view str{arguments[0].column->getDataAt(i)}; throw Exception(
Int64 token_tail = 0; ErrorCodes::BAD_ARGUMENTS,
Int64 token_front = 0; "Invalid expression for function {}, don't find valid characters, str: \"{}\".",
Int64 last_pos = str.length() - 1; getName(),
UInt64 result = 0; String(str));
}
/// ignore '.' and ' ' at the end of string /// last pos character must be character and not be separator or number after ignoring '.' and ' '
while (last_pos >= 0 && (str[last_pos] == ' ' || str[last_pos] == '.')) if (!isalpha(str[last_pos]))
--last_pos; {
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, str: \"{}\".", getName(), String(str));
}
/// no valid characters /// scan spaces at the beginning
if (last_pos < 0) scanSpaces(str, token_tail, last_pos);
{ token_front = token_tail;
throw Exception( /// scan unsigned integer
ErrorCodes::BAD_ARGUMENTS, if (!scanUnsignedInteger(str, token_tail, last_pos))
"Invalid expression for function {}, don't find valid characters, str: \"{}\".", {
getName(), throw Exception(
String(str)); ErrorCodes::BAD_ARGUMENTS,
} "Invalid expression for function {}, find number failed, str: \"{}\".",
getName(),
String(str));
}
/// last pos character must be character and not be separator or number after ignoring '.' and ' ' /// if there is a '.', then scan another integer to get a float number
if (!isalpha(str[last_pos])) if (token_tail <= last_pos && str[token_tail] == '.')
{ {
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, str: \"{}\".", getName(), String(str)); token_tail++;
}
/// scan spaces at the beginning
scanSpaces(str, token_tail, last_pos);
token_front = token_tail;
/// scan unsigned integer
if (!scanUnsignedInteger(str, token_tail, last_pos)) if (!scanUnsignedInteger(str, token_tail, last_pos))
{ {
throw Exception( throw Exception(
ErrorCodes::BAD_ARGUMENTS, ErrorCodes::BAD_ARGUMENTS,
"Invalid expression for function {}, find number failed, str: \"{}\".", "Invalid expression for function {}, find number after '.' failed, str: \"{}\".",
getName(), getName(),
String(str)); String(str));
} }
/// if there is a '.', then scan another integer to get a float number
if (token_tail <= last_pos && str[token_tail] == '.')
{
token_tail++;
if (!scanUnsignedInteger(str, token_tail, last_pos))
{
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Invalid expression for function {}, find number after '.' failed, str: \"{}\".",
getName(),
String(str));
}
}
/// convert float/integer string to float
Float64 base = 0;
std::string_view base_str = str.substr(token_front, token_tail - token_front);
auto value = boost::convert<Float64>(base_str, boost::cnv::strtol());
if (!value.has_value())
{
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Invalid expression for function {}, convert string to float64 failed: \"{}\".",
getName(),
String(base_str));
}
base = value.get();
scanSpaces(str, token_tail, last_pos);
token_front = token_tail;
/// scan a unit
if (!scanUnit(str, token_tail, last_pos))
{
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Invalid expression for function {}, find unit failed, str: \"{}\".",
getName(),
String(str));
}
std::string unit = std::string{str.substr(token_front, token_tail - token_front)};
boost::algorithm::to_lower(unit);
auto iter = size_unit_to_bytes.find(unit);
if (iter == size_unit_to_bytes.end()) /// not find unit
{
throw Exception(
ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, parse unit failed: \"{}\".", getName(), unit);
}
Float64 raw_num_bytes = base * iter->second;
if (raw_num_bytes > MAX_UINT64)
{
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Invalid expression for function {}, result is too big for output data type (UInt64): \"{}\".",
getName(),
raw_num_bytes
);
}
// As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units.
// This doesn't make sense so we round up to indicate the byte size that can fit the passed size.
result = static_cast<UInt64>(std::ceil(raw_num_bytes));
res_data.emplace_back(result);
} }
return col_to; /// convert float/integer string to float
} Float64 base = 0;
std::string_view base_str = str.substr(token_front, token_tail - token_front);
/// scan an unsigned integer number auto value = boost::convert<Float64>(base_str, boost::cnv::strtol());
static bool scanUnsignedInteger(std::string_view & str, Int64 & index, Int64 last_pos) if (!value.has_value())
{
int64_t begin_index = index;
while (index <= last_pos && isdigit(str[index]))
{ {
index++; throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Invalid expression for function {}, convert string to float64 failed: \"{}\".",
getName(),
String(base_str));
} }
return index != begin_index; base = value.get();
}
/// scan a unit scanSpaces(str, token_tail, last_pos);
static bool scanUnit(std::string_view & str, Int64 & index, Int64 last_pos) token_front = token_tail;
{
int64_t begin_index = index; /// scan a unit
while (index <= last_pos && !isdigit(str[index]) && !isSeparator(str[index])) if (!scanUnit(str, token_tail, last_pos))
{ {
index++; throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Invalid expression for function {}, find unit failed, str: \"{}\".",
getName(),
String(str));
} }
return index != begin_index;
}
/// scan spaces std::string unit = std::string{str.substr(token_front, token_tail - token_front)};
static void scanSpaces(std::string_view & str, Int64 & index, Int64 last_pos) boost::algorithm::to_lower(unit);
{ auto iter = size_unit_to_bytes.find(unit);
while (index <= last_pos && (str[index] == ' ')) if (iter == size_unit_to_bytes.end()) /// not find unit
{ {
index++; throw Exception(
ErrorCodes::BAD_ARGUMENTS, "Invalid expression for function {}, parse unit failed: \"{}\".", getName(), unit);
} }
Float64 raw_num_bytes = base * iter->second;
if (raw_num_bytes > MAX_UINT64)
{
throw Exception(
ErrorCodes::BAD_ARGUMENTS,
"Invalid expression for function {}, result is too big for output data type (UInt64): \"{}\".",
getName(),
raw_num_bytes
);
}
// As the input might be an arbitrary decimal number we might end up with a non-integer amount of bytes when parsing binary (eg MiB) units.
// This doesn't make sense so we round up to indicate the byte size that can fit the passed size.
result = static_cast<UInt64>(std::ceil(raw_num_bytes));
res_data.emplace_back(result);
} }
static bool isSeparator(char symbol) return col_to;
}
/// scan an unsigned integer number
static bool scanUnsignedInteger(std::string_view & str, Int64 & index, Int64 last_pos)
{
int64_t begin_index = index;
while (index <= last_pos && isdigit(str[index]))
{ {
return symbol == ';' || symbol == '-' || symbol == '+' || symbol == ',' || symbol == ':' || symbol == ' '; index++;
} }
}; return index != begin_index;
}
/// scan a unit
static bool scanUnit(std::string_view & str, Int64 & index, Int64 last_pos)
{
int64_t begin_index = index;
while (index <= last_pos && !isdigit(str[index]) && !isSeparator(str[index]))
{
index++;
}
return index != begin_index;
}
/// scan spaces
static void scanSpaces(std::string_view & str, Int64 & index, Int64 last_pos)
{
while (index <= last_pos && (str[index] == ' '))
{
index++;
}
}
static bool isSeparator(char symbol)
{
return symbol == ';' || symbol == '-' || symbol == '+' || symbol == ',' || symbol == ':' || symbol == ' ';
}
};
} }