Skip to content

Latest commit

 

History

History
211 lines (194 loc) · 6.51 KB

Examples.md

File metadata and controls

211 lines (194 loc) · 6.51 KB

Examples

Below you can find various examples of code snippets that demonstrate the capabilities of Kaizen.

Simply include the kaizen.h header. No additional setup is required. During development, the kaizen.h header is generated during build (see below for building).

Program arguments

Parse program arguments declaratively:

#include "kaizen.h"

int main(int argc, char* argv[])
{
    zen::cmd_args  args(argv, argc);
    bool verbose = args.accept("-verbose").is_present();
    bool ignore  = args.accept("-ignore" ).is_present();

    // For: -copy from/some/dir to/some/dir
    args.accept("-copy");
    args.get_options("-copy")[0] // "from/some/dir"
    args.get_options("-copy")[1] //   "to/some/dir"
    
    // Or sometime later
    if (args.is_present("-ignore"))
}

Working with files

Open a file and read any line right away:

zen::file             license_text("../LICENSE.txt"_path);
zen::string version = license_text.getline(1);
zen::string license = license_text.getline(3);

Simple ranges

Python-like range notation:

for (int i : zen::in(5))        // i from 0 to 4
for (int i : zen::in(1, 10))    // i from 1 to 9
for (int i : zen::in(0, 10, 2)) // i from 0 to 8, step 2

Our benchmarks consistently show that, for optimized builds, not only is there zero overhead from using zen::in() instead of a raw loop, but sometimes zen::in even ends up slightly faster (yes, faster) than the raw loop for both MSVC (the Visual Studio compiler) as well as GCC/Clang. Compiler optimizations can be full of surprises.

Strings

Python-like substring extractions:

// indices ----> 012345678912345
zen::string z = "Test substrings";

z.substring(  0,   4) == "Test");        // both arguments are indices
z.substring(-20,   4) == "Test");        // negative indices are okay
z.substring(  0,  -5) == "Test subst");  // just like in Python
z.substring(100, 300) == "");            // out-of-bounds indices are okay too
z.substring(  5,  50) == "substrings");  // just like in Python

Rich extraction methods from strings, both arbitrary patterns and common cases:

z = "Hey, [Hello World] 1.2.3 amazing 1/2/2023";

z.starts_with("Hey"))                    // true
z.extract_between('[', ']');             // "Hello World"
z.extract_version();                     // "1.2.3"
z.extract_pattern(R"((\d+\.\d+\.\d+))"); // "1.2.3"
z.extract_date();                        // "1/2/2023"
z.extract_pattern(R"((\d+\/\d+\/\d+))"); // "1/2/2023"

// A drop-in replacement for std::string
std::string x = z; z = x; // and so on

Replace a substring:

z = "I love apples, apples, apples";
z.replace(    "apples", "oranges"); // "I love oranges, apples, apples"
z.replace_all("apples", "oranges"); // "I love oranges, oranges, oranges"

Remove a substring:

z = "Some uninteresting text";
z.remove("uninteresting ");     // "Some text"

Trim whitespaces:

z =         "   Trim   me  ";
z.trim();   // "Trim   me" - from leading & trailing empty spaces
z.deflate() // "Trim me"   - any adjacent spaces are removed

Repeat a pattern of a string:

zen::repeat("/", 10) == "//////////";
zen::repeat(10, "*") == "**********";

Random numbers

Just give me a simple random number for everyday use:

int n = zen::random_int();    // by default between 0 and 10
int m = zen::random_int(1, 5) // or specify another range

Printing & Logging

Python-like printing with additional logging utilities:

std::vector<int> v = {1, 2, 3}
zen::print(v);                  // [1, 2, 3]
zen::print(v, "4", 5);          // [1, 2, 3] 4 5

Or even:

std::vector<std::vector<int>> v = { {1, 2}, {3, 4} };
zen::print(v);                  // [[1, 2], [3, 4]]

In addition, zen::log() is equivalent to zen::print() except that it will automatically append a new line:

zen::log(v, "4", 5); // equivalent to zen::print(v, "4", 5, '\n');

In general, zen::log() calls zen::print(), which, in turn, calls zen::to_string(), which is able to convert to a string a wide range of objects that are intuitively expected to be convertible to a string. For example:

std::vector<int> v  = { 1, 2, 3 };
zen::to_string(v); // [ 1, 2, 2 ]

With arbitrary nestedness of any containers:

std::vector<std::list<std::vector<int>>> vxv = { {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}} };
zen::to_string(vxv);                         // [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

Containers

Richer containers with many useful functions:

zen::vector<int> v;
zen::generate_random(v);  // randomly populate anything resizable & iterable
if (v.contains(42)) {     // easily check for containment
    zen::sum(v);          // easily sum up anything iterable with addable elements
}

// A drop-in replacement for std::vector
std::vector x = v; v = x; // and so on

The standard container::empty() can ambiguously be read as a verb, so Kaizen provides is_empty():

if (v.is_empty())     // same as v.empty()
if (zen::is_empty(c)) // same as c.empty(), works with any iterable container c

Quick tests

Sprinkle around some test cases with ZEN_EXPECT accepting any expression and reporting it if it fails:

const zen::string z = "Test Case";
const zen::vector v = {1, 2, 3, 4};
ZEN_EXPECT(z.ends_with("Case"));     // pass
ZEN_EXPECT(v.contains(7));           // fails, prints: CASE FAIL: ... EXPECTED: v.contains(7)

A static assert that shows the expression that failed:

// Will show something like:
// 'ZEN STATIC ASSERTION FAILED. "FAILED EXPRESSION:": zen::is_iterable_v<int>'
ZEN_STATIC_ASSERT(zen::is_iterable_v<int>, "FAILED EXPRESSION:");

Timer

A simple timer:

// Let's benchmark zen::in
zen::timer timer;
for (int i : zen::in(N)) {
    // Some computation
}
zen::log(timer.stop().duration_string());

Versions

Semantic versioning:

zen::version v1(1, 2, 3, 4567); // construct from numbers

// Expect
v1.major() ==    1;
v1.minor() ==    2;
v1.patch() ==    3;
v1.build() == 4567;

zen::version  v8("8.2.3.4567"); // construct from a string

// Expect
v8.major() ==    8;
v8.minor() ==    2;
v8.patch() ==    3;
v8.build() == 4567;

// Expect
v1 != v8;
v1 <  v8;
v8 >  v1;

using namespace zen::literals::version;

auto v7 = "7.6.5.4321"_version; // construct using string literals
v7.build()    == 4321;

Recursive dereferencing

Dereference any level of nested pointers:

int      _1 = 11;
int*     _2 = &_1;
int**    _3 = &_2;
int***   _4 = &_3;
int****  _5 = &_4;
int***** _6 = &_5;
// and so on

zen::deref(_1); // 11
zen::deref(_3); // 11
zen::deref(_6); // 11