
Utility FSE Library
===================

Developed and maintained by Vojtěch Michal<br/> 
at eForce FEE Prague Formula, 2020, 2021

Universal collection of mostly header only libraries containing hopefully useful stuff: 
wrappers, helper functions and/or classes, as well as meta utilities like git commit querying.

## General overview

**Requirements**:
  - **CMake** ... tested on CMake 3.14
  - **Git** ... expected to be used as git submodule
  - Compilation requires language features of **C++20**

The library is separated into smaller 'modules', that are mostly independent of each other. Each 'module' has exactly one cmake file
situated in `ufsel/cmake` directory, that must be included in order to make use of functionality of corresponding module.
This cmake file automatically takes care of adding defines, compiler flags etc. to make requested module available.

The directory `ufsel/include` contains the C++ source code. Using a module (by means of including corresponding cmake file)
automatically adds this whole directory to the include path. All header files contain preprocessor guards that disable all functionality
by default. The functionality is enabled only when corresponding cmake script is included.
This functionality is internally implemented using preprocessor guards.<br/>
Including a header file and using its content without including corresponsing cmake file will lead to compile time error.<br/>
Please **do not define macros with prefix `UFSEL_`** unless noted otherwise - several customization points are implemented using macros,
otherwise macros starting with prefix `UFSEL_` are used internally by the library.

### Setup
The initial setup is performed in one step. Assuming you are in the directory tree of your project, execute shell command:
```
git submodule add https://eforce1.feld.cvut.cz/gitlab/vomi/ufsel
```
If you plan to use UFSEL as a submodule of your project hosted at eforce1.feld.cvut.cz Gitlab, then it will be necessary to change
its path in `.gitmodules`. Submodules hosted on the same server need to be referenced by relative path instead
(example [here](https://docs.gitlab.com/ee/ci/git_submodules.html)).

To use a specific 'module' X of UFSEL library to its full potential, include the cmake script corresponding to X in your `CMakeLists.txt`.
Add this line (or similar depending on your directory structure) to your `CMakeLists.txt` file:
```
include("${CMAKE_CURRENT_LIST_DIR}/ufsel/cmake/featureYouAreInterestedIn.cmake")
```
List of *features* you may be interested in follows. You can also check the directory `ufsel/cmake` to see precise file names. 

### Library configuration
Some libraries require further configuration by the user.<br/>
This configuration is implemented using dedicated configuration file, whose name is passed to the library using 
a preprocessor definition `UFSEL_CONFIGURATION_FILE`. Each library that needs such special care will state its expectations clearly, 
so refer to individual header files to learn more. Customization points will be implemented as type aliases or constants
wrapped by a namespace corresponding to given library.<br/>
For example the `BitOperations` library expects your configuration file to define several types and values wraped by
namespace `::ufsel::bit`. These types inform the library - among others - about the size of target machine native word.
The configuration may be done as follows:
```cpp
//File ufsel-configuration.hpp located in the application root
#pragma once
#include <cstdint>

namespace ufsel::bit {
	using machine_word = std::uint32_t;
}
```
```cmake
#in file toolchain.cmake
SET(CONFIG_FILES "-DUFSEL_CONFIGURATION_FILE=\"<ufsel-configuration.hpp>\"")
```

### Currently supported features

 - **QueryRepositoryState** ... Storesh SHA1 of ompiled git commit and allows you to query state of the repository at runtime
 - **BitOperations** ... Bit operations, integer slicing, bit iteration
 - **Itertools** ... Collection of helpers bringing Python-like syntax to C++ iteration
 - **Units** ... Collection of physical units. Defines literals, conversion operators and arithmetic.
 - **Assert** ... Implementation of macros `assert()` and `assert_unreachable()`
 - **Memory** ... Logic for advanced memory manipulation (static memory allocator for standard containers)
 - **Functional** ... Higher order functions and types enabling more precise control over the flow of control. Also algorithms for tuples.
 - **Traits** ... Generaly useful types and concepts, queries of properties of types etc.

 ## QueryRepositoryState

 Modifies the build process to issue a call to `git rev-parse` during compilation in order to retrieve the SHA1 hash of `HEAD`.
 Eight leading characters of the hash are then passed to the compiler as `-DUFSEL_GIT_COMMIT_HASH=wwxxyyzz`.
 
 Additionally, this feature detects whether the currently compiled git repository has dirty working tree with uncommitted changes.
The macro `UFSEL_GIT_REPO_DIRTY` is defined to either one or zero accordingly and may be used by client code. 

 Using this cmake module in your project activates the content of header `ufsel/sw_build.hpp`, which contains API to query
 the current repository state.
```cpp
//Synopsis of file include/ufsel/sw_build.hpp
namespace ufsel::git {
	std::uint32_t commit_hash();
	bool has_dirty_working_tree();
}
```

 ## BitOperations
 Header only library implementing 
  - common bitwise operations using variadic function templates,
  - reading and mutation of subsequences of underlying bits of integral values,
  - highly configurable iteration over bits of an integral value.

 All functionality is located within `namespace ufsel::bit`.
```cpp
//Synopsis of header file ufsel/bit.hpp
#include "bit_iterator.hpp"
#include "bit_operations.hpp"
```

```cpp
//Synopsis of header file include/ufsel/bit_iterator.hpp

namespace ufsel::bit {
	namespace iter {

		//Tag types. Objects of these types are used for iteration configuration using the | operator

		//What should we iterate on:
		namespace lvl {

			//Iterate over set bits
			struct ones_t;
			//Iterate over cleared bits
			struct zeros_t;
			//Iterate over all bits
			struct all_bits_t;

			constexpr inline lvl::ones_t ones;
			constexpr inline lvl::zeros_t zeros;
			constexpr inline lvl::all_bits_t all_bits;
		}

		//What shall be returned:
		namespace ret {

			//Return indices of selected bits
			struct indices_t;
			//Return bitmasks of selected bits
			struct bitmasks_t;
			//Return proxies to selected bits
			struct proxy_t;

			constexpr inline ret::indices_t indices;
			constexpr inline ret::bitmasks_t bitmasks;
			constexpr inline ret::proxy_t proxy;
		}

		//Which direction is resired:
		namespace dir {

			//Iteratation starts at the LSB and ends on the MSB
			struct fromLSB_t;
			//Iteratation starts at the MSB and ends on the LSB
			struct fromMSB_t;

			constexpr inline dir::fromMSB_t fromMSB;
			constexpr inline dir::fromLSB_t fromLSB;
		}

		/* Random access iterator traversing the low level bitwise representation of given integral value.
		Starts from least significant bit and goes to the most significant.
		Constructed using the 'begin_for' and 'end_for' static functions, as both begin and end have to keep a copy of iterated value.

		Dereferencing returns either zero iff given bit is cleared or a power of two if given bit is set (2 to the power of current index).
		Current position within the value (the current index) is retrievable.
		Suitable for use with std::reverse_iterator if iteration from msb to lsb is desired.

		Useable by all standard algorithms with iterator based API.*/
		template<typename T, bool use_reference = false>
		struct bit_iterator;

		/* Iterator type supporting iteration over separate bits using a range based for loop.
		Iteration runs over bitmasks (powers of two), not bit indices (e.g. 0 through 31)!
		For iteration over bit indices, see index_iterator

		Iteratively finds the least significant bit that has value equal to 'level' and returns it throught the * operator.
		Takes value to iterate over by value and thus modifications for the purpose of iteration do not propagate to external world.

		Example:
		for (int i : bitmask_iterator<int, 1>{0b1010'0101})
			//do something with i
		In this example, i goes through values 1, 4, 32 and 128 in this order. */
		template<typename T, typename level = lvl::all_bits_t, bool use_reference = false>
		struct bitmask_iterator;

		/* Iterator over separate bits of given value.
		Similar to bitmask_iterator, except that operator* returns index (e.g. 0 through 31 for 4 Byte integer) of current bit. */
		template<typename T, typename level = lvl::ones_t, bool use_reference = false>
		struct index_iterator;

		/* Iterator over separate bits of given value.
		Similar to bitmask_iterator, except that operator* returns proxy to the current bit. */
		template<typename T, typename level = lvl::ones_t, bool use_reference = false>
		struct proxy_iterator;

		//Alternative API for iteration

		namespace impl {

			//Metaclass propagating though the chain of pipe operators 
			//Exposes begin and end iterators to given value. Type of iterators is selected based on user's wish
			template<bool use_reference, typename T, typename Polarity = lvl::ones_t, typename Returnable = ret::indices_t, typename Direction = dir::fromLSB_t>
			struct Iterable;

			/* Modifies the mode of iteration.
			Supplying one_t or zero_t chooses which bits are selected by the iterator.
			Supplying indices_t or bitmasks_t chooses whether index or bitmask of given bit is returned.*/
			template<typename T, typename Polarity, typename Returnable, typename Direction, typename NewStuff, bool use_reference>
			constexpr auto operator|(Iterable<use_reference, T, Polarity, Returnable, Direction>&& lhs, NewStuff rhs);

		} //end namespace impl
	} //end namespace iter

	//Initiate readonly iteration over given value. 
	//Call to this function can be followed by | operators to customize the behaviour
	template<typename T>
	constexpr auto iterate(T value);

	//Initiate iteration over given value, allows mutation.
	//Call to this function can be followed by | operators to customize the behaviour
	template<typename T>
	constexpr auto iterate_mutable(T& value);

	template<typename T, typename rettype, typename polarity>
	constexpr auto make_iterator(T&& value);

	template<typename T, typename polarity>
	constexpr auto make_index_iterator(T&& value, polarity = {});

	template<typename T, typename polarity>
	constexpr auto make_bitmask_iterator(T&& value, polarity = {});

	template<typename T, typename polarity = iter::lvl::all_bits_t>
	constexpr auto make_proxy_iterator(T&& value, polarity = {});
} //end namespace ufsel::bit

```

```cpp

//Synopsis of file include/ufsel/bit_operations.hpp
namespace ufsel::bit {

	/*Returns bitwise disjunction of first argument (e.g. register value)
	and all subsequent arguments identifying separate bits or bitfields.*/
	template<typename T, typename ...Args>
	[[nodiscard]]
	constexpr T set(T value, Args ... args);

	//Mutates first argument INPLACE, sets all bitmasks specified by second and subsequent arguments
	template<typename T, typename ...Args>
	constexpr void set(std::reference_wrapper<T> value, Args ... args);

	//Returns an integer of type T with single bit with given index set
	template<typename T = machine_word>
	[[nodiscard]]
	constexpr T bit(int index);

	//Returns bitwise disjunction of all arguments. They are converted to T before folding over |
	template<typename T = machine_word, typename ...Args>
	[[nodiscard]]
	constexpr T bitmask(Args ... args);

	//Returns object of type T with lower 'width' bits set and the rest cleared
	template<typename T = machine_word>
	[[nodiscard]]
	constexpr T bitmask_of_width(int width);

	//Returns object of type T with only bits from range [higher:lower] (inclusive) set, others cleared
	template<typename T = machine_word>
	[[nodiscard]]
	constexpr T bitmask_between(int higher, int lower);

	//Returns reference to memory location with given address interpreted as type T
	template<typename T = machine_word>
	[[nodiscard]]
	inline volatile T& access_register(std::uintptr_t reg);

	//Returns reference to given memory location interpreted as type T
	template<typename T = machine_word>
	[[nodiscard]]
	inline volatile T& access_register(void volatile* reg);

	// Returns bitwise conjunction of 'value' and subsequent arguments.
	template<typename T, typename ...Args>
	[[nodiscard]]
	constexpr T get(T value, Args ... args);

	//Returns true iff all bits specified by bitmasks are set in value
	template<typename T, typename ...Args>
	[[nodiscard]]
	constexpr bool all_set(T value, Args ...bitmask);

	//Returns true iff all bits specified by indices are cleared in value
	template<typename T, typename ...Args>
	[[nodiscard]]
	constexpr bool all_cleared(T value, Args ...bitmask);

	/*Performs bitwise disjunction of subsequent arguments (bitmasks), negates
	the result and bitwise ands it to the first argument (e.g. a register value).*/
	template<typename T, typename ...Args>
	[[nodiscard]]
	constexpr T clear(T value, Args... args);

	// Clears bits of value matching given bitmasks. Operation is performed INPLACE
	template<typename T, typename ...Args>
	constexpr void clear(std::reference_wrapper<T> value, Args... args);

	/*Performs bitwise disjunction of subsequent arguments (bitmasks), negates
	the result and bitwise ands it to the first argument (e.g. a register value).*/
	template<typename T, typename ...Args>
	[[nodiscard]]
	constexpr T toggle(T value, Args... args);

	/*Performs bitwise disjunction of subsequent arguments (bitmasks), negates
	the result and bitwise ands it to the first argument (e.g. a register value) INPLACE.*/
	template<typename T, typename ...Args>
	constexpr void toggle(std::reference_wrapper<T> value, Args... args);

	//Clears bits of 'value' using 'mask' and overwrites them with 'new_value'.
	//Both mask and new_value are shifted by specified number of bits
	template<typename T, typename U>
	[[nodiscard]]
	constexpr T modify(T value, U mask, typename impl::type_identity<U>::type new_value, int shift = 0);

	//Clears bits of 'value' using 'mask' and overwrites them with 'new_value' INPLACE.
	//Both mask and new_value are shifted by specified number of bits
	template<typename T, typename U>
	constexpr void modify(std::reference_wrapper<T> value, U mask, typename impl::type_identity<U>::type new_value, int shift = 0);
	/*Type used to slice integers into bitfields of custom length and position
	Accepted by sliceable::operator[] that returns proxy to specified subsequence of bits*/
	struct slice;

	namespace impl {

		/*Readonly proxy class mediating access to contiguous subsequence of bits of an integer type T

		Implicitly convertible to T (this implicit conversion reads and returns the underlying bitfield)
		It should be noted that the value is shifted before being returned.
		This way underlying bitfield behaves as if it started at the lsb*/
		template<typename T>
		struct bit_proxy;

		/*Proxy class allowing access and modification of specified contiguous subsequence of bits of given integer

		Implicitly convertible to T (this implicit conversion reads and returns the underlying value)

		Assignable from T. Such operation overwrites underlying bits using the new value (if assigned to bitfield is
		not wide enough, only the lowest bits of the assigned value are taken, the rest discarded*/
		template<typename T>
		struct mutable_bit_proxy;
	}

	/* Wraps a value of integral type T and exposes operator[] allowing bitwise slicing.

	Underlying integer is assigned during construction. It is either stored using local copy
	or a reference, depending on the value of template parameter 'use_reference'. If a reference is used
	and the underlying value is mutated, this modification propagates to the original integer object.*/
	template<bool use_reference, typename T = machine_word>
	struct sliceable;

	//Specialization of sliceable, takes integer by value. Preferred over direct specialization of sliceable
	template<typename T>
	struct sliceable_value : public sliceable<false, T>;

	//Specialization of sliceable, takes integer by reference. Preferred over direct specialization of sliceable
	template<typename T>
	struct sliceable_reference : public sliceable<true, T>;

	/* Takes a reference to a register, reads its value and internally creates a sliceable_value with this initial value.
	All bitwise accesses are forwarded to this sliceable_value which gets modified. The final value is written
	back into the register when lifetime of this object ends (during the destructor call). */
	template<typename T = machine_word>
	struct sliceable_with_deffered_writeback : public sliceable_value<T>;


	//Deduction guides for the two specializations of sliceable
	template<typename T>
	sliceable_value(T)->sliceable_value<T>;

	template<typename T>
	sliceable_reference(T&)->sliceable_reference<T>;

} //end namespace ufsel::bit

namespace ufsel {
	constexpr bit::slice operator ""_to(unsigned long long higher);
}

```


 ### Bitwise operations:
Functions defined in this module oprate on powers of two (or more generally bitmasks) instead of bit indices.
To acquire power of two with bit `x` high, use the function `bit(x)`. e.g. the following holds: `static_assert(bit(11) == 2048);`.
The least significant bit has index zero. 

Most of the functions have two overloads. One is a pure function taking only values of its arguments and returning the result of computation.
The other takes `std::reference_wrapper` as the first argument and performs modification in place (result is immediatelly written back to memory).
The `reference_wrapper` overload is only a syntactic sugar as can be seen from the next example. The following two expressions have the same behavior:
  - `register = ufsel::bit::clear(register, bit(7), 0x1'00);`
  - `ufsel::bit::clear(std::ref(register), 128, 256);`

Functions in this module can be classified as follows:
- Bitmask generation functions: `bit`, `bitmask`, `bitmask_of_width`, `bitmask_between`
- Raw memory access: `access_register`
- Bitwise operations: `get`, `set`, `clear`, `toggle`
- Bitfield modification and querying: `modify`, `all_set`, `all_cleared`
- Blocking delay until some bitmask is set or cleared: 'wait_until_set', 'wait_until_cleared'

Please referer to `include/ufsel/bit_operations.hpp` for documentation of individual functions.

 ### Slicing integers into bitfields:
Objects of type `sliceable` wrap an integral value and expose `operator[]` whose return value is a proxy class.
Classes `bit_proxy` and `mutable_bit_proxy` facilitate read access to contiguous subsequences of bits of the stored value.
Furthermore, objects of type `mutable_bit_proxy` are assignable as well. 
Reads and writes though these types perform bit shifting automatically, the user should therefore use them as if all bitfields 
spanned bits `[length-1 : 0]`. 
If a written value is wider than the available number of bits, it is truncated modulo `2^(width)`.

Integral value can be wrapped by `sliceable` either by copy or by reference. In later case all reads and writes access the referenced
memory location. In former case, the copy of memory location is read and stored in an internal member variable, that is subsequently accessed. 
Choice between value and reference semantics is performed based on a non-type template parameter of type `sliceable`, 
or - more conveniently - using specialized types `sliceable_value` and `sliceable_reference`.

There exists a third variant of `sliceable` - the `sliceable_with_deffered_writeback`. This type uses the same value semantics
as `sliceable_value`, it howver keeps reference to the memory location as well and will copy the internal variable to referenced location
during destructor call. This type is especially optimized when modifying fields of a register one by one, because it buffers modifications
internally (hence is eligible to be placed in CPU register) and writes to memory only when object lifetime ends.

There are two overloads of `sliceable::operator[]`. One accepts plain int, in which
case the function returnsproxy to a single bit with specified index.
The other expects an object of type `slice`, whose constructor takes two indices - the higher 
and the lower end of desired bitfield (both indices are inclusive).
Syntactic sugar in the form of user-defined literal operator and overloaded comma operator on `sliceable`
allow the user to use syntax shown in the next example when constructing an object of type slice.

Example: statement
```cpp
//'15_to, 8' is the same as 'sliceable{15, 8}'
sliceable_value{reg}[15_to, 8] = 0x123`;
```
writes `0x23` to byte 1 of `reg`. No other bits are modified.
Since the `reg` has been wrapped by value, this write access does not propagate
to memory and hence is discarded a the end of this full expression (because of the end of temporary's lifetime).</br>
If `sliceable_reference` was used, then the modification would take effect immediatelly. </br>
If `sliceable_with_deffered_writeback` was used, then the modification would wait till object destructor. 
In this case the object would be a temporary, hence the writeback would occur at the end of full expression.
	
 ### Bitwise iteration:
TODO to be filled

 ## Itertools
 TODO to be filled

 ## Functional
TODO to be filled

 ## Units
 Configured by macros UFSEL_USING_UNIT_LITERALS and UFSEL_USING_UNITS. Defining them will 
 insert a declaration `using namespace ufsel::units` or `ufsel::units::literals` respectivelly
into the global namespace.<br/>
 TODO to be filled

## Traits
TODO to be filled


	
