scnlib

scanf for modern C++

APACHE-2.0 License

Stars
955

Bot releases are visible (Hide)

scnlib - 3.0.0 Latest Release

Published by eliaskosunen 4 months ago

Breaking changes

  • The default behavior for scanning integers is now d (decimal) instead of i (detect base from prefix).
// v3
auto result = scn::scan<int>("077", "{}");
// result->value() == 77
result = scn::scan<int>("078", "{}");
// result->value() == 78

// v2
auto result = scn::scan<int>("077", "{}");
// result->value() == 63
result = scn::scan<int>("078", "{}");
// result->value() == 7
// result->range() == "8"
// (Because of the '0' prefix, an octal number is expected,
//  and '8' is not a valid octal digit, so reading is stopped)
  • A large part of the bundled <ranges>-implementation is removed.
    Only the parts strictly needed for the library are included.
    • The library no longer uses a stdlib provided <ranges>, even if available.
    • This cut down compile times massively for library consumers
    • You now may need to specialize scn::ranges::enable_borrowed_range for your own range types,
      even if you've already specialized std::ranges::enable_borrowed_range.
      Specializations of std::basic_string_view are already borrowed out of the box.
// std::span is a borrowed_range,
// but scnlib doesn't know about it
auto result = scn::scan<...>(std::span{...}, ...);
// decltype(result->range()) is scn::ranges::dangling

namespace scn::ranges {
template <typename T, size_t E>
inline constexpr bool enable_borrowed_range<std::span<T, E>> = true;
}

auto result = scn::scan<...>(std::span{...}, ...);
// decltype(result->range()) is a scn::ranges::subrange<const T*>
  • scn::span is removed
  • scan_arg_store and borrowed_subrange_with_sentinel are removed from the public interface
  • scan_arg_store is changed to be non-copyable and non-movable, for correctness reasons
    (it holds references to itself, copying and moving would be needlessly expensive)
  • The interface of make_scan_result is changed to take a tuple instead of the now unmovable scan_arg_store.
// v3
auto args = make_scan_args<scan_context, Args...>();
auto result = vscan(source, format, args);
return make_scan_result(std::move(result), std::move(args.args()));

// v2
auto args = make_scan_args<scan_context, Args...>();
auto result = vscan(source, format, args);
return make_scan_result(std::move(result), std::move(args));
  • The meaning of the "width" field in format specifiers is changed to mean the minimum field width
    (like in std::format), instead of the maximum (sort of like in scanf)
// v3
auto result = std::scan<int>("123", "{:2}");
// result->value() == 123
// result->range() == ""

// v2
auto result = std::scan<int>("123", "{:2}");
// result->value() == 12
// result->range() == "3"

Features

  • The "precision" field is added as a format specifier,
    which specifies the maximum fields width to scan (like in std::format)
// Scan up to 2 width units
auto result = scn::scan<int>("123", "{:.2}");
// result->value() == 12
// result->range() == "3"
  • Support for field fill and alignment is added.
    This interacts well with the new width and precision fields
// Read an integer, aligned to the right ('>'), with asterisks ('*')
auto result = std::scan<int>("***42", "{:*>}");
// result->value() == 42
// result->range() == ""

// Read an integer, aligned to the left ('<'), with whitespace (default),
// with a maximum total width of 3
auto result = std::scan<int>("42  ", "{:<.3}");
// result->value() == 42
// result->range() == " "
  • In general, there seems to be a ~10% to 20% improvement in run-time performance.

Changes

  • The dependency on simdutf is removed. The library now has no external dependencies to compiled libraries
    (FastFloat, an internal dependency, is a header-only library)
  • The number of source files is dramatically decreased: there are now just the public headers,
    a private implementation header, and a private implementation source file. This cuts down the time needed to
    compile the library, and any user code including it to a half (yes, really!)

Fixes

Full Changelog: https://github.com/eliaskosunen/scnlib/compare/v2.0.3...v3.0.0

scnlib - 2.0.3

Published by eliaskosunen 5 months ago

Fixes:

  • Fix documentation: default format type specifier for integers is i, not d:
    when not explicitly specified by a format specifier, the base of an integer is determined based on its prefix:
    0x... is hexadecimal, 0... or 0o... is octal, 0b... is binary, and everything else is decimal.
  • Fix a compilation error which would occur when scanning more than 11 arguments with scn::scan.
  • Small CMake adjustments to better support use as a subproject (#113, thanks @frankmiller (Frank Miller))
  • Fix misplaced include of GNUInstallDirs in CMake (#111, thanks @WangWeiLin-MV)
  • Allow for externally installed versions for GTest and Google Benchmark (#112, thanks @xvitaly (Vitaly))
  • Adjust the definition of SCN_COMPILER to fix usage with a recent Clang using modules (#109, thanks @Delta-dev-99 (Armando Martin))
  • Allow for more versions of dependencies (simdutf, fast_float)
  • Fix C++23 build failure caused by missing inclusion of <utility> for std::unreachable

Full Changelog: https://github.com/eliaskosunen/scnlib/compare/v2.0.2...v2.0.3

scnlib - 2.0.2

Published by eliaskosunen 8 months ago

Minor fixes:

  • Fix segfault when runtime-parsing {:[^ as a format string.
  • Fix compilation of scan_buffer.cpp on some MSVC versions.
  • Remove stray test/ folder

Full Changelog: https://github.com/eliaskosunen/scnlib/compare/v2.0.1...v2.0.2

scnlib - 2.0.1

Published by eliaskosunen 8 months ago

Minor bugfixes

Full Changelog: https://github.com/eliaskosunen/scnlib/compare/v2.0.0...v2.0.1

scnlib - 2.0.0

Published by eliaskosunen 9 months ago

Major overhaul, both internally and in terms of the library interface. The library is rewritten in its entirety. See the documentation at https://scnlib.dev/, namely the Migration guide for more details.

The changes below are relative to v1. See CHANGELOG.md for changes relative to v2.0.0-beta.

Major changes include:

  • C++17 is required.
  • Several names are changed to include the scan_ prefix.
  • scn::scan returns the scanned values by value. Output parameters are no longer used.
  • scn::scan now accepts all forward_ranges (v1: bidirectional_range + default- and move constructible).
  • scn::scan returns a view (subrange) into its input, and never takes ownership.
  • Scope is more focused: list operations, ignore, getline, and file have been removed.
  • Support for regular expressions.
  • Better Unicode support.
  • Performance improvements.
  • Completely reworked internals.

Full Changelog: https://github.com/eliaskosunen/scnlib/compare/v2.0.0-beta...v2.0.0

scnlib - 1.1.3

Published by eliaskosunen 12 months ago

Expected to be the last release in the v1-branch.
Development efforts are now fully directed towards v2.

Features

  • Allow disabling support for individual types with SCN_DISABLE_TYPE_* (#70, thanks @cjvaughter (CJ Vaughter))
    • Also, allow for disabling the fallbacks to std::from_chars and std::strtod when scanning floats
    • This provides possible binary size reductions, and allows better use in e.g. embedded platforms
  • Allow disabling runtime localization with SCN_DISABLE_LOCALE (#71, thanks @cjvaughter (CJ Vaughter))
  • Parse leading + signs in floats (reported in #77)

Fixes

  • Fix scn::wrap(std::string_view&&) being ambiguous on gcc (reported in #83)
  • Fix compiler error in scn::basic_string_view<CharT>::substr (reported in #86)
  • Fix memory safety issues found with ASan and UBsan in
    small_vector, detail::utf16::validate_next, and detail::get_buffer.
  • Add COMPONENT to CMake install targets (#80, thanks @pawelwod)
  • Fix calculation of SCN_MSVC from _MSC_FULL_VER (#62, thanks @matbech (Mathias Berchtold))
  • Fix MSVC C4146 warning in integer_scanner (#64, thanks @matbech (Mathias Berchtold))
  • Use if constexpr and std::unreachable if available (#61, #78, thanks @matbech (Mathias Berchtold))
  • Improve error messages given from the float parser
scnlib - 2.0.0-beta

Published by eliaskosunen 12 months ago

Major overhaul, both internally and in terms of the library interface. The library is rewritten in its entirety. See the documentation (note the new URL: https://v2.scnlib.dev), namely the Migration guide for more details.

This is a beta pre-release. There may still be some bugs. Changes before v2.0.0 proper are possible, but aren't probably going to be major.

Major changes include:

  • C++17 is required.
  • Several names are changed to include the scan_ prefix.
  • scn::scan returns the scanned values by value. Output parameters are no longer used.
  • scn::scan now accepts all forward_ranges (v1: bidirectional_range + default- and move constructible).
  • scn::scan returns a view (subrange) into its input, and never takes ownership.
  • Scope is more focused: list operations, ignore, getline, and file have been removed.
  • Performance improvements
  • Completely reworked internals
scnlib - 1.1.2

Published by eliaskosunen over 2 years ago

  • Change SCN_VERSION to report the correct version number: 1.1.0 -> 1.1.2 (#57)
scnlib - 1.1.1

Published by eliaskosunen over 2 years ago

  • Fix issue with values being skipped when using files and file.sync() (#56)
    • Every call to file.sync() needs to be accompanied by a call to reset_begin_iterator() to the result object
    • This is a temporary fix, permanent fix coming in v2.0.0
int i;
auto ret = scn::scan(scn::cstdin(), "{}", i);
scn::cstdin().sync();
ret.range().reset_begin_iterator();

// Not necessary with input and prompt
ret = scn::input("{}", i);
scnlib - 1.1

Published by eliaskosunen over 2 years ago

  • Add support for scanning 8-bit integers ((un)signed char, (u)int8_t),
    and characters (char, wchar_t) as integers
int8_t i1, i2;
char c1, c2;
auto ret = scn::scan("1 2 3 4", "{} {:c} {} {:i}", i1, i2, i3, i4);
// ret == true
// i1 == 1
// i2 == '2'
// c1 == '3'
// c2 == 4
  • Fix usage of external fast_float in CMake (#53, thanks @xvitaly (Vitaly Zaitsev))
  • Fix tests on big endian architectures (#54)
  • Fix alignment issues with small_vector on 32-bit architectures

Full Changelog: https://github.com/eliaskosunen/scnlib/compare/v1.0...v1.1

scnlib - 1.0

Published by eliaskosunen over 2 years ago

First stable release!

The library is now deemed production-ready, and backwards-compatibility will be maintained until the next major release comes out, in accordance to semantic versioning. 1.x-versions will be getting security updates after that, until further notice.

If you're migrating from v1.0-rc1, no major changes have been made, only bugfixes.

If you're migrating from v0.4, see the migration guide v0.4 -> v1.0.

If you're new here, see the documentation and the repository.

The feature highlights below are the same compared to those of v1.0-rc1

Feature highlights

New float parsing

Now, by default, scnlib uses https://github.com/fastfloat/fast_float for parsing floating-point values, falling back on std::from_chars and std::strtod only if necessary.

This provides even more performance than before: using scn::scan is now 2x to 8x faster than using std::stringstream, when parsing floats.

New format strings

Many things have changed (see the migration guide above), and the same format strings may now do different things.

// alignment
int i{};
auto result = scn::scan("***1***", "{:*^}", i);
// i == 1
// result.empty() == true

// localization
double d{};
result = scn::scan_localized(std::locale{"fi_FI.UTF-8"}, "3,14", "{:L}", d);
// d == 3.14
// result.empty() == true

// width
std::string str1;
result = scn::scan("abcde", "{:3}", str1);
// str1 == "abc"
// result.range() == "de"

// string set
std::string str2;
result = scn::scan("123abc", "{:[0-9]}", str2);
// str2 == "123"
// result.range() == "abc"

Unicode support

// Parse Unicode code points
scn::code_point cp{};
auto result = scn::scan("äa", "{}", cp);
// cp == 0xe4
// result.range() == "a"

// Parse Unicode strings
std::string s1, s2;
// s1: read until whitespace
// s2: read until non-letter character, according to locale
result = scn::scan_localized(std::locale{"fi_FI.UTF-8"}, "äa1 äa1", "{} {:L[:alpha:]}", s1, s2);
// s1 == "äa1"
// s2 == "äa"
// result.range() == "1"

And more

See CHANGELOG.md and the documentation for more details

Full Changelog (from v1.0-rc1): https://github.com/eliaskosunen/scnlib/compare/v1.0-rc1...v1.0

scnlib - 1.0-rc1

Published by eliaskosunen over 2 years ago

Getting closer to 1.0!

Feature highlights

New float parsing

Now, by default, scnlib uses https://github.com/fastfloat/fast_float for parsing floating-point values, falling back on std::from_chars and std::strtod only if necessary.

This provides even more performance than before.

New format strings

Many things have changed (see the migration guide below), and the same format strings may now do different things.

// alignment
int i{};
auto result = scn::scan("***1***", "{:*^}", i);
// i == 1
// result.empty() == true

// localization
double d{};
result = scn::scan_localized(std::locale{"fi_FI.UTF-8"}, "3,14", "{:L}", d);
// d == 3.14
// result.empty() == true

// width
std::string str1;
result = scn::scan("abcde", "{:3}", str1);
// str1 == "abc"
// result.range() == "de"

// string set
std::string str2;
result = scn::scan("123abc", "{:[0-9]}", str2);
// str2 == "123"
// result.range() == "abc"

Unicode support

// Parse Unicode code points
scn::code_point cp{};
auto result = scn::scan("äa", "{}", cp);
// cp == 0xe4
// result.range() == "a"

// Parse Unicode strings
std::string s1, s2;
// s1: read until whitespace
// s2: read until non-letter character, according to locale
result = scn::scan_localized(std::locale{"fi_FI.UTF-8"}, "äa äa", "{} {:L[:alpha:]}", s1, s2);
// s1 == s2 == "äa"
// result.empty() == true

And more

See CHANGELOG.md and the documentation, namely the migration guide for more details

Full Changelog: https://github.com/eliaskosunen/scnlib/compare/v0.4...v1.0-rc1

scnlib - 0.4

Published by eliaskosunen almost 4 years ago

Planned to be the last 0.x release before 1.0-rc1.

Changes and removals

  • Rework source range handling:
    • Non-views are now accepted as source ranges --
      this includes types like std::string and std::vector<char>
    • Non-reconstructible ranges are now also accepted --
      scanning functions no longer return a reconstructed source range.
      The member function .range() can be used to scan the range again,
      and .reconstruct() reconstructs the range, if possible.
      Other helper member functions are also available.
    • Source ranges are now either taken by const lvalue reference or rvalue reference,
      so they are no longer modified by scanning functions.
      To access the leftover range, use the return value of the scanning function.
  • Rewrite file handling, with hopefully way less bugs this time around
    • Remove file_view and caching ranges
    • Move memory mapped files to the public API
  • Remove default_tag, replace with scan_default function template
  • Remove support for scanf syntax, including scn::scanf and scn::basic_scanf_parse_context.
  • Improve Ranges integration:
    • Move custom Ranges implementation to the public API (out from scn::detail::ranges): scn::custom_ranges
    • Integrate standard library Ranges, if available: scn::std_ranges aliased to std::ranges
    • Use stdlib Ranges, if available, fall back to custom implementation: namespace alias scn::ranges, control behavior with SCN_USE_STD_RANGES

Additions

  • Add more thorough documentation, tests, benchmarks and examples
  • Add scan_list_until

Fixes and minor stuff

scnlib - 0.3

Published by eliaskosunen over 4 years ago

Largely a bugfix release

Changes

  • Remove support for partial successes
    • If the reading of any of the arguments given to scan fail, the whole function fails
    • read-field removed from result
  • Overhaul list scanning
    • Add scan_list

Fixes

  • Fix issues with std::string_view and MSVC debug iterators (#11, #14, #18, #20)
  • Fix some issues with scanning customized types (#15)
  • Add missing support for custom-allocator std::strings (#16)
  • Fix erroneous git command in README (#13)
  • Fix README example
  • Fix erroneous usage of library feature test macros

Thanks to @nanoric and @SuperWig for bug reports!

Removals

  • Remove support for non-std::char_traits std::strings
  • Remove support for clang 3.6
scnlib - 0.2

Published by eliaskosunen almost 5 years ago

There are so many changes, that writing a complete changelog isn't really possible.
The most substantial change is the removal of streams, which have been replaced with C++20-like ranges.
There are also some pretty sweet performance improvements; see benchmarks in README for more details.

See the documentation for more details, a tutorial, and an API reference.

scnlib - 0.1.2

Published by eliaskosunen over 5 years ago

  • Add SCN_RANGES CMake option
  • Add scn::temp helper function
  • Fix -Wpadded warnings on clang
  • Fix -Wfloat-equal and -Wconversion warnings on gcc
  • Fix C4146 error on UWP MSVC
  • Add CONTRIBUTING.md
scnlib - 0.1.1

Published by eliaskosunen over 5 years ago

Quick bugfix release

  • Add more examples
  • Fix #8: Fix segfault when using scn::cstdin() or scn::wcstdin(),
    caused by the copy and move constructor of small_vector setting data pointer to nullptr
    if copying/moving from an empty small_vector.
    (Thanks @SuperWig for reporting!)
  • Fix compilation error when using scn::ranges::get_value.
  • Fix a badge in README (thanks @p1v0t)
scnlib - 0.1

Published by eliaskosunen over 5 years ago

First release!