Initial commit that has most of what I need.

main
Zed A. Shaw 2 weeks ago
parent 933f47a440
commit ad143dca05
  1. 2
      .gitignore
  2. 18
      Makefile
  3. 40
      dbc.cpp
  4. 29
      dbc.hpp
  5. 28
      fsm.hpp
  6. 39
      main.cpp
  7. 28
      meson.build
  8. 13
      scripts/reset_build.ps1
  9. 14
      scripts/reset_build.sh
  10. 39
      tests/dbc.cpp
  11. 67
      tests/fsm.cpp

2
.gitignore vendored

@ -19,3 +19,5 @@ tags
# Persistent undo
[._]*.un~
subprojects
builddir

@ -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

@ -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};
}
}

@ -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);
}

@ -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;
}
};

@ -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;
}

@ -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)

@ -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

@ -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

@ -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");
}
}

@ -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…
Cancel
Save