Giter Site home page Giter Site logo

kaizen's Introduction

Build License: MIT

image

Kaizen

Collection of utilities and enhanced data structures for a wide range of C++ projects in a single header file kaizen.h

Design Philosophy

In pretty much any project written in C++, most of the time only about 1% of the code needs to execute super-fast. While the other 99% doesn't, it usually takes up most of the overall development time by far and, as any code, must therefore be written, read, understood and modified fast. One of the main goals of this library is to serve precisely that need of that 99%.

Over time, functions and tools similar to what can be found in this library make their way into the Standard. For obvious and often justifiable reasons, that process is slow, but even more unfortunately - even after they become available in the Standard, in practice they are not available in an average production code for at least another decade. The second goal of this library, therefore, is to make them available to those who want them today: simply #include "kaizen.h" and off you go.

Kaizen does not aim to be neither radiation-hardened nor generic for all imaginable scenarios and use cases right from the get-go. Instead, inspired by the Japanese concept of Kaizen, emphasizing frequent and gradual improvement, this library builds on top of STL and aims to provide a malleable and growing set of practical, simple and well-tested tools through a single header file that, like a Swiss army knife, includes just enough of everything that can be useful for a broad range of C++ projects right off the bat.

So, for example, even though STL containers were not meant to be derived from (in particular, their destructors are not virtual), zen::string derives from std::string in order to quickly, without having to implement all the conversion operators and delegate functions that a composition-based approach would require, provide the ability to convert to and from std::string at any point in the codebase whenever there's need for the richer interface of working with strings that zen::string provides. Nevertheless, zen::string and similarly derived types in zen do have all the necessary restrictions in place to prevent such dynamic allocations just in case.

This approach is rooted in the philosophy that in the vast majority of cases and projects, the benefits from these utilities far outweigh any theoretical dangers of for some reason allocating zen::string itself dynamically and then deleting it through a pointer to base std::string, whether accidentally or on purpose. Any codebase is far more likely to experience problems and corrosion from the regular breed of bugs that are much easier to make accidentally.

The latest kaizen.h release header can be downloaded from releases. The development version is generated during the build, see below.

Examples

Here's a taste of what you can do with Kaizen right out of the box:

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"))
}

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);

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

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(100, 300) == "");            // out-of-bounds indices are okay too
z.substring(  0,  -5) == "Test subst");  // just like in Python
z.substring(  5,  50) == "substrings");  // just like in Python

// 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"

Python-like printing:

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

Richer containers with many useful functions:

zen::vector<int> v;             // declare & use just like std::vector
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

Many more examples can be found here.

Ways to contribute

Circles signify a potential scale of involvement in terms of time and/or energy. Green circles signify the easy stuff, essentially requiring no coding. Yellow circles signify a potential need to code, although quite often a suggestion would do here as well. Red circles signify a clear need to code.

  1. ๐ŸŸข Review code & commits. Our commits follow the RAPID Practice and therefore are very easy to review.
  2. ๐ŸŸข Suggest a utility. If you have an idea for a common C++ utility code, feel free to suggest in our discussions.
  3. ๐ŸŸข Document. If you see any missing documentation or a discrepancy (wrong code, etc.).
  4. ๐ŸŸก Generalize a utility. If you see how to generalize any code in a meaningful way, like this.
  5. ๐ŸŸก Optimize. If you see how to optimize any code in a meaningful way.
  6. ๐ŸŸก Harden. If you see how to improve the robustness of any code (unhandled edge cases, etc.).
  7. ๐ŸŸก Reduce LOC. If you see ways to reduce lines of code (common sense - with no loss of readability).
  8. ๐Ÿ”ด Implement a utility. If you have a commonly useful utility piece of code.
  9. ๐Ÿ”ด Resolve an issue. Some are in the form of a "TODO" in code.
  10. ๐Ÿ”ด Add tests. There can never be enough tests that cover anything previously not covered.
  11. ๐Ÿ”ด Automate. If you see ways to automate any process and thus save iteration time.

Communication

Prerequisites for building

You'll need the GCC compiler for Linux or MSVC (comes with Visual Studio) for Windows development.

The project is probably more widely and more backward-compatible, but at the moment is being developed and tested with the following tools:

  1. Python 3.11
  2. MSVC 19.37
  3. GCC 9.4.0

Open the repo folder in your favorite IDE (on Windows, if you're not very used to Visual Studio, I recommend using Visual Studio Code with WSL) and follow the steps described below to run it on your system. The main() function simply runs the tests and prints out the report (see a sample screenshot below).

Build & Run on Windows & Linux (including WSL)

  1. Open a Terminal: You can open a terminal window by searching for "Terminal" in your Linux desktop's application menu or by using the keyboard shortcut (usually Ctrl+Alt+T).

  2. Navigate to Project Directory: Use the cd command to navigate to the directory where your project's CMakeLists.txt file is located. Replace path/to/your/cloned/kaizen with the actual path:

    cd path/to/your/cloned/kaizen
  3. Create a Build Directory: It's a good practice to create a separate directory for the build files to keep them isolated from the source files. Inside your project directory, run:

    mkdir build
    cd build
  4. Configure the Project with CMake: Now, from inside the build directory, run CMake to configure the project. This will read the CMakeLists.txt file and generate the necessary Makefiles for building the project. The .. at the end of the command tells CMake to look in the parent directory for the CMakeLists.txt file:

    cmake ..

This will generate convenience utility scripts runbuild_win.bat and runbuild_linx.sh that combine the next steps 5 and 6, so you can simply call the corresponding script for your environment.

NOTE: This will only work smoothly either within a Linux environment (including WSL) or from within a Windows terminal that's integrated into Visual Studio (not Visual Studio Code), where the integrated terminal automatically sets up all the necessary environment variables (pointing to the MSVC compiler cl.exe, etc.) that are automatically configured when you run Visual Studio's own developer command prompt.

If you run this from a Windows terminal inside another IDE like Visual Studio Code, you will probably get an error that looks like this:

-- Building for: NMake Makefiles
-- The C compiler identification is unknown
-- The CXX compiler identification is unknown
CMake Error at CMakeLists.txt:11 (project):
  The CMAKE_C_COMPILER:

    cl

  is not a full path and was not found in the PATH.

If you want to develop using MSVC compiler from Visual Studio Code, there are various ways of setting that up, please see online.

If you need to specify a particular version of g++ or any other build options, you can do so with additional arguments. For example, to set the C++ compiler to g++, you could use:

cmake -DCMAKE_CXX_COMPILER=g++ ..
  1. Compile the Project: After configuring, you can compile the project with:

    cmake --build .

    On Linux, you can also call make directly (does the same thing).

  2. Run the Executable: If the build is successful, you can run the resulting executable from the build directory.

    Linux:

    ./kaizen

    Windows:

    .\kaizen.exe

A build and run will produce a console output that will look like this:

image

kaizen's People

Contributors

heinsaar avatar sargishayrapetyan avatar armenbadal avatar aniketmdinde avatar

Stargazers

Levon Hovhannisyan avatar Azat Manukyan avatar Gagik Sargsyan avatar adrian.d avatar  avatar Brian Hall avatar  avatar  avatar  avatar

Watchers

 avatar

kaizen's Issues

Roadmap

Kaizen 1.0

Library

  • Add all STL containers
  • #3
  • Fuse useful stuff from Qt, Python & JS
  • Ensure all entities are in their right namespace
  • Ensure compilation shows no dangerous warnings
  • Ensure all kaizen.h functions are thoroughly tested
  • Ensure all zen entities have small usage examples in code

Metrics & Tests

  • Add static analysis and integrate with the flow
  • Show & visualize LOC growth for the past year
  • Show & visualize test cases per LOC for non-test dirs

DevOps

  • CI: Set up automated build
  • CI: Set up automated tests
  • CI: Run & cross-check appropriate tests on dev repo structure as well as on single header
  • Create benchmarks & their report format

Kaizen 2.0

  • Add performance tests
  • Maybe split into different translation units to parallelize compilation
  • Devise a way to reuse zen code internally, or keep deliberately decoupled?
    (in 1.0 lib headers are deliberately mostly unaware of each other)
  • Package Kaizen into a module

Only keep top-level zen namespace

Right now header file concatenation results in redundant (but, of course, harmless) reintroduction of namespace zen. For example:

namespace zen { // <----------------- LEAVE ONLY THIS OPENING

template<class T>
struct list : std::list<T>
{
...
};

} // namespace // <------------------ REMOVE


namespace zen { // <----------------- REMOVE

template<class T>
struct vector : std::vector<T>
{
...
};

} // namespace // <<----------------- LEAVE ONLY THIS CLOSING

Extend `ZEN_EXPECT` with composable `EQ`, `GT`, `LT`, etc.

This will allow expressions like:

ZEN_EXPECT(EQ(x, 4));
ZEN_EXPECT(IS_TRUE(expr));
ZEN_EXPECT(AND(GT(x, 0), LT(x, 10)));

Without sacrificing the simplicity of ZEN_EXPECT(expression) for the most common cases as well as staying backward compatible.

Other benefits of these constructs should be the ability to see the exact value of x at failure; for floating-point comparisons, and other special cases, specialized macros can provide tailored behavior that a universal macro cannot. For example, EXPECT_FLOAT_EQ and EXPECT_DOUBLE_EQ take into account the precision issues inherent in floating-point arithmetic, offering a more appropriate comparison than a straightforward equality check, and maybe more.

Use this advice as a starting point.

Check that all headers have `#pragma once`

Add this to the make_kaizen.py script:

def is_pragma_once_present(file_path):
    with open(file_path, 'r') as file:
        lines = file.readlines()
    for line in lines:
        linestrip = line.strip()
        if linestrip == '#pragma donce':
            return True
        elif not linestrip.startswith(('//', '/*', '*/', '*')) and linestrip:
            return False
    return False

def check_headers_in(directory):
    for root, _, files in os.walk(directory):
        for file in fnmatch.filter(files, '*.h*'): # .h and .hpp files
            file_path = os.path.join(root, file)
            if not is_pragma_once_present(file_path):
                print(f'WARNING: #pragma once NOT FOUND IN KAIZEN HEADER {file_path}')

Then, in the same script, call check_headers_in in __main__ for all directories from which Kaizen is composed. At the time of writing, those are:

zen_datas      = os.path.join(project_dir, 'zen/datas')
zen_functions  = os.path.join(project_dir, 'zen/functions')
zen_composites = os.path.join(project_dir, 'zen/composites')

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.