commit 2ab69cd62797c8ed33a89ff22c276d609eb94ca2
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Thu, 25 Nov 2021 21:06:52 +0000
initial commit
Diffstat:
A | .gitignore | | | 5 | +++++ |
A | makefile | | | 25 | +++++++++++++++++++++++++ |
A | src/aio.c | | | 98 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/aio.cpp | | | 80 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/atexit.cpp | | | 33 | +++++++++++++++++++++++++++++++++ |
A | src/bit_cast.cpp | | | 10 | ++++++++++ |
A | src/cat.c | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/cie-1931.cpp | | | 102 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/clock-test.c | | | 21 | +++++++++++++++++++++ |
A | src/cobs.c | | | 141 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/coro.cpp | | | 113 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/crc-table.c | | | 25 | +++++++++++++++++++++++++ |
A | src/crc7.cpp | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/flat-set.cpp | | | 78 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/gl-asteroids.cpp | | | 310 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/guess-number.c | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | src/hush.cpp | | | 39 | +++++++++++++++++++++++++++++++++++++++ |
A | src/io_uring.cpp | | | 142 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/mmallocator.cpp | | | 58 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/model.cpp | | | 124 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/morse.c | | | 112 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/pulse-simple-client.c | | | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
A | src/regex.c | | | 66 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/robin.cpp | | | 123 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/sorts.cpp | | | 154 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/triple-buf.cpp | | | 117 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/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;
+}