Wite
Wite is a small collection of routines and classes that aims to make easy things that should be easy in C++ but are not, for one reason or another.
Install / Use
/learn @kevinchannon/WiteREADME
<br>
<br>
<br>
Table of Contents
Note
Version 1.0.0 is now ready! If you try it and find any problems, please do make create and issue so that we can fix it for the next version and make Wite more useful on more platforms and environments :)
Wite
Wite stands for "Why isn't this easy!?". It's a collection of routines and classes that aims to make easy things that should be easy in C++ but are not, for one reason or another. The aim is to make a small library of things that can just be dropped into a project to make things a little easier. So, if you don't want the weight of introducing a dependency on Boost, or something, then maybe there's something here to help you. At the moment, Wite is header only, so good times! Just plop the files into your source tree and rock on.
The aim here is not to produce necessarily the most complete set of features, nor the most generic, nor the most performant, nor the most memory-efficient, nor, even, the safest implementations. If we were to make all those considerations, then we'd miss out on 99% of the usefulness, for the sake of 1% of the considerations. This is not to say that those considerations are not made, just that they're not the focus.
The focus is to provide things that are simple at the point of use, with implementations that are intuitive and can almost be guessed and just do the right thing in >~95% cases. That is Wite should be:
- Easy to obtain and include in a project
- Easy to call in the project's code
If you're a C++ beginner, then you should be able to acquire and use Wite in your project without too much of a headache. That's the aim. If this is not the case, then let me know, and we'll see what we can do to make it even easier :)
string::split is a good example. There isn't (currently) a standard library function for this and every codebase rolls its own, essentially. Sure, I could get it from Boost, but then I've pulled in quite a heavyweight dependency (or, I've had to exercise a relatively large amount of understanding in order not to pull in a large dependency). Wite's string::split takes one thing (a string-like thing) and returns a std::vector<std::string> with the result in it. Is this the most efficient thing in all cases? No. Is it good enough in 99% of cases? Probably.
If you're looking at some implementation inside Wite and thinking "this is definitely NOT the best way to do this!" and have an idea how to make it better, safer or more generic (without harming the most common case usability, of course) then go for it and raise an issue, or send a pull request, or something :)
Right, on with instructions on how to get going...
Prerequisites
Wite doesn't have any dependencies, so you don't have to worry about that sort of thing. If you're developing new features for Wite, then the tests have a dependency on Catch2, but that is handled by CMake FetchContent, so it should take care of itself (as long as you're connected to the internet). Wite pretty much requires that you're using C++20, so I guess that's a prerequisite of sorts.
Getting Wite
There are a bunch of ways you could choose to consume Wite, here are some possibilities
CMake FetchContent
If your project is CMake-based, then the preferred way to get going is by using CMake FetchContent. You can find an example project that does this in the wite-cmake-example repository.
NuGet
If you use NuGet, then see NuGet.org for more information on acquiring Wite via NuGet. If you're using Visual Studio for your project, then you can consume Wite via the NuGet integration it has. So, you right-click on your project, or solution, and then choose "Manage NuGet packages..." (or something like that) and then you should be able to search for Wite and include it in your project. For an example project that has Wite included this way, see the wite-vs-example repo.
Ain't nobody got time for package management!! Just tell me where to download it!
One of the above options should really be your first call, but if you're in a hurry and don't care about controlling the version, or getting updates and stuff like that, then just straight up downloading it and putting it in your source tree will also do the business. You can get it from here: Releases.
You'll want the "wite-src.zip" file for the version of your choice.
Building
Wite is header only, so there's no "building" of Wite by itself. The relevant bits will get built when you #include them in your files and then build your own project.
Some features of Wite are tunable by the user at compilation time. For a list of the macros that you can define as command-line parameters to the compiler, see the Compiler Macros section at the end of this readme.
Get Started
Once downloaded, or however you installed things, then you should be able to just #include the bit you want to use and get going. If you don't know which bit you want, then just #include <wite/wite.hpp> and you'll get everything.
Everything in Wite is in the wite namespace, and the various sub-parts are in their own sub-namespaces within this. So, the string stuff is all in wite::string and the maths stuff is all in wite::maths, and so on.
Core
#include <wite/core.hpp>
These are some small and very basic classes and functions that can be used in a wide variety of situations.
result
#include <wite/core/result.hpp>
In a world where exceptions are not the mechanism for handling errors, then "result codes" are basically the go-to alternative. These often take the form of an int value that's returned by a function that indicates the error state. Then you define a special value of that code to mean OK and you have a lot of code that looks like this:
// Result-code-returning function; takes a value to populate
int string_populator(std::string&);
...
auto my_string = std::string{};
auto rc = string_populator(my_string);
if (RC_OK != rc) {
// Handle the error gracefully
}
// Use `my_string` for something
This code is a little annoying because:
my_stringis first defined and default constructed and then passed the function to be populated via an ugly "output" argument.- If
string_populatorreturns an error, there has to be some statement somewhere about the state ofmy_stringin this case. Is it left as it was when you passed it in? Is its state undefined? does it get cleared? - There is nothing to prevent you accidentally using
my_stringif you ignore the result code (purposely, or not)
result is intended to be an alternative to this pattern that does not allow you to accidentally ignore the error state. So, the example above would look like this:
const auto string_result = string_maker();
if (string_result.is_error()) { // Alternatively call do `not string_result.ok()`
// Handle the error by calling string_result.error() to get at the error code
}
// Use the result by calling string_result.value() to get the string.
Defining a result type
result is a class template that looks like this:
template <typename Value_T, typename Error_T> class result;
So, you need to tell it what the good result looks like (i.e. a std::string in the example above) and what the bad result looks like, which could just be an int , or you could define some error_code enum, or even some specific class for the errors. Say we had some enum for the errors like:
enum class string_maker_error {
error_1,
error_2,
error_3,
...
error_N
};
Then we would define an alias for the result in this situation:
using string_maker_result = wite::result<std::string, string_maker_error>;
and then the prototype for string_maker just looks like:
string_maker_result string_maker();
And now we have a strongly-typed r
