[RELEASE] u22-v04

This version is submitted for U22 final presentation. (squashed 158 commits)
This commit is contained in:
2020-10-09 00:00:00 +00:00
parent 84c3a02b9a
commit 80b3b82332
277 changed files with 12154 additions and 13836 deletions

View File

@@ -0,0 +1,9 @@
add_library(statman
statman.c
)
if (BUILD_TESTING)
add_executable(statman-test test.c)
target_link_libraries(statman-test statman)
add_test(statman-test statman-test)
endif()

4
util/statman/README.md Normal file
View File

@@ -0,0 +1,4 @@
statman
====
the simplest STATe MANagement system

89
util/statman/statman.c Normal file
View File

@@ -0,0 +1,89 @@
#include "./statman.h"
#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define REDIRECT_MAX_ 100
static const statman_meta_t* statman_get_meta_by_state_(
const statman_meta_t* meta, statman_state_t state) {
assert(meta != NULL);
for (size_t i = 0; meta[i].name != NULL; ++i) {
if (meta[i].state == state) return &meta[i];
}
fprintf(stderr, "statman: unknown state %"PRIu16"\n", state);
abort();
}
static void statman_initialize_state_(
const statman_meta_t* meta,
void* instance,
statman_state_t* state,
size_t depth) {
assert(meta != NULL);
assert(state != NULL);
assert(depth < REDIRECT_MAX_);
const statman_meta_t* m = statman_get_meta_by_state_(meta, *state);
if (m->initialize == NULL) return;
const statman_state_t backup = *state;
m->initialize(m, instance, state);
if (backup != *state) {
statman_initialize_state_(meta, instance, state, depth+1);
}
}
static void statman_update_state_(
const statman_meta_t* meta,
void* instance,
statman_state_t* state,
size_t depth) {
assert(meta != NULL);
assert(state != NULL);
assert(depth < REDIRECT_MAX_);
const statman_meta_t* m = statman_get_meta_by_state_(meta, *state);
if (m->update == NULL) return;
const statman_state_t backup = *state;
m->update(m, instance, state);
if (backup != *state) {
statman_initialize_state_(meta, instance, state, depth+1);
statman_update_state_(meta, instance, state, depth+1);
}
}
void statman_update(
const statman_meta_t* meta, void* instance, statman_state_t* state) {
assert(meta != NULL);
assert(state != NULL);
statman_update_state_(meta, instance, state, 0);
}
void statman_transition_to(
const statman_meta_t* meta,
void* instance,
statman_state_t* state,
statman_state_t next) {
assert(meta != NULL);
assert(state != NULL);
if (*state == next) return;
const statman_meta_t* m = statman_get_meta_by_state_(meta, *state);
if (m->finalize != NULL) {
m->finalize(m, instance, &next);
}
if (*state == next) return;
*state = next;
statman_initialize_state_(meta, instance, state, 0);
}

47
util/statman/statman.h Normal file
View File

@@ -0,0 +1,47 @@
#pragma once
#include <stdint.h>
typedef uint16_t statman_state_t;
typedef struct statman_meta_t statman_meta_t;
struct statman_meta_t {
statman_state_t state;
const char* name;
const void* data;
void
(*initialize)(
const statman_meta_t* meta,
void* instance,
statman_state_t* next
);
void
(*update)(
const statman_meta_t* meta,
void* instance,
statman_state_t* next
);
void
(*finalize)(
const statman_meta_t* meta,
void* instance,
statman_state_t* next
);
};
void
statman_update(
const statman_meta_t* meta,
void* instance,
statman_state_t* state
);
/* don't call in callback functions */
void
statman_transition_to(
const statman_meta_t* meta,
void* instance,
statman_state_t* state,
statman_state_t next
);

160
util/statman/test.c Normal file
View File

@@ -0,0 +1,160 @@
#undef NDEBUG
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include "./statman.h"
typedef enum {
CHECK_POINT_NONE,
CHECK_POINT_STATE0_INITIALIZE,
CHECK_POINT_STATE1_INITIALIZE,
CHECK_POINT_STATE2_INITIALIZE,
CHECK_POINT_STATE3_INITIALIZE,
CHECK_POINT_STATE0_UPDATE,
CHECK_POINT_STATE1_UPDATE,
CHECK_POINT_STATE2_UPDATE,
CHECK_POINT_STATE0_FINALIZE,
CHECK_POINT_STATE1_FINALIZE,
CHECK_POINT_STATE2_FINALIZE,
CHECK_POINT_STATE3_FINALIZE,
} check_point_t;
static check_point_t actual_[256] = {0};
static size_t actual_length_ = 0;
static inline void check_point_(check_point_t cp) {
assert(actual_length_ < sizeof(actual_)/sizeof(actual_[0]));
actual_[actual_length_++] = cp;
}
static void state_initialize_(
const statman_meta_t* meta, void* time, statman_state_t* next) {
assert(meta != NULL);
assert(time != NULL);
assert(next != NULL);
check_point_(CHECK_POINT_STATE0_INITIALIZE+meta->state);
}
static void state3_initialize_(
const statman_meta_t* meta, void* time, statman_state_t* next) {
assert(meta != NULL);
assert(time != NULL);
assert(next != NULL);
check_point_(CHECK_POINT_STATE3_INITIALIZE);
*next = 0;
}
static void state_update_(
const statman_meta_t* meta, void* time, statman_state_t* next) {
assert(meta != NULL);
assert(time != NULL);
assert(next != NULL);
check_point_(CHECK_POINT_STATE0_UPDATE+meta->state);
size_t *t = (typeof(t)) time;
if ((*t)++%2 == 0) *next = meta->state+1;
}
static void state_finalize_(
const statman_meta_t* meta, void* time, statman_state_t* next) {
assert(meta != NULL);
assert(time != NULL);
assert(next != NULL);
check_point_(CHECK_POINT_STATE0_FINALIZE+meta->state);
*next = 0;
}
static const statman_meta_t table_[] = {
{
.state = 0,
.name = "0",
.initialize = state_initialize_,
.update = state_update_,
.finalize = state_finalize_,
},
{
.state = 1,
.name = "1",
.initialize = state_initialize_,
.update = state_update_,
.finalize = state_finalize_,
},
{
.state = 2,
.name = "2",
.initialize = state_initialize_,
.update = state_update_,
.finalize = state_finalize_,
},
{
.state = 3,
.name = "3",
.initialize = state3_initialize_,
},
};
int main(void) {
statman_state_t state = 0;
size_t time = 0;
/* state0 -> state1 */
statman_update(table_, &time, &state);
assert(state == 1);
assert(time == 2);
/* state1 -> state2 */
statman_update(table_, &time, &state);
assert(state == 2);
assert(time == 4);
/* state2 -> state0 */
statman_update(table_, &time, &state);
assert(state == 0);
assert(time == 6);
/* state0 -> state1 */
statman_update(table_, &time, &state);
assert(state == 1);
assert(time == 8);
/* stat1's finalizer forces to move to 0 */
statman_transition_to(table_, &time, &state, 2);
assert(state == 0);
assert(time == 8);
static const check_point_t expects[] = {
CHECK_POINT_STATE0_UPDATE,
CHECK_POINT_STATE1_INITIALIZE,
CHECK_POINT_STATE1_UPDATE,
CHECK_POINT_STATE1_UPDATE,
CHECK_POINT_STATE2_INITIALIZE,
CHECK_POINT_STATE2_UPDATE,
CHECK_POINT_STATE2_UPDATE,
CHECK_POINT_STATE3_INITIALIZE,
CHECK_POINT_STATE0_INITIALIZE,
CHECK_POINT_STATE0_UPDATE,
CHECK_POINT_STATE0_UPDATE,
CHECK_POINT_STATE1_INITIALIZE,
CHECK_POINT_STATE1_UPDATE,
CHECK_POINT_STATE1_FINALIZE,
CHECK_POINT_STATE0_INITIALIZE,
};
assert(actual_length_ == sizeof(expects)/sizeof(expects[0]));
for (size_t i = 0; i < actual_length_; ++i) {
assert(expects[i] == actual_[i]);
}
}