examples

Toy examples in single C files.
Log | Files | Refs

commit 2ab69cd62797c8ed33a89ff22c276d609eb94ca2
Author: Henry Wilson <henry@henryandlizzy.uk>
Date:   Thu, 25 Nov 2021 21:06:52 +0000

initial commit

Diffstat:
A.gitignore | 5+++++
Amakefile | 25+++++++++++++++++++++++++
Asrc/aio.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/aio.cpp | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/atexit.cpp | 33+++++++++++++++++++++++++++++++++
Asrc/bit_cast.cpp | 10++++++++++
Asrc/cat.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/cie-1931.cpp | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/clock-test.c | 21+++++++++++++++++++++
Asrc/cobs.c | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/coro.cpp | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/crc-table.c | 25+++++++++++++++++++++++++
Asrc/crc7.cpp | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/flat-set.cpp | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gl-asteroids.cpp | 310+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/guess-number.c | 40++++++++++++++++++++++++++++++++++++++++
Asrc/hush.cpp | 39+++++++++++++++++++++++++++++++++++++++
Asrc/io_uring.cpp | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/mmallocator.cpp | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/model.cpp | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/morse.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/pulse-simple-client.c | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/regex.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/robin.cpp | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sorts.cpp | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/triple-buf.cpp | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/whichtty.c | 14++++++++++++++
27 files changed, 2210 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,5 @@ +* + +!*.* +!*/ +!makefile diff --git a/makefile b/makefile @@ -0,0 +1,25 @@ +CXXFLAGS := -std=c++20 + + +c_sources := $(wildcard src/*.c) +cpp_sources := $(wildcard src/*.cpp) + +c_targets := $(notdir $(basename $(c_sources))) +cpp_targets := $(notdir $(basename $(cpp_sources))) + +VPATH := src + +all: all-c all-c++ + +all-c: $(c_targets) +all-c++: $(cpp_targets) + +clean: + $(RM) $(c_targets) $(cpp_targets) + +aio: -lrt +io_uring: -luring +pulse-simple-client: -lpulse-simple -lm +gl-asteroids: -lglfw -lGL -lm + +.PHONY: clean all all-c all-cpp diff --git a/src/aio.c b/src/aio.c @@ -0,0 +1,98 @@ +#include <aio.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <errno.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +int main(int argc, char* argv[]) +{ + ++argv; + --argc; + + unsigned int width = 0; + + char* bufs[argc]; + struct aiocb aios[argc]; + struct aiocb* liop[argc]; + + for (int i = 0; i < argc; ++i) + { + struct aiocb* a = aios + i; + int f = open(argv[i], O_RDONLY); + struct stat s; + + fstat(f, &s); + + if (!S_ISREG(s.st_mode)) + { + printf("%s not a regular file!\n", argv[i]); + exit(1); + } + + bufs[i] = malloc(s.st_size); + + a->aio_fildes = f; + a->aio_lio_opcode = LIO_READ; + a->aio_offset = 0; + a->aio_buf = bufs[i]; + a->aio_nbytes = (size_t)s.st_size; + a->aio_sigevent.sigev_notify = SIGEV_NONE; + a->aio_reqprio = 0; + + liop[i] = a; + + unsigned len = strlen(argv[i]); + if (len > width) + width = len; + } + + lio_listio(LIO_NOWAIT, liop, argc, NULL); + + int cycles = 0; + + while (argc) + { + printf("cycle %u:\n", ++cycles); + aio_suspend((struct aiocb const* const*)liop, argc, NULL); + + for (int i = 0; i < argc; ) + { + switch(aio_error(liop[i])) + { + case EINPROGRESS: + ++i; + continue; + + case 0: + + break; + default: + exit(1); + } + + size_t size = aio_return(liop[i]); + char* str = bufs[i], *end = str + size; + unsigned lines = 0; + + while (str < end) + if (*str++ == '\n') + ++lines; + + free(bufs[i]); + printf(" %*s: %6lu bytes, %4u lines\n", width, argv[i], size, lines); + if (i >= --argc) + break; + + bufs[i] = bufs[argc]; + argv[i] = argv[argc]; + liop[i] = liop[argc]; + } + } + + return 0; +} + diff --git a/src/aio.cpp b/src/aio.cpp @@ -0,0 +1,80 @@ +#include <iostream> +#include <vector> +#include <iomanip> + +#include <aio.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <dirent.h> + +struct x +{ + struct aiocb a; + dirent e; + char buf[]; +}; + +int main(int argc, char* argv[]) +{ + DIR* d = opendir("."); + int dfd = dirfd(d); + + std::vector<struct aiocb*> liop; + + while (auto e = readdir(d)) + { + if (DT_REG != e->d_type) + continue; + + int f = openat(dfd, e->d_name, O_RDONLY); + + struct stat s; + fstat(f, &s); + + struct x* buf = (struct x*)malloc(sizeof(struct x) + s.st_size); + buf->a = {f, LIO_READ, 0, &buf->buf, (size_t)s.st_size, {SIGEV_NONE}, 0}; + buf->e = *e; + + liop.push_back(&buf->a); + } + + lio_listio(LIO_NOWAIT, liop.data(), liop.size(), NULL); + + int outstanding = liop.size(); + int cycles = 0; + + while (outstanding) + { + ++cycles; + aio_suspend(liop.data(), liop.size(), NULL); + for (auto& iop : liop) + { + if (!iop) + continue; + + size_t b = iop->aio_nbytes; + char* s = (char*)const_cast<void*>(iop->aio_buf), *end = s + b; + struct x* x = (struct x*)(s - offsetof(struct x, buf)); + unsigned n = 0; + + if (int err = aio_error(iop); err == EINPROGRESS) + continue; + else if (err) + exit(1); + + iop = nullptr; + --outstanding; + while (s < end) + if (*s++ == '\n') + ++n; + + using std::cout, std::setw; + + cout << setw(20) << x->e.d_name << ": " << setw(6) << b << " bytes, " << setw(4) << n << " lines, cycle " << cycles << '\n'; + } + } + + std::cout << "Read after " << cycles << " cycles\n"; + return 0; +} + diff --git a/src/atexit.cpp b/src/atexit.cpp @@ -0,0 +1,33 @@ +#include <cstdio> +#include <cstdlib> + +struct foo +{ + ~foo() + { + puts(__PRETTY_FUNCTION__); + } +}; + +static void atexit_func() +{ + puts(__PRETTY_FUNCTION__); +} +static void at_quick_exit_func() +{ + puts(__PRETTY_FUNCTION__); +} + + +int main() +{ + auto x = foo(); + + std::atexit(atexit_func); + std::at_quick_exit(at_quick_exit_func); + + +// std::_Exit(0); +// std::quick_exit(0); +// std::exit(0); +} diff --git a/src/bit_cast.cpp b/src/bit_cast.cpp @@ -0,0 +1,10 @@ +#include <bit> +#include <iostream> + +using namespace std; + +int main() +{ + std::cout << (endian::native == endian::big ? "big\n" : "little\n"); + return 0; +} diff --git a/src/cat.c b/src/cat.c @@ -0,0 +1,68 @@ +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +static void die(char const* str) +{ + perror(str); + exit(EXIT_FAILURE); +} + +static void do_write(char const* buf, ssize_t size) +{ + while (size) + { + ssize_t n = write(1, buf, size); + if (n < 0) + die("write"); + + buf += n; + size -= n; + } +} + +int main(int argc, char const* argv[]) +{ + struct stat s; + int fds[argc]; + + --argc; + ++argv; + + if (argc == 0) + { + argv[0] = "-"; + ++argc; + } + + for (int i = 0; i < argc; ++i) + { + char const* path = argv[i]; + + if (!strcmp("-", path)) + fds[i] = 0; + else if (stat(path, &s)) + die("stat"); + else if ((fds[i] = open(path, O_RDONLY)) < 0) + die("open"); + } + + for (int i = 0; i < argc; ++i) + { + char buf[4096]; + ssize_t n; + int fd = fds[i]; + + while ((n = read(fd, buf, sizeof(buf))) > 0) + do_write(buf, n); + if (n < 0) + die("read"); + + close(fd); + } + return EXIT_SUCCESS; +} diff --git a/src/cie-1931.cpp b/src/cie-1931.cpp @@ -0,0 +1,102 @@ +#include <cmath> +#include <iostream> +#include <sstream> + +inline double gaussian(double x, double a, double u, double s1, double s2) { + double t = (x - u) / (x < u ? s1 : s2); + return a * exp(-(t * t) / 2); +} + +struct XYZ +{ + double x = 0, y = 0, z = 0; + + XYZ() = default; + XYZ(double _x, double _y, double _z) + : x(_x) + , y(_y) + , z(_z) + {} + + XYZ(double w) + : x(gaussian(w, 1.056, 599.8, 37.9, 31.0) + gaussian(w, 0.362, 442.0, 16.0, 26.7) + gaussian(w, -0.065, 501.1, 20.4, 26.2)) + , y(gaussian(w, 0.821, 568.8, 46.9, 40.5) + gaussian(w, 0.286, 530.9, 16.3, 31.1)) + , z(gaussian(w, 1.217, 437.0, 11.8, 36.0) + gaussian(w, 0.681, 459.0, 26.0, 13.8)) + {} + + XYZ operator *(double mult) const + { + return XYZ{x*mult, y*mult, z*mult}; + } + XYZ& operator +=(XYZ rhs) + { + x += rhs.x; + y += rhs.y; + z += rhs.z; + return *this; + } + double sum(void) const + { + return x + y + z; + } +}; + +struct XYZ xyzFromWavelength(double x) { + struct XYZ color; + return color; +} + +struct XYZ xyzFromWavelengthDistribution(double x, double s) +{ + struct XYZ color; + double delta = 0.1; + + for (double l = 380; l <= 780; l += delta) + color += xyzFromWavelength(l) *gaussian(l, 1, x, s, s); + + return color * delta; +} + +int main(int argc, char* argv[]) +{ +/**/ + if (2 > argc || argc > 3) + { + std::cerr << "cie-1931 wavelength [spread]\n"; + return 1; + } + + double x[2]; + + for (int i = 1; i < argc; ++i) + { + std::string num(argv[i]); + std::istringstream ss(num); + + if (not (ss >> x[i-1])) + { + std::cerr << "Wavelength must be in nanometers\n"; + return 1; + } + } + + struct XYZ xyz; + if (argc == 2) + { + xyz = xyzFromWavelength(x[0]); + std::cout << x[0] << "nm\n\n"; + } else + { + xyz = xyzFromWavelengthDistribution(x[0], x[1]); + std::cout << x[0] << "nm +-(" << x[1] << ")\n\n"; + } +/**/ + + std::cout << "X: " << xyz.x << "\nY: " << xyz.y << "\nZ: " << xyz.z << "\n\n"; + + double sum = xyz.sum(); + + std::cout << "x: " << (xyz.x / sum) << "\ny: " << (xyz.y / sum) << "\n"; + + return 0; +} diff --git a/src/clock-test.c b/src/clock-test.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <unistd.h> +#include <time.h> + +int main() +{ + struct timespec res, tp1, tp2; + + clock_getres(CLOCK_MONOTONIC, &res); + + clock_gettime(CLOCK_MONOTONIC, &tp1); + usleep(100); + clock_gettime(CLOCK_MONOTONIC, &tp2); + + printf("resolution: %ld sec %ld ns\n", res.tv_sec, res.tv_nsec); + printf("time1: %ld / %ld\n", tp1.tv_sec, tp1.tv_nsec); + printf("time2: %ld / %ld\n", tp2.tv_sec, tp2.tv_nsec); + printf("diff: %ld ns\n", (tp2.tv_sec - tp1.tv_sec) * 1000000000 + tp2.tv_nsec - tp1.tv_nsec); + + return 0; +} diff --git a/src/cobs.c b/src/cobs.c @@ -0,0 +1,141 @@ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +size_t cobs_encoded_max_size(size_t size) +{ + return 2 + size + size/254; +} + +size_t cobs_encode(void* buf, void const* data, size_t len) +{ + unsigned char const* in = data, *end = in + len; + unsigned char* out = buf; + unsigned char* code_out = out++; + + while (in != end) + { + if (out - code_out == 0xFF) + { + *code_out = 0xFF; + code_out = out++; + continue; + } + + if (*in) + { + *out++ = *in; + } + else + { + *code_out = out - code_out; + code_out = out++; + } + ++in; + } + + *code_out = out - code_out; + *out++ = 0; + + assert(out - (unsigned char*)buf <= cobs_encoded_max_size(len)); + return out - (unsigned char*)buf; +} + +size_t cobs_decode(void* buf, void const* data, size_t len) +{ + unsigned char const* in = data, *end = in + len; + unsigned char* out = buf; + unsigned char n = 0xFF; + + if (!in[len-1]) // not zero terminated + return 0; + + while (*in) + { + if (n != 0xFF) + *out++ = 0; + + n = *in; + + if (in + n >= end) // overrun + return 0; + + memcpy(out, in + 1, n - 1); + out += n - 1; + in += n; + } + + if (in + 1 != end) // underrun + return 0; + + return out - (unsigned char*)buf; +} + +struct +{ + size_t de_siz; + unsigned char* decoded, *encoded; +} const tests[] = { + {1, "\0", "\x01\x01"}, + {1, "A", "\x02" "A"}, + {2, "\0\0", "\x01\x01\x01"}, + {4, "AB\0C", "\x03""AB\x02""C"}, + {4, "ABCD", "\x05""ABCD"}, + {4, "A\0\0\0", "\x02""A\x01\x01\x01"}, +}; + +void encode_and_print(void* in, size_t size) +{ + unsigned char buf[1024]; + size_t n = cobs_encode(buf, in, size); + printf("(%lu)", n); + for (unsigned j = 0; j < 4; ++j) + printf(" %2x", buf[j]); + printf(" ..."); + for (unsigned j = n - 5; j < n; ++j) + printf(" %2x", buf[j]); + putchar('\n'); +} +int main(void) +{ + unsigned char buf[1024]; + unsigned char buf2[1024]; + for (unsigned i = 0; i < sizeof(tests) / sizeof(*tests); ++i) + { + memset(buf, '?', sizeof(buf)); + size_t n = cobs_encode(buf, tests[i].decoded, tests[i].de_siz); + assert(strlen(tests[i].encoded)+1 == n); + assert(!memcmp(buf, tests[i].encoded, n)); + n = cobs_decode(buf2, buf, n); + assert(tests[i].de_siz == n); + assert(!memcmp(buf2, tests[i].decoded, n)); + + printf("%u OK\n", i); + } + + unsigned char in[512]; + + for (unsigned i = 0; i < 0xFE; ++i) // 01 -> FE + in[i] = i+1; + encode_and_print(in, 0xFE); + + for (unsigned i = 0; i < 0xFF; ++i) // 00 -> FE + in[i] = i; + encode_and_print(in, 0xFF); + + for (unsigned i = 0; i < 0xFF; ++i) // 01 -> FF + in[i] = i+1; + encode_and_print(in, 0xFF); + + for (unsigned i = 0; i < 0xFF; ++i) // 02 -> FF 00 + in[i] = i+2; + encode_and_print(in, 0xFF); + + for (unsigned i = 0; i < 0xFF; ++i) // 03 -> FF 00 01 + in[i] = i+3; + encode_and_print(in, 0xFF); + + + return 0; +} diff --git a/src/coro.cpp b/src/coro.cpp @@ -0,0 +1,113 @@ +#include <coroutine> +#include <iostream> +#include <vector> + +struct unique_coroutine +{ + struct promise_type + { + ~promise_type() + {} + unique_coroutine get_return_object() { return *this; } + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() {} + void return_void() {} + }; + + unique_coroutine(promise_type& p) + : h(std::coroutine_handle<promise_type>::from_promise(p)) + {} + + ~unique_coroutine() + { + if (h) + h.destroy(); + } + + unique_coroutine(unique_coroutine const&) = delete; + unique_coroutine& operator =(unique_coroutine const&) = delete; + + unique_coroutine(unique_coroutine&& old) + : h(old.h) + { + old.h = h.from_address(nullptr); + } + + unique_coroutine& operator =(unique_coroutine&& old) + { + if (&old == this) + return *this; + + if (h) + h.destroy(); + + h = old.h; + old.h = h.from_address(nullptr); + return *this; + } + + bool done(void) const + { + return h.done(); + } + + bool operator()(void) + { + h(); + return done(); + } + +private: + std::coroutine_handle<> h; +}; + +bool done(unique_coroutine const& c) +{ + return c.done(); +} + +struct state +{ + ~state() + { + std::cout << "~state()" << std::endl; + } +}; + +unique_coroutine counter(int from, int to) +{ + state s; + for (int i = from; i < to; ++i) + { + std::cout << "counter [" << from << ',' << to << "): " << i; + + if (i >= to) + break; + std::cout << " ..." << std::endl; + co_await std::suspend_always{}; + } + std::cout << "DONE" << std::endl; + co_return; +} + +int main() +{ + std::vector<unique_coroutine> tasks; + tasks.push_back(counter(1,3)); + tasks.push_back(counter(4,5)); + tasks.push_back(counter(0,7)); + + std::erase_if(tasks, done); + + for (int i = 0; i < 4 and not tasks.empty(); ++i) + { + std::erase_if(tasks, [](auto& t) { return t(); }); + std::cout << std::endl; + } + + if (not tasks.empty()) + std::cout << "Finishing early, cleaning up state of suspended tasks..." << std::endl; + + return 0; +} diff --git a/src/crc-table.c b/src/crc-table.c @@ -0,0 +1,25 @@ +#include <stdio.h> + +unsigned crc_manual(unsigned poly, unsigned crc) +{ + for (unsigned j = 8; j; --j) + crc = (crc & 1) * poly ^ crc >> 1; + + return crc; +} + +int main() +{ + unsigned poly = 0x89; +#if 0 + for (unsigned i = 0; i <= 0xFF; ++i) + printf("[%2u] 0x%02x\n", i, crc_manual(poly, i)); +#else + + for (unsigned i = 0; i < 0x10; ++i) + printf("A[%2u] 0x%02x\n", i, crc_manual(poly, i)); + + for (unsigned i = 0; i < 0x10; ++i) + printf("B[%2u] 0x%02x\n", i, crc_manual(poly, i << 4)); +#endif +} diff --git a/src/crc7.cpp b/src/crc7.cpp @@ -0,0 +1,68 @@ +#include <iostream> +#include <cstdint> +#include <vector> +#include <array> +#include <iterator> + +uint8_t CRCTable[256]; + +void GenerateCRCTable() +{ + int i, j; + uint8_t CRCPoly = 0x89; // the value of our CRC-7 polynomial + + // generate a table value for all 256 possible byte values + for (i = 0; i < 256; ++i) { + CRCTable[i] = (i & 0x80) ? i ^ CRCPoly : i; + for (j = 1; j < 8; ++j) { + CRCTable[i] <<= 1; + if (CRCTable[i] & 0x80) + CRCTable[i] ^= CRCPoly; + } + } +} + +// adds a message byte to the current CRC-7 to get a the new CRC-7 +uint8_t CRCAdd(uint8_t CRC, uint8_t message_byte) +{ + return CRCTable[(CRC << 1) ^ message_byte]; +} + +// returns the CRC-7 for a message of "length" bytes +uint8_t getCRC(uint8_t message[], int length) +{ + int i; + uint8_t CRC = 0; + + for (i = 0; i < length; ++i) + CRC = CRCAdd(CRC, message[i]); + + return CRC; +} + +void PrintFrame(std::array<uint8_t, 6> & f) +{ + for (auto e : f) + std::cout << std::hex << (int) e << " "; + std::cout << std::endl; +} + +int main() +{ + GenerateCRCTable(); + + std::copy(std::begin(CRCTable), std::end(CRCTable), std::ostream_iterator<unsigned>(std::cout, ", ")); + + std::vector<std::array<uint8_t, 6>> CommandFrames; + CommandFrames.push_back({{0x40, 0, 0, 0, 0, 0}}); + CommandFrames.push_back({{0x48, 0, 0, 1, 0xAA, 0}}); + CommandFrames.push_back({{0x69, 0x40, 0, 0, 0, 0}}); + CommandFrames.push_back({{0x77, 0x00, 0, 0, 0, 0}}); + CommandFrames.push_back({{0x7A, 0x00, 0, 0, 0, 0}}); + + std::cout << "\n\nCommand, Argument, CRC7" << std::endl; + for (auto &Frame : CommandFrames) { + Frame[5] = (getCRC(Frame.data(), 5) << 1) | 1; + PrintFrame(Frame); + } +} diff --git a/src/flat-set.cpp b/src/flat-set.cpp @@ -0,0 +1,78 @@ +#include <vector> +#include <iostream> +#include <iterator> + +template <typename T> +struct flat_set +{ + using const_iterator = std::vector<T>::const_iterator; + using iterator = const_iterator; + using size_type = std::vector<T>::size_type; + + flat_set() = default; + + bool empty(void) const noexcept { return storage.empty(); } + size_type size(void) const noexcept { return storage.size(); } + size_type max_size(void) const noexcept { return storage.max_size(); } + + void clear(void) noexcept { storage.clear(); } + + const_iterator begin() const noexcept { return storage.begin(); } + const_iterator end() const noexcept { return storage.end(); } + const_iterator rbegin() const noexcept { return storage.rbegin(); } + const_iterator rend() const noexcept { return storage.rend(); } + + std::pair<iterator, bool> insert(int v) + { + if (auto it = lower_bound(v); it != storage.end() && *it == v) + return {it, false}; + else + return {storage.insert(it, v), true}; + } + template <typename I> + void insert(I first, I last) + { + while (first != last) + insert(*first++); + } + void insert(std::initializer_list<T> ilist) + { + insert(ilist.begin(), ilist.end()); + } + + const_iterator erase(const_iterator pos) { return storage.erase(pos); } + const_iterator erase(const_iterator first, const_iterator last) { return storage.erase(first, last); } + size_type erase(T const& key) + { + if (auto it = find(key); it != end()) + { + erase(it); + return 1; + } + return 0; + } + + size_type count(T const& key) const noexcept { return std::binary_search(begin(), end(), key); } + + const_iterator lower_bound(T const& key) const { return std::lower_bound(begin(), end(), key); } + const_iterator upper_bound(T const& key) const { return std::upper_bound(begin(), end(), key); } + + const_iterator find(T const& key) const { return std::find(begin(), end(), key); } + +private: + std::vector<T> storage; +}; + +int main() +{ + flat_set<int> ints; + + ints.insert({5,5,6,3,5,10}); + + ints.insert(4); + ints.erase(6); + + std::copy(ints.begin(), ints.end(), std::ostream_iterator<int>(std::cout, "\n")); + + return !std::is_sorted(ints.begin(), ints.end()); +} diff --git a/src/gl-asteroids.cpp b/src/gl-asteroids.cpp @@ -0,0 +1,310 @@ +#include <GLFW/glfw3.h> +#include <cmath> +#include <vector> +#include <span> +#include <random> +#include <array> +#include <iostream> +#include <algorithm> +#include <thread> +#include <chrono> + +struct coord +{ + coord() = default; + coord(float s) + : x(s) + , y(s) + {} + coord(float _x, float _y) + : x(_x) + , y(_y) + {} + float x = 0, y = 0; +}; + +struct color +{ + float r, g, b; +}; + +struct visual +{ + GLint mode; + std::span<coord const> v; + std::span<color const> c; +}; + +coord const shipv[] = {{0, 2}, {1, -1}, {-1, -1}, {1,-1}, {.5,0}, {.5,0}}; +color const shipc[] = {{1,1,1}, {.5,.5,.5}}; + +coord const flamev[3] = {{0, -2}, {.5, -1}, {-.5, -1}}; +color const flamec[] = {{1,0,0}, {1,1,0}}; + +coord const rockv1[] = {{0, 0}, {1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, 0}}; +coord const rockv2[] = {{0, 0}, {1, 0}, {.7,.7}, {0, 1}, {-1, 0}, {-.9,-.9}, {0, -1}, {1, 0}}; +coord const rockv3[] = {{0, 0}, {1, 0}, {.7,.4}, {0, 1}, {-.8,.6}, {-1, 0}, {-.6,-.5}, {0, -1}, {1, 0}}; +coord const rockv4[] = {{0, 0}, {1, 0}, {.6,.4}, {0, .5}, {-.3,.6}, {-1, 0}, {-.6,-.5}, {0, -1}, {1, 0}}; + +color const rockc[] = {{.5,.5,.5}, {.3,.3,.3}}; + +visual ship{GL_TRIANGLES, shipv, shipc}; +visual flame{GL_TRIANGLES, flamev, flamec}; +visual rock1{GL_TRIANGLE_FAN, rockv1, rockc}; +visual rock2{GL_TRIANGLE_FAN, rockv2, rockc}; +visual rock3{GL_TRIANGLE_FAN, rockv3, rockc}; +visual rock4{GL_TRIANGLE_FAN, rockv4, rockc}; +std::array<visual const*, 4> rock_types = {&rock1, &rock2, &rock3, &rock4}; + +float wrap(float n, float min, float max) +{ + if (n >= max) + return n - max + min; + else if (n < min) + return n + max - min; + else + return n; +} + +void glCoord(coord c) +{ + glVertex2f(c.x, c.y); +} +void glColor(color c) +{ + glColor3f(c.r, c.g, c.b); +} + +coord operator +(coord lhs, coord rhs) +{ + return {lhs.x + rhs.x, lhs.y + rhs.y}; +} + +coord& operator +=(coord& lhs, coord rhs) +{ + return lhs = lhs + rhs; +} + +coord operator -(coord rhs) +{ + return {-rhs.x, -rhs.y}; +} + +coord operator - (coord lhs, coord rhs) +{ + return lhs + -rhs; +} + +coord operator *(coord lhs, coord rhs) +{ + return {lhs.x * rhs.x, lhs.y * rhs.y}; +} + +coord& operator *=(coord& lhs, coord rhs) +{ + lhs = lhs * rhs; + return lhs; +} + +coord rotate(coord o, float a) +{ + float s = sin(a), c = cos(a); + return {o.x*c + o.y*s, o.y*c - o.x*s}; +} + +struct physics +{ + coord pos, vel; + float rot, ang_mom, scale; + void move(float dt) + { + pos += vel * dt; + pos.x = wrap(pos.x, -1, 1); + pos.y = wrap(pos.y, -1, 1); + rot += ang_mom * dt; + } +}; + +bool is_colliding(physics const& a, physics const& b) +{ + float len = a.scale + b.scale; + auto d = a.pos - b.pos; + + return d.x * d.x + d.y * d.y < len * len; +} + +void draw(visual const& v, physics const& p) +{ + glBegin(v.mode); + + for (unsigned i = 0; i < v.v.size(); ++i) + { + if (i < v.c.size()) + glColor(v.c[i]); + glCoord(rotate(v.v[i] * p.scale, p.rot) + p.pos); + } + + glEnd(); +} + +struct entity +{ + visual const* v; + physics p; + + entity() = delete; + entity(visual const& _v, physics _p) + : v(&_v) + , p(_p) + {} + + void draw() + { + ::draw(*v, p); + } +}; + +int main(int argc, char* argv[]) +{ + unsigned score = 0; + + std::random_device rd; + std::default_random_engine gen(rd()); + std::uniform_real_distribution<float> dis_p(-1,1); + std::uniform_real_distribution<float> dis_s(0.05,0.25); + std::uniform_real_distribution<float> dis_v(0.02,0.05); + std::uniform_int_distribution<int> dis_d(0,7); + std::uniform_real_distribution<float> dis_a(-3,3); + + glfwInit(); + + GLFWwindow* w = glfwCreateWindow(926, 926, argv[0], NULL, NULL); + + glfwMakeContextCurrent(w); + + float last_t = glfwGetTime(); + + std::vector<entity> rocks; + std::vector<entity> bullets; + + float rock_time = 1, bullet_time = 0; + physics s{{}, {}, 0.f, 0.f, .06f}; + + while (!glfwWindowShouldClose(w) && glfwGetKey(w, GLFW_KEY_ESCAPE) != GLFW_PRESS) + { + float t = glfwGetTime(); + float dt = t - last_t; + + if (rock_time < t) + { + rock_time += (rocks.size() < 3 ? 2 : 6) / log(t+1); + + static unsigned rtype; + + ++rtype; + rtype %= rock_types.size(); + + int dir = dis_d(gen); + + coord v(dis_v(gen), dis_v(gen)); + if (dir & 1) + v.x = -v.x; + if (dir & 2) + v.y = -v.y; + + coord p = {dis_p(gen), 1}; + if (dir & 3) + std::swap(p.x, p.y); + + rocks.emplace_back(*rock_types[rtype], physics{p, v, 0, dis_a(gen), dis_s(gen)}); + } + + if (glfwGetKey(w, GLFW_KEY_SPACE) == GLFW_PRESS && bullet_time < t) + { + bullet_time = t + .5f; + + bullets.emplace_back(ship, s); + auto& b = bullets.back().p; + + b.scale /= 3; + b.vel += {(float)sin(b.rot), (float)cos(b.rot)}; + } + + last_t = t; + + int kl = glfwGetKey(w, GLFW_KEY_LEFT) == GLFW_PRESS; + int kr = glfwGetKey(w, GLFW_KEY_RIGHT) == GLFW_PRESS; + + if (kl ^ kr) + s.ang_mom = kr ? 2 : -2; + else + s.ang_mom = 0; + + + bool up = glfwGetKey(w, GLFW_KEY_UP) == GLFW_PRESS; + if (up) + { + float sr = sin(s.rot), cr = cos(s.rot); + s.vel += coord{sr, cr} * dt; + } + glClearColor(0,0,0,1); + glClear(GL_COLOR_BUFFER_BIT); + + for (auto& r : rocks) + r.p.move(dt); + for (auto& b : bullets) + b.p.move(dt); + s.move(dt); + + if(any_of(rocks.begin(), rocks.end(), [&s](auto& r) { return is_colliding(s, r.p); })) + glfwSetWindowShouldClose(w, 1); + + for (unsigned i = 0; i < rocks.size();) + { + auto r = rocks.begin() + i; + for (auto b = bullets.begin(); b < bullets.end();) + { + if (is_colliding(r->p, b->p)) + { + if (r->p.scale > .1f) + { + r->p.vel *= 1.5f; + r->p.scale /= 2; + rocks.push_back(*r); + rocks.back().p.vel *= -1; + rocks.back().p.ang_mom *= -1.5f; + ++i; + } + else + rocks.erase(r); + + b = bullets.erase(b); + ++score; + goto bang; + } + ++b; + } + ++i; + bang: continue; + } + + for (auto& r : rocks) + r.draw(); + for (auto& b : bullets) + b.draw(); + + draw(ship, s); + if (up) + draw(flame, s); + + glfwSwapBuffers(w); + glfwPollEvents(); + } + glfwDestroyWindow(w); + glfwTerminate(); + + std::cout << "Score: " << score << '\n'; + using namespace std::chrono_literals; + std::this_thread::sleep_for(1s); + return 0; +} diff --git a/src/guess-number.c b/src/guess-number.c @@ -0,0 +1,40 @@ +#include <stdio.h> +#include <time.h> +#include <sys/random.h> + +int main() +{ + unsigned short n, guess, score = 0; + + time_t start = time(NULL); + + getrandom(&n, sizeof(n), 0); + + do + { + printf("Enter number: "); + + int res = scanf("%hu", &guess); + switch (res) + { + case EOF: + puts("\nGiving up so soon?"); + return 0; + case 0: + scanf("%*[^\n]"); + puts("Invalid input, Try again!"); + break; + case 1: + ++score; + if (n < guess) + puts("Lower!"); + else if (n > guess) + puts("Higher!"); + } + } while (guess != n); + + time_t end = time(NULL); + + printf("Congratultions, your score is %u\n", score * (end - start)); + return 0; +} diff --git a/src/hush.cpp b/src/hush.cpp @@ -0,0 +1,39 @@ +#include <iostream> +#include <sstream> +#include <cstdlib> +#include <memory> +#include <unistd.h> + +using namespace std; + +auto pwd(void) +-> unique_ptr<char, void(*)(void*)> +{ + return {getcwd(nullptr, 0), free}; +} + +int main(int, char**) +{ + string buf; + + auto wd = pwd(); + + for (;;) + { + cout << '[' << wd.get() << "] " << flush; + if (!getline(cin, buf)) + break; + + cout << buf << '\n'; + + istringstream is(buf); + while (getline(is, buf, '\0')) + cout << " " << buf; + + cout << '\n'; + } + + cout << "Done!\n"; + + return EXIT_SUCCESS; +} diff --git a/src/io_uring.cpp b/src/io_uring.cpp @@ -0,0 +1,142 @@ +#include <liburing.h> +#include <iostream> +#include <coroutine> +#include <span> + +struct awaitable; + +struct uring +{ + uring(unsigned entries, unsigned flags) + { + if (io_uring_queue_init(entries, &ring, flags)) + throw std::system_error(errno, std::system_category()); + } + + ~uring(void) + { + io_uring_queue_exit(&ring); + } + + uring(const uring&) = delete; + uring& operator =(const uring&) = delete; + + io_uring_sqe* get_sqe(void) + { + return io_uring_get_sqe(&ring); + } + + int submit(void) + { + return io_uring_submit(&ring); + } + + bool process_completion(void); + awaitable read(int, std::span<char>, unsigned); + awaitable write(int, std::span<char const>, unsigned); + unsigned n = 0; +private: + io_uring ring; +}; + +struct task +{ + struct promise_type + { + int res; + + void get_return_object(void) const noexcept + {} + auto initial_suspend(void) const noexcept + { + return std::suspend_never{}; + } + auto final_suspend(void) const noexcept + { + return std::suspend_always{}; + } + void unhandled_exception(void) const noexcept + { + std::terminate(); + } + void return_void(void) const noexcept + {} + }; +}; + +struct awaitable +{ + uring& u; + io_uring_sqe& sqe; + task::promise_type* p; + + bool await_ready(void) const noexcept + { + return false; + } + void await_suspend(std::coroutine_handle<task::promise_type> h) + { + p = &h.promise(); + io_uring_sqe_set_data(&sqe, h.address()); + u.submit(); + u.n++; + } + int await_resume() + { + return p->res; + } +}; + +bool uring::process_completion(void) +{ + if (!n) + return false; + --n; + + io_uring_cqe* cqe; + if (io_uring_wait_cqe(&ring, &cqe)) + throw std::system_error(errno, std::system_category()); + + auto addr = io_uring_cqe_get_data(cqe); + auto h = std::coroutine_handle<task::promise_type>::from_address(addr); + h.promise().res = cqe->res; + h.resume(); + + return true; +} + +awaitable uring::read(int fd, std::span<char> buf, unsigned flags) +{ + auto sqe = get_sqe(); + io_uring_prep_read(sqe, fd, buf.data(), buf.size(), flags); + return {*this, *sqe}; +} +awaitable uring::write(int fd, std::span<char const> buf, unsigned flags) +{ + auto sqe = get_sqe(); + io_uring_prep_write(sqe, fd, buf.data(), buf.size(), flags); + return {*this, *sqe}; +} + +task read_routine(uring& u) +{ + char b[128]; + std::span<char> buf(b); + int fd = 1; + unsigned flags = 0; + int n = co_await u.read(0, buf, 0); + co_await u.write(1, {b, n}, 0); + co_return; +} + +int main() +{ + uring r(128, 0); + + read_routine(r); + + while (r.process_completion()) + {} + + return 0; +} diff --git a/src/mmallocator.cpp b/src/mmallocator.cpp @@ -0,0 +1,58 @@ +#include <vector> +#include <iostream> + +using namespace std; + +template <typename T> +struct mmallocator +{ + using value_type = T; + mmallocator() + { + cout << __PRETTY_FUNCTION__ << '\n'; + } + template <typename U> constexpr mmallocator(const mmallocator<U>&) noexcept + {} + [[nodiscard]] T* allocate(std::size_t const n) + { + if (n > std::size_t(-1) / sizeof(T)) + throw std::bad_alloc(); + + if (auto p = static_cast<T*>(std::malloc(n*sizeof(T)))) + return p; + + throw std::bad_alloc(); + } + void deallocate(T* p, std::size_t) noexcept + { + std::free(p); + } +}; + +template <class T, class U> +bool operator==(const mmallocator<T>&, const mmallocator<U>&) +{ + return true; +} + +template <class T, class U> +bool operator!=(const mmallocator<T>&, const mmallocator<U>&) +{ + return false; +} + +int main() +{ + mmallocator<char const*> mm; + + std::vector<char const*, mmallocator<char const*>> v(mm); + std::vector<char const*, mmallocator<char const*>> v2(mm); + + v.push_back("Hello"); + v.push_back("World"); + + for (auto const s : v) + cout << s << '\n'; + + return 0; +} diff --git a/src/model.cpp b/src/model.cpp @@ -0,0 +1,124 @@ +#include <iostream> +#include <sstream> +#include <vector> +#include <set> + +using namespace std; + +struct vertex { + float x, y, z; +}; + +std::vector<vertex> v; + +string buf; + +void add_vertices(void) +{ + cout << "Adding Vertices...\n"; + float x, y, z; + while (getline(cin, buf)) + { + istringstream ss; + ss.str(buf); + ss >> x >> y >> z; + if (!ss) + break; + v.push_back({x, y, z}); + } +} + +struct primitives +{ + string type; + vector<uint8_t> indices; +}; + +primitives add_primitives(string type) +{ + primitives p; + p.type = type; + + while (getline(cin, buf)) + { + istringstream ss; + ss.str(buf); + + unsigned const line_start = p.indices.size(); + + unsigned tmp; + while (ss >> tmp) + { + if (tmp > v.size()) + throw std::runtime_error("Primitive index out of range!"); + + if (line_start && line_start == p.indices.size()) + p.indices.push_back(0xff); + + p.indices.push_back(tmp); + } + + if (line_start == p.indices.size()) + break; + } + + if (p.indices.empty()) + throw std::runtime_error("Empty Primitive array!"); + + return p; +} + +void print_primitives(primitives const& p) +{ + cout << p.type << '\n'; + unsigned n = 0; + for (auto P : p.indices) + { + if (P == 0xff) + cout << "Restart\n"; + else + cout << " " << n++ << ": " << +P << " [" << v[P].x << ' ' << v[P].y << ' ' << v[P].z << "]\n"; + } +} + +set<string> types = { + "GL_POINTS", + "GL_LINES", + "GL_LINE_STRIP", + "GL_LINE_LOOP", + "GL_TRIANGLES", + "GL_TRIANGLE_STRIP", + "GL_TRIANGLE_FAN", + "GL_QUADS", + "GL_QUAD_STRIP", +}; + +int main() +{ + std::vector<primitives> prims; + + while (getline(cin, buf)) + { + istringstream ss; + ss.str(buf); + ss >> buf; + + if (buf == "GL_FLOAT") + add_vertices(); + + else if (types.count(buf)) + prims.push_back(add_primitives(buf)); + } + + cout << "\nPrinting Vertices:\n"; + for (auto V : v) + cout << '[' << V.x << ' ' << V.y << ' ' << V.z << "]\n"; + + unsigned n = 0; + cout << "\nPrinting Primitives:\n"; + for (auto const& p : prims) + { + cout << n++ << ": "; + print_primitives(p); + } +} diff --git a/src/morse.c b/src/morse.c @@ -0,0 +1,112 @@ +#include <stdio.h> +#include <ctype.h> + +void put_morse_char(unsigned dit) +{ + putchar(dit ? '.' : '_'); +} + +void put_morse_seq(unsigned seq) +{ + putchar(' '); + while (seq > 1) + { + put_morse_char(seq & 1); + seq >>= 1; + } +} + +unsigned char seqs[] = +{ + ['1'] = 0b100001, + ['2'] = 0b100011, + ['3'] = 0b100111, + ['4'] = 0b101111, + ['5'] = 0b111111, + ['6'] = 0b111110, + ['7'] = 0b111100, + ['8'] = 0b111000, + ['9'] = 0b110000, + ['0'] = 0b100000, + + ['A'] = 0b101, + ['B'] = 0b11110, + ['C'] = 0b11010, + ['D'] = 0b1110, + ['E'] = 0b11, + ['F'] = 0b11011, + ['G'] = 0b1100, + ['H'] = 0b11111, + ['I'] = 0b111, + ['J'] = 0b10001, + ['K'] = 0b1010, + ['L'] = 0b11101, + ['M'] = 0b100, + ['N'] = 0b110, + ['O'] = 0b1000, + ['P'] = 0b11001, + ['Q'] = 0b10100, + ['R'] = 0b1101, + ['S'] = 0b1111, + ['T'] = 0b10, + ['U'] = 0b1011, + ['V'] = 0b10111, + ['W'] = 0b1001, + ['X'] = 0b10110, + ['Y'] = 0b10010, + ['Z'] = 0b11100, + + ['.'] = 0b1010101, + [','] = 0b1001100, + ['?'] = 0b1110011, + ['\''] = 0b1100001, + ['!'] = 0b1001010, + ['/'] = 0b110110, + ['('] = 0b110010, + [')'] = 0b1010010, + ['&'] = 0b111101, + [':'] = 0b1111000, + [';'] = 0b1101010, + ['='] = 0b101110, + ['+'] = 0b110101, + ['-'] = 0b1011110, + ['_'] = 0b1010011, + ['"'] = 0b1101101, + ['$'] = 0b10110111, + ['@'] = 0b1101001, + + [1] = 0b101010, + [2] = 0b101010, + [3] = 0b1010111, + [4] = 0b1010111, + [6] = 0b110111, +}; + +void put_morse(char c) +{ + unsigned char m = seqs[toupper(c)]; + if (m) + put_morse_seq(m); + else + putchar('\n'); +} + +void put_morse_str(char const* str) +{ + while (*str) + put_morse(*str++); +} + +int main() +{ + for (;;) + { + int c = getchar(); + if (c <= 0) + break; + put_morse(c); + } + + putchar ('\n'); + return 0; +} diff --git a/src/pulse-simple-client.c b/src/pulse-simple-client.c @@ -0,0 +1,44 @@ +#include <pulse/simple.h> +#include <stdio.h> +#include <math.h> + + +int main(int argc, char* argv[]) +{ + pa_sample_spec ss = { + .format = PA_SAMPLE_S16NE, + .channels = 1, + .rate = 44100, + }; + + pa_simple* s = pa_simple_new( + NULL, + argv[0], + PA_STREAM_PLAYBACK, + NULL, + "Music", + &ss, + NULL, + NULL, + NULL); + + if (!s) + perror("pa_simple_new"); + +#define BUF_LEN (44100 / 200) +#define pi 3.1415 +#define tau (2*pi) + + signed short buf[BUF_LEN]; + + for (unsigned i = 0; i < BUF_LEN; ++i) + { + double t = i * tau / BUF_LEN; + buf[i] = sin(t) * (1 << 15); + } + for (unsigned i = 0; i < 400; ++i) + { + if (pa_simple_write(s, buf, sizeof(buf), NULL)) + perror("pa_simple_write"); + } +} diff --git a/src/regex.c b/src/regex.c @@ -0,0 +1,66 @@ +#include <regex.h> +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +char const* const tests[] = +{ + "hello world", + "10=5", + "big=small" +}; + + + +int main(int argc, char* argv[]) +{ + //char const re[] = R"~(^(?:(\d+)|([^=]+))=(?:(\d+)|([^=]+))$)~"; + char const re[] = "^((\\d+)|([^=]+))=((\\d+)|([^=]+))$"; + regex_t preg; + + int err = regcomp(&preg, re, REG_EXTENDED); + if (err) + { + char buf[256]; + regerror(err, &preg, buf, sizeof(buf)); + puts(buf); + return 1; + } + + + + for (unsigned i = 0; i < ARRAY_SIZE(tests); ++i) + { + char const* const str = tests[i]; + regmatch_t pmatch[7]; + printf("'%s':\n", str); + int res = regexec(&preg, str, ARRAY_SIZE(pmatch), pmatch, 0); + if (res == REG_NOMATCH) + { + puts("NO MATCH"); + continue; + } + assert(!res); + for (unsigned j = 0; j < ARRAY_SIZE(pmatch); ++j) + { + char buf[128]; + if (pmatch[j].rm_so == -1) + continue; + + size_t len = pmatch[j].rm_eo - pmatch[j].rm_so; + len = min(len, ARRAY_SIZE(buf) - 1); + *strncpy(buf, str, len) = '\0'; + printf(" %d -> %d: '%s'\n", pmatch[j].rm_so, pmatch[j].rm_eo, buf); + } + } + + regfree(&preg); + + return 0; +} diff --git a/src/robin.cpp b/src/robin.cpp @@ -0,0 +1,123 @@ +#include <coroutine> +#include <iostream> +#include <deque> + +struct round_robin_scheduler : std::suspend_always +{ + std::deque<std::coroutine_handle<>> tasks; + + bool await_ready(void) const noexcept + { + return tasks.empty(); + } + + void schedule(std::coroutine_handle<> h) + { + tasks.push_back(h); + } + + std::coroutine_handle<> next(void) noexcept + { + auto h = tasks.front(); + tasks.pop_front(); + return h; + } + + std::coroutine_handle<> await_suspend(std::coroutine_handle<> h) + { + schedule(h); + return next(); + } + + round_robin_scheduler(void) = default; + + void destroy(void) + { + if (not tasks.empty()) + std::cout << "Finishing early, cleaning up state of suspended tasks..." << std::endl; + + for (auto h : tasks) + h.destroy(); + } + + ~round_robin_scheduler() + { + destroy(); + } + + round_robin_scheduler(round_robin_scheduler&& old) + : tasks(std::move(old.tasks)) + {} + + round_robin_scheduler& operator =(round_robin_scheduler&& old) + { + destroy(); + tasks = std::move(old.tasks); + return *this; + } + + bool operator ()(void) noexcept + { + if (tasks.empty()) + return false; + + next()(); + return true; + } +} round_robin; + +struct fire_forget_coroutine +{ + struct promise_type + { + ~promise_type() {} + void get_return_object(void) {} + std::suspend_always initial_suspend(void) + { + round_robin.schedule(std::coroutine_handle<promise_type>::from_promise(*this)); + return {}; + } + void return_void(void) {} + std::suspend_never final_suspend(void) noexcept + { + round_robin(); + return {}; + } + void unhandled_exception(void) { std::terminate(); } + }; +}; + +struct state +{ + ~state() + { + std::cout << " ~state()" << std::endl; + } +}; + +fire_forget_coroutine counter(int from, int to) +{ + state s; + + for (int i = from;; ++i) + { + std::cout << "counter [" << from << ',' << to << "): " << i; + if (i >= to) + break; + std::cout << std::endl; + co_await round_robin; + } + std::cout << " DONE" << std::endl; + co_return; +} + +int main() +{ + counter(1,3); + counter(4,5); + counter(0,7); + + round_robin(); + + return 0; +} diff --git a/src/sorts.cpp b/src/sorts.cpp @@ -0,0 +1,154 @@ +#include <array> +#include <vector> +#include <cstdlib> +#include <iostream> +#include <iomanip> +#include <span> +#include <numeric> +#include <string_view> + +template <typename T> +void bubble_sort(std::span<T> const& elements) +{ + bool unsorted = true; + + for (auto end = elements.end(); unsorted && end != elements.begin(); --end) + { + unsorted = false; + + for (auto cur = elements.begin(); cur != end; ++cur) + if (auto next = cur + 1; *cur > *next) + { + std::swap(*cur, *next); + unsorted = true; + } + } +} + +template <typename T> +void insertion_sort(std::span<T> const& elements) +{ + for (auto it = elements.begin(); it != elements.end(); ++it) + for (auto cur = it; cur != elements.begin(); --cur) + if (auto next = cur - 1; *cur < *next) + std::swap(*cur, *next); + else + break; +} + +template <typename T> +void selection_sort(std::span<T> const& elements) +{ + for (auto it = elements.begin(); it != elements.end(); ++it) + if (auto next = std::min_element(it, elements.end()); it != next) + std::swap(*it, *next); +} + +template <typename T> +struct reverse_wrapper +{ + T& c_; + reverse_wrapper(T& c) : c_(c) {} + + typename T::reverse_iterator begin() {return c_.rbegin();} + typename T::reverse_iterator end() {return c_.rend(); } +}; + +template <typename T> +void radix_sort(std::span<T> const& elements) +{ + std::vector<T> storage(elements.size()); + std::span<T> in = elements, out = storage; + + constexpr unsigned z = 3; + constexpr unsigned radix = 1 << (1 << z); + constexpr unsigned mask = radix - 1; + unsigned passes = std::numeric_limits<T>::digits >> z; + unsigned shift = 0; + std::array<unsigned, radix> buckets = {}; + + if (passes % 2) + { + std::copy(in.begin(), in.end(), out.begin()); + std::swap(in, out); + } + + while (passes--) + { + for (unsigned i = 0; i < radix; ++i) + buckets[i] = std::count_if(in.begin(), in.end(), [i, shift](auto n) + { + return (n >> shift & mask) == i; + }); + + std::partial_sum(buckets.begin(), buckets.end(), buckets.begin()); + + for (auto n : reverse_wrapper(in)) + out[--buckets[n >> shift & mask]] = n; + + std::swap(in, out); + shift += 1 << z; + } +} + +using base_type = unsigned char; +using sort_fn_t = void (*)(std::span<base_type> const&); +using namespace std::literals; + +struct +{ + char option(void) const + { + return std::tolower(name[0]); + } + + sort_fn_t fn; + char name[12]; +} const menu[] = +{ + {bubble_sort, "Bubble"}, + {insertion_sort, "Insertion"}, + {radix_sort, "Radix"}, + {selection_sort, "Selection"}, +}; + +[[ noreturn ]] +void usage(void) +{ + std::cerr << "Usage:\n\tsorts OPTION\n\n"; + + for (auto const& e : menu) + std::cerr << "\t-" << e.option() << '\t' << e.name << " sort\n"; + + std::exit(1); +} + +sort_fn_t get_sort_fn(std::string_view arg) +{ + if (arg.size() != 2 || arg[0] != '-') + usage(); + + for (auto const& e : menu) + if (arg[1] == e.option()) + return e.fn; + + usage(); +} + +int main(int argc, char* argv[]) +{ + if (argc != 2) + usage(); + + auto sort_fn = get_sort_fn(argv[1]); + + std::array<base_type, 100> ints; + std::generate(ints.begin(), ints.end(), rand); + + sort_fn(ints); + + for (auto const& n : ints) + std::cout << std::setw(10) << +n << '\n'; + + return !std::is_sorted(ints.begin(), ints.end()); +} diff --git a/src/triple-buf.cpp b/src/triple-buf.cpp @@ -0,0 +1,117 @@ +#include <array> +#include <atomic> +#include <iostream> + +enum states +{ + wro, + wrn, + rwo, + rwn, + + wor, + wnr, + row, + rnw, + + owr, + nwr, + orw, + nrw, +}; + +struct state_table +{ + enum states push_next, pull_next; + unsigned char in, out; +}; + +constexpr struct state_table table[] = +{ + [wro] = {nrw, wro, 0, 1}, + [wrn] = {nrw, wor, 0, 1}, + [rwo] = {rnw, rwo, 1, 0}, + [rwn] = {rnw, owr, 1, 0}, + [wor] = {nwr, wor, 0, 2}, + [wnr] = {nwr, wro, 0, 2}, + [row] = {rwn, row, 2, 0}, + [rnw] = {rwn, orw, 2, 0}, + [owr] = {wnr, owr, 1, 2}, + [nwr] = {wnr, rwo, 1, 2}, + [orw] = {wrn, orw, 2, 1}, + [nrw] = {wrn, row, 2, 1}, +}; + +template <typename T> +struct triple_buffer +{ + std::array<T, 3> bufs; + std::atomic<enum states> state; + + T& get_write() + { + return bufs[table[state].in]; + } + + T& get_read() + { + return bufs[table[state].out]; + } + + void push(void) + { + enum states desired, expected = state; + do + { + desired = table[expected].push_next; + + } while (not state.compare_exchange_strong(expected, desired, std::memory_order::seq_cst, std::memory_order::seq_cst)); + } + + bool pull(void) + { + enum states desired, expected = state; + do + { + desired = table[expected].pull_next; + + if (desired == expected) + return false; + + } while (not state.compare_exchange_strong(expected, desired, std::memory_order::seq_cst, std::memory_order::seq_cst)); + + return true; + } +}; + + +int main(void) +{ + triple_buffer<int> b; + + b.get_write() = 5; + b.push(); + + b.pull(); + std::cout << b.get_read() << '\n'; + b.pull(); + std::cout << b.get_read() << '\n'; + + b.get_write() = 6; + b.push(); + + b.get_write() = 7; + b.push(); + + std::cout << b.get_read() << '\n'; + b.pull(); + std::cout << b.get_read() << '\n'; + + b.get_write() = 8; + b.push(); + + b.pull(); + std::cout << b.get_read() << '\n'; + + return 0; +} diff --git a/src/whichtty.c b/src/whichtty.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <stdio.h> + +#include <unistd.h> + +int main() +{ + char const* ttyname_s = ttyname(STDIN_FILENO); + char const* ctermid_s = ctermid(NULL); + + printf("ttyname: %s\nctermid: %s\n", ttyname_s, ctermid_s); + + return EXIT_SUCCESS; +}