diff --git a/code/bash/aliases.sh b/code/bash/aliases.sh new file mode 100644 index 0000000000000000000000000000000000000000..8f43bb2af89cf68980fe21add1f1d3af7a2c94df --- /dev/null +++ b/code/bash/aliases.sh @@ -0,0 +1,8 @@ +alias cf="clang-format --style=WebKit -i" +alias C="clang++ -std=c++20 -stdlib=libc++ -Ofast" +alias Cm="clang++ -std=c++20 -stdlib=libc++ -Ofast -fmodules -fimplicit-module-maps -fprebuilt-module-path=." +alias Cixx="clang++ -std=c++20 -stdlib=libc++ -Ofast -fmodules -fimplicit-module-maps --precompile -xc++-module -fprebuilt-module-path=." +alias G="g++ -std=c++20 -pedantic -Wall -O3" +alias Gm="g++ -std=c++20 -fmodules-ts -pedantic -Wall -O3" +alias Gh="g++ -std=c++20 -fmodules-ts -xc++-system-header -O3" + diff --git a/code/bash/pathutils.sh b/code/bash/pathutils.sh new file mode 100644 index 0000000000000000000000000000000000000000..4922204faa3a8ee4bc7d6bbde943474f37cab622 --- /dev/null +++ b/code/bash/pathutils.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# *********************************************** +# Programming in C++ +# 08 -- 12 May 2023 +# Jülich Supercomputing Centre +# *********************************************** + +rmspecial() { + sed -e 's/[]\/()$*.^|[]/\\&/g' <<< "$1" +} + +# Usage: +# prepend_path NAME_OF_PATH_ENV_VAR LOCATION_TO_PREPEND +prepend_path() { + local pathtochange prevpath + pathtochange=$1 + prevpath=${!pathtochange} + if [ -d "$2" ]; then + [[ ":${prevpath}:" != *":$2:"* ]] && prevpath="$2:${prevpath}" + fi + eval "export ${pathtochange}=${prevpath}" +} + +# Usage: +# remove_path_element NAME_OF_PATH_ENV_VAR LOCATION_TO_REMOVE_FROM_IT +remove_path_element() { + local pathtochange prevpath toremove + pathtochange=$1 + prevpath=${!pathtochange} + toremove=$(rmspecial $2) + prevpath=$(eval "echo ${prevpath} | sed -e 's#$toremove:##'") + prevpath=$(eval "echo ${prevpath} | sed -e 's#:$toremove##'") + eval "export ${pathtochange}=${prevpath}" +} + +# Usage: +# pathadd /a/b/c/bin +pathadd() { + prepend_path PATH $1 +} +# Usage: +# pathrm /a/b/c/bin +pathrm() { + remove_path_element PATH $1 +} +libpathadd() { + prepend_path LD_LIBRARY_PATH $1 + prepend_path LD_RUN_PATH $1 + prepend_path LIBRARY_PATH $1 +} +libpathrm() { + remove_path_element LD_LIBRARY_PATH $1 + remove_path_element LD_RUN_PATH $1 + remove_path_element LIBRARY_PATH $1 +} + +incpathadd() { + prepend_path CPATH $1 +} +incpathrm() { + remove_path_element CPATH $1 +} +manpathadd() { + prepend_path MANPATH $1 +} +manpathrm() { + remove_path_element MANPATH $1 +} +cmpathadd() { + prepend_path CMAKE_PREFIX_PATH $1 +} +cmpathrm() { + remove_path_element CMAKE_PREFIX_PATH $1 +} +pypathadd() { + prepend_path PYTHONPATH $1 +} +pycmpathrm() { + remove_path_element PYTHONPATH $1 +} + + diff --git a/code/include/CountingIterator.hh b/code/include/CountingIterator.hh new file mode 100644 index 0000000000000000000000000000000000000000..ab63f41b38f7bf846198805eb436a332f7dc9191 --- /dev/null +++ b/code/include/CountingIterator.hh @@ -0,0 +1,55 @@ +#pragma once +#include <iterator> +#include <type_traits> +#include <concepts> + +template <std::integral T> +struct CountingIterator { + using difference_type = std::make_signed_t<T>; + using value_type = T; + using pointer = T*; + using reference = T&; + using iterator_category = std::random_access_iterator_tag; + + constexpr auto operator++() noexcept -> CountingIterator { return { ++val }; } + constexpr auto operator++(int) noexcept -> CountingIterator { return { val++ }; } + constexpr auto operator--() noexcept -> CountingIterator { return { --val }; } + constexpr auto operator--(int) noexcept -> CountingIterator { return { val-- }; } + constexpr auto operator+=(difference_type d) + { + val += d; + return *this; + } + constexpr auto operator-=(difference_type d) + { + val -= d; + return *this; + } + constexpr auto operator<(CountingIterator other) const noexcept -> bool { return val < other.val; } + constexpr auto operator==(CountingIterator other) const noexcept -> bool { return val == other.val; } + constexpr auto operator!=(CountingIterator other) const noexcept -> bool { return val != other.val; } + constexpr auto operator>(CountingIterator other) const noexcept -> bool { return val > other.val; } + constexpr auto operator<=(CountingIterator other) const noexcept -> bool { return val <= other.val; } + constexpr auto operator>=(CountingIterator other) const noexcept -> bool { return val >= other.val; } + constexpr auto operator*() const noexcept { return val; } + constexpr auto operator*() noexcept -> auto& { return val; } + constexpr auto operator->() noexcept -> auto* { return &val; } + constexpr auto operator-(CountingIterator other) const noexcept -> difference_type { return val - other.val; } + constexpr auto operator+(difference_type d) const noexcept -> CountingIterator { return { val + d }; } + constexpr auto operator[](size_t d) const noexcept { return val + d; } + T val {}; +}; +template <std::integral T> +struct Sequence { + constexpr auto begin() const noexcept { return beg; } + constexpr auto end() const noexcept { return nde; } + using iterator = CountingIterator<T>; + iterator beg{}; + iterator nde{std::numeric_limits<T>::max()}; + Sequence(T b, T e) noexcept : beg{b}, nde{e} {} + explicit Sequence(T b) noexcept : beg{b} {} +}; + +template <std::integral T> +constexpr auto algo_counter(T t) noexcept -> CountingIterator<T> { return {t}; } + diff --git a/code/include/FileAsLines.hh b/code/include/FileAsLines.hh new file mode 100644 index 0000000000000000000000000000000000000000..73d5bb1e1d9584fbabd8a3731942cc133ab45e13 --- /dev/null +++ b/code/include/FileAsLines.hh @@ -0,0 +1,41 @@ +#pragma once +#include <filesystem> +#include <fstream> +#include <string> +#include <vector> + +class FileAsLines { +public: + using iterator = std::vector<std::string>::iterator; + void read(std::filesystem::path nm) + { + std::ifstream fin { nm }; + std::string line; + while (getline(fin, line)) + mylines.push_back(line); + } + FileAsLines(std::filesystem::path nm) { read(nm); } + FileAsLines() = default; + FileAsLines(const FileAsLines&) = default; + FileAsLines(FileAsLines&&) = default; + FileAsLines& operator=(const FileAsLines&) = default; + FileAsLines& operator=(FileAsLines&&) = default; + ~FileAsLines() = default; + inline size_t size() const { return mylines.size(); } + inline bool empty() const { return mylines.empty(); } + inline const std::string& operator[](size_t i) const { return mylines[i]; } + inline std::string& operator[](size_t i) { return mylines[i]; } + inline const std::string& front() const { return mylines.front(); } + inline std::string& front() { return mylines.front(); } + inline const std::string& back() const { return mylines.back(); } + inline std::string& back() { return mylines.back(); } + inline decltype(auto) begin() { return mylines.begin(); } + inline decltype(auto) end() { return mylines.end(); } + inline decltype(auto) begin() const { return mylines.cbegin(); } + inline decltype(auto) end() const { return mylines.cend(); } + +private: + std::vector<std::string> mylines; +}; +std::ostream& operator<<(std::ostream& os, const FileAsLines& lines); + diff --git a/code/include/Vbose.hh b/code/include/Vbose.hh new file mode 100644 index 0000000000000000000000000000000000000000..d55244b79a3f69c423907f521e65453b80773324 --- /dev/null +++ b/code/include/Vbose.hh @@ -0,0 +1,76 @@ +#pragma once + +#include <iomanip> +#include <iostream> +#include <string> + +class Vbose { +public: + Vbose() + { + std::cout << "Default constructor of object at " << ((size_t)this) << "\n"; + } + inline auto getval() const { return nm; } + inline void setval(const std::string& nw) { nm = nw; } + + Vbose(const Vbose& v) + : nm(v.nm) + { + std::cout << "Copy constructor of object at " << ((size_t)this) << ". "; + std::cout << "Source for copy is at " << ((size_t)&v) << "\n"; + } + Vbose(Vbose&& v) noexcept + : nm(std::move(v.nm)) + { + std::cout << "Move constructor of object at " << ((size_t)this) << ". "; + std::cout << "Source for move is at " << ((size_t)&v) << "\n"; + } + + Vbose(std::string gs) noexcept + : nm(gs) + { + std::cout << "Constructor of object at " << ((size_t)this) << ","; + std::cout << " using string " << std::quoted(gs) << "\n"; + } + + auto operator=(const Vbose& v) -> Vbose& + { + std::cout << "Assignment operator: LHS @ " << ((size_t)this) << "(" << nm << "), "; + std::cout << "RHS @ " << ((size_t)&v) << "(" << std::quoted(v.nm) << ")\n"; + if (this != &v) { + nm = v.nm; + } + return *this; + } + + auto operator=(Vbose&& v) -> Vbose& + { + std::cout << "Move assignment operator: LHS @ " << ((size_t)this) << "(" << std::quoted(nm) << "), "; + std::cout << "RHS @ " << ((size_t)&v) << "(" << std::quoted(v.nm) << ")\n"; + std::swap(nm, v.nm); + return *this; + } + + ~Vbose() + { + std::cout << "Destructor of object at " << ((size_t)this) << " with data " << std::quoted(nm) << "\n"; + } + + auto operator+(const Vbose& v) -> Vbose + { + std::cout << "Inside operator + ()\n"; + return {nm + "+" + v.nm}; + } + auto value() const noexcept -> std::string + { + return nm; + } + void value(const std::string& vl) + { + std::cout << "Changing internal value of object at " << ((size_t)this) << " from " << nm << " to " << vl << "\n"; + nm = vl; + } + +private: + std::string nm { "Uninitialized" }; +}; diff --git a/code/include/binform17.hh b/code/include/binform17.hh new file mode 100644 index 0000000000000000000000000000000000000000..d52ff9f5c779014322002c6b7eb1cba409469a76 --- /dev/null +++ b/code/include/binform17.hh @@ -0,0 +1,49 @@ +#include <iostream> +#include <bitset> +#include <cstddef> +#include <iomanip> + +namespace cxx2022 { +using byte = unsigned char; + +template <class T> +auto bits(T var) +{ + std::remove_cv_t<std::remove_reference_t<T>> loc{var}; + unsigned long bytes{0UL}; + byte* in = reinterpret_cast<byte *>(&loc); + byte* out = reinterpret_cast<byte *>(&bytes); + std::copy(in, in + sizeof(loc), out); + return std::bitset<8*sizeof(decltype(loc))>(bytes) ; +} + +void showbits(double var) +{ + std::cout << "bits for double value " << var << "\n"; + auto b = bits(var).to_string(); + std::cout << "raw = " << b << "\n"; + std::cout << "sign exponent mantissa\n" + << std::setw(6) << std::left << b[0] + << std::setw(16) << std::left << b.substr(1UL, 11) + << " " << b.substr(12) << "\n\n"; +} + +void showbits(float var) +{ + std::cout << "bits for float value " << var << "\n"; + auto b = bits(var).to_string(); + std::cout << "raw = " << b << "\n"; + std::cout << "sign exponent mantissa\n" + << std::setw(6) << std::left << b[0] + << std::setw(16) << std::left << b.substr(1UL, 8) + << " " << b.substr(9) << "\n\n"; +} + +template <class T> +void showbits(T var) +{ + std::cout << "bits for " << var << " with non-floating point type : " << bits(var) << "\n"; +} + +} + diff --git a/code/include/cxx20format b/code/include/cxx20format new file mode 100644 index 0000000000000000000000000000000000000000..029ba91ad96ca7e8fe11eba5d4545f3185f8f57d --- /dev/null +++ b/code/include/cxx20format @@ -0,0 +1,12 @@ +#include <version> +#ifdef __cpp_lib_format + #include<format> + using std::format; +#elif __has_include (<fmt/format.h>) + #define FMT_HEADER_ONLY + #include<fmt/core.h> + #include<fmt/format.h> + using fmt::format; + #warning Using external format.h header from the fmt library. +#endif + diff --git a/code/include/cxx20ranges b/code/include/cxx20ranges new file mode 100644 index 0000000000000000000000000000000000000000..989fe0678f4f85bb3e84064d75710094316f92fc --- /dev/null +++ b/code/include/cxx20ranges @@ -0,0 +1,14 @@ +#include <version> +#ifdef __cpp_lib_ranges + #include<ranges> + namespace sr = std::ranges; + namespace sv = std::views; +#elif __has_include (<range/v3/all.hpp>) + #include<range/v3/all.hpp> + namespace sr = ranges; + namespace sv = ranges::views; + #warning Using rangesv3 3rd party library +#else +#error No suitable header for C++20 ranges was found! +#endif + diff --git a/code/include/print_tuple.hh b/code/include/print_tuple.hh new file mode 100644 index 0000000000000000000000000000000000000000..7ea143f130ef4df6ff44b98a06b99cf54eb0130b --- /dev/null +++ b/code/include/print_tuple.hh @@ -0,0 +1,26 @@ +#pragma once +#include <tuple> +#include <iostream> +#include <iomanip> + +template <class ... Args> +std::ostream & operator<<(std::ostream & strm, const std::tuple<Args...> & t) +{ + using namespace std; + auto print_one = [&strm](const auto & onearg) -> ostream & { + using bare_type = remove_cv_t<remove_reference_t<decltype(onearg)>>; + if constexpr (is_same_v<bare_type, string>) + strm << quoted(onearg); + else + strm << onearg; + return strm; + }; + auto print_components = [&](const auto & ... args){ + ((print_one(args) << ", "), ...); + }; + strm << "["; + apply(print_components, t); + return strm <<"]"; +} + + diff --git a/code/include/range_output.hh b/code/include/range_output.hh new file mode 100644 index 0000000000000000000000000000000000000000..65508ea662b844944d0a06891f8e2b3a1832359c --- /dev/null +++ b/code/include/range_output.hh @@ -0,0 +1,113 @@ +#pragma once +#include <algorithm> +#include <iomanip> +#include <iosfwd> +#include <cxx20ranges> +#include <string> + +namespace output { +template <class C> +concept RawArray = std::is_array_v<C>; +template <class C> +concept ArrayClass = requires(C c) +{ + { c[1ul] }; + { c.size() }; +}; + +template <class C> +concept StringLike = std::convertible_to<C, std::string_view>; + +namespace { + //auto size(const Container auto& C) { return C.size(); } + auto size(const RawArray auto& C) { return std::extent_v<std::remove_cvref_t<decltype(C)>>; } +} + +template <class C> +concept ArrayLike = (not StringLike<C>)and(ArrayClass<C> or RawArray<C>); + +template <class T> +void write_possibly_quoted(std::ostream& os, T&& t) +{ + if constexpr (StringLike<T>) { + os << std::quoted(t); + } else { + os << t; + } +} + +std::ostream& operator<<(std::ostream& os, const ArrayLike auto& c) +{ + os << "["; + auto sz = size(c); + for (size_t i {}; i != sz; ++i) { + write_possibly_quoted(os, c[i]); + if (i + 1 < sz) + os << ", "; + } + return os << "]"; +} + +template <class T> +requires(not StringLike<T> and sr::range<T>) + std::ostream& + operator<<(std::ostream& os, T&& r) +{ + os << "["; + for (auto el : r) { + write_possibly_quoted(os, el); + os << ", "; + } + return os << "]"; +} +template <class SepType> +class rprinter { + std::ostream* strmptr = nullptr; + SepType sep; + +public: + rprinter(SepType s) + : sep { s } + { + } + rprinter(const rprinter&) noexcept = default; + std::ostream& stream() { return *strmptr; } + void stream(std::ostream& os) { strmptr = &os; } + const auto& separator() const noexcept { return sep; } +}; +template <> +class rprinter<void> { + std::ostream* strmptr = nullptr; + +public: + std::ostream& stream() { return *strmptr; } + void stream(std::ostream& os) { strmptr = &os; } +}; + +template <class T> +rprinter<T> operator<<(std::ostream& os, rprinter<T> r) +{ + r.stream(os); + return { r }; +} +template <class T> +std::ostream& operator<<(rprinter<T> vp, sr::range auto&& t) +{ + if constexpr (std::is_same_v<T, void>) { + for (auto&& el : t) + vp.stream() << el; + } else { + if (not sr::empty(t)) { + vp.stream() << *sr::begin(t); + sr::for_each(t | sv::drop(1), [&vp](auto&& el) { + vp.stream() << vp.separator() << el; + }); + } + } + return vp.stream(); +} + +inline rprinter<void> unseparated; +inline rprinter<const char*> comma_separated { ", " }; + +} diff --git a/code/include/timeit.hh b/code/include/timeit.hh new file mode 100644 index 0000000000000000000000000000000000000000..6201609dcac252bd91782db45d7cff7335630754 --- /dev/null +++ b/code/include/timeit.hh @@ -0,0 +1,65 @@ +#pragma once + +#include <chrono> +#include <cmath> +#include <iostream> +#include <string_view> + +template <typename Callable, typename... Args> +void timeit(std::string_view testname, unsigned reps, Callable&& f, Args&&... args) +{ + using namespace std::chrono; + double tmin {}, tmax {}, ttot {}, t2tot {}; + for (auto i = 0u; i < reps; ++i) { + auto start = high_resolution_clock::now(); + std::forward<Callable>(f)(std::forward<Args>(args)...); + auto end = high_resolution_clock::now(); + auto intv = duration<double>(end - start).count(); + if (i == 0u) { + tmin = tmax = intv; + } else { + tmax = std::max(tmax, intv); + tmin = std::min(tmin, intv); + } + ttot += intv; + t2tot += (intv * intv); + } + enum class TUnit { sec, + msec, + usec, + nsec }; + TUnit u = TUnit::sec; + if (tmin < 1.0) + u = TUnit::msec; + if (tmin < 1.e-3) + u = TUnit::usec; + if (tmin < 1.e-6) + u = TUnit::nsec; + double tmean = ttot / reps; + double t2mean = t2tot / reps; + double tstdv = sqrt(t2mean - tmean * tmean); + std::string unitstring { " seconds" }; + double conv { 1.0 }; + switch (u) { + case TUnit::msec: + unitstring = " milliseconds"; + conv = 1000.0; + break; + case TUnit::usec: + unitstring = " microseconds"; + conv = 1000000.0; + break; + case TUnit::nsec: + unitstring = " nanoseconds"; + conv = 1000000000.0; + break; + case TUnit::sec: + default: + break; + }; + std::cout << "Timing results for " << testname << " from " << reps << " repeatitions...\n"; + std::cout << "Mean = " << tmean * conv << unitstring << "\n"; + std::cout << "Std. dev = " << tstdv * conv << unitstring << "\n"; + std::cout << "Minimum = " << tmin * conv << unitstring << "\n"; + std::cout << "Maximum = " << tmax * conv << unitstring << "\n"; +}