Initial commit that has most of what I need.
This commit is contained in:
parent
933f47a440
commit
ad143dca05
11 changed files with 317 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -19,3 +19,5 @@ tags
|
||||||
# Persistent undo
|
# Persistent undo
|
||||||
[._]*.un~
|
[._]*.un~
|
||||||
|
|
||||||
|
subprojects
|
||||||
|
builddir
|
||||||
|
|
18
Makefile
Normal file
18
Makefile
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
all: build test
|
||||||
|
|
||||||
|
reset:
|
||||||
|
powershell -executionpolicy bypass .\scripts\reset_build.ps1
|
||||||
|
|
||||||
|
build:
|
||||||
|
meson compile -j 4 -C builddir
|
||||||
|
|
||||||
|
test: build
|
||||||
|
./builddir/runtests
|
||||||
|
|
||||||
|
install: build test
|
||||||
|
powershell "cp ./builddir/subprojects/libgit2-1.8.1/liblibgit2package.dll ."
|
||||||
|
powershell "cp ./builddir/subprojects/efsw/libefsw.dll ."
|
||||||
|
powershell "cp builddir/escape_turings_tarpit.exe ."
|
||||||
|
|
||||||
|
clean:
|
||||||
|
meson compile --clean -C builddir
|
40
dbc.cpp
Normal file
40
dbc.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "dbc.hpp"
|
||||||
|
|
||||||
|
void dbc::log(const string &message) {
|
||||||
|
fmt::print("{}\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbc::sentinel(const string &message) {
|
||||||
|
string err = fmt::format("[SENTINEL!] {}\n", message);
|
||||||
|
throw dbc::SentinelError{err};
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbc::pre(const string &message, bool test) {
|
||||||
|
if(!test) {
|
||||||
|
string err = fmt::format("[PRE!] {}\n", message);
|
||||||
|
throw dbc::PreCondError{err};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbc::pre(const string &message, std::function<bool()> tester) {
|
||||||
|
dbc::pre(message, tester());
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbc::post(const string &message, bool test) {
|
||||||
|
if(!test) {
|
||||||
|
string err = fmt::format("[POST!] {}\n", message);
|
||||||
|
throw dbc::PostCondError{err};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbc::post(const string &message, std::function<bool()> tester) {
|
||||||
|
dbc::post(message, tester());
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbc::check(bool test, const string &message) {
|
||||||
|
if(!test) {
|
||||||
|
string err = fmt::format("[CHECK!] {}\n", message);
|
||||||
|
fmt::println("{}", err);
|
||||||
|
throw dbc::CheckError{err};
|
||||||
|
}
|
||||||
|
}
|
29
dbc.hpp
Normal file
29
dbc.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
namespace dbc {
|
||||||
|
class Error {
|
||||||
|
public:
|
||||||
|
const string message;
|
||||||
|
Error(string m) : message{m} {}
|
||||||
|
Error(const char *m) : message{m} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CheckError : public Error {};
|
||||||
|
class SentinelError : public Error {};
|
||||||
|
class PreCondError : public Error {};
|
||||||
|
class PostCondError : public Error {};
|
||||||
|
|
||||||
|
void log(const string &message);
|
||||||
|
void sentinel(const string &message);
|
||||||
|
void pre(const string &message, bool test);
|
||||||
|
void pre(const string &message, std::function<bool()> tester);
|
||||||
|
void post(const string &message, bool test);
|
||||||
|
void post(const string &message, std::function<bool()> tester);
|
||||||
|
void check(bool test, const string &message);
|
||||||
|
}
|
28
fsm.hpp
Normal file
28
fsm.hpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
#ifndef FSM_DEBUG
|
||||||
|
#define FSM_STATE(C, S, E, ...) case C::S: S(E, ##__VA_ARGS__); break
|
||||||
|
#else
|
||||||
|
#define FSM_STATE(C, S, E, ...) case C::S: fmt::println(">> " #C " " #S " event={}, state={}", int(E), int(_state)); S(E, ##__VA_ARGS__); fmt::println("<< " #C " state={}", int(_state)); break
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename S, typename E>
|
||||||
|
class DeadSimpleFSM {
|
||||||
|
protected:
|
||||||
|
// BUG: don't put this in your class because state() won't work
|
||||||
|
S _state = S::START;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename... Types>
|
||||||
|
void event(E event, Types... args);
|
||||||
|
|
||||||
|
void state(S next_state) {
|
||||||
|
_state = next_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool in_state(S state) {
|
||||||
|
return _state == state;
|
||||||
|
}
|
||||||
|
};
|
39
main.cpp
Normal file
39
main.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <ftxui/dom/elements.hpp>
|
||||||
|
#include <ftxui/screen/screen.hpp>
|
||||||
|
#include <ftxui/screen/string.hpp>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using namespace ftxui;
|
||||||
|
|
||||||
|
auto summary = [&] {
|
||||||
|
auto content = vbox({
|
||||||
|
hbox({text(L"- done: "), text(L"3") | bold}) | color(Color::Green),
|
||||||
|
hbox({text(L"- active: "), text(L"2") | bold}) | color(Color::RedLight),
|
||||||
|
hbox({text(L"- queue: "), text(L"9") | bold}) | color(Color::Red),
|
||||||
|
});
|
||||||
|
return window(text(L" Summary "), content);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto document = //
|
||||||
|
vbox({
|
||||||
|
hbox({
|
||||||
|
summary(),
|
||||||
|
summary(),
|
||||||
|
summary() | flex,
|
||||||
|
}),
|
||||||
|
summary(),
|
||||||
|
summary(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Limit the size of the document to 80 char.
|
||||||
|
document = document | size(WIDTH, LESS_THAN, 80);
|
||||||
|
|
||||||
|
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
|
||||||
|
Render(screen, document);
|
||||||
|
|
||||||
|
std::cout << screen.ToString() << '\0' << std::endl;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
28
meson.build
Normal file
28
meson.build
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
project('lcthw-utilities', 'cpp',
|
||||||
|
default_options: ['cpp_std=c++20'])
|
||||||
|
|
||||||
|
catch2 = dependency('catch2-with-main')
|
||||||
|
fmt = dependency('fmt')
|
||||||
|
json = dependency('nlohmann_json')
|
||||||
|
ftxui_screen = dependency('ftxui-screen')
|
||||||
|
ftxui_dom = dependency('ftxui-dom')
|
||||||
|
ftxui_component = dependency('ftxui-component')
|
||||||
|
|
||||||
|
dependencies = [catch2, fmt,
|
||||||
|
ftxui_screen, ftxui_dom, ftxui_component,
|
||||||
|
json]
|
||||||
|
|
||||||
|
runtests = executable('runtests', [
|
||||||
|
'dbc.cpp',
|
||||||
|
'tests/fsm.cpp',
|
||||||
|
'tests/dbc.cpp',
|
||||||
|
],
|
||||||
|
dependencies: dependencies)
|
||||||
|
|
||||||
|
roguish = executable('roguish', [
|
||||||
|
'dbc.cpp',
|
||||||
|
'main.cpp'
|
||||||
|
],
|
||||||
|
dependencies: dependencies)
|
||||||
|
|
||||||
|
test('tests', runtests)
|
13
scripts/reset_build.ps1
Normal file
13
scripts/reset_build.ps1
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
mv .\subprojects\packagecache .
|
||||||
|
rm -recurse -force .\subprojects\,.\builddir\
|
||||||
|
mkdir subprojects
|
||||||
|
mv .\packagecache .\subprojects\
|
||||||
|
cp *.wrap subprojects
|
||||||
|
mkdir builddir
|
||||||
|
meson wrap install fmt
|
||||||
|
meson wrap install catch2
|
||||||
|
meson wrap install ftxui
|
||||||
|
meson wrap install nlohmann_json
|
||||||
|
# $env:CC="clang"
|
||||||
|
# $env:CXX="clang++"
|
||||||
|
meson setup --default-library=static --prefer-static builddir
|
14
scripts/reset_build.sh
Normal file
14
scripts/reset_build.sh
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
mv -f ./subprojects/packagecache .
|
||||||
|
rm -rf subprojects builddir
|
||||||
|
mkdir subprojects
|
||||||
|
mv packagecache ./subprojects/
|
||||||
|
mkdir builddir
|
||||||
|
cp *.wrap subprojects
|
||||||
|
meson wrap install fmt
|
||||||
|
meson wrap install catch2
|
||||||
|
meson wrap install ftxui
|
||||||
|
meson wrap install nlohmann_json
|
||||||
|
meson setup builddir
|
39
tests/dbc.cpp
Normal file
39
tests/dbc.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include "dbc.hpp"
|
||||||
|
|
||||||
|
using namespace dbc;
|
||||||
|
|
||||||
|
TEST_CASE("basic feature tests", "[utils]") {
|
||||||
|
log("Logging a message.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
sentinel("This shouldn't happen.");
|
||||||
|
} catch(SentinelError) {
|
||||||
|
log("Sentinel happened.");
|
||||||
|
}
|
||||||
|
|
||||||
|
pre("confirm positive cases work", 1 == 1);
|
||||||
|
pre("confirm positive lambda", [&]{ return 1 == 1;});
|
||||||
|
post("confirm positive post", 1 == 1);
|
||||||
|
post("confirm postitive post with lamdba", [&]{ return 1 == 1;});
|
||||||
|
|
||||||
|
check(1 == 1, "one equals 1");
|
||||||
|
|
||||||
|
try {
|
||||||
|
check(1 == 2, "this should fail");
|
||||||
|
} catch(CheckError err) {
|
||||||
|
log("check fail worked");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pre("failing pre", 1 == 3);
|
||||||
|
} catch(PreCondError err) {
|
||||||
|
log("pre fail worked");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
post("failing post", 1 == 4);
|
||||||
|
} catch(PostCondError err) {
|
||||||
|
log("post faile worked");
|
||||||
|
}
|
||||||
|
}
|
67
tests/fsm.cpp
Normal file
67
tests/fsm.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <string>
|
||||||
|
#include "../fsm.hpp"
|
||||||
|
|
||||||
|
using namespace fmt;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
enum class MyState {
|
||||||
|
START, RUNNING, END
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MyEvent {
|
||||||
|
STARTED, PUSH, QUIT
|
||||||
|
};
|
||||||
|
|
||||||
|
class MyFSM : public DeadSimpleFSM<MyState, MyEvent> {
|
||||||
|
public:
|
||||||
|
void event(MyEvent ev, string data="") {
|
||||||
|
switch(_state) {
|
||||||
|
FSM_STATE(MyState, START, ev);
|
||||||
|
FSM_STATE(MyState, RUNNING, ev, data);
|
||||||
|
FSM_STATE(MyState, END, ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void START(MyEvent ev) {
|
||||||
|
println("<<< START");
|
||||||
|
state(MyState::RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RUNNING(MyEvent ev, string &data) {
|
||||||
|
if(ev == MyEvent::QUIT) {
|
||||||
|
println("<<< QUITTING {}", data);
|
||||||
|
state(MyState::END);
|
||||||
|
} else {
|
||||||
|
println("<<< RUN: {}", data);
|
||||||
|
state(MyState::RUNNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void END(MyEvent ev) {
|
||||||
|
println("<<< STOP");
|
||||||
|
state(MyState::END);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE("confirm fsm works with optional data", "[utils]") {
|
||||||
|
MyFSM fsm;
|
||||||
|
|
||||||
|
REQUIRE(fsm.in_state(MyState::START));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::STARTED);
|
||||||
|
REQUIRE(fsm.in_state(MyState::RUNNING));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH);
|
||||||
|
REQUIRE(fsm.in_state(MyState::RUNNING));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH);
|
||||||
|
REQUIRE(fsm.in_state(MyState::RUNNING));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::PUSH);
|
||||||
|
REQUIRE(fsm.in_state(MyState::RUNNING));
|
||||||
|
|
||||||
|
fsm.event(MyEvent::QUIT, "DONE!");
|
||||||
|
REQUIRE(fsm.in_state(MyState::END));
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue