Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ include(cmake/tbb.cmake)
include(cmake/rocksdb.cmake)
include(cmake/libevent.cmake)
include(cmake/fmt.cmake)
include(cmake/fast_float.cmake)
include(cmake/spdlog.cmake)
include(cmake/jsoncons.cmake)
include(cmake/xxhash.cmake)
Expand All @@ -209,6 +210,7 @@ list(APPEND EXTERNAL_LIBS lz4)
list(APPEND EXTERNAL_LIBS zstd)
list(APPEND EXTERNAL_LIBS zlib_with_headers)
list(APPEND EXTERNAL_LIBS fmt)
list(APPEND EXTERNAL_LIBS fast_float)
list(APPEND EXTERNAL_LIBS spdlog)
if (ENABLE_LUAJIT)
list(APPEND EXTERNAL_LIBS luajit)
Expand Down
4 changes: 4 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ NB: RocksDB is dual-licensed under both the GPLv2 and Apache 2.0 License.
This product uses it under the Apache 2.0 License.

* oneTBB(https://github.com/oneapi-src/oneTBB)
* fast_float(https://github.com/fastfloat/fast_float)

NB: fast_float is available under Apache-2.0, MIT, or Boost Software License Version 1.0.
This product uses it under the Apache 2.0 License and reuses the text in the root LICENSE file.

Files src/common/rocksdb_crc32c.h and src/storage/batch_debugger.h are modified from RocksDB.
Files src/types/bloom_filter.* are modified from Apache Arrow.
Expand Down
31 changes: 31 additions & 0 deletions cmake/fast_float.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

include_guard()

include(cmake/utils.cmake)

FetchContent_DeclareGitHubWithMirror(fast_float
fastfloat/fast_float v8.2.4
MD5=0744790f2d40c9a2e5ef021476e59796
)

FetchContent_MakeAvailableWithArgs(fast_float
FASTFLOAT_TEST=OFF
FASTFLOAT_BENCHMARKS=OFF
FASTFLOAT_INSTALL=OFF
)
49 changes: 15 additions & 34 deletions src/common/parse_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
#pragma once

#include <charconv>
#include <string_view>
#include <tuple>
#include <type_traits>

#include "fast_float/fast_float.h"
#include "status.h"

template <typename T>
Expand Down Expand Up @@ -91,53 +93,32 @@ StatusOr<T> ParseInt(std::string_view v, NumericRange<T> range, int base = 10) {
// available units: K, M, G, T, P
StatusOr<std::uint64_t> ParseSizeAndUnit(std::string_view v);

// we cannot use std::from_chars for floating-point numbers,
// since it is available since gcc/libstdc++ 11 and libc++ 20.
template <typename>
struct ParseFloatFunc;

template <>
struct ParseFloatFunc<float> {
constexpr static const auto value = strtof;
};

template <>
struct ParseFloatFunc<double> {
constexpr static const auto value = strtod;
};

template <>
struct ParseFloatFunc<long double> {
constexpr static const auto value = strtold;
};

// TryParseFloat parses a string to a floating-point number,
// it returns the first unmatched character position instead of an error status
template <typename T = double> // float or double
StatusOr<ParseResultAndPos<T>> TryParseFloat(const char *str) {
char *end = nullptr;
template <typename T = double, std::enable_if_t<std::is_same_v<T, float> || std::is_same_v<T, double>, int> = 0>
StatusOr<ParseResultAndPos<T>> TryParseFloat(std::string_view v) {
T result = 0;
auto [end, ec] =
fast_float::from_chars(v.data(), v.data() + v.size(), result,
fast_float::chars_format::general | fast_float::chars_format::allow_leading_plus);

errno = 0;
T result = ParseFloatFunc<T>::value(str, &end);

if (str == end) {
if (v.data() == end) {
return {Status::NotOK, "not started as a number"};
}

if (errno) {
return Status::FromErrno();
if (ec != std::errc()) {
return {Status::NotOK, std::make_error_code(ec).message()};
}

return {result, end};
}

// ParseFloat parses a string to a floating-point number
template <typename T = double> // float or double
StatusOr<T> ParseFloat(const std::string &str) {
const char *begin = str.c_str();
auto [result, pos] = GET_OR_RET(TryParseFloat<T>(begin));
template <typename T = double>
StatusOr<T> ParseFloat(std::string_view str) {
auto [result, pos] = GET_OR_RET(TryParseFloat<T>(str));

if (pos != begin + str.size()) {
if (pos != str.data() + str.size()) {
return {Status::NotOK, "encounter non-number characters"};
}

Expand Down
13 changes: 9 additions & 4 deletions tests/cppunit/parse_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <gtest/gtest.h>
#include <parse_util.h>

#include <cmath>

TEST(ParseUtil, TryParseInt) {
long long v = 0;
const char *str = "12345hellooo", *end = nullptr;
Expand Down Expand Up @@ -70,21 +72,24 @@ TEST(ParseUtil, ParseSizeAndUnit) {

TEST(ParseUtil, ParseFloat) {
std::string v = "1.23";
ASSERT_EQ(*TryParseFloat(v.c_str()), ParseResultAndPos<double>(1.23, v.c_str() + v.size()));
ASSERT_EQ(*TryParseFloat(v), ParseResultAndPos<double>(1.23, v.c_str() + v.size()));

v = "25345.346e65hello";
ASSERT_EQ(*TryParseFloat(v.c_str()), ParseResultAndPos<double>(25345.346e65, v.c_str() + v.size() - 5));
ASSERT_EQ(*TryParseFloat(v), ParseResultAndPos<double>(25345.346e65, v.c_str() + v.size() - 5));

ASSERT_FALSE(TryParseFloat("eeeeeeee"));
ASSERT_FALSE(TryParseFloat(" "));
ASSERT_FALSE(TryParseFloat(""));
ASSERT_FALSE(TryParseFloat(" abcd"));

v = " 1e8 ";
ASSERT_EQ(*TryParseFloat(v.c_str()), ParseResultAndPos<double>(1e8, v.c_str() + v.size() - 3));
v = "1e8 ";
ASSERT_EQ(*TryParseFloat(v), ParseResultAndPos<double>(1e8, v.c_str() + v.size() - 3));

ASSERT_EQ(*ParseFloat("1.23"), 1.23);
ASSERT_EQ(*ParseFloat("1.23e2"), 1.23e2);
ASSERT_TRUE(std::isinf(*ParseFloat("+inf")));
ASSERT_TRUE(std::isnan(*ParseFloat("nan")));
ASSERT_FALSE(ParseFloat("1.2 "));
ASSERT_FALSE(ParseFloat("1.2hello"));
ASSERT_FALSE(ParseFloat("1e100000"));
}
Loading