A header-only IO library implemented in C++20, internally a wrapper over stdio
.
The library is under development and subject to change. Contributions are welcome (but keep in mind that I’m very opinionated). You can also log an issue if you spot a bug or if you want a particular feature not already listed in TODO.
- Clean and consistent interface
- Pretty-printing STL containers and pointers
- Initializing (multiple) variables on read (no mutation necessary)
- No
sync_with_stdio
, so should be faster thaniostream
- No runtime format strings, so might be faster than
stdio
Add it to your Git project as a submodule:
git submodule add [email protected]:natewind/cleario.git
Or simply clone:
git clone --recurse-submodules [email protected]:natewind/cleario.git
Include the public interface:
#include "cleario/include.hpp"
To read a value of type T
:
auto const x = clear::read<T>(); // x: T
To read multiple values of types Ts
:
auto const xs = clear::read<Ts...>(); // xs: std::tuple<Ts...>
If the end of the file is reached or there are no values of type(s) T
/Ts
to read, the behaviour is undefined.
To read safely:
// maybe_x: std::optional<T>
auto const maybe_x = clear::safe_read<T>();
// maybe_xs: std::optional<std::tuple<Ts...>>
auto const maybe_xs = clear::safe_read<Ts...>();
auto const [a, b] = clear::read<char, char>(); // qw
auto const [t, f] = clear::read<bool, bool>(); // True False
Integral types (except for char) in different bases:
auto const a = clear::read<int>(); // 123
auto const b = clear::read<clear::bin<int>>(); // 0b1111011
auto const c = clear::read<clear::oct<int>>(); // 0o173
auto const d = clear::read<clear::hex<int>>(); // 0x7b
Explicit decimal base to read an integer into char
:
auto const e = clear::read<clear::dec<char>>(); // 123
If a read fails, characters from the input stream are consumed until the one that induced the failure.
To print one or more values without a newline:
clear::print("Helo, World! ", 42, ' ', true); // Hello, World! 42 True
With a newline:
clear::println("Helo, World! ", 42, ' ', true); // Hello, World! 42 True
To flush stdout
:
clear::flush();
All three functions return true
on success and false
on failure. print
/ println
aborts after the first unsuccessful write.
clear::println('a', 'b', 'c'); // abc
char const*
std::string
std::string_view
auto const str = std::string("Qwerty");
clear::println(str); // Qwerty
clear::println(true, ' ', false); // True False
Integral types (except for char) in different bases:
clear::println(150); // 150
clear::println(clear::bin {150}); // 0b10010110
clear::println(clear::oct {150}); // 0o226
clear::println(clear::hex {150}); // 0x96
Explicit decimal base to print char
as an integer:
clear::println(clear::dec {'q'}); // 113
float
double
long double
Chooses the shortest notation between std::chars_format::fixed
and std::chars_format::scientific
:
clear::println(3.14); // 3.14
clear::println(-0.0000000005); // -5e-10
T*
std::unique_ptr
std::shared_ptr
auto const x = 5;
auto const ptr = static_cast<void*>(&x);
clear::println(&x); // <int object at 0x7ffcb52c6c54>
clear::println(ptr); // <object at 0x7ffcb52c6c54>
clear::println(std::optional<int> {}); // None
clear::println(std::optional {12}); // Some(12)
clear::println(std::tuple(5, false, "qwerty")); // (5, False, qwerty)
T[]
std::array
std::vector
std::deque
std::forward_list
std::list
auto const vec = std::vector {1, 2, 3, 4, 5};
clear::println(vec); // [1, 2, 3, 4, 5]
std::set
std::multiset
std::unordered_set
std::unordered_multiset
auto const set = std::set {1, 2, 3, 4, 5};
clear::println(set); // {1, 2, 3, 4, 5}
std::map
std::multimap
std::unordered_map
std::unordered_multimap
auto const map = std::unordered_map {{"a", 1}, {"b", 2}, {"c", 3}, {"d", 4}, {"e", 5}};
clear::println(map); // {e: 5, c: 3, b: 2, d: 4, a: 1}
Consider a type:
struct Point { int x, y; };
To make it printable, implement print
for it by calling print
on already printable types:
template <>
auto clear::io::print(Point const &point) -> bool
{
return print('(', point.x, ", ", point.y, ')');
}
Try it out:
clear::println(Point {3, 4}); // (3, 4)
To open a file:
auto file = clear::open("file.txt", "w");
The access modes are the same ones used with std::fopen
(the default is "r+"
). Files are movable (but not copyable) and close automatically when leaving the scope.
To open a file safely (because it can fail):
auto maybe_file = clear::safe_open("maybe_file.txt", "w"); // returns std::optional
To write to a file, simply use print
/ println
and flush
as member functions:
file.println("Helo, World! ", 42, ' ', true);
if (maybe_file)
maybe_file->println("Helo, World! ", 42, ' ', true);
To read from a file, use read
/ safe_read
as a member function:
auto const [a, b] = open("input.txt").read<char, int>();