All Projects → eliaskosunen → Scnlib

eliaskosunen / Scnlib

Licence: apache-2.0
scanf for modern C++

Programming Languages

cpp
1120 projects

Projects that are alternatives of or similar to Scnlib

Tags Input
🔖 <input type="tags"> like magic
Stars: ✭ 312 (-13.09%)
Mutual labels:  input
Validator.js
String validation
Stars: ✭ 18,842 (+5148.47%)
Mutual labels:  input
Input Framer
Framer module to add inputs to your prototypes and easily turn your designs inputs into real inputs
Stars: ✭ 342 (-4.74%)
Mutual labels:  input
Tag
ID3, MP4 and OGG/FLAC metadata parsing in Go
Stars: ✭ 314 (-12.53%)
Mutual labels:  parsing
Rofimoji
An emoji and character picker for rofi 😁
Stars: ✭ 319 (-11.14%)
Mutual labels:  input
Estree
The ESTree Spec
Stars: ✭ 3,867 (+977.16%)
Mutual labels:  parsing
Rime Wubi86 Jidian
86五笔极点码表 for Rime (鼠须管 - macOS)(小狼毫 - Windows)五笔输入法
Stars: ✭ 302 (-15.88%)
Mutual labels:  input
Vncorenlp
A Vietnamese natural language processing toolkit (NAACL 2018)
Stars: ✭ 354 (-1.39%)
Mutual labels:  parsing
Libuv
Cross-platform asynchronous I/O
Stars: ✭ 18,615 (+5085.24%)
Mutual labels:  io
Como Lang Ng
como-lang-ng is now ana-lang, located at https://github.com/analang/ana
Stars: ✭ 342 (-4.74%)
Mutual labels:  parsing
Monio
Async-capable IO monad for JS
Stars: ✭ 311 (-13.37%)
Mutual labels:  io
Maya
Datetimes for Humans™
Stars: ✭ 3,298 (+818.66%)
Mutual labels:  parsing
Atto
friendly little parsers
Stars: ✭ 340 (-5.29%)
Mutual labels:  parsing
Vxe Table
🐬 vxe-table vue 表格解决方案
Stars: ✭ 4,242 (+1081.62%)
Mutual labels:  input
File Upload With Preview
🖼 A simple file-upload utility that shows a preview of the uploaded image. Written in pure JavaScript. No dependencies. Works well with Bootstrap 4 or without a framework.
Stars: ✭ 352 (-1.95%)
Mutual labels:  input
Pom
PEG parser combinators using operator overloading without macros.
Stars: ✭ 310 (-13.65%)
Mutual labels:  parsing
Clangkit
ClangKit provides an Objective-C frontend to LibClang. Source tokenization, diagnostics and fix-its are actually implemented.
Stars: ✭ 330 (-8.08%)
Mutual labels:  parsing
React Native Phone Input
Phone input box for React Native
Stars: ✭ 356 (-0.84%)
Mutual labels:  input
Reek
Code smell detector for Ruby
Stars: ✭ 3,693 (+928.69%)
Mutual labels:  parsing
Vue Numeric
Input field component to display a formatted currency value based on Vue.js
Stars: ✭ 341 (-5.01%)
Mutual labels:  input

scnlib

Linux macOS Windows Latest Release License C++ Standard

#include <scn/scn.h>
#include <cstdio>

int main() {
    int i;
    // Read an integer from stdin
    // with an accompanying message
    scn::prompt("What's your favorite number? ", "{}", i);
    printf("Oh, cool, %d!", i);
}

// Example result:
// What's your favorite number? 42
// Oh, cool, 42!

What is this?

scnlib is a modern C++ library for replacing scanf and std::istream. This library attempts to move us ever so closer to replacing iostreams and C stdio altogether. It's faster than iostream (see Benchmarks) and type-safe, unlike scanf. Think {fmt} but in the other direction.

This library is the reference implementation of the ISO C++ standards proposal P1729 "Text Parsing".

This library is currently of pre-release quality (version 0.4), but its interface and behavior should remain relatively stable. Unless significant design flaws can be found, the next major release will be 1.0-rc1. 1.0 will be released when an rc-version will prove itself reasonably bug-free.

Documentation

The documentation can be found online, from https://scnlib.readthedocs.io.

To build the docs yourself, build the doc and doc-sphinx targets generated by CMake. The doc target requires Doxygen, and doc-sphinx requires Python 3.8, Sphinx and Breathe.

Examples

Reading a std::string

#include <scn/scn.h>
#include <iostream>
#include <string_view>

int main() {
    std::string word;
    auto result = scn::scan("Hello world", "{}", word);

    std::cout << word << '\n'; // Will output "Hello"
    std::cout << result.string() << '\n';  // Will output " world!"
}

Reading multiple values

#include <scn/scn.h>

int main() {
    int i, j;
    auto result = scn::scan("123 456 foo", "{} {}", i, j);
    // result == true
    // i == 123
    // j == 456

    std::string str;
    ret = scn::scan(ret.range(), "{}", str);
    // result == true
    // str == "foo"
}

Using the tuple-return API

#include <scn/scn.h>
#include <scn/tuple_return.h>

int main() {
    auto [r, i] = scn::scan_tuple<int>("42", "{}");
    // r is a result object, contextually convertible to `bool`
    // i == 42
}

Error handling

#include <scn/scn.h>
#include <string_view>
#include <iostream>

int main() {
    int i;
    // "foo" is not a valid integer
    auto result = scn::scan("foo", "{}", i);
    if (!result) {
        // i is not touched (still unconstructed)
        // result.range() == "foo" (range not advanced)
        std::cout << "Integer parsing failed with message: " << result.error().msg() << '\n';
    }
}

Features

  • Blazing-fast parsing of values (see benchmarks)
  • Modern C++ interface, featuring type safety (variadic templates), convenience (ranges) and customizability
    • No << chevron >> hell
    • Requires C++11 or newer
  • "{python}"-like format string syntax
  • Optionally header only
  • Minimal code size increase (see benchmarks)
  • No exceptions (supports building with -fno-exceptions -fno-rtti with minimal loss of functionality)
    • Localization requires exceptions, because of the way std::locale is

Installing

scnlib uses CMake. If your project already uses CMake, integration is easy. First, clone, build, and install the library

# Whereever you cloned scnlib to
$ mkdir build
$ cd build
$ cmake ..
$ make -j
$ make install

Then, in your project:

# Find scnlib package
find_package(scn CONFIG REQUIRED)

# Target which you'd like to use scnlib
# scn::scn-header-only to use the header-only version
add_executable(my_program ...)
target_link_libraries(my_program scn::scn)

Alternatively, if you have scnlib downloaded somewhere, or maybe even bundled inside your project (like a git submodule), you can use add_subdirectory:

add_subdirectory(path/to/scnlib)

# like above
add_executable(my_program ...)
target_link_libraries(my_program scn::scn)

See docs for usage without CMake.

Compiler support

Every commit is tested with

  • gcc 5.5 and newer (until v10)
  • clang 6.0 and newer (until v10)
  • Visual Studio 2017 and 2019
  • gcc 10 on ARM, and clang on macOS

with very extreme warning flags (see cmake/flags.cmake) and with multiple build configurations for each compiler.

Other compilers and compiler versions may work, but it is not guaranteed. If your compiler does not work, it may be a bug in the library. However, support will not be provided for:

  • GCC 4.9 (or earlier): C++11 support is too buggy
  • VS 2015 (or earlier): unable to handle templates

Benchmarks

Run-time performance

Benchmark results

These benchmarks were run on a Ubuntu 20.04 machine running kernel version 5.4.0-52, with an Intel Core i5-6600K processor, and compiled with gcc version 9.3.0, with -O3 -DNDEBUG -march=native. The source code for the benchmarks can be seen in the benchmark directory.

You can run the benchmarks yourself by enabling SCN_BUILD_BENCHMARKS. SCN_BUILD_BENCHMARKS is enabled by default if scn is the root CMake project, and disabled otherwise.

$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release -DSCN_BUILD_BENCHMARKS=ON -DSCN_NATIVE_ARCH=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON ..
$ make -j
# choose benchmark to run in ./benchmark/runtime/*/bench-*
$ ./benchmark/runtime/integer/bench-int

Performance comparison benchmarks with Boost.Spirit.x3 can be found here

Times are in nanoseconds of CPU time. Lower is better.

Integer parsing (int)

Test std::stringstream sscanf scn::scan scn::scan_default
Test 1 274 96.5 43.0 40.3
Test 2 77.7 526 68.1 60.5

Floating-point parsing (double)

Test std::stringstream sscanf scn::scan
Test 1 416 164 167
Test 2 223 570 195

Reading random whitespace-separated strings

Character type scn::scan scn::scan and string_view std::stringstream
char 40.7 38.0 50.2
wchar_t 42.7 38.3 122

Test 1 vs. Test 2

In the above comparisons:

  • "Test 1" refers to parsing a single value from a string which only contains the string representation for that value. The time used for constructing parser state is included. For example, the source string could be "123". In this case, a parser is constructed, and a value (123) is parsed. This test is called "single" in the benchmark sources.
  • "Test 2" refers to the average time of parsing a value from a string containing multiple string representations separated by spaces. The time used for constructing parser state is not included. For example, the source string could be "123 456". In this case, a parser is constructed before the timer is started. Then, a single value is read from the source, and the source is advanced to the start of the next value. The time it took to parse a single value is averaged out. This test is called "repeated" in the benchmark sources.

Code size

Code size benchmarks test code bloat for nontrivial projects. It generates 25 translation units and reads values from stdin five times to simulate a medium sized project. The resulting executable size is shown in the following tables.

The code was compiled on Ubuntu 20.04 with g++ 9.3.0. scnlib is linked dynamically to level out the playing field compared to already dynamically linked libc and libstdc++. See the directory benchmark/bloat for more information, e.g. templates for each TU.

To run these tests yourself:

$ cd build
# For Debug
$ cmake -DCMAKE_BUILD_TYPE=Debug -DSCN_BLOAT=ON -DBUILD_SHARED_LIBS=ON -DSCN_INSTALL=OFF ..
# For Release
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DSCN_BLOAT=ON -DBUILD_SHARED_LIBS=ON -DSCN_INSTALL=OFF ..
# For Minimized Release
$ cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DSCN_BLOAT=ON -DBUILD_SHARED_LIBS=ON -DSCN_INSTALL=OFF ..

$ make -j
$ ./benchmark/bloat/run-bloat-tests.py ./benchmark/bloat

Sizes are in kibibytes (KiB). Lower is better.

Minimized build (-Os -DNDEBUG)

Method Executable size Stripped size
empty 18 14
scanf 23 18
std::istream / std::cin 25 18
scn::input 35 30
scn::input (header only) 138 98

Release build (-O3 -DNDEBUG)

Method Executable size Stripped size
empty 18 14
scanf 24 18
std::istream / std::cin 30 22
scn::input 41 34
scn::input (header only) 177 146

Debug build (-g)

Method Executable size Stripped size
empty 29 14
scanf 600 18
std::istream / std::cin 662 22
scn::input 1709 51
scn::input (header only) 6858 281

Build time

This test measures the time it takes to compile a binary when using different libraries. Note, that the time it takes to compile the library is not taken into account (unfair measurement against precompiled stdlibs).

These tests were run on an Ubuntu 20.04 machine with an i5-6600K and 16 GB of RAM, using GCC 9.3.0. The compiler flags for a debug build were -g, and -O3 -DNDEBUG for a release build.

To run these tests yourself, enable CMake flag SCN_BUILD_BUILDTIME. In order for these tests to work, c++ must point to a gcc-compatible C++ compiler binary, and a POSIX-compatible /usr/bin/time must be present.

$ cd build
$ cmake -DSCN_BUILD_BUILDTIME=ON ..
$ make -j
$ ./benchmark/buildtime/run-buildtime-tests.sh

Build time

Time is in seconds of CPU time (user time + sys/kernel time). Lower is better.

Method Debug Release
empty 0.03 0.04
scanf 0.24 0.25
std::istream / std::cin 0.29 0.31
scn::input 0.53 0.62
scn::input (header only) 1.38 2.54

Memory consumption

Memory is in mebibytes (MiB). Lower is better.

Method Debug Release
empty 22.3 23.9
scanf 47.0 46.7
std::istream / std::cin 55.2 54.7
scn::input 82.9 83.9
scn::input (header only) 143.1 167.6

Acknowledgements

The contents of this library are heavily influenced by {fmt} and its derivative works.
https://github.com/fmtlib/fmt

The bundled ranges implementation found from this library is based on NanoRange:
https://github.com/tcbrindle/NanoRange

License

scnlib is licensed under the Apache License, version 2.0.
Copyright (c) 2017 Elias Kosunen
See LICENSE for further details

See the directory licenses/ for third-party licensing information.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].