2024-08-14 00:33:52 +03:00
|
|
|
#ifndef MODIFIERS_H_
|
|
|
|
#define MODIFIERS_H_
|
|
|
|
|
|
|
|
#include "defs.h"
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
size_t byte_length;
|
|
|
|
uint8_t *bits;
|
|
|
|
} ModifierSet;
|
|
|
|
|
2024-08-17 15:47:53 +03:00
|
|
|
typedef int32_t Modifier;
|
|
|
|
|
2024-08-17 16:17:49 +03:00
|
|
|
typedef enum {
|
|
|
|
MODOP_SET,
|
|
|
|
MODOP_UNSET,
|
|
|
|
MODOP_TOGGLE,
|
|
|
|
} ModifierOperation;
|
|
|
|
|
2024-08-14 00:33:52 +03:00
|
|
|
#define EMPTY_MODIFIER_SET ((ModifierSet) {.byte_length = 0, .bits = NULL})
|
2024-08-17 16:04:20 +03:00
|
|
|
#define MODIFIER_MAX ((Modifier) 0xFFFFF)
|
2024-08-14 00:33:52 +03:00
|
|
|
|
|
|
|
__attribute__((unused)) inline static ModifierSet
|
|
|
|
modifier_set_copy(const ModifierSet old)
|
|
|
|
{
|
|
|
|
ModifierSet result = old;
|
|
|
|
result.bits = malloc(result.byte_length);
|
|
|
|
if (!result.bits) {
|
|
|
|
result.byte_length = 0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
memcpy(result.bits, old.bits, result.byte_length);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_destruct(ModifierSet * old)
|
|
|
|
{
|
|
|
|
if (old->bits) {
|
|
|
|
free(old->bits);
|
|
|
|
}
|
|
|
|
old->bits = NULL;
|
|
|
|
old->byte_length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static bool
|
|
|
|
modifier_set_extend(ModifierSet * old, size_t new_byte_length)
|
|
|
|
{
|
|
|
|
if (new_byte_length > old->byte_length) {
|
|
|
|
uint8_t *bits = realloc(old->bits, new_byte_length);
|
|
|
|
if (!bits) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
memset(bits + old->byte_length, 0, new_byte_length - old->byte_length);
|
|
|
|
old->bits = bits;
|
|
|
|
old->byte_length = new_byte_length;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_set_from(ModifierSet * target, const ModifierSet source)
|
|
|
|
{
|
|
|
|
modifier_set_extend(target, source.byte_length);
|
|
|
|
for (size_t i = 0; i < target->byte_length; ++i) {
|
2024-08-17 15:47:22 +03:00
|
|
|
if (i >= source.byte_length) {
|
|
|
|
return;
|
|
|
|
}
|
2024-08-14 00:33:52 +03:00
|
|
|
target->bits[i] |= source.bits[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_unset_from(ModifierSet * target, const ModifierSet source)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < target->byte_length; ++i) {
|
2024-08-17 15:47:22 +03:00
|
|
|
if (i >= source.byte_length) {
|
|
|
|
return;
|
|
|
|
}
|
2024-08-14 00:33:52 +03:00
|
|
|
target->bits[i] &= ~source.bits[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_toggle_from(ModifierSet * target, const ModifierSet source)
|
|
|
|
{
|
|
|
|
modifier_set_extend(target, source.byte_length);
|
|
|
|
for (size_t i = 0; i < target->byte_length; ++i) {
|
2024-08-17 15:47:22 +03:00
|
|
|
if (i >= source.byte_length) {
|
|
|
|
return;
|
|
|
|
}
|
2024-08-14 00:33:52 +03:00
|
|
|
target->bits[i] ^= source.bits[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-17 15:47:53 +03:00
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_index_and_mask(Modifier modifier, size_t * byte_index, uint8_t * mask)
|
|
|
|
{
|
|
|
|
if (byte_index) {
|
|
|
|
*byte_index = modifier >> 3;
|
|
|
|
}
|
|
|
|
if (mask) {
|
|
|
|
*mask = 1 << (modifier & 7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static bool
|
|
|
|
modifier_set_has(ModifierSet collection, Modifier element)
|
|
|
|
{
|
|
|
|
size_t byte_index;
|
|
|
|
uint8_t mask;
|
|
|
|
modifier_index_and_mask(element, &byte_index, &mask);
|
|
|
|
if (byte_index >= collection.byte_length) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (collection.bits[byte_index] & mask) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_set(ModifierSet * target, Modifier element)
|
|
|
|
{
|
|
|
|
size_t byte_index;
|
|
|
|
uint8_t mask;
|
|
|
|
modifier_index_and_mask(element, &byte_index, &mask);
|
2024-08-17 16:45:10 +03:00
|
|
|
if (!modifier_set_extend(target, byte_index + 1)) {
|
|
|
|
return;
|
|
|
|
}
|
2024-08-17 15:47:53 +03:00
|
|
|
target->bits[byte_index] |= mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_unset(ModifierSet * target, Modifier element)
|
|
|
|
{
|
|
|
|
size_t byte_index;
|
|
|
|
uint8_t mask;
|
|
|
|
modifier_index_and_mask(element, &byte_index, &mask);
|
|
|
|
if (byte_index >= target->byte_length) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
target->bits[byte_index] &= ~mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_toggle(ModifierSet * target, Modifier element)
|
|
|
|
{
|
|
|
|
size_t byte_index;
|
|
|
|
uint8_t mask;
|
|
|
|
modifier_index_and_mask(element, &byte_index, &mask);
|
2024-08-17 16:45:10 +03:00
|
|
|
if (!modifier_set_extend(target, byte_index + 1)) {
|
|
|
|
return;
|
|
|
|
}
|
2024-08-17 15:47:53 +03:00
|
|
|
target->bits[byte_index] ^= mask;
|
|
|
|
}
|
|
|
|
|
2024-08-17 16:17:49 +03:00
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_operation_from(ModifierSet * target, const ModifierSet source, ModifierOperation op)
|
|
|
|
{
|
|
|
|
switch (op) {
|
|
|
|
case MODOP_SET:
|
|
|
|
modifier_set_set_from(target, source);
|
|
|
|
return;
|
|
|
|
case MODOP_UNSET:
|
|
|
|
modifier_set_unset_from(target, source);
|
|
|
|
return;
|
|
|
|
case MODOP_TOGGLE:
|
|
|
|
modifier_set_toggle_from(target, source);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static void
|
|
|
|
modifier_set_operation(ModifierSet * target, Modifier element, ModifierOperation op)
|
|
|
|
{
|
|
|
|
switch (op) {
|
|
|
|
case MODOP_SET:
|
|
|
|
modifier_set_set(target, element);
|
|
|
|
return;
|
|
|
|
case MODOP_UNSET:
|
|
|
|
modifier_set_unset(target, element);
|
|
|
|
return;
|
|
|
|
case MODOP_TOGGLE:
|
|
|
|
modifier_set_toggle(target, element);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((unused)) inline static ModifierOperation
|
|
|
|
modifier_operation_parse(const char* name)
|
|
|
|
{
|
|
|
|
if (!name) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (strcmp(name, "set") == 0) {
|
|
|
|
return MODOP_SET;
|
|
|
|
}
|
|
|
|
if (strcmp(name, "unset") == 0) {
|
|
|
|
return MODOP_UNSET;
|
|
|
|
}
|
|
|
|
if (strcmp(name, "reset") == 0) {
|
|
|
|
return MODOP_UNSET;
|
|
|
|
}
|
2024-08-18 16:23:49 +03:00
|
|
|
if (strcmp(name, "toggle") == 0) {
|
2024-08-17 16:17:49 +03:00
|
|
|
return MODOP_TOGGLE;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2024-08-14 00:33:52 +03:00
|
|
|
#endif /* end of include guard: MODIFIERS_H_ */
|