meta: rename core module to fx namespace

This commit is contained in:
2026-05-02 14:36:59 +01:00
parent b072632499
commit 7db5fefe25
69 changed files with 0 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
include(../cmake/Templates.cmake)
add_fx_module(
NAME core
SUBDIRS hash)
+891
View File
@@ -0,0 +1,891 @@
/*
The Clear BSD License
Copyright (c) 2023 Max Wash
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the disclaimer
below) provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
*/
/* templated AVL binary tree implementation
this file implements an extensible AVL binary tree data structure.
the primary rule of an AVL binary tree is that for a given node N,
the heights of N's left and right substs can differ by at most 1.
the height of a subst is the length of the longest path between
the root of the subst and a leaf node, including the root node itself.
the height of a leaf node is 1.
when a node is inserted into or deleted from the tree, this rule may
be broken, in which the tree must be rotated to restore the balance.
no more than one rotation is required for any insert operations,
while multiple rotations may be required for a delete operation.
there are four types of rotations that can be applied to a tree:
- left rotation
- right rotation
- double left rotations
- double right rotations
by enforcing the balance rule, for a tree with n nodes, the worst-case
performance for insert, delete, and search operations is guaranteed
to be O(log n).
this file intentionally excludes any kind of search function implementation.
it is up to the programmer to implement their own tree node type
using fx_bst_node, and their own search function using fx_bst.
this allows the programmer to define their own node types with complex
non-integer key types. bst.h contains a number of macros to help
define these functions. the macros do all the work, you just have to
provide a comparator function.
*/
#include <fx/core/bst.h>
#include <stddef.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define IS_LEFT_CHILD(p, c) ((p) && (c) && ((p)->n_left == (c)))
#define IS_RIGHT_CHILD(p, c) ((p) && (c) && ((p)->n_right == (c)))
#define HAS_LEFT_CHILD(x) ((x) && ((x)->n_left))
#define HAS_RIGHT_CHILD(x) ((x) && ((x)->n_right))
#define HAS_NO_CHILDREN(x) ((x) && (!(x)->n_left) && (!(x)->n_right))
#define HAS_ONE_CHILD(x) \
((HAS_LEFT_CHILD(x) && !HAS_RIGHT_CHILD(x)) \
|| (!HAS_LEFT_CHILD(x) && HAS_RIGHT_CHILD(x)))
#define HAS_TWO_CHILDREN(x) (HAS_LEFT_CHILD(x) && HAS_RIGHT_CHILD(x))
#define HEIGHT(x) ((x) ? (x)->n_height : 0)
struct fx_bst_iterator_p {
size_t i, depth;
fx_bst_node *node;
fx_bst *_b;
};
static inline void update_height(struct fx_bst_node *x)
{
x->n_height = MAX(HEIGHT(x->n_left), HEIGHT((x->n_right))) + 1;
}
static inline int bf(struct fx_bst_node *x)
{
int bf = 0;
if (!x) {
return bf;
}
if (x->n_right) {
bf += x->n_right->n_height;
}
if (x->n_left) {
bf -= x->n_left->n_height;
}
return bf;
}
/* perform a left rotation on a subst
if you have a tree like this:
Z
/ \
X .
/ \
. Y
/ \
. .
and you perform a left rotation on node X,
you will get the following tree:
Z
/ \
Y .
/ \
X .
/ \
. .
note that this function does NOT update fx_height for the rotated
nodes. it is up to you to call update_height_to_root().
*/
static void rotate_left(struct fx_bst *tree, struct fx_bst_node *x)
{
struct fx_bst_node *y = x->n_right;
struct fx_bst_node *p = x->n_parent;
if (y->n_left) {
y->n_left->n_parent = x;
}
x->n_right = y->n_left;
if (!p) {
tree->bst_root = y;
} else if (x == p->n_left) {
p->n_left = y;
} else {
p->n_right = y;
}
x->n_parent = y;
y->n_left = x;
y->n_parent = p;
}
static void update_height_to_root(struct fx_bst_node *x)
{
while (x) {
update_height(x);
x = x->n_parent;
}
}
/* perform a right rotation on a subst
if you have a tree like this:
Z
/ \
. X
/ \
Y .
/ \
. .
and you perform a right rotation on node X,
you will get the following tree:
Z
/ \
. Y
/ \
. X
/ \
. .
note that this function does NOT update fx_height for the rotated
nodes. it is up to you to call update_height_to_root().
*/
static void rotate_right(struct fx_bst *tree, struct fx_bst_node *y)
{
struct fx_bst_node *x = y->n_left;
struct fx_bst_node *p = y->n_parent;
if (x->n_right) {
x->n_right->n_parent = y;
}
y->n_left = x->n_right;
if (!p) {
tree->bst_root = x;
} else if (y == p->n_left) {
p->n_left = x;
} else {
p->n_right = x;
}
y->n_parent = x;
x->n_right = y;
x->n_parent = p;
}
/* for a given node Z, perform a right rotation on Z's right child,
followed by a left rotation on Z itself.
if you have a tree like this:
Z
/ \
. X
/ \
Y .
/ \
. .
and you perform a double-left rotation on node Z,
you will get the following tree:
Y
/ \
/ \
Z X
/ \ / \
. . . .
note that, unlike rotate_left and rotate_right, this function
DOES update fx_height for the rotated nodes (since it needs to be
done in a certain order).
*/
static void rotate_double_left(struct fx_bst *tree, struct fx_bst_node *z)
{
struct fx_bst_node *x = z->n_right;
struct fx_bst_node *y = x->n_left;
rotate_right(tree, x);
rotate_left(tree, z);
update_height(z);
update_height(x);
while (y) {
update_height(y);
y = y->n_parent;
}
}
/* for a given node Z, perform a left rotation on Z's left child,
followed by a right rotation on Z itself.
if you have a tree like this:
Z
/ \
X .
/ \
. Y
/ \
. .
and you perform a double-right rotation on node Z,
you will get the following tree:
Y
/ \
/ \
X Z
/ \ / \
. . . .
note that, unlike rotate_left and rotate_right, this function
DOES update fx_height for the rotated nodes (since it needs to be
done in a certain order).
*/
static void rotate_double_right(struct fx_bst *tree, struct fx_bst_node *z)
{
struct fx_bst_node *x = z->n_left;
struct fx_bst_node *y = x->n_right;
rotate_left(tree, x);
rotate_right(tree, z);
update_height(z);
update_height(x);
while (y) {
update_height(y);
y = y->n_parent;
}
}
/* run after an insert operation. checks that the balance factor
of the local subst is within the range -1 <= BF <= 1. if it
is not, rotate the subst to restore balance.
note that at most one rotation should be required after a node
is inserted into the tree.
this function depends on all nodes in the tree having
correct fx_height values.
@param w the node that was just inserted into the tree
*/
static void insert_fixup(struct fx_bst *tree, struct fx_bst_node *w)
{
struct fx_bst_node *z = NULL, *y = NULL, *x = NULL;
z = w;
while (z) {
if (bf(z) >= -1 && bf(z) <= 1) {
goto next_ancestor;
}
if (IS_LEFT_CHILD(z, y)) {
if (IS_LEFT_CHILD(y, x)) {
rotate_right(tree, z);
update_height_to_root(z);
} else {
rotate_double_right(tree, z);
}
} else {
if (IS_LEFT_CHILD(y, x)) {
rotate_double_left(tree, z);
} else {
rotate_left(tree, z);
update_height_to_root(z);
}
}
next_ancestor:
x = y;
y = z;
z = z->n_parent;
}
}
/* run after a delete operation. checks that the balance factor
of the local subst is within the range -1 <= BF <= 1. if it
is not, rotate the subst to restore balance.
note that, unlike insert_fixup, multiple rotations may be required
to restore balance after a node is deleted.
this function depends on all nodes in the tree having
correct fx_height values.
@param w one of the following:
- the parent of the node that was deleted if the node
had no children.
- the parent of the node that replaced the deleted node
if the deleted node had two children.
- the node that replaced the node that was deleted, if
the node that was deleted had one child.
*/
static void delete_fixup(struct fx_bst *tree, struct fx_bst_node *w)
{
struct fx_bst_node *z = w;
while (z) {
if (bf(z) > 1) {
if (bf(z->n_right) >= 0) {
rotate_left(tree, z);
update_height_to_root(z);
} else {
rotate_double_left(tree, z);
}
} else if (bf(z) < -1) {
if (bf(z->n_left) <= 0) {
rotate_right(tree, z);
update_height_to_root(z);
} else {
rotate_double_right(tree, z);
}
}
z = z->n_parent;
}
}
/* updates fx_height for all nodes between the inserted node and the root
of the tree, and calls insert_fixup.
@param node the node that was just inserted into the tree.
*/
void fx_bst_insert_fixup(struct fx_bst *tree, struct fx_bst_node *node)
{
node->n_height = 0;
struct fx_bst_node *cur = node;
while (cur) {
update_height(cur);
cur = cur->n_parent;
}
insert_fixup(tree, node);
}
/* remove a node from a tree.
this function assumes that `node` has no children, and therefore
doesn't need to be replaced.
updates fx_height for all nodes between `node` and the tree root.
@param node the node to delete.
*/
static struct fx_bst_node *remove_node_with_no_children(
struct fx_bst *tree, struct fx_bst_node *node)
{
struct fx_bst_node *w = node->n_parent;
struct fx_bst_node *p = node->n_parent;
node->n_parent = NULL;
if (!p) {
tree->bst_root = NULL;
} else if (IS_LEFT_CHILD(p, node)) {
p->n_left = NULL;
} else {
p->n_right = NULL;
}
while (p) {
update_height(p);
p = p->n_parent;
}
return w;
}
/* remove a node from a tree.
this function assumes that `node` has one child.
the child of `node` is inherited by `node`'s parent, and `node` is removed.
updates fx_height for all nodes between the node that replaced
`node` and the tree root.
@param node the node to delete.
*/
static struct fx_bst_node *replace_node_with_one_subst(
struct fx_bst *tree, struct fx_bst_node *node)
{
struct fx_bst_node *p = node->n_parent;
struct fx_bst_node *z = NULL;
if (HAS_LEFT_CHILD(node)) {
z = node->n_left;
} else {
z = node->n_right;
}
struct fx_bst_node *w = z;
if (!p) {
tree->bst_root = z;
} else if (IS_LEFT_CHILD(p, node)) {
p->n_left = z;
} else if (IS_RIGHT_CHILD(p, node)) {
p->n_right = z;
}
z->n_parent = p;
node->n_parent = NULL;
node->n_left = node->n_right = NULL;
while (z) {
update_height(z);
z = z->n_parent;
}
return w;
}
/* remove a node from a tree.
this function assumes that `node` has two children.
find the in-order successor Y of `node` (the largest node in `node`'s left
sub-tree), removes `node` from the tree and moves Y to where `node` used to
be.
if Y has a child (it will never have more than one), have Y's parent inherit
Y's child.
updates fx_height for all nodes between the deepest node that was modified
and the tree root.
@param z the node to delete.
*/
static struct fx_bst_node *replace_node_with_two_substs(
struct fx_bst *tree, struct fx_bst_node *z)
{
/* x will replace z */
struct fx_bst_node *x = z->n_left;
while (x->n_right) {
x = x->n_right;
}
/* y is the node that will replace x (if x has a left child) */
struct fx_bst_node *y = x->n_left;
/* w is the starting point for the height update and fixup */
struct fx_bst_node *w = x;
if (w->n_parent != z) {
w = w->n_parent;
}
if (y) {
w = y;
}
if (IS_LEFT_CHILD(x->n_parent, x)) {
x->n_parent->n_left = y;
} else if (IS_RIGHT_CHILD(x->n_parent, x)) {
x->n_parent->n_right = y;
}
if (y) {
y->n_parent = x->n_parent;
}
if (IS_LEFT_CHILD(z->n_parent, z)) {
z->n_parent->n_left = x;
} else if (IS_RIGHT_CHILD(z->n_parent, z)) {
z->n_parent->n_right = x;
}
x->n_parent = z->n_parent;
x->n_left = z->n_left;
x->n_right = z->n_right;
if (x->n_left) {
x->n_left->n_parent = x;
}
if (x->n_right) {
x->n_right->n_parent = x;
}
if (!x->n_parent) {
tree->bst_root = x;
}
struct fx_bst_node *cur = w;
while (cur) {
update_height(cur);
cur = cur->n_parent;
}
return w;
}
/* delete a node from the tree and re-balance it afterwards */
void fx_bst_delete(struct fx_bst *tree, struct fx_bst_node *node)
{
struct fx_bst_node *w = NULL;
if (HAS_NO_CHILDREN(node)) {
w = remove_node_with_no_children(tree, node);
} else if (HAS_ONE_CHILD(node)) {
w = replace_node_with_one_subst(tree, node);
} else if (HAS_TWO_CHILDREN(node)) {
w = replace_node_with_two_substs(tree, node);
}
if (w) {
delete_fixup(tree, w);
}
node->n_left = node->n_right = node->n_parent = NULL;
}
static struct fx_bst_node *first_node(const struct fx_bst *tree, int *depth)
{
/* the first node in the tree is the node with the smallest key.
we keep moving left until we can't go any further */
struct fx_bst_node *cur = tree->bst_root;
int d = 0;
if (!cur) {
*depth = 0;
return NULL;
}
while (cur->n_left) {
d++;
cur = cur->n_left;
}
*depth = d;
return cur;
}
struct fx_bst_node *fx_bst_first(const struct fx_bst *tree)
{
int d;
return first_node(tree, &d);
}
static struct fx_bst_node *last_node(const struct fx_bst *tree, int *depth)
{
/* the first node in the tree is the node with the largest key.
we keep moving right until we can't go any further */
struct fx_bst_node *cur = tree->bst_root;
int d = 0;
if (!cur) {
return NULL;
}
while (cur->n_right) {
d++;
cur = cur->n_right;
}
*depth = d;
return cur;
}
fx_bst_node *fx_bst_last(const struct fx_bst *tree)
{
int d;
return last_node(tree, &d);
}
static fx_bst_node *next_node(const struct fx_bst_node *node, int *depth_diff)
{
if (!node) {
return NULL;
}
int depth = 0;
/* there are two possibilities for the next node:
1. if `node` has a right sub-tree, every node in this sub-tree is
bigger than node. the in-order successor of `node` is the smallest
node in this subst.
2. if `node` has no right sub-tree, we've reached the largest node in
the sub-tree rooted at `node`. we need to go back to our parent
and continue the search elsewhere.
*/
if (node->n_right) {
/* case 1: step into `node`'s right sub-tree and keep going
left to find the smallest node */
struct fx_bst_node *cur = node->n_right;
depth++;
while (cur->n_left) {
cur = cur->n_left;
depth++;
}
*depth_diff = depth;
return cur;
}
/* case 2: keep stepping back up towards the root of the tree.
if we encounter a step where we are our parent's left child,
we've found a parent with a value larger than us. this parent
is the in-order successor of `node` */
while (node->n_parent && node->n_parent->n_left != node) {
node = node->n_parent;
depth--;
}
*depth_diff = depth - 1;
return node->n_parent;
}
static fx_bst_node *prev_node(const struct fx_bst_node *node, int *depth_diff)
{
if (!node) {
return NULL;
}
int depth = 0;
/* there are two possibilities for the previous node:
1. if `node` has a left sub-tree, every node in this sub-tree is
smaller than `node`. the in-order predecessor of `node` is the
largest node in this subst.
2. if `node` has no left sub-tree, we've reached the smallest node in
the sub-tree rooted at `node`. we need to go back to our parent
and continue the search elsewhere.
*/
if (node->n_left) {
/* case 1: step into `node`'s left sub-tree and keep going
right to find the largest node */
fx_bst_node *cur = node->n_left;
depth++;
while (cur->n_right) {
cur = cur->n_right;
depth++;
}
*depth_diff = depth;
return cur;
}
/* case 2: keep stepping back up towards the root of the tree.
if we encounter a step where we are our parent's right child,
we've found a parent with a value smaller than us. this parent
is the in-order predecessor of `node`. */
while (node->n_parent && node->n_parent->n_right != node) {
node = node->n_parent;
depth--;
}
*depth_diff = depth - 1;
return node->n_parent;
}
fx_bst_node *fx_bst_next(const struct fx_bst_node *node)
{
int d;
return next_node(node, &d);
}
fx_bst_node *fx_bst_prev(const struct fx_bst_node *node)
{
int d;
return prev_node(node, &d);
}
void fx_bst_move(
struct fx_bst *tree, struct fx_bst_node *dest, struct fx_bst_node *src)
{
if (src->n_parent) {
if (src->n_parent->n_left == src) {
src->n_parent->n_left = dest;
} else {
src->n_parent->n_right = dest;
}
}
if (src->n_left) {
src->n_left->n_parent = dest;
}
if (src->n_right) {
src->n_right->n_parent = dest;
}
if (tree->bst_root == src) {
tree->bst_root = dest;
}
memmove(dest, src, sizeof *src);
}
fx_iterator *fx_bst_begin(struct fx_bst *tree)
{
fx_iterator *it_obj = fx_object_create(FX_TYPE_BST_ITERATOR);
if (!it_obj) {
return NULL;
}
struct fx_bst_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_BST_ITERATOR);
int depth = 0;
it->_b = (struct fx_bst *)tree;
it->i = 0;
it->node = first_node(tree, &depth);
it->depth = depth;
return it_obj;
}
const fx_iterator *fx_bst_cbegin(const struct fx_bst *tree)
{
fx_iterator *it_obj = fx_object_create(FX_TYPE_BST_ITERATOR);
if (!it_obj) {
return NULL;
}
struct fx_bst_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_BST_ITERATOR);
int depth = 0;
it->_b = (struct fx_bst *)tree;
it->i = 0;
it->node = first_node(tree, &depth);
it->depth = depth;
return it_obj;
}
static enum fx_status iterator_move_next(const fx_iterator *obj)
{
struct fx_bst_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_BST_ITERATOR);
int depth_diff = 0;
struct fx_bst_node *next = next_node(it->node, &depth_diff);
if (!next) {
it->node = NULL;
it->depth = 0;
it->i++;
return false;
}
it->node = next;
it->i++;
it->depth += depth_diff;
return true;
}
static enum fx_status iterator_erase(fx_iterator *obj)
{
struct fx_bst_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_BST_ITERATOR);
if (!it->node) {
return FX_ERR_OUT_OF_BOUNDS;
}
int depth_diff = 0;
struct fx_bst_node *next = next_node(it->node, &depth_diff);
fx_bst_delete(it->_b, it->node);
if (!next) {
it->node = NULL;
it->depth = 0;
} else {
it->node = next;
it->depth = 0;
struct fx_bst_node *cur = next->n_parent;
while (cur) {
it->depth++;
cur = cur->n_parent;
}
}
return FX_SUCCESS;
}
static fx_iterator_value iterator_get_value(fx_iterator *obj)
{
struct fx_bst_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_BST_ITERATOR);
return FX_ITERATOR_VALUE_PTR(it->node);
}
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
{
struct fx_bst_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_BST_ITERATOR);
return FX_ITERATOR_VALUE_CPTR(it->node);
}
/*** CLASS DEFINITION *********************************************************/
// ---- fx_bst_iterator DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_bst_iterator)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
FX_TYPE_CLASS_DEFINITION_END(fx_bst_iterator)
FX_TYPE_DEFINITION_BEGIN(fx_bst_iterator)
FX_TYPE_ID(0x432779d7, 0xc03a, 0x48ea, 0xae8f, 0x12c666c767ae);
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
FX_TYPE_CLASS(fx_bst_iterator_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_bst_iterator_p);
FX_TYPE_DEFINITION_END(fx_bst_iterator)
+375
View File
@@ -0,0 +1,375 @@
#include "printf.h"
#include <fx/core/bstr.h>
#include <fx/core/rope.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHECK_FLAG(str, f) ((((str)->bstr_flags) & (f)) == (f))
#define IS_DYNAMIC(p) (CHECK_FLAG(p, FX_BSTR_F_ALLOC))
/* number of bytes that bstr_buf is extended by when required */
#define CAPACITY_STEP 32
void fx_bstr_begin(struct fx_bstr *str, char *buf, size_t max)
{
memset(str, 0x0, sizeof *str);
str->bstr_magic = FX_BSTR_MAGIC;
str->bstr_buf = buf;
str->bstr_capacity = max;
str->bstr_len = 0;
str->bstr_flags = FX_BSTR_F_NONE;
}
void fx_bstr_begin_dynamic(struct fx_bstr *str)
{
memset(str, 0x0, sizeof *str);
str->bstr_magic = FX_BSTR_MAGIC;
str->bstr_buf = NULL;
str->bstr_capacity = 0;
str->bstr_len = 0;
str->bstr_flags = FX_BSTR_F_ALLOC;
}
static char *truncate_buffer(char *s, size_t len)
{
if (!s || !len) {
return NULL;
}
char *final = realloc(s, len + 1);
if (!final) {
return s;
}
final[len] = '\0';
return final;
}
char *fx_bstr_end(struct fx_bstr *str)
{
char *out = str->bstr_buf;
size_t len = str->bstr_len;
if (IS_DYNAMIC(str) && str->bstr_capacity - 1 > str->bstr_len) {
/* bstr_buf is larger than required to contain the string.
* re-allocate it so it's only as large as necessary */
out = truncate_buffer(out, len);
}
if (str->bstr_istack) {
free(str->bstr_istack);
}
memset(str, 0x0, sizeof *str);
return out;
}
enum fx_status fx_bstr_reserve(struct fx_bstr *strv, size_t len)
{
if (!IS_DYNAMIC(strv)) {
return FX_SUCCESS;
}
if (strv->bstr_capacity > 0 && strv->bstr_capacity - 1 >= len) {
return FX_SUCCESS;
}
char *new_buf = realloc(strv->bstr_buf, len + 1);
if (!new_buf) {
return FX_ERR_NO_MEMORY;
}
strv->bstr_buf = new_buf;
strv->bstr_capacity = len + 1;
strv->bstr_buf[strv->bstr_len] = '\0';
return FX_SUCCESS;
}
static int current_indent(struct fx_bstr *str)
{
if (!str->bstr_istack || !str->bstr_istack_size) {
return 0;
}
return str->bstr_istack[str->bstr_istack_ptr];
}
static void __formatter_putchar(struct fx_bstr *str, char c)
{
if (str->bstr_capacity > 0 && str->bstr_len < str->bstr_capacity - 1) {
str->bstr_buf[str->bstr_len++] = c;
str->bstr_buf[str->bstr_len] = '\0';
return;
}
if (!CHECK_FLAG(str, FX_BSTR_F_ALLOC)) {
return;
}
size_t old_capacity = str->bstr_capacity;
size_t new_capacity = old_capacity + CAPACITY_STEP;
char *new_buf = realloc(str->bstr_buf, new_capacity);
if (!new_buf) {
return;
}
str->bstr_buf = new_buf;
str->bstr_capacity = new_capacity;
str->bstr_buf[str->bstr_len++] = c;
str->bstr_buf[str->bstr_len] = '\0';
}
static void formatter_putchar(struct fx_bstr *f, char c)
{
if (f->bstr_add_indent && c != '\n') {
int indent = current_indent(f);
for (int i = 0; i < indent; i++) {
__formatter_putchar(f, ' ');
__formatter_putchar(f, ' ');
}
f->bstr_add_indent = 0;
}
__formatter_putchar(f, c);
if (c == '\n') {
f->bstr_add_indent = 1;
}
}
static void bstr_fctprintf(char c, void *arg)
{
struct fx_bstr *str = arg;
formatter_putchar(str, c);
}
static enum fx_status bstr_putcs(
struct fx_bstr *str, const char *s, size_t len, size_t *nr_written)
{
for (size_t i = 0; i < len; i++) {
formatter_putchar(str, s[i]);
}
if (nr_written) {
*nr_written = len;
}
return FX_SUCCESS;
}
static enum fx_status bstr_puts(struct fx_bstr *str, const char *s, size_t *nr_written)
{
size_t i;
for (i = 0; s[i]; i++) {
formatter_putchar(str, s[i]);
}
if (nr_written) {
*nr_written = i;
}
return FX_SUCCESS;
}
enum fx_status fx_bstr_push_indent(struct fx_bstr *str, int indent)
{
if (!str->bstr_istack) {
str->bstr_istack = calloc(4, sizeof(int));
str->bstr_istack_size = 4;
str->bstr_istack_ptr = 0;
}
if (str->bstr_istack_ptr + 1 > str->bstr_istack_size) {
int *buf = realloc(
str->bstr_istack,
(str->bstr_istack_size + 4) * sizeof(int));
if (!buf) {
return FX_ERR_NO_MEMORY;
}
str->bstr_istack = buf;
str->bstr_istack_size += 4;
}
int cur_indent = str->bstr_istack[str->bstr_istack_ptr];
str->bstr_istack[++str->bstr_istack_ptr] = cur_indent + indent;
return FX_SUCCESS;
}
enum fx_status fx_bstr_pop_indent(struct fx_bstr *strv)
{
if (strv->bstr_istack_ptr > 0) {
strv->bstr_istack_ptr--;
}
return FX_SUCCESS;
}
enum fx_status fx_bstr_write_char(struct fx_bstr *str, char c)
{
formatter_putchar(str, c);
return FX_SUCCESS;
}
enum fx_status fx_bstr_write_chars(
struct fx_bstr *str, const char *s, size_t len, size_t *nr_written)
{
return bstr_putcs(str, s, len, nr_written);
}
enum fx_status fx_bstr_write_cstr(struct fx_bstr *str, const char *s, size_t *nr_written)
{
return bstr_puts(str, s, nr_written);
}
enum fx_status fx_bstr_write_cstr_list(
struct fx_bstr *str, const char **strs, size_t *nr_written)
{
size_t w = 0;
enum fx_status status = FX_SUCCESS;
for (size_t i = 0; strs[i]; i++) {
size_t tmp = 0;
status = bstr_puts(str, strs[i], &tmp);
w += tmp;
if (FX_ERR(status)) {
break;
}
}
if (nr_written) {
*nr_written = w;
}
return status;
}
enum fx_status fx_bstr_write_cstr_array(
struct fx_bstr *str, const char **strs, size_t count, size_t *nr_written)
{
enum fx_status status = FX_SUCCESS;
size_t w = 0;
for (size_t i = 0; i < count; i++) {
if (!strs[i]) {
continue;
}
size_t tmp = 0;
status = bstr_puts(str, strs[i], &tmp);
w += tmp;
if (FX_ERR(status)) {
break;
}
}
if (nr_written) {
*nr_written = w;
}
return status;
}
enum fx_status fx_bstr_add_many(struct fx_bstr *str, size_t *nr_written, ...)
{
va_list arg;
va_start(arg, nr_written);
const char *s = NULL;
size_t w = 0;
enum fx_status status = FX_SUCCESS;
while ((s = va_arg(arg, const char *))) {
size_t tmp = 0;
status = bstr_puts(str, s, &tmp);
w += tmp;
if (FX_ERR(status)) {
break;
}
}
if (nr_written) {
*nr_written = w;
}
return status;
}
enum fx_status fx_bstr_write_rope(
fx_bstr *strv, const struct fx_rope *rope, size_t *nr_written)
{
size_t start = strv->bstr_len;
enum fx_status status = fx_rope_to_bstr(rope, strv);
size_t end = strv->bstr_len;
if (nr_written) {
*nr_written = end - start;
}
return status;
}
enum fx_status fx_bstr_write_fmt(
struct fx_bstr *str, size_t *nr_written, const char *format, ...)
{
va_list arg;
va_start(arg, format);
enum fx_status result = fx_bstr_write_vfmt(str, nr_written, format, arg);
va_end(arg);
return result;
}
enum fx_status fx_bstr_write_vfmt(
struct fx_bstr *str, size_t *nr_written, const char *format, va_list arg)
{
size_t start = str->bstr_len;
z__fx_fctprintf(bstr_fctprintf, str, format, arg);
size_t end = str->bstr_len;
if (nr_written) {
*nr_written = end - start;
}
/* TODO update z__fx_fctprintf to support propagating error codes */
return FX_SUCCESS;
}
char *fx_bstr_rope(const struct fx_rope *rope, size_t *nr_written)
{
struct fx_bstr str;
fx_bstr_begin_dynamic(&str);
fx_bstr_write_rope(&str, rope, nr_written);
return fx_bstr_end(&str);
}
char *fx_bstr_fmt(size_t *nr_written, const char *format, ...)
{
va_list arg;
va_start(arg, format);
char *s = fx_bstr_vfmt(nr_written, format, arg);
va_end(arg);
return s;
}
char *fx_bstr_vfmt(size_t *nr_written, const char *format, va_list arg)
{
struct fx_bstr str;
fx_bstr_begin_dynamic(&str);
fx_bstr_write_vfmt(&str, nr_written, format, arg);
return fx_bstr_end(&str);
}
+79
View File
@@ -0,0 +1,79 @@
#include "class.h"
#include "type.h"
#include <assert.h>
#include <fx/core/class.h>
#include <stdlib.h>
#include <string.h>
void *fx_class_get(fx_type id)
{
struct fx_type_registration *r = fx_type_get_registration(id);
if (!r) {
return NULL;
}
return r->r_class;
}
const char *fx_class_get_name(const struct _fx_class *c)
{
if (!c) {
return NULL;
}
assert(c->c_magic == FX_CLASS_MAGIC);
return c->c_type->r_info->t_name;
}
void *fx_class_get_interface(const struct _fx_class *c, const union fx_type *id)
{
if (!c) {
return NULL;
}
assert(c->c_magic == FX_CLASS_MAGIC);
const struct fx_type_registration *type_reg = c->c_type;
struct fx_type_component *comp
= fx_type_get_component(&type_reg->r_components, id);
if (!comp) {
return NULL;
}
return (char *)c + comp->c_class_data_offset;
}
fx_result fx_class_instantiate(
struct fx_type_registration *type, struct _fx_class **out_class)
{
struct _fx_class *out = malloc(type->r_class_size);
if (!out) {
return FX_RESULT_ERR(NO_MEMORY);
}
memset(out, 0x0, type->r_class_size);
out->c_magic = FX_CLASS_MAGIC;
out->c_type = type;
struct fx_queue_entry *entry = fx_queue_first(&type->r_class_hierarchy);
while (entry) {
struct fx_type_component *comp
= fx_unbox(struct fx_type_component, entry, c_entry);
const struct fx_type_info *class_info = comp->c_type->r_info;
void *class_data = (char *)out + comp->c_class_data_offset;
if (class_info->t_class_init) {
class_info->t_class_init(out, class_data);
}
entry = fx_queue_next(entry);
}
*out_class = out;
return FX_RESULT_SUCCESS;
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef _CLASS_H_
#define _CLASS_H_
#include <fx/core/error.h>
#include <fx/core/misc.h>
#include <stdint.h>
struct fx_type_registration;
struct _fx_class {
uint64_t c_magic;
const struct fx_type_registration *c_type;
};
extern fx_result fx_class_instantiate(
struct fx_type_registration *type, struct _fx_class **out);
#endif
+1381
View File
File diff suppressed because it is too large Load Diff
+213
View File
@@ -0,0 +1,213 @@
#include <fx/core/endian.h>
fx_i16 fx_i16_htob(uint16_t v)
{
fx_i16 x;
#ifdef BIG_ENDIAN
x.i_uval = v;
#else
uint8_t *b = (uint8_t *)&v;
x.i_bytes[0] = b[1];
x.i_bytes[1] = b[0];
#endif
return x;
}
fx_i16 fx_i16_htos(uint16_t v)
{
fx_i16 x;
#ifdef LITTLE_ENDIAN
x.i_uval = v;
#else
uint8_t *b = (uint8_t *)&v;
x.i_bytes[0] = b[1];
x.i_bytes[1] = b[0];
#endif
return x;
}
uint16_t fx_i16_btoh(fx_i16 v)
{
uint16_t x;
#ifdef BIG_ENDIAN
x = v.i_uval;
#else
uint8_t *b = (uint8_t *)&x;
b[0] = v.i_bytes[1];
b[1] = v.i_bytes[0];
#endif
return x;
}
uint16_t fx_i16_stoh(fx_i16 v)
{
uint16_t x;
#ifdef LITTLE_ENDIAN
x = v.i_uval;
#else
uint8_t *b = (uint8_t *)&x;
b[0] = v.i_bytes[1];
b[1] = v.i_bytes[0];
#endif
return x;
}
fx_i32 fx_i32_htob(uint32_t v)
{
fx_i32 x;
#ifdef BIG_ENDIAN
x.i_uval = v;
#else
uint8_t *b = (uint8_t *)&v;
x.i_bytes[0] = b[3];
x.i_bytes[1] = b[2];
x.i_bytes[2] = b[1];
x.i_bytes[3] = b[0];
#endif
return x;
}
fx_i32 fx_i32_htos(uint32_t v)
{
fx_i32 x;
#ifdef LITTLE_ENDIAN
x.i_uval = v;
#else
uint8_t *b = (uint8_t *)&v;
x.i_bytes[0] = b[3];
x.i_bytes[1] = b[2];
x.i_bytes[2] = b[1];
x.i_bytes[3] = b[0];
#endif
return x;
}
uint32_t fx_i32_btoh(fx_i32 v)
{
uint32_t x;
#ifdef BIG_ENDIAN
x = v.i_uval;
#else
uint8_t *b = (uint8_t *)&x;
b[0] = v.i_bytes[3];
b[1] = v.i_bytes[2];
b[2] = v.i_bytes[1];
b[3] = v.i_bytes[0];
#endif
return x;
}
uint32_t fx_i32_stoh(fx_i32 v)
{
uint32_t x;
#ifdef LITTLE_ENDIAN
x = v.i_uval;
#else
uint8_t *b = (uint8_t *)&x;
b[0] = v.i_bytes[3];
b[1] = v.i_bytes[2];
b[2] = v.i_bytes[1];
b[3] = v.i_bytes[0];
#endif
return x;
}
fx_i64 fx_i64_htob(uint64_t v)
{
fx_i64 x;
#ifdef BIG_ENDIAN
x.i_uval = v;
#else
uint8_t *b = (uint8_t *)&v;
x.i_bytes[0] = b[7];
x.i_bytes[1] = b[6];
x.i_bytes[2] = b[5];
x.i_bytes[3] = b[4];
x.i_bytes[4] = b[3];
x.i_bytes[5] = b[2];
x.i_bytes[6] = b[1];
x.i_bytes[7] = b[0];
#endif
return x;
}
fx_i64 fx_i64_htos(uint64_t v)
{
fx_i64 x;
#ifdef LITTLE_ENDIAN
x.i_uval = v;
#else
uint8_t *b = (uint8_t *)&v;
x.i_bytes[0] = b[7];
x.i_bytes[1] = b[6];
x.i_bytes[2] = b[5];
x.i_bytes[3] = b[4];
x.i_bytes[4] = b[3];
x.i_bytes[5] = b[2];
x.i_bytes[6] = b[1];
x.i_bytes[7] = b[0];
#endif
return x;
}
uint64_t fx_i64_btoh(fx_i64 v)
{
uint64_t x;
#ifdef BIG_ENDIAN
x = v.i_uval;
#else
uint8_t *b = (uint8_t *)&x;
b[0] = v.i_bytes[7];
b[1] = v.i_bytes[6];
b[2] = v.i_bytes[5];
b[3] = v.i_bytes[4];
b[4] = v.i_bytes[3];
b[5] = v.i_bytes[2];
b[6] = v.i_bytes[1];
b[7] = v.i_bytes[0];
#endif
return x;
}
uint64_t fx_i64_stoh(fx_i64 v)
{
uint64_t x;
#ifdef LITTLE_ENDIAN
x = v.i_uval;
#else
uint8_t *b = (uint8_t *)&x;
b[0] = v.i_bytes[7];
b[1] = v.i_bytes[6];
b[2] = v.i_bytes[5];
b[3] = v.i_bytes[4];
b[4] = v.i_bytes[3];
b[5] = v.i_bytes[2];
b[6] = v.i_bytes[1];
b[7] = v.i_bytes[0];
#endif
return x;
}
+1059
View File
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
#ifndef _FX_ERROR_H_
#define _FX_ERROR_H_
#include <fx/core/error.h>
#include <fx/core/queue.h>
struct fx_error_stack_frame {
fx_queue_entry f_entry;
const char *f_file;
unsigned int f_line_number;
const char *f_function;
};
struct fx_error_submsg {
fx_queue_entry msg_entry;
fx_error_submsg_type msg_type;
char *msg_content;
const struct fx_error_msg *msg_msg;
struct fx_error_template_parameter msg_params[FX_ERROR_TEMPLATE_PARAMETER_MAX];
};
struct fx_error {
const struct fx_error_vendor *err_vendor;
fx_error_status_code err_code;
const struct fx_error_definition *err_def;
const struct fx_error_msg *err_msg;
char *err_description;
struct fx_error_template_parameter err_params[FX_ERROR_TEMPLATE_PARAMETER_MAX];
struct fx_queue err_submsg;
struct fx_queue err_stack;
fx_queue_entry err_entry;
struct fx_error *err_caused_by;
};
#endif
+178
View File
@@ -0,0 +1,178 @@
#include "hash.h"
#include <fx/core/hash.h>
#include <fx/core/rope.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define FNV1_OFFSET_BASIS 0xcbf29ce484222325
#define FNV1_PRIME 0x100000001b3
extern struct fx_hash_function_ops z__fx_md4_ops;
extern struct fx_hash_function_ops z__fx_md5_ops;
extern struct fx_hash_function_ops z__fx_sha1_ops;
extern struct fx_hash_function_ops z__fx_sha2_224_ops;
extern struct fx_hash_function_ops z__fx_sha2_256_ops;
extern struct fx_hash_function_ops z__fx_sha2_384_ops;
extern struct fx_hash_function_ops z__fx_sha2_512_ops;
extern struct fx_hash_function_ops z__fx_sha3_224_ops;
extern struct fx_hash_function_ops z__fx_sha3_256_ops;
extern struct fx_hash_function_ops z__fx_sha3_384_ops;
extern struct fx_hash_function_ops z__fx_sha3_512_ops;
extern struct fx_hash_function_ops z__fx_shake128_ops;
extern struct fx_hash_function_ops z__fx_shake256_ops;
static const struct fx_hash_function_ops *hash_functions[] = {
[FX_HASH_NONE] = NULL,
[FX_HASH_MD4] = &z__fx_md4_ops,
[FX_HASH_MD5] = &z__fx_md5_ops,
[FX_HASH_SHA1] = &z__fx_sha1_ops,
[FX_HASH_SHA2_224] = &z__fx_sha2_224_ops,
[FX_HASH_SHA2_256] = &z__fx_sha2_256_ops,
[FX_HASH_SHA2_384] = &z__fx_sha2_384_ops,
[FX_HASH_SHA2_512] = &z__fx_sha2_512_ops,
[FX_HASH_SHA3_224] = &z__fx_sha3_224_ops,
[FX_HASH_SHA3_256] = &z__fx_sha3_256_ops,
[FX_HASH_SHA3_384] = &z__fx_sha3_384_ops,
[FX_HASH_SHA3_512] = &z__fx_sha3_512_ops,
[FX_HASH_SHAKE128] = &z__fx_shake128_ops,
[FX_HASH_SHAKE256] = &z__fx_shake256_ops,
};
static const size_t nr_hash_functions
= sizeof hash_functions / sizeof hash_functions[0];
uint64_t fx_hash_cstr(const char *s)
{
size_t x = 0;
return fx_hash_cstr_ex(s, &x);
}
uint64_t fx_hash_cstr_ex(const char *s, size_t *len)
{
uint64_t hash = FNV1_OFFSET_BASIS;
size_t i = 0;
for (i = 0; s[i]; i++) {
hash ^= s[i];
hash *= FNV1_PRIME;
}
if (len) {
*len = i;
}
return hash;
}
enum fx_status fx_hash_ctx_init(struct fx_hash_ctx *ctx, enum fx_hash_function func)
{
if (func < 0 || func >= nr_hash_functions) {
return FX_ERR_NOT_SUPPORTED;
}
const struct fx_hash_function_ops *hash_function = hash_functions[func];
if (!hash_function) {
return FX_ERR_NOT_SUPPORTED;
}
memset(ctx, 0x0, sizeof *ctx);
ctx->ctx_func = func;
ctx->ctx_ops = hash_function;
if (hash_function->hash_init) {
hash_function->hash_init(ctx);
}
return FX_SUCCESS;
}
enum fx_status fx_hash_ctx_reset(struct fx_hash_ctx *ctx)
{
if (ctx->ctx_func == FX_HASH_NONE || !ctx->ctx_ops) {
return FX_ERR_BAD_STATE;
}
memset(&ctx->ctx_state, 0x0, sizeof ctx->ctx_state);
if (ctx->ctx_ops->hash_init) {
ctx->ctx_ops->hash_init(ctx);
}
return FX_SUCCESS;
}
enum fx_status fx_hash_ctx_update(struct fx_hash_ctx *ctx, const void *p, size_t len)
{
if (!ctx->ctx_ops) {
return FX_ERR_BAD_STATE;
}
if (!ctx->ctx_ops->hash_update) {
return FX_ERR_NOT_SUPPORTED;
}
ctx->ctx_ops->hash_update(ctx, p, len);
return FX_SUCCESS;
}
static void update_rope(const fx_rope *rope, void *arg)
{
struct fx_hash_ctx *ctx = arg;
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
char tmp[64];
size_t len = 0;
switch (type) {
case FX_ROPE_F_CHAR:
fx_hash_ctx_update(ctx, &rope->r_v.v_char, sizeof rope->r_v.v_char);
break;
case FX_ROPE_F_CSTR:
case FX_ROPE_F_CSTR_BORROWED:
case FX_ROPE_F_CSTR_STATIC:
fx_hash_ctx_update(
ctx, rope->r_v.v_cstr.s, strlen(rope->r_v.v_cstr.s));
break;
case FX_ROPE_F_INT:
len = snprintf(tmp, sizeof tmp, "%" PRIdPTR, rope->r_v.v_int);
fx_hash_ctx_update(ctx, tmp, len);
break;
case FX_ROPE_F_UINT:
len = snprintf(tmp, sizeof tmp, "%" PRIuPTR, rope->r_v.v_uint);
fx_hash_ctx_update(ctx, tmp, len);
break;
default:
break;
}
}
enum fx_status fx_hash_ctx_update_rope(
struct fx_hash_ctx *ctx, const struct fx_rope *rope)
{
fx_rope_iterate(rope, update_rope, ctx);
return FX_SUCCESS;
}
enum fx_status fx_hash_ctx_finish(
struct fx_hash_ctx *ctx, void *out_digest, size_t out_max)
{
if (!ctx->ctx_ops) {
return FX_ERR_BAD_STATE;
}
if (!ctx->ctx_ops->hash_finish) {
return FX_ERR_NOT_SUPPORTED;
}
ctx->ctx_ops->hash_finish(ctx, out_digest, out_max);
memset(&ctx->ctx_state, 0x0, sizeof ctx->ctx_state);
if (ctx->ctx_ops->hash_init) {
ctx->ctx_ops->hash_init(ctx);
}
return FX_SUCCESS;
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef _HASH_H_
#define _HASH_H_
#include <stddef.h>
struct fx_hash_ctx;
struct fx_hash_function_ops {
void (*hash_init)(struct fx_hash_ctx *);
void (*hash_update)(struct fx_hash_ctx *, const void *, size_t);
void (*hash_finish)(struct fx_hash_ctx *, void *, size_t);
};
#endif
+268
View File
@@ -0,0 +1,268 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD4 Message-Digest Algorithm (RFC 1320).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
#include "hash.h"
#include <fx/core/hash.h>
#include <stdint.h>
#include <string.h>
/*
* The basic MD4 functions.
*
* F and G are optimized compared to their RFC 1320 definitions, with the
* optimization for F borrowed from Colin Plumb's MD5 implementation.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
/*
* The MD4 transformation for all three rounds.
*/
#define STEP(f, a, b, c, d, x, s) \
(a) += f((b), (c), (d)) + (x); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));
/*
* SET reads 4 input bytes in little-endian byte order and stores them in a
* properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned memory
* accesses is just an optimization. Nothing will break if it fails to detect
* a suitable architecture.
*
* Unfortunately, this optimization may be a C strict aliasing rules violation
* if the caller's data buffer has effective type that cannot be aliased by
* uint32_t. In practice, this problem may occur if these MD4 routines are
* inlined into a calling function, or with future and dangerously advanced
* link-time optimizations. For the time being, keeping these MD4 routines in
* their own translation unit avoids the problem.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) (*(uint32_t *)&ptr[(n) * 4])
#define GET(n) SET(n)
#else
#define SET(n) \
(ctx->ctx_state.md4.block[(n)] = (uint32_t)ptr[(n) * 4] \
| ((uint32_t)ptr[(n) * 4 + 1] << 8) \
| ((uint32_t)ptr[(n) * 4 + 2] << 16) \
| ((uint32_t)ptr[(n) * 4 + 3] << 24))
#define GET(n) (ctx->ctx_state.md4.block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update the bit
* counters. There are no alignment requirements.
*/
static const void *body(struct fx_hash_ctx *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
uint32_t a, b, c, d;
uint32_t saved_a, saved_b, saved_c, saved_d;
const uint32_t ac1 = 0x5a827999, ac2 = 0x6ed9eba1;
ptr = (const unsigned char *)data;
a = ctx->ctx_state.md4.a;
b = ctx->ctx_state.md4.b;
c = ctx->ctx_state.md4.c;
d = ctx->ctx_state.md4.d;
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 3)
STEP(F, d, a, b, c, SET(1), 7)
STEP(F, c, d, a, b, SET(2), 11)
STEP(F, b, c, d, a, SET(3), 19)
STEP(F, a, b, c, d, SET(4), 3)
STEP(F, d, a, b, c, SET(5), 7)
STEP(F, c, d, a, b, SET(6), 11)
STEP(F, b, c, d, a, SET(7), 19)
STEP(F, a, b, c, d, SET(8), 3)
STEP(F, d, a, b, c, SET(9), 7)
STEP(F, c, d, a, b, SET(10), 11)
STEP(F, b, c, d, a, SET(11), 19)
STEP(F, a, b, c, d, SET(12), 3)
STEP(F, d, a, b, c, SET(13), 7)
STEP(F, c, d, a, b, SET(14), 11)
STEP(F, b, c, d, a, SET(15), 19)
/* Round 2 */
STEP(G, a, b, c, d, GET(0) + ac1, 3)
STEP(G, d, a, b, c, GET(4) + ac1, 5)
STEP(G, c, d, a, b, GET(8) + ac1, 9)
STEP(G, b, c, d, a, GET(12) + ac1, 13)
STEP(G, a, b, c, d, GET(1) + ac1, 3)
STEP(G, d, a, b, c, GET(5) + ac1, 5)
STEP(G, c, d, a, b, GET(9) + ac1, 9)
STEP(G, b, c, d, a, GET(13) + ac1, 13)
STEP(G, a, b, c, d, GET(2) + ac1, 3)
STEP(G, d, a, b, c, GET(6) + ac1, 5)
STEP(G, c, d, a, b, GET(10) + ac1, 9)
STEP(G, b, c, d, a, GET(14) + ac1, 13)
STEP(G, a, b, c, d, GET(3) + ac1, 3)
STEP(G, d, a, b, c, GET(7) + ac1, 5)
STEP(G, c, d, a, b, GET(11) + ac1, 9)
STEP(G, b, c, d, a, GET(15) + ac1, 13)
/* Round 3 */
STEP(H, a, b, c, d, GET(0) + ac2, 3)
STEP(H, d, a, b, c, GET(8) + ac2, 9)
STEP(H, c, d, a, b, GET(4) + ac2, 11)
STEP(H, b, c, d, a, GET(12) + ac2, 15)
STEP(H, a, b, c, d, GET(2) + ac2, 3)
STEP(H, d, a, b, c, GET(10) + ac2, 9)
STEP(H, c, d, a, b, GET(6) + ac2, 11)
STEP(H, b, c, d, a, GET(14) + ac2, 15)
STEP(H, a, b, c, d, GET(1) + ac2, 3)
STEP(H, d, a, b, c, GET(9) + ac2, 9)
STEP(H, c, d, a, b, GET(5) + ac2, 11)
STEP(H, b, c, d, a, GET(13) + ac2, 15)
STEP(H, a, b, c, d, GET(3) + ac2, 3)
STEP(H, d, a, b, c, GET(11) + ac2, 9)
STEP(H, c, d, a, b, GET(7) + ac2, 11)
STEP(H, b, c, d, a, GET(15) + ac2, 15)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx->ctx_state.md4.a = a;
ctx->ctx_state.md4.b = b;
ctx->ctx_state.md4.c = c;
ctx->ctx_state.md4.d = d;
return ptr;
}
void md4_init(struct fx_hash_ctx *ctx)
{
ctx->ctx_state.md4.a = 0x67452301;
ctx->ctx_state.md4.b = 0xefcdab89;
ctx->ctx_state.md4.c = 0x98badcfe;
ctx->ctx_state.md4.d = 0x10325476;
ctx->ctx_state.md4.lo = 0;
ctx->ctx_state.md4.hi = 0;
}
void md4_update(struct fx_hash_ctx *ctx, const void *data, unsigned long size)
{
uint32_t saved_lo;
unsigned long used, available;
saved_lo = ctx->ctx_state.md4.lo;
if ((ctx->ctx_state.md4.lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->ctx_state.md4.hi++;
ctx->ctx_state.md4.hi += size >> 29;
used = saved_lo & 0x3f;
if (used) {
available = 64 - used;
if (size < available) {
memcpy(&ctx->ctx_state.md4.buffer[used], data, size);
return;
}
memcpy(&ctx->ctx_state.md4.buffer[used], data, available);
data = (const unsigned char *)data + available;
size -= available;
body(ctx, ctx->ctx_state.md4.buffer, 64);
}
if (size >= 64) {
data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
memcpy(ctx->ctx_state.md4.buffer, data, size);
}
#define OUT(dst, src) \
(dst)[0] = (unsigned char)(src); \
(dst)[1] = (unsigned char)((src) >> 8); \
(dst)[2] = (unsigned char)((src) >> 16); \
(dst)[3] = (unsigned char)((src) >> 24);
void md4_finish(struct fx_hash_ctx *ctx, void *out, size_t max)
{
unsigned char *result = out;
unsigned long used, available;
used = ctx->ctx_state.md4.lo & 0x3f;
ctx->ctx_state.md4.buffer[used++] = 0x80;
available = 64 - used;
if (available < 8) {
memset(&ctx->ctx_state.md4.buffer[used], 0, available);
body(ctx, ctx->ctx_state.md4.buffer, 64);
used = 0;
available = 64;
}
memset(&ctx->ctx_state.md4.buffer[used], 0, available - 8);
ctx->ctx_state.md4.lo <<= 3;
OUT(&ctx->ctx_state.md4.buffer[56], ctx->ctx_state.md4.lo)
OUT(&ctx->ctx_state.md4.buffer[60], ctx->ctx_state.md4.hi)
body(ctx, ctx->ctx_state.md4.buffer, 64);
OUT(&result[0], ctx->ctx_state.md4.a)
OUT(&result[4], ctx->ctx_state.md4.b)
OUT(&result[8], ctx->ctx_state.md4.c)
OUT(&result[12], ctx->ctx_state.md4.d)
}
struct fx_hash_function_ops z__fx_md4_ops = {
.hash_init = md4_init,
.hash_update = md4_update,
.hash_finish = md4_finish,
};
+238
View File
@@ -0,0 +1,238 @@
/* This implementation was sourced from
* https://github.com/galenguyer/md5
* and is in the public domain. */
#include "hash.h"
#include <fx/core/hash.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define F(x, y, z) (z ^ (x & (y ^ z)))
#define G(x, y, z) (y ^ (z & (x ^ y)))
#define H(x, y, z) (x ^ y ^ z)
#define I(x, y, z) (y ^ (x | ~z))
#define ROTATE_LEFT(x, s) (x << s | x >> (32 - s))
#define STEP(f, a, b, c, d, x, t, s) \
(a += f(b, c, d) + x + t, a = ROTATE_LEFT(a, s), a += b)
void md5_init(struct fx_hash_ctx *ctx)
{
ctx->ctx_state.md5.a = 0x67452301;
ctx->ctx_state.md5.b = 0xefcdab89;
ctx->ctx_state.md5.c = 0x98badcfe;
ctx->ctx_state.md5.d = 0x10325476;
ctx->ctx_state.md5.count[0] = 0;
ctx->ctx_state.md5.count[1] = 0;
}
uint8_t *md5_transform(struct fx_hash_ctx *ctx, const void *data, uintmax_t size)
{
uint8_t *ptr = (uint8_t *)data;
uint32_t a, b, c, d, aa, bb, cc, dd;
#define GET(n) (ctx->ctx_state.md5.block[(n)])
#define SET(n) \
(ctx->ctx_state.md5.block[(n)] = ((uint32_t)ptr[(n) * 4 + 0] << 0) \
| ((uint32_t)ptr[(n) * 4 + 1] << 8) \
| ((uint32_t)ptr[(n) * 4 + 2] << 16) \
| ((uint32_t)ptr[(n) * 4 + 3] << 24))
a = ctx->ctx_state.md5.a;
b = ctx->ctx_state.md5.b;
c = ctx->ctx_state.md5.c;
d = ctx->ctx_state.md5.d;
do {
aa = a;
bb = b;
cc = c;
dd = d;
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7);
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12);
STEP(F, c, d, a, b, SET(2), 0x242070db, 17);
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22);
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7);
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12);
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17);
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22);
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7);
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12);
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17);
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22);
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7);
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12);
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17);
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22);
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5);
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9);
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14);
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20);
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5);
STEP(G, d, a, b, c, GET(10), 0x02441453, 9);
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14);
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20);
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5);
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9);
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14);
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20);
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5);
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9);
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14);
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20);
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4);
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11);
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16);
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23);
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4);
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11);
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16);
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23);
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4);
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11);
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16);
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23);
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4);
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11);
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16);
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23);
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6);
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10);
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15);
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21);
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6);
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10);
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15);
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21);
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6);
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10);
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15);
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21);
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6);
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10);
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15);
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21);
a += aa;
b += bb;
c += cc;
d += dd;
ptr += 64;
} while (size -= 64);
ctx->ctx_state.md5.a = a;
ctx->ctx_state.md5.b = b;
ctx->ctx_state.md5.c = c;
ctx->ctx_state.md5.d = d;
#undef GET
#undef SET
return ptr;
}
void md5_update(struct fx_hash_ctx *ctx, const void *buffer, size_t buffer_size)
{
uint32_t saved_low = ctx->ctx_state.md5.count[0];
uint32_t used;
uint32_t free;
if ((ctx->ctx_state.md5.count[0] = ((saved_low + buffer_size) & 0x1fffffff))
< saved_low) {
ctx->ctx_state.md5.count[1]++;
}
ctx->ctx_state.md5.count[1] += (uint32_t)(buffer_size >> 29);
used = saved_low & 0x3f;
if (used) {
free = 64 - used;
if (buffer_size < free) {
memcpy(&ctx->ctx_state.md5.input[used], buffer,
buffer_size);
return;
}
memcpy(&ctx->ctx_state.md5.input[used], buffer, free);
buffer = (uint8_t *)buffer + free;
buffer_size -= free;
md5_transform(ctx, ctx->ctx_state.md5.input, 64);
}
if (buffer_size >= 64) {
buffer = md5_transform(
ctx, buffer, buffer_size & ~(unsigned long)0x3f);
buffer_size = buffer_size % 64;
}
memcpy(ctx->ctx_state.md5.input, buffer, buffer_size);
}
void md5_finish(struct fx_hash_ctx *ctx, void *out, size_t max)
{
uint32_t used = ctx->ctx_state.md5.count[0] & 0x3f;
ctx->ctx_state.md5.input[used++] = 0x80;
uint32_t free = 64 - used;
if (free < 8) {
memset(&ctx->ctx_state.md5.input[used], 0, free);
md5_transform(ctx, ctx->ctx_state.md5.input, 64);
used = 0;
free = 64;
}
memset(&ctx->ctx_state.md5.input[used], 0, free - 8);
unsigned char digest[FX_DIGEST_LENGTH_MD5];
ctx->ctx_state.md5.count[0] <<= 3;
ctx->ctx_state.md5.input[56] = (uint8_t)(ctx->ctx_state.md5.count[0]);
ctx->ctx_state.md5.input[57] = (uint8_t)(ctx->ctx_state.md5.count[0] >> 8);
ctx->ctx_state.md5.input[58]
= (uint8_t)(ctx->ctx_state.md5.count[0] >> 16);
ctx->ctx_state.md5.input[59]
= (uint8_t)(ctx->ctx_state.md5.count[0] >> 24);
ctx->ctx_state.md5.input[60] = (uint8_t)(ctx->ctx_state.md5.count[1]);
ctx->ctx_state.md5.input[61] = (uint8_t)(ctx->ctx_state.md5.count[1] >> 8);
ctx->ctx_state.md5.input[62]
= (uint8_t)(ctx->ctx_state.md5.count[1] >> 16);
ctx->ctx_state.md5.input[63]
= (uint8_t)(ctx->ctx_state.md5.count[1] >> 24);
md5_transform(ctx, ctx->ctx_state.md5.input, 64);
digest[0] = (uint8_t)(ctx->ctx_state.md5.a);
digest[1] = (uint8_t)(ctx->ctx_state.md5.a >> 8);
digest[2] = (uint8_t)(ctx->ctx_state.md5.a >> 16);
digest[3] = (uint8_t)(ctx->ctx_state.md5.a >> 24);
digest[4] = (uint8_t)(ctx->ctx_state.md5.b);
digest[5] = (uint8_t)(ctx->ctx_state.md5.b >> 8);
digest[6] = (uint8_t)(ctx->ctx_state.md5.b >> 16);
digest[7] = (uint8_t)(ctx->ctx_state.md5.b >> 24);
digest[8] = (uint8_t)(ctx->ctx_state.md5.c);
digest[9] = (uint8_t)(ctx->ctx_state.md5.c >> 8);
digest[10] = (uint8_t)(ctx->ctx_state.md5.c >> 16);
digest[11] = (uint8_t)(ctx->ctx_state.md5.c >> 24);
digest[12] = (uint8_t)(ctx->ctx_state.md5.d);
digest[13] = (uint8_t)(ctx->ctx_state.md5.d >> 8);
digest[14] = (uint8_t)(ctx->ctx_state.md5.d >> 16);
digest[15] = (uint8_t)(ctx->ctx_state.md5.d >> 24);
memcpy(out, digest, fx_min(size_t, sizeof digest, max));
}
struct fx_hash_function_ops z__fx_md5_ops = {
.hash_init = md5_init,
.hash_update = md5_update,
.hash_finish = md5_finish,
};
+267
View File
@@ -0,0 +1,267 @@
/*
SHA-1 in C
By Steve Reid <steve@edmweb.com>
100% Public Domain
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
/* #define SHA1HANDSOFF * Copies data before messing with it. */
#define SHA1HANDSOFF
#include "hash.h"
#include <fx/core/hash.h>
#include <stdio.h>
#include <string.h>
/* for uint32_t */
#include <stdint.h>
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#if defined(LITTLE_ENDIAN)
#define blk0(i) \
(block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \
| (rol(block->l[i], 8) & 0x00FF00FF))
#elif defined(BIG_ENDIAN)
#define blk0(i) block->l[i]
#else
#error "Endianness not defined!"
#endif
#define blk(i) \
(block->l[i & 15] \
= rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \
^ block->l[(i + 2) & 15] ^ block->l[i & 15], \
1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v, w, x, y, z, i) \
z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R1(v, w, x, y, z, i) \
z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
w = rol(w, 30);
#define R2(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
w = rol(w, 30);
#define R3(v, w, x, y, z, i) \
z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
w = rol(w, 30);
#define R4(v, w, x, y, z, i) \
z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
w = rol(w, 30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
{
uint32_t a, b, c, d, e;
typedef union {
unsigned char c[64];
uint32_t l[16];
} CHAR64LONG16;
#ifdef SHA1HANDSOFF
CHAR64LONG16 block[1]; /* use array to appear as a pointer */
memcpy(block, buffer, 64);
#else
/* The following had better never be used because it causes the
* pointer-to-const buffer to be cast into a pointer to non-const.
* And the result is written through. I threw a "const" in, hoping
* this will cause a diagnostic.
*/
CHAR64LONG16 *block = (const CHAR64LONG16 *)buffer;
#endif
/* Copy context->ctx_state.sha1.state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a, b, c, d, e, 0);
R0(e, a, b, c, d, 1);
R0(d, e, a, b, c, 2);
R0(c, d, e, a, b, 3);
R0(b, c, d, e, a, 4);
R0(a, b, c, d, e, 5);
R0(e, a, b, c, d, 6);
R0(d, e, a, b, c, 7);
R0(c, d, e, a, b, 8);
R0(b, c, d, e, a, 9);
R0(a, b, c, d, e, 10);
R0(e, a, b, c, d, 11);
R0(d, e, a, b, c, 12);
R0(c, d, e, a, b, 13);
R0(b, c, d, e, a, 14);
R0(a, b, c, d, e, 15);
R1(e, a, b, c, d, 16);
R1(d, e, a, b, c, 17);
R1(c, d, e, a, b, 18);
R1(b, c, d, e, a, 19);
R2(a, b, c, d, e, 20);
R2(e, a, b, c, d, 21);
R2(d, e, a, b, c, 22);
R2(c, d, e, a, b, 23);
R2(b, c, d, e, a, 24);
R2(a, b, c, d, e, 25);
R2(e, a, b, c, d, 26);
R2(d, e, a, b, c, 27);
R2(c, d, e, a, b, 28);
R2(b, c, d, e, a, 29);
R2(a, b, c, d, e, 30);
R2(e, a, b, c, d, 31);
R2(d, e, a, b, c, 32);
R2(c, d, e, a, b, 33);
R2(b, c, d, e, a, 34);
R2(a, b, c, d, e, 35);
R2(e, a, b, c, d, 36);
R2(d, e, a, b, c, 37);
R2(c, d, e, a, b, 38);
R2(b, c, d, e, a, 39);
R3(a, b, c, d, e, 40);
R3(e, a, b, c, d, 41);
R3(d, e, a, b, c, 42);
R3(c, d, e, a, b, 43);
R3(b, c, d, e, a, 44);
R3(a, b, c, d, e, 45);
R3(e, a, b, c, d, 46);
R3(d, e, a, b, c, 47);
R3(c, d, e, a, b, 48);
R3(b, c, d, e, a, 49);
R3(a, b, c, d, e, 50);
R3(e, a, b, c, d, 51);
R3(d, e, a, b, c, 52);
R3(c, d, e, a, b, 53);
R3(b, c, d, e, a, 54);
R3(a, b, c, d, e, 55);
R3(e, a, b, c, d, 56);
R3(d, e, a, b, c, 57);
R3(c, d, e, a, b, 58);
R3(b, c, d, e, a, 59);
R4(a, b, c, d, e, 60);
R4(e, a, b, c, d, 61);
R4(d, e, a, b, c, 62);
R4(c, d, e, a, b, 63);
R4(b, c, d, e, a, 64);
R4(a, b, c, d, e, 65);
R4(e, a, b, c, d, 66);
R4(d, e, a, b, c, 67);
R4(c, d, e, a, b, 68);
R4(b, c, d, e, a, 69);
R4(a, b, c, d, e, 70);
R4(e, a, b, c, d, 71);
R4(d, e, a, b, c, 72);
R4(c, d, e, a, b, 73);
R4(b, c, d, e, a, 74);
R4(a, b, c, d, e, 75);
R4(e, a, b, c, d, 76);
R4(d, e, a, b, c, 77);
R4(c, d, e, a, b, 78);
R4(b, c, d, e, a, 79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
memset(block, '\0', sizeof(block));
#endif
}
/* sha_init - Initialize new context */
static void sha_init(struct fx_hash_ctx *context)
{
/* SHA1 initialization constants */
context->ctx_state.sha1.state[0] = 0x67452301;
context->ctx_state.sha1.state[1] = 0xEFCDAB89;
context->ctx_state.sha1.state[2] = 0x98BADCFE;
context->ctx_state.sha1.state[3] = 0x10325476;
context->ctx_state.sha1.state[4] = 0xC3D2E1F0;
context->ctx_state.sha1.count[0] = context->ctx_state.sha1.count[1] = 0;
}
/* Run your data through this. */
static void sha_update(struct fx_hash_ctx *context, const void *p, size_t len)
{
const unsigned char *data = p;
uint32_t i, j;
j = context->ctx_state.sha1.count[0];
if ((context->ctx_state.sha1.count[0] += len << 3) < j)
context->ctx_state.sha1.count[1]++;
context->ctx_state.sha1.count[1] += (len >> 29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
memcpy(&context->ctx_state.sha1.buffer[j], data, (i = 64 - j));
SHA1Transform(
context->ctx_state.sha1.state,
context->ctx_state.sha1.buffer);
for (; i + 63 < len; i += 64) {
SHA1Transform(context->ctx_state.sha1.state, &data[i]);
}
j = 0;
} else
i = 0;
memcpy(&context->ctx_state.sha1.buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
static void sha_finish(struct fx_hash_ctx *context, void *out, size_t max)
{
unsigned i;
unsigned char finalcount[8] = {0};
unsigned char c;
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->ctx_state.sha1
.count[(i >= 4 ? 0 : 1)]
>> ((3 - (i & 3)) * 8))
& 255); /* Endian independent */
}
char digest[FX_DIGEST_LENGTH_SHA1];
c = 0200;
sha_update(context, &c, 1);
while ((context->ctx_state.sha1.count[0] & 504) != 448) {
c = 0000;
sha_update(context, &c, 1);
}
sha_update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)((context->ctx_state.sha1.state[i >> 2]
>> ((3 - (i & 3)) * 8))
& 255);
}
memcpy(out, digest, fx_min(size_t, sizeof digest, max));
/* Wipe variables */
memset(&finalcount, '\0', sizeof(finalcount));
}
struct fx_hash_function_ops z__fx_sha1_ops = {
.hash_init = sha_init,
.hash_update = sha_update,
.hash_finish = sha_finish,
};
+42
View File
@@ -0,0 +1,42 @@
// SHA-224. Adapted from LibTomCrypt. This code is Public Domain
#include "hash.h"
#include <fx/core/hash.h>
#include <string.h>
extern void z__fx_sha2_256_update(
struct fx_hash_ctx *md, const void *src, size_t inlen);
extern void z__fx_sha2_256_finish(struct fx_hash_ctx *md, void *out, size_t max);
static void sha_init(struct fx_hash_ctx *md)
{
md->ctx_state.sha2_256.curlen = 0;
md->ctx_state.sha2_256.length = 0;
md->ctx_state.sha2_256.state[0] = 0xc1059ed8UL;
md->ctx_state.sha2_256.state[1] = 0x367cd507UL;
md->ctx_state.sha2_256.state[2] = 0x3070dd17UL;
md->ctx_state.sha2_256.state[3] = 0xf70e5939UL;
md->ctx_state.sha2_256.state[4] = 0xffc00b31UL;
md->ctx_state.sha2_256.state[5] = 0x68581511UL;
md->ctx_state.sha2_256.state[6] = 0x64f98fa7UL;
md->ctx_state.sha2_256.state[7] = 0xbefa4fa4UL;
}
static void sha_update(struct fx_hash_ctx *md, const void *in, size_t inlen)
{
z__fx_sha2_256_update(md, in, inlen);
}
static void sha_finish(struct fx_hash_ctx *md, void *out, size_t max)
{
unsigned char res[FX_DIGEST_LENGTH_SHA2_256];
z__fx_sha2_256_finish(md, res, max);
/* truncate the digest to 224 bits */
memcpy(out, res, fx_min(size_t, max, FX_DIGEST_LENGTH_224));
}
struct fx_hash_function_ops z__fx_sha2_224_ops = {
.hash_init = sha_init,
.hash_update = sha_update,
.hash_finish = sha_finish,
};
+215
View File
@@ -0,0 +1,215 @@
// SHA-256. Adapted from LibTomCrypt. This code is Public Domain
#include "hash.h"
#include <fx/core/hash.h>
#include <string.h>
static const uint32_t K[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
};
static uint32_t min(uint32_t x, uint32_t y)
{
return x < y ? x : y;
}
static uint32_t load32(const unsigned char *y)
{
return ((uint32_t)(y[0]) << 24) | ((uint32_t)(y[1]) << 16)
| ((uint32_t)(y[2]) << 8) | ((uint32_t)(y[3]) << 0);
}
static void store64(uint64_t x, unsigned char *y)
{
for (int i = 0; i != 8; ++i)
y[i] = (x >> ((7 - i) * 8)) & 255;
}
static void store32(uint32_t x, unsigned char *y)
{
for (int i = 0; i != 4; ++i)
y[i] = (x >> ((3 - i) * 8)) & 255;
}
static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z)
{
return z ^ (x & (y ^ z));
}
static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z)
{
return ((x | y) & z) | (x & y);
}
static uint32_t Rot(uint32_t x, uint32_t n)
{
return (x >> (n & 31)) | (x << (32 - (n & 31)));
}
static uint32_t Sh(uint32_t x, uint32_t n)
{
return x >> n;
}
static uint32_t Sigma0(uint32_t x)
{
return Rot(x, 2) ^ Rot(x, 13) ^ Rot(x, 22);
}
static uint32_t Sigma1(uint32_t x)
{
return Rot(x, 6) ^ Rot(x, 11) ^ Rot(x, 25);
}
static uint32_t Gamma0(uint32_t x)
{
return Rot(x, 7) ^ Rot(x, 18) ^ Sh(x, 3);
}
static uint32_t Gamma1(uint32_t x)
{
return Rot(x, 17) ^ Rot(x, 19) ^ Sh(x, 10);
}
static void RND(
uint32_t *t0, uint32_t *t1, uint32_t W[], uint32_t a, uint32_t b,
uint32_t c, uint32_t *d, uint32_t e, uint32_t f, uint32_t g,
uint32_t *h, uint32_t i)
{
(*t0) = *h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
(*t1) = Sigma0(a) + Maj(a, b, c);
(*d) += *t0;
(*h) = *t0 + *t1;
}
static void sha_compress(struct fx_hash_ctx *md, const unsigned char *buf)
{
uint32_t S[8], W[64], t0, t1, t;
// Copy state into S
for (int i = 0; i < 8; i++)
S[i] = md->ctx_state.sha2_256.state[i];
// Copy the state into 512-bits into W[0..15]
for (int i = 0; i < 16; i++)
W[i] = load32(buf + (4 * i));
// Fill W[16..63]
for (int i = 16; i < 64; i++)
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
// Compress
for (int i = 0; i < 64; ++i) {
RND(&t0, &t1, W, S[0], S[1], S[2], &S[3], S[4], S[5], S[6],
&S[7], i);
t = S[7];
S[7] = S[6];
S[6] = S[5];
S[5] = S[4];
S[4] = S[3];
S[3] = S[2];
S[2] = S[1];
S[1] = S[0];
S[0] = t;
}
// Feedback
for (int i = 0; i < 8; i++)
md->ctx_state.sha2_256.state[i]
= md->ctx_state.sha2_256.state[i] + S[i];
}
// Public interface
static void sha_init(struct fx_hash_ctx *md)
{
md->ctx_state.sha2_256.curlen = 0;
md->ctx_state.sha2_256.length = 0;
md->ctx_state.sha2_256.state[0] = 0x6A09E667UL;
md->ctx_state.sha2_256.state[1] = 0xBB67AE85UL;
md->ctx_state.sha2_256.state[2] = 0x3C6EF372UL;
md->ctx_state.sha2_256.state[3] = 0xA54FF53AUL;
md->ctx_state.sha2_256.state[4] = 0x510E527FUL;
md->ctx_state.sha2_256.state[5] = 0x9B05688CUL;
md->ctx_state.sha2_256.state[6] = 0x1F83D9ABUL;
md->ctx_state.sha2_256.state[7] = 0x5BE0CD19UL;
}
void z__fx_sha2_256_update(struct fx_hash_ctx *md, const void *src, size_t inlen)
{
const uint32_t block_size = sizeof md->ctx_state.sha2_256.buf;
const unsigned char *in = (const unsigned char *)(src);
while (inlen > 0) {
if (md->ctx_state.sha2_256.curlen == 0 && inlen >= block_size) {
sha_compress(md, in);
md->ctx_state.sha2_256.length += block_size * 8;
in += block_size;
inlen -= block_size;
} else {
uint32_t n = min(
inlen,
(block_size - md->ctx_state.sha2_256.curlen));
memcpy(md->ctx_state.sha2_256.buf
+ md->ctx_state.sha2_256.curlen,
in, n);
md->ctx_state.sha2_256.curlen += n;
in += n;
inlen -= n;
if (md->ctx_state.sha2_256.curlen == block_size) {
sha_compress(md, md->ctx_state.sha2_256.buf);
md->ctx_state.sha2_256.length += 8 * block_size;
md->ctx_state.sha2_256.curlen = 0;
}
}
}
}
void z__fx_sha2_256_finish(struct fx_hash_ctx *md, void *out, size_t max)
{
// Increase the length of the message
md->ctx_state.sha2_256.length += md->ctx_state.sha2_256.curlen * 8;
// Append the '1' bit
md->ctx_state.sha2_256.buf[md->ctx_state.sha2_256.curlen++]
= (unsigned char)(0x80);
// If the length is currently above 56 bytes we append zeros then compress.
// Then we can fall back to padding zeros and length encoding like normal.
if (md->ctx_state.sha2_256.curlen > 56) {
while (md->ctx_state.sha2_256.curlen < 64)
md->ctx_state.sha2_256.buf[md->ctx_state.sha2_256.curlen++]
= 0;
sha_compress(md, md->ctx_state.sha2_256.buf);
md->ctx_state.sha2_256.curlen = 0;
}
// Pad upto 56 bytes of zeroes
while (md->ctx_state.sha2_256.curlen < 56)
md->ctx_state.sha2_256.buf[md->ctx_state.sha2_256.curlen++] = 0;
// Store length
store64(md->ctx_state.sha2_256.length, md->ctx_state.sha2_256.buf + 56);
sha_compress(md, md->ctx_state.sha2_256.buf);
unsigned char digest[FX_DIGEST_LENGTH_SHA2_256];
// Copy output
for (int i = 0; i < 8; i++)
store32(md->ctx_state.sha2_256.state[i],
(unsigned char *)&digest[(4 * i)]);
memcpy(out, digest, fx_min(size_t, sizeof digest, max));
}
struct fx_hash_function_ops z__fx_sha2_256_ops = {
.hash_init = sha_init,
.hash_update = z__fx_sha2_256_update,
.hash_finish = z__fx_sha2_256_finish,
};
+42
View File
@@ -0,0 +1,42 @@
// SHA-384. Adapted from LibTomCrypt. This code is Public Domain
#include "hash.h"
#include <fx/core/hash.h>
#include <string.h>
extern void z__fx_sha2_512_update(
struct fx_hash_ctx *md, const void *src, size_t inlen);
extern void z__fx_sha2_512_finish(struct fx_hash_ctx *md, void *out, size_t max);
void sha_init(struct fx_hash_ctx *md)
{
md->ctx_state.sha2_512.curlen = 0;
md->ctx_state.sha2_512.length = 0;
md->ctx_state.sha2_512.state[0] = 0xcbbb9d5dc1059ed8ULL;
md->ctx_state.sha2_512.state[1] = 0x629a292a367cd507ULL;
md->ctx_state.sha2_512.state[2] = 0x9159015a3070dd17ULL;
md->ctx_state.sha2_512.state[3] = 0x152fecd8f70e5939ULL;
md->ctx_state.sha2_512.state[4] = 0x67332667ffc00b31ULL;
md->ctx_state.sha2_512.state[5] = 0x8eb44a8768581511ULL;
md->ctx_state.sha2_512.state[6] = 0xdb0c2e0d64f98fa7ULL;
md->ctx_state.sha2_512.state[7] = 0x47b5481dbefa4fa4ULL;
}
static void sha_update(struct fx_hash_ctx *md, const void *in, size_t inlen)
{
z__fx_sha2_512_update(md, in, inlen);
}
static void sha_finish(struct fx_hash_ctx *md, void *out, size_t max)
{
unsigned char res[FX_DIGEST_LENGTH_SHA2_512];
z__fx_sha2_512_finish(md, res, max);
/* truncate the digest to 384 bits */
memcpy(out, res, fx_min(size_t, max, FX_DIGEST_LENGTH_384));
}
struct fx_hash_function_ops z__fx_sha2_384_ops = {
.hash_init = sha_init,
.hash_update = sha_update,
.hash_finish = sha_finish,
};
+236
View File
@@ -0,0 +1,236 @@
// SHA-512. Adapted from LibTomCrypt. This code is Public Domain
#include "hash.h"
#include <fx/core/hash.h>
#include <stdint.h>
#include <string.h>
static const uint64_t K[80]
= {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
static uint32_t min(uint32_t x, uint32_t y)
{
return x < y ? x : y;
}
static void store64(uint64_t x, unsigned char *y)
{
for (int i = 0; i != 8; ++i)
y[i] = (x >> ((7 - i) * 8)) & 255;
}
static uint64_t load64(const unsigned char *y)
{
uint64_t res = 0;
for (int i = 0; i != 8; ++i)
res |= (uint64_t)(y[i]) << ((7 - i) * 8);
return res;
}
static uint64_t Ch(uint64_t x, uint64_t y, uint64_t z)
{
return z ^ (x & (y ^ z));
}
static uint64_t Maj(uint64_t x, uint64_t y, uint64_t z)
{
return ((x | y) & z) | (x & y);
}
static uint64_t Rot(uint64_t x, uint64_t n)
{
return (x >> (n & 63)) | (x << (64 - (n & 63)));
}
static uint64_t Sh(uint64_t x, uint64_t n)
{
return x >> n;
}
static uint64_t Sigma0(uint64_t x)
{
return Rot(x, 28) ^ Rot(x, 34) ^ Rot(x, 39);
}
static uint64_t Sigma1(uint64_t x)
{
return Rot(x, 14) ^ Rot(x, 18) ^ Rot(x, 41);
}
static uint64_t Gamma0(uint64_t x)
{
return Rot(x, 1) ^ Rot(x, 8) ^ Sh(x, 7);
}
static uint64_t Gamma1(uint64_t x)
{
return Rot(x, 19) ^ Rot(x, 61) ^ Sh(x, 6);
}
static void RND(
uint64_t W[], uint64_t *t0, uint64_t *t1, uint64_t a, uint64_t b,
uint64_t c, uint64_t *d, uint64_t e, uint64_t f, uint64_t g,
uint64_t *h, uint64_t i)
{
*t0 = *h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];
*t1 = Sigma0(a) + Maj(a, b, c);
*d += *t0;
*h = *t0 + *t1;
}
static void sha_compress(struct fx_hash_ctx *md, const unsigned char *buf)
{
uint64_t S[8], W[80], t0, t1;
// Copy state into S
for (int i = 0; i < 8; i++) {
S[i] = md->ctx_state.sha2_512.state[i];
}
// Copy the state into 1024-bits into W[0..15]
for (int i = 0; i < 16; i++) {
W[i] = load64(buf + (8 * i));
}
// Fill W[16..79]
for (int i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
// Compress
for (int i = 0; i < 80; i += 8) {
RND(W, &t0, &t1, S[0], S[1], S[2], &S[3], S[4], S[5], S[6],
&S[7], i + 0);
RND(W, &t0, &t1, S[7], S[0], S[1], &S[2], S[3], S[4], S[5],
&S[6], i + 1);
RND(W, &t0, &t1, S[6], S[7], S[0], &S[1], S[2], S[3], S[4],
&S[5], i + 2);
RND(W, &t0, &t1, S[5], S[6], S[7], &S[0], S[1], S[2], S[3],
&S[4], i + 3);
RND(W, &t0, &t1, S[4], S[5], S[6], &S[7], S[0], S[1], S[2],
&S[3], i + 4);
RND(W, &t0, &t1, S[3], S[4], S[5], &S[6], S[7], S[0], S[1],
&S[2], i + 5);
RND(W, &t0, &t1, S[2], S[3], S[4], &S[5], S[6], S[7], S[0],
&S[1], i + 6);
RND(W, &t0, &t1, S[1], S[2], S[3], &S[4], S[5], S[6], S[7],
&S[0], i + 7);
}
// Feedback
for (int i = 0; i < 8; i++)
md->ctx_state.sha2_512.state[i]
= md->ctx_state.sha2_512.state[i] + S[i];
}
// Public interface
static void sha_init(struct fx_hash_ctx *md)
{
md->ctx_state.sha2_512.curlen = 0;
md->ctx_state.sha2_512.length = 0;
md->ctx_state.sha2_512.state[0] = 0x6a09e667f3bcc908ULL;
md->ctx_state.sha2_512.state[1] = 0xbb67ae8584caa73bULL;
md->ctx_state.sha2_512.state[2] = 0x3c6ef372fe94f82bULL;
md->ctx_state.sha2_512.state[3] = 0xa54ff53a5f1d36f1ULL;
md->ctx_state.sha2_512.state[4] = 0x510e527fade682d1ULL;
md->ctx_state.sha2_512.state[5] = 0x9b05688c2b3e6c1fULL;
md->ctx_state.sha2_512.state[6] = 0x1f83d9abfb41bd6bULL;
md->ctx_state.sha2_512.state[7] = 0x5be0cd19137e2179ULL;
}
void z__fx_sha2_512_update(struct fx_hash_ctx *md, const void *src, size_t inlen)
{
const uint32_t block_size = sizeof md->ctx_state.sha2_512.block;
const unsigned char *in = (const unsigned char *)src;
while (inlen > 0) {
if (md->ctx_state.sha2_512.curlen == 0 && inlen >= block_size) {
sha_compress(md, in);
md->ctx_state.sha2_512.length += block_size * 8;
in += block_size;
inlen -= block_size;
} else {
uint32_t n = min(
inlen,
(block_size - md->ctx_state.sha2_512.curlen));
memcpy(md->ctx_state.sha2_512.block
+ md->ctx_state.sha2_512.curlen,
in, n);
md->ctx_state.sha2_512.curlen += n;
in += n;
inlen -= n;
if (md->ctx_state.sha2_512.curlen == block_size) {
sha_compress(md, md->ctx_state.sha2_512.block);
md->ctx_state.sha2_512.length += 8 * block_size;
md->ctx_state.sha2_512.curlen = 0;
}
}
}
}
void z__fx_sha2_512_finish(struct fx_hash_ctx *md, void *out, size_t max)
{
// Increase the length of the message
md->ctx_state.sha2_512.length += md->ctx_state.sha2_512.curlen * 8ULL;
// Append the '1' bit
md->ctx_state.sha2_512.block[md->ctx_state.sha2_512.curlen++] = 0x80;
// If the length is currently above 112 bytes we append zeros then compress.
// Then we can fall back to padding zeros and length encoding like normal.
if (md->ctx_state.sha2_512.curlen > 112) {
while (md->ctx_state.sha2_512.curlen < 128)
md->ctx_state.sha2_512.block[md->ctx_state.sha2_512.curlen++]
= 0;
sha_compress(md, md->ctx_state.sha2_512.block);
md->ctx_state.sha2_512.curlen = 0;
}
// Pad upto 120 bytes of zeroes
// note: that from 112 to 120 is the 64 MSB of the length. We assume
// that you won't hash 2^64 bits of data... :-)
while (md->ctx_state.sha2_512.curlen < 120) {
md->ctx_state.sha2_512.block[md->ctx_state.sha2_512.curlen++] = 0;
}
// Store length
store64(md->ctx_state.sha2_512.length, md->ctx_state.sha2_512.block + 120);
sha_compress(md, md->ctx_state.sha2_512.block);
unsigned char digest[FX_DIGEST_LENGTH_SHA2_512];
// Copy output
for (int i = 0; i < 8; i++) {
store64(md->ctx_state.sha2_512.state[i],
(unsigned char *)&digest[(8 * i)]);
}
memcpy(out, digest, fx_min(size_t, sizeof digest, max));
}
struct fx_hash_function_ops z__fx_sha2_512_ops = {
.hash_init = sha_init,
.hash_update = z__fx_sha2_512_update,
.hash_finish = z__fx_sha2_512_finish,
};
+333
View File
@@ -0,0 +1,333 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Markku-Juhani O. Saarinen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// sha3.c
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
// Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3"
// Revised 03-Sep-15 for portability + OpenSSL - style API
#include "hash.h"
#include <fx/core/hash.h>
#include <fx/core/misc.h>
#include <string.h>
#ifndef KECCAKF_ROUNDS
#define KECCAKF_ROUNDS 24
#endif
#ifndef ROTL64
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif
// update the state with given number of rounds
void sha3_keccakf(uint64_t st[25])
{
// constants
const uint64_t keccakf_rndc[24]
= {0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008};
const int keccakf_rotc[24]
= {1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44};
const int keccakf_piln[24]
= {10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1};
// variables
int i, j, r;
uint64_t t, bc[5];
#if !defined(LITTLE_ENDIAN)
uint8_t *v;
// endianess conversion. this is redundant on little-endian targets
for (i = 0; i < 25; i++) {
v = (uint8_t *)&st[i];
st[i] = ((uint64_t)v[0]) | (((uint64_t)v[1]) << 8)
| (((uint64_t)v[2]) << 16) | (((uint64_t)v[3]) << 24)
| (((uint64_t)v[4]) << 32) | (((uint64_t)v[5]) << 40)
| (((uint64_t)v[6]) << 48) | (((uint64_t)v[7]) << 56);
}
#endif
// actual iteration
for (r = 0; r < KECCAKF_ROUNDS; r++) {
// Theta
for (i = 0; i < 5; i++)
bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15]
^ st[i + 20];
for (i = 0; i < 5; i++) {
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
for (j = 0; j < 25; j += 5)
st[j + i] ^= t;
}
// Rho Pi
t = st[1];
for (i = 0; i < 24; i++) {
j = keccakf_piln[i];
bc[0] = st[j];
st[j] = ROTL64(t, keccakf_rotc[i]);
t = bc[0];
}
// Chi
for (j = 0; j < 25; j += 5) {
for (i = 0; i < 5; i++)
bc[i] = st[j + i];
for (i = 0; i < 5; i++)
st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
}
// Iota
st[0] ^= keccakf_rndc[r];
}
#if !defined(LITTLE_ENDIAN)
// endianess conversion. this is redundant on little-endian targets
for (i = 0; i < 25; i++) {
v = (uint8_t *)&st[i];
t = st[i];
v[0] = t & 0xFF;
v[1] = (t >> 8) & 0xFF;
v[2] = (t >> 16) & 0xFF;
v[3] = (t >> 24) & 0xFF;
v[4] = (t >> 32) & 0xFF;
v[5] = (t >> 40) & 0xFF;
v[6] = (t >> 48) & 0xFF;
v[7] = (t >> 56) & 0xFF;
}
#endif
}
// Initialize the context for SHA3
int sha3_init(struct fx_hash_ctx *c, int mdlen)
{
int i;
for (i = 0; i < 25; i++)
c->ctx_state.sha3.st.q[i] = 0;
c->ctx_state.sha3.mdlen = mdlen;
c->ctx_state.sha3.rsiz = 200 - 2 * mdlen;
c->ctx_state.sha3.pt = 0;
return 1;
}
// update state with more data
void sha3_update(struct fx_hash_ctx *c, const void *data, size_t len)
{
size_t i;
int j;
j = c->ctx_state.sha3.pt;
for (i = 0; i < len; i++) {
c->ctx_state.sha3.st.b[j++] ^= ((const uint8_t *)data)[i];
if (j >= c->ctx_state.sha3.rsiz) {
sha3_keccakf(c->ctx_state.sha3.st.q);
j = 0;
}
}
c->ctx_state.sha3.pt = j;
}
// finalize and output a hash
int sha3_final(void *md, struct fx_hash_ctx *c)
{
int i;
c->ctx_state.sha3.st.b[c->ctx_state.sha3.pt] ^= 0x06;
c->ctx_state.sha3.st.b[c->ctx_state.sha3.rsiz - 1] ^= 0x80;
sha3_keccakf(c->ctx_state.sha3.st.q);
for (i = 0; i < c->ctx_state.sha3.mdlen; i++) {
((uint8_t *)md)[i] = c->ctx_state.sha3.st.b[i];
}
return 1;
}
// compute a SHA-3 hash (md) of given byte length from "in"
void *sha3(const void *in, size_t inlen, void *md, int mdlen)
{
struct fx_hash_ctx sha3;
sha3_init(&sha3, mdlen);
sha3_update(&sha3, in, inlen);
sha3_final(md, &sha3);
return md;
}
// SHAKE128 and SHAKE256 extensible-output functionality
void shake_xof(struct fx_hash_ctx *c)
{
c->ctx_state.sha3.st.b[c->ctx_state.sha3.pt] ^= 0x1F;
c->ctx_state.sha3.st.b[c->ctx_state.sha3.rsiz - 1] ^= 0x80;
sha3_keccakf(c->ctx_state.sha3.st.q);
c->ctx_state.sha3.pt = 0;
}
void shake_out(struct fx_hash_ctx *c, void *out, size_t len)
{
size_t i;
int j;
j = c->ctx_state.sha3.pt;
for (i = 0; i < len; i++) {
if (j >= c->ctx_state.sha3.rsiz) {
sha3_keccakf(c->ctx_state.sha3.st.q);
j = 0;
}
((uint8_t *)out)[i] = c->ctx_state.sha3.st.b[j++];
}
c->ctx_state.sha3.pt = j;
}
static void sha3_224_init(struct fx_hash_ctx *ctx)
{
sha3_init(ctx, FX_DIGEST_LENGTH_SHA3_224);
}
static void sha3_224_finish(struct fx_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[FX_DIGEST_LENGTH_SHA3_224];
sha3_final(md, ctx);
memcpy(out, md, fx_min(size_t, sizeof md, max));
}
static void sha3_256_init(struct fx_hash_ctx *ctx)
{
sha3_init(ctx, FX_DIGEST_LENGTH_SHA3_256);
}
static void sha3_256_finish(struct fx_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[FX_DIGEST_LENGTH_SHA3_256];
sha3_final(md, ctx);
memcpy(out, md, fx_min(size_t, sizeof md, max));
}
static void sha3_384_init(struct fx_hash_ctx *ctx)
{
sha3_init(ctx, FX_DIGEST_LENGTH_SHA3_384);
}
static void sha3_384_finish(struct fx_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[FX_DIGEST_LENGTH_SHA3_384];
sha3_final(md, ctx);
memcpy(out, md, fx_min(size_t, sizeof md, max));
}
static void sha3_512_init(struct fx_hash_ctx *ctx)
{
sha3_init(ctx, FX_DIGEST_LENGTH_SHA3_512);
}
static void sha3_512_finish(struct fx_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[FX_DIGEST_LENGTH_SHA3_512];
sha3_final(md, ctx);
memcpy(out, md, fx_min(size_t, sizeof md, max));
}
static void shake128_init(struct fx_hash_ctx *ctx)
{
sha3_init(ctx, FX_DIGEST_LENGTH_SHAKE128);
}
static void shake128_finish(struct fx_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[FX_DIGEST_LENGTH_SHAKE128];
shake_xof(ctx);
shake_out(ctx, md, sizeof md);
memcpy(out, md, fx_min(size_t, sizeof md, max));
}
static void shake256_init(struct fx_hash_ctx *ctx)
{
sha3_init(ctx, FX_DIGEST_LENGTH_SHAKE256);
}
static void shake256_finish(struct fx_hash_ctx *ctx, void *out, size_t max)
{
unsigned char md[FX_DIGEST_LENGTH_SHAKE256];
shake_xof(ctx);
shake_out(ctx, md, sizeof md);
memcpy(out, md, fx_min(size_t, sizeof md, max));
}
struct fx_hash_function_ops z__fx_sha3_224_ops = {
.hash_init = sha3_224_init,
.hash_update = sha3_update,
.hash_finish = sha3_224_finish,
};
struct fx_hash_function_ops z__fx_sha3_256_ops = {
.hash_init = sha3_256_init,
.hash_update = sha3_update,
.hash_finish = sha3_256_finish,
};
struct fx_hash_function_ops z__fx_sha3_384_ops = {
.hash_init = sha3_384_init,
.hash_update = sha3_update,
.hash_finish = sha3_384_finish,
};
struct fx_hash_function_ops z__fx_sha3_512_ops = {
.hash_init = sha3_512_init,
.hash_update = sha3_update,
.hash_finish = sha3_512_finish,
};
struct fx_hash_function_ops z__fx_shake128_ops = {
.hash_init = shake128_init,
.hash_update = sha3_update,
.hash_finish = shake128_finish,
};
struct fx_hash_function_ops z__fx_shake256_ops = {
.hash_init = shake256_init,
.hash_update = sha3_update,
.hash_finish = shake256_finish,
};
View File
+21
View File
@@ -0,0 +1,21 @@
#ifndef FX_CORE_BITOP_H_
#define FX_CORE_BITOP_H_
#include <fx/core/misc.h>
FX_API int fx_popcountl(long v);
FX_API int fx_ctzl(long v);
FX_API int fx_clzl(long v);
#if defined(__GNUC__) || defined(__clang__)
#define fx_cmpxchg(v, expected_val, new_val) \
__atomic_compare_exchange_n( \
v, expected_val, new_val, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED)
#elif defined(_MSC_VER)
/* TODO add MSVC support */
#error MSVC intrinsics not yet supported
#else
#error Unsupported compiler
#endif
#endif
+359
View File
@@ -0,0 +1,359 @@
#ifndef FX_CORE_BST_H_
#define FX_CORE_BST_H_
#include <fx/core/iterator.h>
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
FX_DECLS_BEGIN;
#define FX_BST_INIT {0}
#define FX_TYPE_BST_ITERATOR (fx_bst_iterator_get_type())
FX_DECLARE_TYPE(fx_bst_iterator);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_bst_iterator)
FX_TYPE_CLASS_DECLARATION_END(fx_bst_iterator)
/* defines a simple node insertion function.
this function assumes that your nodes have simple integer keys that can be
compared with the usual operators.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
int key;
fx_bst_node base;
}
You would use the following call to generate an insert function for a tree
with this node type:
BST_DEFINE_SIMPLE_INSERT(
struct my_tree_node,
base,
key,
my_tree_node_insert);
Which would emit a function defined like:
static void my_tree_node_insert(fx_bst *tree, struct my_tree_node *node);
@param node_type your custom tree node type. usually a structure that
contains a fx_bst_node member.
@param container_node_member the name of the fx_bst_node member variable
within your custom type.
@param container_key_member the name of the key member variable within your
custom type.
@param function_name the name of the function to generate.
*/
#define FX_BST_DEFINE_SIMPLE_INSERT( \
node_type, container_node_member, container_key_member, function_name) \
void function_name(fx_bst *tree, node_type *node) \
{ \
if (!tree->bst_root) { \
tree->bst_root = &node->container_node_member; \
fx_bst_insert_fixup(tree, &node->container_node_member); \
return; \
} \
\
fx_bst_node *cur = tree->bst_root; \
while (1) { \
node_type *cur_node = fx_unbox( \
node_type, cur, container_node_member); \
fx_bst_node *next = NULL; \
\
if (node->container_key_member \
>= cur_node->container_key_member) { \
next = fx_bst_right(cur); \
\
if (!next) { \
fx_bst_put_right( \
cur, \
&node->container_node_member); \
break; \
} \
} else if ( \
node->container_key_member \
< cur_node->container_key_member) { \
next = fx_bst_left(cur); \
\
if (!next) { \
fx_bst_put_left( \
cur, \
&node->container_node_member); \
break; \
} \
} \
\
cur = next; \
} \
\
fx_bst_insert_fixup(tree, &node->container_node_member); \
}
/* defines a node insertion function.
this function should be used for trees with complex node keys that cannot be
directly compared. a comparator for your keys must be supplied.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
complex_key_t key;
fx_bst_node base;
}
You would need to define a comparator function or macro with the following
signature:
int my_comparator(struct my_tree_node *a, struct my_tree_node *b);
Which implements the following:
return -1 if a < b
return 0 if a == b
return 1 if a > b
You would use the following call to generate an insert function for a tree
with this node type:
BST_DEFINE_INSERT(struct my_tree_node, base, key, my_tree_node_insert,
my_comparator);
Which would emit a function defined like:
static void my_tree_node_insert(fx_bst *tree, struct my_tree_node *node);
@param node_type your custom tree node type. usually a structure that
contains a fx_bst_node member.
@param container_node_member the name of the fx_bst_node member variable
within your custom type.
@param container_key_member the name of the key member variable within your
custom type.
@param function_name the name of the function to generate.
@param comparator the name of a comparator function or functional-macro that
conforms to the requirements listed above.
*/
#define FX_BST_DEFINE_INSERT( \
node_type, container_node_member, container_key_member, function_name, \
comparator) \
void function_name(fx_bst *tree, node_type *node) \
{ \
if (!tree->bst_root) { \
tree->bst_root = &node->container_node_member; \
fx_bst_insert_fixup(tree, &node->container_node_member); \
return; \
} \
\
fx_bst_node *cur = tree->bst_root; \
while (1) { \
node_type *cur_node = fx_unbox( \
node_type, cur, container_node_member); \
fx_bst_node *next = NULL; \
int cmp = comparator(node, cur_node); \
\
if (cmp >= 0) { \
next = fx_bst_right(cur); \
\
if (!next) { \
fx_bst_put_right( \
cur, \
&node->container_node_member); \
break; \
} \
} else if (cmp < 0) { \
next = fx_bst_left(cur); \
\
if (!next) { \
fx_bst_put_left( \
cur, \
&node->container_node_member); \
break; \
} \
} else { \
return; \
} \
\
cur = next; \
} \
\
fx_bst_insert_fixup(tree, &node->container_node_member); \
}
/* defines a simple tree search function.
this function assumes that your nodes have simple integer keys that can be
compared with the usual operators.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
int key;
fx_bst_node base;
}
You would use the following call to generate a search function for a tree
with this node type:
BST_DEFINE_SIMPLE_GET(struct my_tree_node, int, base, key,
my_tree_node_get);
Which would emit a function defined like:
static struct my_tree_node *my_tree_node_get(fx_bst *tree, int key);
@param node_type your custom tree node type. usually a structure that
contains a fx_bst_node member.
@param key_type the type name of the key embedded in your custom tree node
type. this type must be compatible with the builtin comparison operators.
@param container_node_member the name of the fx_bst_node member variable
within your custom type.
@param container_key_member the name of the key member variable within your
custom type.
@param function_name the name of the function to generate.
*/
#define FX_BST_DEFINE_SIMPLE_GET( \
node_type, key_type, container_node_member, container_key_member, \
function_name) \
node_type *function_name(const fx_bst *tree, key_type key) \
{ \
fx_bst_node *cur = tree->bst_root; \
while (cur) { \
node_type *cur_node = fx_unbox( \
node_type, cur, container_node_member); \
if (key > cur_node->container_key_member) { \
cur = fx_bst_right(cur); \
} else if (key < cur_node->container_key_member) { \
cur = fx_bst_left(cur); \
} else { \
return cur_node; \
} \
} \
\
return NULL; \
}
#define fx_bst_foreach(it, bst) \
for (int z__fx_unique_name() = fx_bst_iterator_begin(bst, it); \
(it)->node != NULL; fx_bst_iterator_next(it))
/* binary tree nodes. this *cannot* be used directly. you need to define a
custom node type that contains a member variable of type fx_bst_node.
you would then use the supplied macros to define functions to manipulate your
custom binary tree.
*/
typedef struct fx_bst_node {
struct fx_bst_node *n_parent, *n_left, *n_right;
unsigned short n_height;
} fx_bst_node;
/* binary tree. unlike fx_bst_node, you can define variables of type fx_bst.
*/
typedef struct fx_bst {
fx_bst_node *bst_root;
} fx_bst;
FX_API fx_type fx_bst_iterator_get_type(void);
/* re-balance a binary tree after an insertion operation.
NOTE that, if you define an insertion function using BST_DEFINE_INSERT or
similar, this function will automatically called for you.
@param tree the tree to re-balance.
@param node the node that was just inserted into the tree.
*/
FX_API void fx_bst_insert_fixup(fx_bst *tree, fx_bst_node *node);
/* delete a node from a binary tree and re-balance the tree afterwards.
@param tree the tree to delete from
@param node the node to delete.
*/
FX_API void fx_bst_delete(fx_bst *tree, fx_bst_node *node);
/* get the first node in a binary tree.
this will be the node with the smallest key (i.e. the node that is
furthest-left from the root)
*/
FX_API fx_bst_node *fx_bst_first(const fx_bst *tree);
/* get the last node in a binary tree.
this will be the node with the largest key (i.e. the node that is
furthest-right from the root)
*/
FX_API fx_bst_node *fx_bst_last(const fx_bst *tree);
/* for any binary tree node, this function returns the node with the
* next-largest key value */
FX_API fx_bst_node *fx_bst_next(const fx_bst_node *node);
/* for any binary tree node, this function returns the node with the
* next-smallest key value */
FX_API fx_bst_node *fx_bst_prev(const fx_bst_node *node);
/* return true if the bst is empty, false otherwise */
static inline bool fx_bst_empty(const fx_bst *tree)
{
return tree->bst_root == NULL;
}
/* sets `child` as the immediate left-child of `parent` */
static inline void fx_bst_put_left(fx_bst_node *parent, fx_bst_node *child)
{
parent->n_left = child;
child->n_parent = parent;
}
/* sets `child` as the immediate right-child of `parent` */
static inline void fx_bst_put_right(fx_bst_node *parent, fx_bst_node *child)
{
parent->n_right = child;
child->n_parent = parent;
}
/* get the immediate left-child of `node` */
static inline fx_bst_node *fx_bst_left(fx_bst_node *node)
{
return node->n_left;
}
/* get the immediate right-child of `node` */
static inline fx_bst_node *fx_bst_right(fx_bst_node *node)
{
return node->n_right;
}
/* get the immediate parent of `node` */
static inline fx_bst_node *fx_bst_parent(fx_bst_node *node)
{
return node->n_parent;
}
FX_API void fx_bst_move(fx_bst *tree, fx_bst_node *dest, fx_bst_node *src);
/* get the height of `node`.
the height of a node is defined as the length of the longest path
between the node and a leaf node.
this count includes the node itself, so the height of a leaf node will be 1.
*/
static inline unsigned short fx_bst_height(fx_bst_node *node)
{
return node->n_height;
}
FX_API fx_iterator *fx_bst_begin(fx_bst *tree);
FX_API const fx_iterator *fx_bst_cbegin(const fx_bst *tree);
#ifdef __cplusplus
}
#endif
#endif
+71
View File
@@ -0,0 +1,71 @@
#ifndef FX_CORE_BSTR_H_
#define FX_CORE_BSTR_H_
#include <fx/core/misc.h>
#include <fx/core/status.h>
#include <stdarg.h>
#include <stddef.h>
#define FX_BSTR_MAGIC 0x5005500550055005ULL
struct fx_rope;
enum fx_bstr_flags {
FX_BSTR_F_NONE = 0x00u,
FX_BSTR_F_ALLOC = 0x01u,
};
typedef struct fx_bstr {
uint64_t bstr_magic;
enum fx_bstr_flags bstr_flags;
char *bstr_buf;
/* total number of characters in bstr_buf, not including null terminator */
size_t bstr_len;
/* number of bytes allocated for bstr_buf (includes space for the null
* terminator) */
size_t bstr_capacity;
int *bstr_istack;
int bstr_add_indent;
size_t bstr_istack_ptr, bstr_istack_size;
} fx_bstr;
FX_API void fx_bstr_begin(fx_bstr *strv, char *buf, size_t max);
FX_API void fx_bstr_begin_dynamic(fx_bstr *strv);
FX_API char *fx_bstr_end(fx_bstr *strv);
FX_API fx_status fx_bstr_reserve(fx_bstr *strv, size_t len);
static inline size_t fx_bstr_get_size(const fx_bstr *str)
{
return str->bstr_len;
}
static inline size_t fx_bstr_get_capacity(const fx_bstr *str)
{
return str->bstr_capacity;
}
FX_API fx_status fx_bstr_push_indent(fx_bstr *strv, int indent);
FX_API fx_status fx_bstr_pop_indent(fx_bstr *strv);
FX_API fx_status fx_bstr_write_char(fx_bstr *strv, char c);
FX_API fx_status fx_bstr_write_chars(
fx_bstr *strv, const char *cs, size_t len, size_t *nr_written);
FX_API fx_status fx_bstr_write_cstr(
fx_bstr *strv, const char *str, size_t *nr_written);
FX_API fx_status fx_bstr_write_cstr_list(
fx_bstr *strv, const char **strs, size_t *nr_written);
FX_API fx_status fx_bstr_write_cstr_array(
fx_bstr *strv, const char **strs, size_t count, size_t *nr_written);
FX_API fx_status fx_bstr_write_cstr_varg(fx_bstr *strv, size_t *nr_written, ...);
FX_API fx_status fx_bstr_write_rope(
fx_bstr *strv, const struct fx_rope *rope, size_t *nr_written);
FX_API fx_status fx_bstr_write_fmt(
fx_bstr *strv, size_t *nr_written, const char *format, ...);
FX_API fx_status fx_bstr_write_vfmt(
fx_bstr *strv, size_t *nr_written, const char *format, va_list arg);
FX_API char *fx_bstr_rope(const struct fx_rope *rope, size_t *nr_written);
FX_API char *fx_bstr_fmt(size_t *nr_written, const char *format, ...);
FX_API char *fx_bstr_vfmt(size_t *nr_written, const char *format, va_list arg);
#endif
+15
View File
@@ -0,0 +1,15 @@
#ifndef FX_OBJECT_CLASS_H_
#define FX_OBJECT_CLASS_H_
#include <fx/core/type.h>
#define FX_CLASS_MAGIC 0xDEADFACEDCAFEBEDULL
#define FX_CLASS(p) ((fx_class *)(p))
typedef struct _fx_class fx_class;
FX_API void *fx_class_get(fx_type id);
FX_API const char *fx_class_get_name(const fx_class *c);
FX_API void *fx_class_get_interface(const fx_class *c, fx_type id);
#endif
+41
View File
@@ -0,0 +1,41 @@
#ifndef FX_CORE_ENCODING_H_
#define FX_CORE_ENCODING_H_
#include <fx/core/misc.h>
#include <stdbool.h>
#include <stdint.h>
#define FX_WCHAR_INVALID ((fx_wchar) - 1)
typedef int32_t fx_wchar;
FX_API bool fx_wchar_is_alpha(fx_wchar c);
FX_API bool fx_wchar_is_number(fx_wchar c);
static inline bool fx_wchar_is_bin_digit(fx_wchar c)
{
return c >= '0' && c <= '1';
}
static inline bool fx_wchar_is_oct_digit(fx_wchar c)
{
return c >= '0' && c <= '7';
}
FX_API bool fx_wchar_is_hex_digit(fx_wchar c);
FX_API bool fx_wchar_is_space(fx_wchar c);
static inline bool fx_wchar_is_alnum(fx_wchar c)
{
return fx_wchar_is_alpha(c) || fx_wchar_is_number(c);
}
FX_API bool fx_wchar_is_punct(fx_wchar c);
FX_API bool fx_wchar_utf8_is_valid_scalar(fx_wchar c);
FX_API unsigned int fx_wchar_utf8_header_decode(char c);
FX_API unsigned int fx_wchar_utf8_codepoint_size(fx_wchar c);
FX_API fx_wchar fx_wchar_utf8_codepoint_decode(const char *s);
FX_API unsigned int fx_wchar_utf8_codepoint_encode(fx_wchar c, char s[4]);
FX_API unsigned int fx_wchar_utf8_codepoint_stride(const char *s);
FX_API size_t fx_wchar_utf8_codepoint_count(const char *s, size_t nr_bytes);
FX_API size_t fx_wchar_utf8_string_encoded_size(
const fx_wchar *s, size_t nr_codepoints);
#endif
+49
View File
@@ -0,0 +1,49 @@
#ifndef FX_CORE_ENDIAN_H_
#define FX_CORE_ENDIAN_H_
#include <fx/core/misc.h>
#include <stdint.h>
typedef struct {
union {
unsigned char i_bytes[sizeof(uint16_t)];
int16_t i_val;
uint16_t i_uval;
};
} fx_i16;
typedef struct {
union {
unsigned char i_bytes[sizeof(uint32_t)];
int32_t i_val;
uint32_t i_uval;
};
} fx_i32;
typedef struct {
union {
unsigned char i_bytes[sizeof(uint64_t)];
int64_t i_val;
uint64_t i_uval;
};
} fx_i64;
FX_API fx_i16 fx_i16_htob(uint16_t v);
FX_API fx_i16 fx_i16_htos(uint16_t v);
FX_API uint16_t fx_i16_btoh(fx_i16 v);
FX_API uint16_t fx_i16_stoh(fx_i16 v);
FX_API fx_i32 fx_i32_htob(uint32_t v);
FX_API fx_i32 fx_i32_htos(uint32_t v);
FX_API uint32_t fx_i32_btoh(fx_i32 v);
FX_API uint32_t fx_i32_stoh(fx_i32 v);
FX_API fx_i64 fx_i64_htob(uint64_t v);
FX_API fx_i64 fx_i64_htos(uint64_t v);
FX_API uint64_t fx_i64_btoh(fx_i64 v);
FX_API uint64_t fx_i64_stoh(fx_i64 v);
#endif
+418
View File
@@ -0,0 +1,418 @@
#ifndef FX_CORE_ERROR_H_
#define FX_CORE_ERROR_H_
#include <fx/core/misc.h>
#include <fx/core/status.h>
#include <stdarg.h>
#include <stdbool.h>
#define FX_ERROR_TEMPLATE_PARAMETER_MAX 4
#define FX_ERROR_MSG_ID_INVALID ((unsigned long)-1)
#define FX_CATCH(err, expr) ((err = (expr)) != NULL)
#define fx_result_is_error(result) ((result) != NULL)
#define fx_result_is_success(result) ((result) == NULL)
#define FX_RESULT_SUCCESS ((fx_result)NULL)
#define FX_RESULT_ERR(err_name) \
fx_error_with_code(fx_error_vendor_get_builtin(), FX_ERR_##err_name)
#define FX_RESULT_ERR_WITH_STRING(err_name, ...) \
fx_error_with_string( \
fx_error_vendor_get_builtin(), FX_ERR_##err_name, __VA_ARGS__)
#define FX_RESULT_STATUS(code) \
((code) == FX_SUCCESS \
? FX_RESULT_SUCCESS \
: (fx_error_with_code(fx_error_vendor_get_builtin(), code)))
#define FX_RESULT_STATUS_WITH_STRING(code, ...) \
((code) == FX_SUCCESS \
? FX_RESULT_SUCCESS \
: (fx_error_with_string( \
fx_error_vendor_get_builtin(), code, __VA_ARGS__)))
#define FX_ERRORS_BUILTIN (fx_error_vendor_get_builtin())
#define FX_ERRORS_ERRNO (fx_error_vendor_get_errno())
#define FX_ERROR_PARAM(name, value) \
(fx_error_template_parameter) \
{ \
.param_name = (name), .param_value = (uintptr_t)(value), \
}
#define FX_ERROR_TEMPLATE_PARAM(name, type, format) \
(fx_error_template_parameter_definition) \
{ \
.param_name = (name), .param_type = (type), \
.param_format = (format), \
}
#define FX_ERROR_DEFINITION(code, name, msg) \
[code] = (fx_error_definition) \
{ \
.err_name = (name), .err_message = (msg), \
}
#define FX_ERROR_DEFINITION_TEMPLATE(code, name, msg, ...) \
[code] = (fx_error_definition) \
{ \
.err_name = (name), .err_message = (msg), \
.err_params = __VA_ARGS__, \
}
#define FX_ERROR_MSG(id, content) \
[id] = (fx_error_msg) \
{ \
.msg_message = (content), \
}
#define FX_ERROR_MSG_TEMPLATE(id, content, ...) \
[id] = (fx_error_msg) \
{ \
.msg_message = (content), .msg_params = __VA_ARGS__, \
}
#define z__fx_error_create_status(status_code) \
(z__fx_error_create( \
fx_error_vendor_get_builtin(), status_code, NULL, NULL, 0, \
NULL, NULL))
/* Error creation macros */
#define fx_error_with_code(vendor, code) \
(z__fx_error_create( \
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, NULL))
#define fx_error_caused_by_error(vendor, code, cause_error) \
(z__fx_error_create( \
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, NULL))
#define fx_error_caused_by_status(vendor, code, cause_status) \
(z__fx_error_create( \
vendor, code, z__fx_error_create_status(cause_status), \
__FILE__, __LINE__, __FUNCTION__, NULL))
#define fx_error_caused_by_code(vendor, code, cause_vendor, cause_code) \
(z__fx_error_create( \
vendor, code, fx_error_with_code(cause_vendor, cause_code), \
__FILE__, __LINE__, __FUNCTION__, NULL))
#define fx_error_with_string(vendor, code, ...) \
(z__fx_error_create( \
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__))
#define fx_error_with_string_caused_by_error(vendor, code, cause_error, ...) \
(z__fx_error_create( \
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, \
__VA_ARGS__))
#define fx_error_with_string_caused_by_status(vendor, code, cause_status, ...) \
(z__fx_error_create( \
vendor, code, z__fx_error_create_status(cause_status), \
__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__))
#define fx_error_with_msg(vendor, code, msg_id) \
(z__fx_error_create_msg( \
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, msg_id, \
(fx_error_template_parameter[]) {{}}))
#define fx_error_with_msg_caused_by_error(vendor, code, cause_error, msg_id) \
(z__fx_error_create_msg( \
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, \
msg_id, (fx_error_template_parameter[]) {{}}))
#define fx_error_with_msg_caused_by_status(vendor, code, cause_status, msg_id) \
(z__fx_error_create_msg( \
vendor, code, z__fx_error_create_status(cause_status), \
__FILE__, __LINE__, __FUNCTION__, msg_id, \
(fx_error_template_parameter[]) {{}}))
#define fx_error_with_msg_template(vendor, code, msg_id, ...) \
(z__fx_error_create_msg( \
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, msg_id, \
(fx_error_template_parameter[]) {__VA_ARGS__, {}}))
#define fx_error_with_msg_template_caused_by_error( \
vendor, code, cause_error, msg_id, ...) \
(z__fx_error_create_msg( \
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, \
msg_id, (fx_error_template_parameter[]) {__VA_ARGS__, {}}))
#define fx_error_with_msg_template_caused_by_status( \
vendor, code, cause_status, msg_id, ...) \
(z__fx_error_create_msg( \
vendor, code, z__fx_error_create_status(cause_status), \
__FILE__, __LINE__, __FUNCTION__, msg_id, \
(fx_error_template_parameter[]) {__VA_ARGS__, {}}))
#define fx_error_with_template(vendor, code, ...) \
(z__fx_error_create_template( \
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, \
(fx_error_template_parameter[]) {__VA_ARGS__, {}}))
#define fx_error_with_template_caused_by_error(vendor, code, cause_error, ...) \
(z__fx_error_create_template( \
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, \
(fx_error_template_parameter[]) {__VA_ARGS__, {}}))
#define fx_error_with_template_caused_by_status(vendor, code, cause_status, ...) \
(z__fx_error_create_template( \
vendor, code, z__fx_error_create_status(cause_status), \
__FILE__, __LINE__, __FUNCTION__, \
(fx_error_template_parameter[]) {__VA_ARGS__, {}}))
/* Error propagation macros */
#define fx_result_propagate(err) \
(z__fx_error_propagate(err, __FILE__, __LINE__, __FUNCTION__))
#define fx_error_caused_by(err, caused_by) (z__fx_error_caused_by(err, caused_by))
#define fx_error_caused_by_fx_status(err, status) \
(z__fx_error_caused_by_fx_status(err, status))
#define fx_error_replace(err, caused_by) \
(z__fx_error_propagate(err, __FILE__, __LINE__, __FUNCTION__))
/* Error throw macros */
#define z__fx_throw(err) (z__fx_error_throw(err, NULL, 0, NULL))
#define fx_throw(err) (z__fx_error_throw(err, __FILE__, __LINE__, __FUNCTION__))
#define fx_throw_status(status) \
(z__fx_error_throw( \
z__fx_error_create( \
fx_error_vendor_get_builtin(), status, NULL, NULL, 0, \
NULL, NULL), \
__FILE__, __LINE__, __FUNCTION__))
#define fx_throw_status_string(status, ...) \
(z__fx_error_throw( \
z__fx_error_create( \
fx_error_vendor_get_builtin(), status, NULL, NULL, 0, \
NULL, __VA_ARGS__), \
__FILE__, __LINE__, __FUNCTION__))
#define fx_throw_error_code(vendor, code) \
z__fx_throw(fx_error_with_code(vendor, code))
#define fx_throw_error_caused_by_error(vendor, code, cause) \
z__fx_throw(fx_error_caused_by_error(vendor, code, cause))
#define fx_throw_error_caused_by_status(vendor, code, cause) \
z__fx_throw(fx_error_caused_by_status(vendor, code, cause))
#define fx_throw_error_with_string(vendor, code, ...) \
z__fx_throw(fx_error_with_string(vendor, code, __VA_ARGS__))
#define fx_throw_error_with_string_caused_by_error(vendor, code, cause, ...) \
z__fx_throw(fx_error_with_string_caused_by_error( \
vendor, code, cause, __VA_ARGS__))
#define fx_throw_error_with_string_caused_by_status(vendor, code, cause, ...) \
z__fx_throw(fx_error_with_string_caused_by_status( \
vendor, code, cause, __VA_ARGS__))
#define fx_throw_error_with_msg(vendor, code, msg_id) \
z__fx_throw(fx_error_with_msg(vendor, code, msg_id))
#define fx_throw_error_with_msg_caused_by_error(vendor, code, cause, msg_id) \
z__fx_throw(fx_error_with_msg_caused_by_error(vendor, code, cause, msg_id))
#define fx_throw_error_with_msg_caused_by_status(vendor, code, cause, msg_id) \
z__fx_throw(fx_error_with_msg_caused_by_status(vendor, code, cause, msg_id))
#define fx_throw_error_with_msg_template(vendor, code, msg_id, ...) \
z__fx_throw(fx_error_with_msg_template(vendor, code, msg_id, __VA_ARGS__))
#define fx_throw_error_with_msg_template_caused_by_error( \
vendor, code, cause, msg_id, ...) \
z__fx_throw(fx_error_with_msg_template_caused_by_error( \
vendor, code, cause, msg_id, __VA_ARGS__))
#define fx_throw_error_with_msg_template_caused_by_status( \
vendor, code, cause, msg_id, ...) \
z__fx_throw(fx_error_with_msg_template_caused_by_status( \
vendor, code, cause, msg_id, __VA_ARGS__))
#define fx_throw_error_with_template(vendor, code, ...) \
z__fx_throw(fx_error_with_template(vendor, code, __VA_ARGS__))
#define fx_throw_error_with_template_caused_by_error(vendor, code, cause, ...) \
z__fx_throw(fx_error_with_template_caused_by_error( \
vendor, code, cause, __VA_ARGS__))
#define fx_throw_error_with_template_caused_by_status(vendor, code, cause, ...) \
z__fx_throw(fx_error_with_template_caused_by_status( \
vendor, code, cause, __VA_ARGS__))
#define FX_ERR_MSG(s) \
{ \
.msg_type = FX_ERROR_MESSAGE_ERROR, \
.msg_content = (s), \
}
#define FX_ERR_MSG_WARN(s) \
{ \
.msg_type = FX_ERROR_MESSAGE_WARN, \
.msg_content = (s), \
}
#define FX_ERR_MSG_INFO(s) \
{ \
.msg_type = FX_ERROR_MESSAGE_INFO, \
.msg_content = (s), \
}
#define FX_ERR_MSG_END(s) \
{ \
.msg_type = FX_ERROR_MESSAGE_NONE, \
.msg_content = NULL, \
}
typedef enum fx_error_submsg_type {
FX_ERROR_SUBMSG_NONE = 0,
FX_ERROR_SUBMSG_ERROR,
FX_ERROR_SUBMSG_WARNING,
FX_ERROR_SUBMSG_INFO,
} fx_error_submsg_type;
typedef enum fx_error_report_flags {
FX_ERROR_REPORT_NONE = 0,
FX_ERROR_REPORT_STATUS = 0x01u,
FX_ERROR_REPORT_DESCRIPTION = 0x02u,
FX_ERROR_REPORT_SUBMSG = 0x04u,
FX_ERROR_REPORT_STACK_TRACE = 0x08u,
FX_ERROR_REPORT_CAUSE = 0x10u,
FX_ERROR_REPORT_MINIMAL = FX_ERROR_REPORT_STATUS | FX_ERROR_REPORT_DESCRIPTION,
FX_ERROR_REPORT_DEFAULT = FX_ERROR_REPORT_MINIMAL | FX_ERROR_REPORT_SUBMSG
| FX_ERROR_REPORT_CAUSE,
FX_ERROR_REPORT_ALL = FX_ERROR_REPORT_DEFAULT | FX_ERROR_REPORT_STACK_TRACE,
} fx_error_report_flags;
typedef enum fx_error_template_parameter_type {
FX_ERROR_TEMPLATE_PARAM_NONE = 0,
FX_ERROR_TEMPLATE_PARAM_STRING,
FX_ERROR_TEMPLATE_PARAM_CHAR,
FX_ERROR_TEMPLATE_PARAM_INT,
FX_ERROR_TEMPLATE_PARAM_UINT,
FX_ERROR_TEMPLATE_PARAM_LONG,
FX_ERROR_TEMPLATE_PARAM_ULONG,
FX_ERROR_TEMPLATE_PARAM_LONGLONG,
FX_ERROR_TEMPLATE_PARAM_ULONGLONG,
FX_ERROR_TEMPLATE_PARAM_SIZE_T,
FX_ERROR_TEMPLATE_PARAM_INTPTR,
FX_ERROR_TEMPLATE_PARAM_UINTPTR,
FX_ERROR_TEMPLATE_PARAM_PTR,
} fx_error_template_parameter_type;
typedef struct fx_error_template_parameter_definition {
const char *param_name;
fx_error_template_parameter_type param_type;
const char *param_format;
} fx_error_template_parameter_definition;
typedef struct fx_error_template_parameter {
const char *param_name;
uintptr_t param_value;
const struct fx_error_template_parameter_definition *__param_def;
} fx_error_template_parameter;
struct fx_error_vendor;
typedef struct fx_error fx_error;
typedef struct fx_error *fx_result;
typedef struct fx_error_submsg fx_error_submsg;
typedef struct fx_error_stack_frame fx_error_stack_frame;
typedef long fx_error_status_code;
typedef unsigned long fx_error_msg_id;
typedef struct fx_error_definition {
const char *err_name;
const char *err_message;
const fx_error_template_parameter_definition err_params[FX_ERROR_TEMPLATE_PARAMETER_MAX];
} fx_error_definition;
typedef struct fx_error_msg {
const char *msg_message;
const fx_error_template_parameter_definition msg_params[FX_ERROR_TEMPLATE_PARAMETER_MAX];
} fx_error_msg;
typedef const fx_error_definition *(*fx_error_status_code_get_definition)(
const struct fx_error_vendor *, fx_error_status_code);
typedef const fx_error_msg *(*fx_error_msg_get_definition)(
const struct fx_error_vendor *, fx_error_msg_id);
typedef void (*fx_error_report_function)(
const struct fx_error *, fx_error_report_flags);
typedef struct fx_error_vendor {
const char *v_name;
fx_error_status_code_get_definition v_status_get_definition;
fx_error_msg_get_definition v_msg_get_definition;
const fx_error_definition *v_error_definitions;
size_t v_error_definitions_length;
const fx_error_msg *v_msg;
size_t v_msg_length;
} fx_error_vendor;
FX_API fx_error *z__fx_error_create_template(
const fx_error_vendor *, fx_error_status_code, fx_error *, const char *,
unsigned int, const char *, const fx_error_template_parameter[]);
FX_API fx_error *z__fx_error_create_string(
const fx_error_vendor *, fx_error_status_code, fx_error *, const char *,
unsigned int, const char *, const char *, va_list);
FX_API fx_error *z__fx_error_create_msg(
const fx_error_vendor *, fx_error_status_code, fx_error *, const char *,
unsigned int, const char *, fx_error_msg_id,
const fx_error_template_parameter[]);
FX_API fx_error *z__fx_error_propagate(
fx_error *, const char *, unsigned int, const char *);
FX_API fx_error *z__fx_error_caused_by(fx_error *, fx_error *);
FX_API fx_error *z__fx_error_caused_by_fx_status(fx_error *, fx_status);
FX_API void z__fx_error_throw(fx_error *, const char *, unsigned int, const char *);
FX_API bool fx_result_is(
fx_result result, const fx_error_vendor *vendor, fx_error_status_code code);
FX_API const fx_error_vendor *fx_error_vendor_get_builtin(void);
FX_API const fx_error_vendor *fx_error_vendor_get_errno(void);
FX_API const fx_error_definition *fx_error_vendor_get_error_definition(
const fx_error_vendor *vendor, fx_error_status_code code);
FX_API const char *fx_error_vendor_get_status_code_name(
const fx_error_vendor *vendor, fx_error_status_code code);
FX_API const char *fx_error_vendor_get_status_code_description(
const fx_error_vendor *vendor, fx_error_status_code code);
FX_API const fx_error_msg *fx_error_vendor_get_msg(
const fx_error_vendor *vendor, fx_error_msg_id msg_id);
static inline fx_error *z__fx_error_create(
const fx_error_vendor *v, fx_error_status_code c, fx_error *c2,
const char *f0, unsigned int l, const char *f1, const char *d, ...)
{
va_list arg;
va_start(arg, d);
fx_error *err = z__fx_error_create_string(v, c, c2, f0, l, f1, d, arg);
va_end(arg);
return err;
}
FX_API enum fx_status fx_error_add_submsg_string(
fx_error *error, fx_error_submsg_type type, const char *msg, ...);
FX_API enum fx_status z__fx_error_add_submsg_template(
fx_error *error, fx_error_submsg_type type, fx_error_msg_id msg_id,
fx_error_template_parameter param[]);
#define fx_error_add_submsg(error, type, msg_id) \
(z__fx_error_add_submsg_template( \
error, type, msg_id, (fx_error_template_parameter[]) {{}}))
#define fx_error_add_submsg_template(error, type, msg_id, ...) \
(z__fx_error_add_submsg_template( \
error, type, msg_id, \
(fx_error_template_parameter[]) {__VA_ARGS__, {}}))
FX_API void fx_error_discard(fx_error *error);
FX_API fx_error_status_code fx_error_get_status_code(const fx_error *error);
FX_API const fx_error_vendor *fx_error_get_vendor(const fx_error *error);
FX_API const fx_error_definition *fx_error_get_definition(const fx_error *error);
FX_API const fx_error_template_parameter *fx_error_get_template_parameter(
const fx_error *error, const char *param_name);
FX_API const fx_error_template_parameter *fx_error_get_template_parameters(
const fx_error *error);
FX_API const char *fx_error_get_description(const fx_error *error);
FX_API const fx_error_msg *fx_error_get_msg(const fx_error *error);
FX_API const fx_error_submsg *fx_error_get_first_submsg(const fx_error *error);
FX_API const fx_error_submsg *fx_error_get_next_submsg(
const fx_error *error, const fx_error_submsg *msg);
FX_API const fx_error_stack_frame *fx_error_get_first_stack_frame(
const fx_error *error);
FX_API const fx_error_stack_frame *fx_error_get_next_stack_frame(
const fx_error *error, const fx_error_stack_frame *frame);
FX_API const fx_error *fx_error_get_caused_by(const fx_error *error);
FX_API fx_error_submsg_type fx_error_submsg_get_type(const fx_error_submsg *msg);
FX_API const char *fx_error_submsg_get_content(const fx_error_submsg *msg);
FX_API const fx_error_msg *fx_error_submsg_get_msg(const fx_error_submsg *msg);
FX_API const fx_error_template_parameter *fx_error_submsg_get_template_parameters(
const fx_error_submsg *msg);
FX_API const char *fx_error_stack_frame_get_filepath(
const fx_error_stack_frame *frame);
FX_API unsigned int fx_error_stack_frame_get_line_number(
const fx_error_stack_frame *frame);
FX_API const char *fx_error_stack_frame_get_function_name(
const fx_error_stack_frame *frame);
FX_API const fx_error_template_parameter_definition *fx_error_definition_get_template_parameter(
const fx_error_definition *error_def, const char *param_name);
FX_API const char *fx_error_msg_get_content(const fx_error_msg *msg);
FX_API const fx_error_template_parameter_definition *fx_error_msg_get_template_parameter(
const fx_error_msg *msg, const char *param_name);
FX_API void fx_set_error_report_function(
fx_error_report_function func, fx_error_report_flags flags);
#endif
View File
+111
View File
@@ -0,0 +1,111 @@
#ifndef FX_CORE_HASH_H_
#define FX_CORE_HASH_H_
#include <fx/core/misc.h>
#include <fx/core/status.h>
#include <stddef.h>
#include <stdint.h>
#define FX_DIGEST_LENGTH_128 16
#define FX_DIGEST_LENGTH_160 20
#define FX_DIGEST_LENGTH_192 24
#define FX_DIGEST_LENGTH_224 28
#define FX_DIGEST_LENGTH_256 32
#define FX_DIGEST_LENGTH_384 48
#define FX_DIGEST_LENGTH_512 64
#define FX_DIGEST_LENGTH_MD4 FX_DIGEST_LENGTH_128
#define FX_DIGEST_LENGTH_MD5 FX_DIGEST_LENGTH_128
#define FX_DIGEST_LENGTH_SHA1 FX_DIGEST_LENGTH_160
#define FX_DIGEST_LENGTH_SHA2_224 FX_DIGEST_LENGTH_224
#define FX_DIGEST_LENGTH_SHA2_256 FX_DIGEST_LENGTH_256
#define FX_DIGEST_LENGTH_SHA2_384 FX_DIGEST_LENGTH_384
#define FX_DIGEST_LENGTH_SHA2_512 FX_DIGEST_LENGTH_512
#define FX_DIGEST_LENGTH_SHA3_224 FX_DIGEST_LENGTH_224
#define FX_DIGEST_LENGTH_SHA3_256 FX_DIGEST_LENGTH_256
#define FX_DIGEST_LENGTH_SHA3_384 FX_DIGEST_LENGTH_384
#define FX_DIGEST_LENGTH_SHA3_512 FX_DIGEST_LENGTH_512
#define FX_DIGEST_LENGTH_SHAKE128 FX_DIGEST_LENGTH_128
#define FX_DIGEST_LENGTH_SHAKE256 FX_DIGEST_LENGTH_256
struct fx_hash_function_ops;
struct fx_rope;
typedef enum fx_hash_function {
FX_HASH_NONE = 0,
FX_HASH_MD4,
FX_HASH_MD5,
FX_HASH_SHA1,
FX_HASH_SHA2_224,
FX_HASH_SHA2_256,
FX_HASH_SHA2_384,
FX_HASH_SHA2_512,
FX_HASH_SHA3_224,
FX_HASH_SHA3_256,
FX_HASH_SHA3_384,
FX_HASH_SHA3_512,
FX_HASH_SHAKE128,
FX_HASH_SHAKE256,
} fx_hash_function;
typedef struct fx_hash_ctx {
fx_hash_function ctx_func;
const struct fx_hash_function_ops *ctx_ops;
union {
struct {
uint32_t lo, hi;
uint32_t a, b, c, d;
uint32_t block[16];
unsigned char buffer[64];
} md4;
struct {
unsigned int count[2];
unsigned int a, b, c, d;
unsigned int block[16];
unsigned char input[64];
} md5;
struct {
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[64];
} sha1;
struct {
uint64_t curlen;
uint64_t length;
unsigned char buf[128];
uint32_t state[8];
} sha2_256;
struct {
uint64_t curlen;
uint64_t length;
unsigned char block[256];
uint64_t state[8];
} sha2_512;
struct {
union {
uint8_t b[200];
uint64_t q[25];
} st;
int pt, rsiz, mdlen;
} sha3;
} ctx_state;
} fx_hash_ctx;
FX_API uint64_t fx_hash_cstr(const char *s);
FX_API uint64_t fx_hash_cstr_ex(const char *s, size_t *len);
FX_API fx_status fx_hash_ctx_init(fx_hash_ctx *ctx, fx_hash_function func);
FX_API fx_status fx_hash_ctx_reset(fx_hash_ctx *ctx);
FX_API fx_status fx_hash_ctx_update(fx_hash_ctx *ctx, const void *p, size_t len);
FX_API fx_status fx_hash_ctx_update_rope(fx_hash_ctx *ctx, const struct fx_rope *rope);
FX_API fx_status fx_hash_ctx_finish(
fx_hash_ctx *ctx, void *out_digest, size_t out_max);
#endif
+32
View File
@@ -0,0 +1,32 @@
#ifndef FX_INIT_H_
#define FX_INIT_H_
#ifdef __cplusplus
#define FX_INIT(f) \
static void f(void); \
struct f##_t_ { \
f##_t_(void) \
{ \
f(); \
} \
}; \
static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU", read)
#define FX_INIT2_(f, p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker, "/include:" p #f "_")) static void f(void)
#ifdef _WIN64
#define FX_INIT(f) FX_INIT2_(f, "")
#else
#define FX_INIT(f) FX_INIT2_(f, "_")
#endif
#else
#define FX_INIT(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
#endif
+93
View File
@@ -0,0 +1,93 @@
#ifndef FX_CORE_ITERATOR_H_
#define FX_CORE_ITERATOR_H_
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <fx/core/status.h>
#include <stdbool.h>
FX_DECLS_BEGIN;
#define fx_foreach(type, var, iterator) \
for (type var = (type)fx_iterator_get_value(iterator).v_int; \
FX_OK(fx_iterator_get_status(iterator)); \
fx_iterator_move_next(iterator), \
var = (type)fx_iterator_get_value(iterator).v_int)
#define fx_foreach_ptr(type, var, iterator) \
for (type *var = (type *)fx_iterator_get_value(iterator).v_ptr; \
FX_OK(fx_iterator_get_status(iterator)); \
fx_iterator_move_next(iterator), \
var = (type *)fx_iterator_get_value(iterator).v_ptr)
#define fx_foreach_c(type, var, iterator) \
for (type var = (type)fx_iterator_get_cvalue(iterator).v_int; \
FX_OK(fx_iterator_get_status(iterator)); \
fx_iterator_move_next(iterator), \
var = (type)fx_iterator_get_cvalue(iterator).v_int)
#define fx_foreach_cptr(type, var, iterator) \
for (const type *var \
= (const type *)fx_iterator_get_cvalue(iterator).v_cptr; \
FX_OK(fx_iterator_get_status(iterator)); \
fx_iterator_move_next(iterator), \
var = (const type *)fx_iterator_get_cvalue(iterator).v_cptr)
#define FX_ITERATOR_VALUE_INT(v) ((fx_iterator_value) {.v_int = (v)})
#define FX_ITERATOR_VALUE_PTR(v) ((fx_iterator_value) {.v_ptr = (v)})
#define FX_ITERATOR_VALUE_CPTR(v) ((const fx_iterator_value) {.v_cptr = (v)})
#define FX_ITERATOR_VALUE_NULL ((fx_iterator_value) {})
#define FX_ITERATOR_VALUE_IS_NULL(v) ((v)->v_ptr == NULL)
#define FX_TYPE_ITERATOR (fx_iterator_get_type())
#define FX_TYPE_ITERABLE (fx_iterable_get_type())
typedef union fx_iterator_value {
uintptr_t v_int;
void *v_ptr;
const void *v_cptr;
} fx_iterator_value;
__FX_DECLARE_TYPE(fx_iterator);
FX_DECLARE_TYPE(fx_iterable);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_iterator)
fx_status (*it_move_next)(const fx_iterator *);
fx_status (*it_erase)(fx_iterator *);
fx_iterator_value (*it_get_value)(fx_iterator *);
const fx_iterator_value (*it_get_cvalue)(const fx_iterator *);
FX_TYPE_CLASS_DECLARATION_END(fx_iterator)
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_iterable)
fx_iterator *(*it_begin)(fx_iterable *);
const fx_iterator *(*it_cbegin)(const fx_iterable *);
FX_TYPE_CLASS_DECLARATION_END(fx_iterable)
FX_API fx_type fx_iterator_get_type(void);
FX_API fx_type fx_iterable_get_type(void);
static inline const fx_iterator *fx_iterator_ref(const fx_iterator *p)
{
return fx_object_ref((fx_object *)p);
}
static inline void fx_iterator_unref(const fx_iterator *p)
{
fx_object_unref((fx_object *)p);
}
FX_API fx_iterator *fx_iterator_begin(fx_iterable *it);
FX_API const fx_iterator *fx_iterator_cbegin(const fx_iterable *it);
FX_API fx_status fx_iterator_get_status(const fx_iterator *it);
FX_API fx_status fx_iterator_set_status(const fx_iterator *it, fx_status status);
FX_API fx_status fx_iterator_move_next(const fx_iterator *it);
FX_API fx_iterator_value fx_iterator_get_value(fx_iterator *it);
FX_API const fx_iterator_value fx_iterator_get_cvalue(const fx_iterator *it);
FX_API fx_status fx_iterator_erase(fx_iterator *it);
static inline bool fx_iterator_is_valid(const fx_iterator *it)
{
return FX_OK(fx_iterator_get_status(it));
}
FX_DECLS_END;
#endif
+197
View File
@@ -0,0 +1,197 @@
#ifndef FX_CORE_MACROS_H_
#define FX_CORE_MACROS_H_
#include <fx/core/class.h>
#include <fx/core/object.h>
#include <fx/core/thread.h>
#include <fx/core/type.h>
#include <stdlib.h>
#define __FX_IFACE_I0(p, x) p##x
#define __FX_IFACE_I1(p, x) __FX_IFACE_I0(p, x)
/* Type definitions macros (for use in .c source file) */
#define FX_TYPE_CLASS_DEFINITION_BEGIN(type_name) \
static void type_name##_class_init(fx_class *p, void *d) \
{
#define FX_TYPE_CLASS_DEFINITION_END(type_name) }
#define FX_TYPE_CLASS_INTERFACE_BEGIN(interface_name, interface_id) \
interface_name##_class *__FX_IFACE_I1(iface, __LINE__) \
= fx_class_get_interface(p, interface_id); \
if (!__FX_IFACE_I1(iface, __LINE__)) { \
fx_throw_error_with_msg_template( \
FX_ERRORS_BUILTIN, FX_ERR_CLASS_INIT_FAILURE, \
FX_MSG_CLASS_SPECIFIES_UNKNOWN_INTERFACE, \
FX_ERROR_PARAM("class_name", fx_class_get_name(p)), \
FX_ERROR_PARAM("interface_name", #interface_name)); \
exit(-1); \
} else { \
interface_name##_class *iface = __FX_IFACE_I1(iface, __LINE__);
#define FX_TYPE_CLASS_INTERFACE_END(interface_name, interface_id) }
#define FX_INTERFACE_ENTRY(slot) iface->slot
#define FX_TYPE_DEFINITION_BEGIN(name) \
static fx_type_info name##_type_info = {0}; \
static void name##_class_init(fx_class *, void *); \
static void name##_type_init(void) \
{ \
fx_type_info *type_info = &name##_type_info; \
unsigned int nr_vtables = 0; \
type_info->t_name = #name; \
type_info->t_class_init = name##_class_init;
#define FX_TYPE_DEFINITION_END(name) \
fx_result result = fx_type_register(type_info); \
if (fx_result_is_error(result)) { \
fx_throw_error_caused_by_error( \
FX_ERRORS_BUILTIN, FX_ERR_TYPE_REGISTRATION_FAILURE, \
result); \
abort(); \
} \
} \
fx_type name##_get_type(void) \
{ \
static fx_once static_type_init = FX_ONCE_INIT; \
\
if (fx_init_once(&static_type_init)) { \
name##_type_init(); \
} \
\
return &name##_type_info.t_id; \
}
#define FX_TYPE_ID(a, b, c, d, e) fx_type_id_init(&type_info->t_id, a, b, c, d, e)
#define FX_TYPE_EXTENDS(parent_id) \
fx_type_id_copy(parent_id, &type_info->t_parent_id)
#define FX_TYPE_IMPLEMENTS(interface_id) \
fx_type_id_copy( \
interface_id, \
&type_info->t_interfaces[type_info->t_nr_interfaces++])
#define FX_TYPE_CLASS(class_struct) \
type_info->t_class_size = sizeof(class_struct)
#define FX_TYPE_FLAGS(flags) type_info->t_flags = (flags)
#define FX_TYPE_INSTANCE_INIT(func) type_info->t_instance_init = (func)
#define FX_TYPE_INSTANCE_FINI(func) type_info->t_instance_fini = (func)
#if 0
#define FX_TYPE_VTABLE_BEGIN(vtable_struct, interface_id) \
vtable_struct __FX_IFACE_I1(iface, __LINE__) = {0}; \
{ \
vtable_struct *iface = &__FX_IFACE_I1(iface, __LINE__); \
type_info->t_vtables[nr_vtables].v_vtable = iface; \
type_info->t_vtables[nr_vtables].v_interface_id = interface_id; \
nr_vtables++;
#define FX_TYPE_VTABLE_END(vtable_struct, interface_id) }
#endif
#define FX_TYPE_INSTANCE_PRIVATE(instance_struct) \
type_info->t_instance_private_size = sizeof(instance_struct)
#define FX_TYPE_INSTANCE_PROTECTED(instance_struct) \
type_info->t_instance_protected_size = sizeof(instance_struct)
/* Type declaration macros (for use in .h header file) */
#define __FX_DECLARE_TYPE(name) \
typedef FX_TYPE_FWDREF(name) name; \
typedef struct _##name##_class name##_class;
#define FX_DECLARE_TYPE(name) \
__FX_DECLARE_TYPE(name); \
static inline name *name##_ref(name *p) \
{ \
return fx_object_ref(p); \
} \
static inline void name##_unref(name *p) \
{ \
fx_object_unref(p); \
}
#define FX_TYPE_CLASS_DECLARATION_BEGIN(name) struct _##name##_class {
#define FX_TYPE_CLASS_DECLARATION_END(name) \
} \
;
#define FX_TYPE_VIRTUAL_METHOD(return_type, method_name) \
return_type(*method_name)
#define FX_TYPE_DEFAULT_CONSTRUCTOR(type_name, type_id) \
static inline type_name *type_name##_create(void) \
{ \
return fx_object_create(type_id); \
}
/* Other macros */
#define FX_CLASS_DISPATCH_VIRTUAL( \
type_name, type_id, default_value, func, object, ...) \
do { \
type_name##_class *iface \
= fx_object_get_interface(object, type_id); \
if (iface && iface->func) { \
return iface->func(object, __VA_ARGS__); \
} else { \
return default_value; \
} \
} while (0)
#define FX_CLASS_DISPATCH_VIRTUAL_0(type_name, type_id, default_value, func, object) \
do { \
type_name##_class *iface \
= fx_object_get_interface(object, type_id); \
if (iface && iface->func) { \
return iface->func(object); \
} else { \
return default_value; \
} \
} while (0)
#define FX_CLASS_DISPATCH_VIRTUAL_V(type_name, type_id, func, object, ...) \
do { \
type_name##_class *iface \
= fx_object_get_interface(object, type_id); \
if (iface && iface->func) { \
iface->func(object, __VA_ARGS__); \
return; \
} \
} while (0)
#define FX_CLASS_DISPATCH_VIRTUAL_V0(type_name, type_id, func, object) \
do { \
type_name##_class *iface \
= fx_object_get_interface(object, type_id); \
if (iface && iface->func) { \
iface->func(object); \
return; \
} \
} while (0)
#define FX_CLASS_DISPATCH_STATIC(type_id, func_name, obj, ...) \
do { \
void *priv = fx_object_get_private(obj, type_id); \
return func_name(priv, __VA_ARGS__); \
} while (0)
#define FX_CLASS_DISPATCH_STATIC_V(type_id, func_name, obj, ...) \
do { \
void *priv = fx_object_get_private(obj, type_id); \
func_name(priv, __VA_ARGS__); \
} while (0)
#define FX_CLASS_DISPATCH_STATIC_0(type_id, func_name, obj) \
do { \
void *priv = fx_object_get_private(obj, type_id); \
return func_name(priv); \
} while (0)
#define FX_CLASS_DISPATCH_STATIC_V0(type_id, func_name, obj) \
do { \
void *priv = fx_object_get_private(obj, type_id); \
func_name(priv); \
} while (0)
#ifdef __cplusplus
#define FX_DECLS_BEGIN extern "C" {
#define FX_DECLS_END }
#else
#define FX_DECLS_BEGIN
#define FX_DECLS_END
#endif
#endif
+118
View File
@@ -0,0 +1,118 @@
#ifndef FX_CORE_MISC_H_
#define FX_CORE_MISC_H_
#include <stddef.h>
#include <stdint.h>
#ifndef _Nonnull
#define _Nonnull
#endif
#define FX_NPOS ((size_t)-1)
#define fx_min(type, x, y) (z__fx_min_##type(x, y))
#define fx_max(type, x, y) (z__fx_max_##type(x, y))
#define fx_unbox(type, box, member) \
((type *_Nonnull)((box) ? (uintptr_t)(box) - (offsetof(type, member)) : 0))
#define z__fx_merge_(a, b) a##b
#define z__fx_label_(a) z__fx_merge_(__unique_name_, a)
#define z__fx_unique_name() z__fx_label_(__LINE__)
#define z__fx_numargs(arg_type, ...) \
(sizeof((arg_type[]) {__VA_ARGS__}) / sizeof(arg_type))
#ifdef _MSC_VER
#ifdef FX_STATIC
#define FX_API extern
#else
#ifdef FX_EXPORT
#define FX_API extern __declspec(dllexport)
#else
#define FX_API extern __declspec(dllimport)
#endif
#endif
#else
#define FX_API extern
#endif
static inline char z__fx_min_char(char x, char y)
{
return x < y ? x : y;
}
static inline unsigned char z__fx_min_uchar(unsigned char x, unsigned char y)
{
return x < y ? x : y;
}
static inline int z__fx_min_int(int x, int y)
{
return x < y ? x : y;
}
static inline unsigned int z__fx_min_uint(unsigned int x, unsigned int y)
{
return x < y ? x : y;
}
static inline long z__fx_min_long(long x, long y)
{
return x < y ? x : y;
}
static inline unsigned int z__fx_min_ulong(unsigned long x, unsigned long y)
{
return x < y ? x : y;
}
static inline long long z__fx_min_longlong(long long x, long long y)
{
return x < y ? x : y;
}
static inline unsigned long long z__fx_min_ulonglong(
unsigned long long x, unsigned long long y)
{
return x < y ? x : y;
}
static inline size_t z__fx_min_size_t(size_t x, size_t y)
{
return x < y ? x : y;
}
static inline char z__fx_max_char(char x, char y)
{
return x > y ? x : y;
}
static inline unsigned char z__fx_max_uchar(unsigned char x, unsigned char y)
{
return x > y ? x : y;
}
static inline int z__fx_max_int(int x, int y)
{
return x > y ? x : y;
}
static inline unsigned int z__fx_max_uint(unsigned int x, unsigned int y)
{
return x > y ? x : y;
}
static inline long z__fx_max_long(long x, long y)
{
return x > y ? x : y;
}
static inline unsigned int z__fx_max_ulong(unsigned long x, unsigned long y)
{
return x > y ? x : y;
}
static inline long long z__fx_max_longlong(long long x, long long y)
{
return x > y ? x : y;
}
static inline unsigned long long z__fx_max_ulonglong(
unsigned long long x, unsigned long long y)
{
return x > y ? x : y;
}
static inline size_t z__fx_max_size_t(size_t x, size_t y)
{
return x > y ? x : y;
}
FX_API size_t fx_int_length(intptr_t v);
FX_API size_t fx_uint_length(uintptr_t v);
#endif // FX_CORE_MISC_H_
+39
View File
@@ -0,0 +1,39 @@
#ifndef FX_CORE_OBJECT_H_
#define FX_CORE_OBJECT_H_
#include <fx/core/misc.h>
#include <fx/core/type.h>
#define FX_OBJECT_MAGIC 0xDECAFC0C0ABEEF13ULL
#define FX_OBJECT(p) ((fx_object *)(p))
#define FX_TYPE_OBJECT (fx_object_get_type())
#define FX_TYPE_FWDREF(name) struct _fx_object
#define FX_RV(p) (fx_object_make_rvalue(p))
typedef FX_TYPE_FWDREF(fx_object) fx_object;
typedef struct _fx_object_class {
void (*to_string)(const fx_object *, FX_TYPE_FWDREF(fx_stream) *);
} fx_object_class;
FX_API fx_type fx_object_get_type(void);
FX_API void *fx_object_get_private(const fx_object *object, fx_type type);
FX_API void *fx_object_get_protected(const fx_object *object, fx_type type);
FX_API void *fx_object_get_interface(const fx_object *object, fx_type type);
FX_API fx_status fx_object_get_data(
const fx_object *object, fx_type type, void **priv, void **prot,
void **iface);
FX_API fx_object *fx_object_ref(fx_object *p);
FX_API void fx_object_unref(fx_object *p);
FX_API fx_object *fx_object_make_rvalue(fx_object *p);
FX_API fx_object *fx_object_create(fx_type type);
FX_API void fx_object_to_string(const fx_object *p, FX_TYPE_FWDREF(fx_stream) * out);
FX_API bool fx_object_is_type(const fx_object *p, fx_type type);
#endif
+82
View File
@@ -0,0 +1,82 @@
#ifndef FX_CORE_QUEUE_H_
#define FX_CORE_QUEUE_H_
#include <fx/core/iterator.h>
#include <fx/core/macros.h>
#include <fx/core/status.h>
#include <stdbool.h>
#include <string.h>
FX_DECLS_BEGIN;
#define FX_TYPE_QUEUE_ITERATOR (fx_queue_iterator_get_type())
FX_DECLARE_TYPE(fx_queue_iterator);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_queue_iterator)
FX_TYPE_CLASS_DECLARATION_END(fx_queue_iterator)
#define FX_QUEUE_INIT ((fx_queue) {.q_first = NULL, .q_last = NULL})
#define FX_QUEUE_ENTRY_INIT ((fx_queue_entry) {.qe_next = NULL, .qe_prev = NULL})
typedef struct fx_queue_entry {
struct fx_queue_entry *qe_next;
struct fx_queue_entry *qe_prev;
} fx_queue_entry;
typedef struct fx_queue {
fx_queue_entry *q_first;
fx_queue_entry *q_last;
} fx_queue;
static inline void fx_queue_init(fx_queue *q)
{
memset(q, 0x00, sizeof *q);
}
static inline bool fx_queue_empty(const fx_queue *q)
{
return q ? (q->q_first == NULL) : true;
}
static inline fx_queue_entry *fx_queue_first(const fx_queue *q)
{
return q ? q->q_first : NULL;
}
static inline fx_queue_entry *fx_queue_last(const fx_queue *q)
{
return q ? q->q_last : NULL;
}
static inline fx_queue_entry *fx_queue_next(const fx_queue_entry *entry)
{
return entry ? entry->qe_next : NULL;
}
static inline fx_queue_entry *fx_queue_prev(const fx_queue_entry *entry)
{
return entry ? entry->qe_prev : NULL;
}
FX_API fx_type fx_queue_iterator_get_type(void);
FX_API size_t fx_queue_length(const fx_queue *q);
FX_API void fx_queue_insert_before(
fx_queue *q, fx_queue_entry *entry, fx_queue_entry *before);
FX_API void fx_queue_insert_after(
fx_queue *q, fx_queue_entry *entry, fx_queue_entry *after);
FX_API void fx_queue_push_front(fx_queue *q, fx_queue_entry *entry);
FX_API void fx_queue_push_back(fx_queue *q, fx_queue_entry *entry);
FX_API fx_queue_entry *fx_queue_pop_front(fx_queue *q);
FX_API fx_queue_entry *fx_queue_pop_back(fx_queue *q);
FX_API void fx_queue_move(fx_queue *q, fx_queue_entry *dest, fx_queue_entry *src);
FX_API void fx_queue_delete(fx_queue *q, fx_queue_entry *entry);
FX_API void fx_queue_delete_all(fx_queue *q);
FX_API fx_iterator *fx_queue_begin(fx_queue *q);
FX_API fx_iterator *fx_queue_cbegin(const fx_queue *q);
FX_DECLS_END;
#endif
+37
View File
@@ -0,0 +1,37 @@
#ifndef FX_RANDOM_H_
#define FX_RANDOM_H_
#include <fx/core/status.h>
#include <stddef.h>
struct fx_random_algorithm;
typedef enum fx_random_flags {
/* algorithm selection */
FX_RANDOM_MT19937 = 0x01u,
/* generation flags */
FX_RANDOM_SECURE = 0x100u,
} fx_random_flags;
typedef struct fx_random_ctx {
fx_random_flags __f;
struct fx_random_algorithm *__a;
union {
struct {
unsigned long long mt[312];
size_t mti;
} __mt19937;
};
} fx_random_ctx;
FX_API fx_random_ctx *fx_random_global_ctx(void);
FX_API fx_status fx_random_init(fx_random_ctx *ctx, fx_random_flags flags);
FX_API unsigned long long fx_random_next_int64(fx_random_ctx *ctx);
FX_API double fx_random_next_double(fx_random_ctx *ctx);
FX_API void fx_random_next_bytes(
fx_random_ctx *ctx, unsigned char *out, size_t nbytes);
#endif
+47
View File
@@ -0,0 +1,47 @@
#ifndef FX_CORE_RINGBUFFER_H_
#define FX_CORE_RINGBUFFER_H_
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <fx/core/status.h>
FX_DECLS_BEGIN;
#define FX_TYPE_RINGBUFFER (fx_ringbuffer_get_type())
FX_DECLARE_TYPE(fx_ringbuffer);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_ringbuffer)
FX_TYPE_CLASS_DECLARATION_END(fx_ringbuffer)
FX_API fx_type fx_ringbuffer_get_type(void);
FX_API fx_ringbuffer *fx_ringbuffer_create(size_t capacity);
FX_API fx_ringbuffer *fx_ringbuffer_create_with_buffer(void *ptr, size_t capacity);
FX_API fx_status fx_ringbuffer_clear(fx_ringbuffer *buf);
FX_API fx_status fx_ringbuffer_read(
fx_ringbuffer *buf, void *p, size_t count, size_t *nr_read);
FX_API fx_status fx_ringbuffer_write(
fx_ringbuffer *buf, const void *p, size_t count, size_t *nr_written);
FX_API int fx_ringbuffer_getc(fx_ringbuffer *buf);
FX_API fx_status fx_ringbuffer_putc(fx_ringbuffer *buf, int c);
FX_API size_t fx_ringbuffer_write_capacity_remaining(const fx_ringbuffer *buf);
FX_API size_t fx_ringbuffer_available_data_remaining(const fx_ringbuffer *buf);
FX_API fx_status fx_ringbuffer_open_read_buffer(
fx_ringbuffer *buf, const void **ptr, size_t *length);
FX_API fx_status fx_ringbuffer_close_read_buffer(
fx_ringbuffer *buf, const void **ptr, size_t nr_read);
FX_API fx_status fx_ringbuffer_open_write_buffer(
fx_ringbuffer *buf, void **ptr, size_t *capacity);
FX_API fx_status fx_ringbuffer_close_write_buffer(
fx_ringbuffer *buf, void **ptr, size_t nr_written);
FX_DECLS_END;
#endif
+109
View File
@@ -0,0 +1,109 @@
#ifndef FX_CORE_ROPE_H_
#define FX_CORE_ROPE_H_
#include <fx/core/hash.h>
#include <fx/core/misc.h>
#include <fx/core/stream.h>
#include <stdint.h>
#include <string.h>
struct fx_string;
struct fx_bstr;
#define FX_ROPE_TYPE(f) ((f) & 0xFF)
#define FX_ROPE_CHAR(c) \
\
{ \
.r_flags = FX_ROPE_F_CHAR, .r_len_total = 1, \
.r_v = {.v_char = (c) } \
}
#define FX_ROPE_CSTR(str) \
{ \
.r_flags = FX_ROPE_F_CSTR_BORROWED, \
.r_len_total = strlen(str), \
.r_v = { \
.v_cstr = { \
.s = (str), \
.hash = fx_hash_cstr(str), \
}, \
}, \
}
#define FX_ROPE_CSTR_STATIC(str) \
{ \
.r_flags = FX_ROPE_F_CSTR_STATIC, \
.r_len_total = strlen(str), \
.r_v = { \
.v_cstr = { \
.s = (str), \
.hash = fx_hash_cstr(str), \
}, \
}, \
}
#define FX_ROPE_INT(v) \
\
{ \
.r_flags = FX_ROPE_F_INT, .r_len_total = fx_int_length(v), \
.r_v = {.v_int = (v) } \
}
#define FX_ROPE_UINT(v) \
\
{ \
.r_flags = FX_ROPE_F_UINT, .r_len_total = fx_uint_length(v), \
.r_v = {.v_uint = (v) } \
}
typedef enum fx_rope_flags {
FX_ROPE_F_NONE = 0x0000u,
FX_ROPE_F_CHAR = 0x0001u,
FX_ROPE_F_CSTR = 0x0002u,
FX_ROPE_F_CSTR_BORROWED = 0x0003u,
FX_ROPE_F_CSTR_STATIC = 0x0004u,
FX_ROPE_F_INT = 0x0005u,
FX_ROPE_F_UINT = 0x0006u,
FX_ROPE_F_COMPOSITE = 0x0007u,
FX_ROPE_F_MALLOC = 0x0100u,
} fx_rope_flags;
typedef struct fx_rope {
fx_rope_flags r_flags;
unsigned long r_len_left, r_len_total;
union {
char v_char;
intptr_t v_int;
uintptr_t v_uint;
struct {
const char *s;
uint64_t hash;
} v_cstr;
struct {
const struct fx_rope *r_left, *r_right;
} v_composite;
} r_v;
} fx_rope;
FX_API void fx_rope_init_char(fx_rope *rope, char c);
FX_API void fx_rope_init_cstr(fx_rope *rope, const char *s);
FX_API void fx_rope_init_cstr_borrowed(fx_rope *rope, const char *s);
FX_API void fx_rope_init_cstr_static(fx_rope *rope, const char *s);
FX_API void fx_rope_init_int(fx_rope *rope, intptr_t v);
FX_API void fx_rope_init_uint(fx_rope *rope, uintptr_t v);
FX_API void fx_rope_destroy(fx_rope *rope);
FX_API void fx_rope_iterate(
const fx_rope *rope, void (*func)(const fx_rope *, void *), void *arg);
FX_API size_t fx_rope_get_size(const fx_rope *rope);
FX_API void fx_rope_concat(fx_rope *result, const fx_rope *left, const fx_rope *right);
FX_API void fx_rope_join(fx_rope *result, const fx_rope **ropes, size_t nr_ropes);
FX_API fx_status fx_rope_to_cstr(const fx_rope *rope, char *out, size_t max);
FX_API fx_status fx_rope_to_bstr(const fx_rope *rope, struct fx_bstr *str);
FX_API fx_status fx_rope_to_string(const fx_rope *rope, fx_stream *out);
#endif
+48
View File
@@ -0,0 +1,48 @@
#ifndef FX_CORE_STATUS_H_
#define FX_CORE_STATUS_H_
#include <fx/core/misc.h>
#define FX_OK(status) ((enum fx_status)((uintptr_t)(status)) == FX_SUCCESS)
#define FX_ERR(status) ((status) != FX_SUCCESS)
typedef enum fx_status {
FX_SUCCESS = 0x00u,
FX_ERR_NO_MEMORY,
FX_ERR_OUT_OF_BOUNDS,
FX_ERR_INVALID_ARGUMENT,
FX_ERR_NAME_EXISTS,
FX_ERR_NOT_SUPPORTED,
FX_ERR_BAD_STATE,
FX_ERR_NO_ENTRY,
FX_ERR_NO_DATA,
FX_ERR_NO_SPACE,
FX_ERR_UNKNOWN_FUNCTION,
FX_ERR_BAD_FORMAT,
FX_ERR_IO_FAILURE,
FX_ERR_IS_DIRECTORY,
FX_ERR_NOT_DIRECTORY,
FX_ERR_PERMISSION_DENIED,
FX_ERR_BUSY,
/* fx-compress specific code */
FX_ERR_COMPRESSION_FAILURE,
/* fx-object specific code */
FX_ERR_TYPE_REGISTRATION_FAILURE,
FX_ERR_CLASS_INIT_FAILURE,
} fx_status;
typedef enum fx_status_msg {
FX_MSG_SUCCESS = 0,
/* fx-object specific messages */
FX_MSG_TYPE_REGISTRATION_FAILURE,
FX_MSG_CLASS_INIT_FAILURE,
FX_MSG_CLASS_SPECIFIES_UNKNOWN_INTERFACE,
} fx_status_msg;
FX_API const char *fx_status_to_string(fx_status status);
FX_API const char *fx_status_description(fx_status status);
#endif
+100
View File
@@ -0,0 +1,100 @@
#ifndef FX_CORE_STREAM_H_
#define FX_CORE_STREAM_H_
#include <fx/core/encoding.h>
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <fx/core/status.h>
#include <stdarg.h>
#include <stdio.h>
FX_DECLS_BEGIN;
#define fx_stdin (z__fx_stream_get_stdin())
#define fx_stdout (z__fx_stream_get_stdout())
#define fx_stderr (z__fx_stream_get_stderr())
#define FX_TYPE_STREAM (fx_stream_get_type())
#define FX_TYPE_STREAM_BUFFER (fx_stream_buffer_get_type())
FX_DECLARE_TYPE(fx_stream);
FX_DECLARE_TYPE(fx_stream_buffer);
typedef enum fx_stream_mode {
FX_STREAM_READ = 0x01u,
FX_STREAM_WRITE = 0x02u,
FX_STREAM_BINARY = 0x10u,
Z__FX_STREAM_STATIC = 0x80u,
} fx_stream_mode;
typedef enum fx_stream_seek_origin {
FX_STREAM_SEEK_START = 0x01u,
FX_STREAM_SEEK_CURRENT = 0x02u,
FX_STREAM_SEEK_END = 0x03u,
} fx_stream_seek_origin;
typedef struct fx_stream_cfg {
fx_stream_mode s_mode;
} fx_stream_cfg;
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_stream)
fx_status (*s_close)(fx_stream *);
fx_status (*s_seek)(fx_stream *, long long, fx_stream_seek_origin);
fx_status (*s_tell)(const fx_stream *, size_t *);
fx_status (*s_getc)(fx_stream *, fx_wchar *);
fx_status (*s_read)(fx_stream *, void *, size_t, size_t *);
fx_status (*s_write)(fx_stream *, const void *, size_t, size_t *);
fx_status (*s_reserve)(fx_stream *, size_t);
FX_TYPE_CLASS_DECLARATION_END(fx_stream)
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_stream_buffer)
FX_TYPE_CLASS_DECLARATION_END(fx_stream_buffer)
FX_API fx_type fx_stream_get_type();
FX_API fx_type fx_stream_buffer_get_type();
FX_API fx_stream *z__fx_stream_get_stdin(void);
FX_API fx_stream *z__fx_stream_get_stdout(void);
FX_API fx_stream *z__fx_stream_get_stderr(void);
FX_API fx_stream_buffer *fx_stream_buffer_create(void *p, size_t len);
FX_API fx_stream_buffer *fx_stream_buffer_create_dynamic(size_t buffer_size);
FX_API fx_stream *fx_stream_open_fp(FILE *fp);
FX_API fx_status fx_stream_reserve(fx_stream *stream, size_t len);
FX_API fx_status fx_stream_seek(
fx_stream *stream, long long offset, fx_stream_seek_origin origin);
FX_API size_t fx_stream_cursor(const fx_stream *stream);
FX_API fx_status fx_stream_push_indent(fx_stream *stream, int indent);
FX_API fx_status fx_stream_pop_indent(fx_stream *stream);
FX_API fx_status fx_stream_read_char(fx_stream *stream, fx_wchar *c);
FX_API fx_status fx_stream_read_bytes(
fx_stream *stream, void *buf, size_t count, size_t *nr_read);
FX_API fx_status fx_stream_read_line(fx_stream *stream, char *s, size_t max);
FX_API fx_status fx_stream_read_line_s(fx_stream *src, fx_stream *dest);
FX_API fx_status fx_stream_read_all_bytes(
fx_stream *stream, void *p, size_t max, size_t *nr_read);
FX_API fx_status fx_stream_read_all_bytes_s(
fx_stream *src, fx_stream *dest, fx_stream_buffer *buffer, size_t *nr_read);
FX_API fx_status fx_stream_write_char(fx_stream *stream, fx_wchar c);
FX_API fx_status fx_stream_write_cstr(
fx_stream *stream, const char *s, size_t *nr_written);
FX_API fx_status fx_stream_write_bytes(
fx_stream *stream, const void *buf, size_t count, size_t *nr_written);
FX_API fx_status fx_stream_write_fmt(
fx_stream *stream, size_t *nr_written, const char *format, ...);
FX_API fx_status fx_stream_write_vfmt(
fx_stream *stream, size_t *nr_written, const char *format, va_list arg);
FX_DECLS_END;
#endif
+35
View File
@@ -0,0 +1,35 @@
#ifndef FX_CORE_STRINGSTREAM_H_
#define FX_CORE_STRINGSTREAM_H_
#include <fx/core/macros.h>
#include <fx/core/misc.h>
#include <fx/core/status.h>
#include <fx/core/stream.h>
#include <stddef.h>
FX_DECLS_BEGIN;
#define FX_TYPE_STRINGSTREAM (fx_stringstream_get_type())
FX_DECLARE_TYPE(fx_stringstream);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_stringstream)
FX_TYPE_CLASS_DECLARATION_END(fx_stringstream)
FX_API fx_type fx_stringstream_get_type(void);
FX_API fx_stringstream *fx_stringstream_create(void);
FX_API fx_stringstream *fx_stringstream_create_with_buffer(char *buf, size_t max);
FX_API fx_status fx_stringstream_reset(fx_stringstream *strv);
FX_API fx_status fx_stringstream_reset_with_buffer(
fx_stringstream *strv, char *buf, size_t max);
FX_API const char *fx_stringstream_ptr(const fx_stringstream *strv);
FX_API char *fx_stringstream_steal(fx_stringstream *strv);
FX_API size_t fx_stringstream_get_length(const fx_stringstream *strv);
FX_DECLS_END;
#endif
+36
View File
@@ -0,0 +1,36 @@
#ifndef FX_CORE_THREAD_H_
#define FX_CORE_THREAD_H_
#include <fx/core/bitop.h>
#include <fx/core/misc.h>
#include <stdbool.h>
#if defined(__APPLE__) || defined(__linux__) || defined(__rosetta__)
#include <pthread.h>
#define FX_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
typedef pthread_mutex_t fx_mutex;
#else
#error Unsupported compiler/system
#endif
#define FX_ONCE_INIT ((fx_once)0)
typedef struct fx_thread fx_thread;
typedef int fx_once;
static inline bool fx_init_once(fx_once *once)
{
int x = 0;
return fx_cmpxchg(once, &x, 1);
}
FX_API fx_thread *fx_thread_self(void);
FX_API bool fx_mutex_lock(fx_mutex *mut);
FX_API bool fx_mutex_trylock(fx_mutex *mut);
FX_API bool fx_mutex_unlock(fx_mutex *mut);
#endif
+66
View File
@@ -0,0 +1,66 @@
#ifndef FX_CORE_TYPE_H_
#define FX_CORE_TYPE_H_
#include <fx/core/error.h>
#include <fx/core/misc.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define FX_TYPE_MAX_INTERFACES 64
struct _fx_class;
struct _fx_object;
typedef void (*fx_class_init_function)(struct _fx_class *, void *);
typedef void (*fx_instance_init_function)(struct _fx_object *, void *);
typedef void (*fx_instance_fini_function)(struct _fx_object *, void *);
typedef const union fx_type {
struct {
uint64_t p00, p01;
} a;
unsigned char b[16];
} *fx_type;
typedef enum fx_type_flags {
FX_TYPE_F_ABSTRACT = 0x01u,
} fx_type_flags;
typedef struct fx_type_info {
union fx_type t_id;
union fx_type t_parent_id;
const char *t_name;
fx_type_flags t_flags;
union fx_type t_interfaces[FX_TYPE_MAX_INTERFACES];
size_t t_nr_interfaces;
size_t t_class_size;
fx_class_init_function t_class_init;
size_t t_instance_private_size;
size_t t_instance_protected_size;
fx_instance_init_function t_instance_init;
fx_instance_fini_function t_instance_fini;
} fx_type_info;
FX_API void fx_type_id_init(
union fx_type *out, uint32_t a, uint16_t b, uint16_t c, uint16_t d,
uint64_t e);
static inline void fx_type_id_copy(fx_type src, union fx_type *dest)
{
dest->a.p00 = src->a.p00;
dest->a.p01 = src->a.p01;
}
static inline int fx_type_id_compare(fx_type a, fx_type b)
{
if (a == b) {
return 0;
}
return memcmp(a, b, sizeof(union fx_type));
}
FX_API fx_result fx_type_register(fx_type_info *info);
#endif
+115
View File
@@ -0,0 +1,115 @@
#include <fx/core/iterator.h>
/*** PRIVATE DATA *************************************************************/
struct fx_iterator_p {
enum fx_status it_status;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static enum fx_status iterator_get_status(const struct fx_iterator_p *it)
{
return it->it_status;
}
static enum fx_status iterator_set_status(struct fx_iterator_p *it, fx_status status)
{
it->it_status = status;
return FX_SUCCESS;
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_iterator *fx_iterator_begin(fx_iterable *it)
{
FX_CLASS_DISPATCH_VIRTUAL_0(fx_iterable, FX_TYPE_ITERABLE, NULL, it_begin, it);
}
const fx_iterator *fx_iterator_cbegin(const fx_iterable *it)
{
FX_CLASS_DISPATCH_VIRTUAL_0(fx_iterable, FX_TYPE_ITERABLE, NULL, it_cbegin, it);
}
enum fx_status fx_iterator_get_status(const fx_iterator *it)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ITERATOR, iterator_get_status, it);
}
enum fx_status fx_iterator_set_status(const fx_iterator *it, fx_status status)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ITERATOR, iterator_set_status, it, status);
}
enum fx_status fx_iterator_move_next(const fx_iterator *it)
{
enum fx_status status = FX_ERR_NOT_SUPPORTED;
fx_iterator_class *iface = fx_object_get_interface(it, FX_TYPE_ITERATOR);
if (iface && iface->it_move_next) {
status = iface->it_move_next(it);
}
struct fx_iterator_p *p = fx_object_get_private(it, FX_TYPE_ITERATOR);
p->it_status = status;
return status;
}
fx_iterator_value fx_iterator_get_value(fx_iterator *it)
{
FX_CLASS_DISPATCH_VIRTUAL_0(
fx_iterator, FX_TYPE_ITERATOR, FX_ITERATOR_VALUE_NULL,
it_get_value, it);
}
const fx_iterator_value fx_iterator_get_cvalue(const fx_iterator *it)
{
FX_CLASS_DISPATCH_VIRTUAL_0(
fx_iterator, FX_TYPE_ITERATOR, FX_ITERATOR_VALUE_NULL,
it_get_cvalue, it);
}
fx_status fx_iterator_erase(fx_iterator *it)
{
enum fx_status status = FX_ERR_NOT_SUPPORTED;
fx_iterator_class *iface = fx_object_get_interface(it, FX_TYPE_ITERATOR);
if (iface && iface->it_erase) {
status = iface->it_erase(it);
}
struct fx_iterator_p *p = fx_object_get_private(it, FX_TYPE_ITERATOR);
p->it_status = status;
return status;
}
/*** CLASS DEFINITION *********************************************************/
// ---- fx_iterator DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_iterator)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_iterator)
FX_TYPE_DEFINITION_BEGIN(fx_iterator)
FX_TYPE_FLAGS(FX_TYPE_F_ABSTRACT);
FX_TYPE_ID(0xfd40b67f, 0x7087, 0x40a9, 0x8fd8, 0x8ae27bd58c9e);
FX_TYPE_CLASS(fx_iterator_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_iterator_p);
FX_TYPE_DEFINITION_END(fx_iterator)
// ---- fx_iterable DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_iterable)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_iterable)
FX_TYPE_DEFINITION_BEGIN(fx_iterable)
FX_TYPE_FLAGS(FX_TYPE_F_ABSTRACT);
FX_TYPE_ID(0x4bbabf2d, 0xfc5d, 0x40cc, 0x89fc, 0x164085e47f73);
FX_TYPE_CLASS(fx_iterable_class);
FX_TYPE_DEFINITION_END(fx_iterable)
+38
View File
@@ -0,0 +1,38 @@
#include <fx/core/misc.h>
#define LENGTH_RET(v, boundary, len) \
if ((v) < (boundary)) \
return (len);
size_t fx_int_length(intptr_t v)
{
size_t len = 0;
if (v < 0) {
v *= -1;
len++;
}
return len + fx_uint_length(v);
}
size_t fx_uint_length(uintptr_t v)
{
LENGTH_RET(v, 10, 1);
LENGTH_RET(v, 100, 2);
LENGTH_RET(v, 1000, 3);
LENGTH_RET(v, 10000, 4);
LENGTH_RET(v, 100000, 5);
LENGTH_RET(v, 1000000, 6);
LENGTH_RET(v, 10000000, 7);
LENGTH_RET(v, 100000000, 8);
LENGTH_RET(v, 1000000000, 9);
LENGTH_RET(v, 10000000000, 10);
size_t len = 0;
while (v > 0) {
v /= 10;
len++;
}
return len;
}
+245
View File
@@ -0,0 +1,245 @@
/*
A C-program for MT19937-64 (2004/9/29 version).
Coded by Takuji Nishimura and Makoto Matsumoto.
This is a 64-bit version of Mersenne Twister pseudorandom number
generator.
Before using, initialize the state by using init_genrand64(seed)
or init_by_array64(init_key, key_length).
Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
References:
T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
ACM Transactions on Modeling and
Computer Simulation 10. (2000) 348--357.
M. Matsumoto and T. Nishimura,
``Mersenne Twister: a 623-dimensionally equidistributed
uniform pseudorandom number generator''
ACM Transactions on Modeling and
Computer Simulation 8. (Jan. 1998) 3--30.
Any feedback is very welcome.
http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
*/
#include "random.h"
#include <fx/core/random.h>
#define NN 312
#define MM 156
#define MATRIX_A 0xB5026F5AA96619E9ULL
#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */
#define LM 0x7FFFFFFFULL /* Least significant 31 bits */
/* initializes mt[NN] with a seed */
static void init_genrand64(struct fx_random_ctx *context, unsigned long long seed)
{
context->__mt19937.mt[0] = seed;
for (context->__mt19937.mti = 1; context->__mt19937.mti < NN;
context->__mt19937.mti++)
context->__mt19937.mt[context->__mt19937.mti]
= (6364136223846793005ULL
* (context->__mt19937.mt[context->__mt19937.mti - 1]
^ (context->__mt19937
.mt[context->__mt19937.mti - 1]
>> 62))
+ context->__mt19937.mti);
}
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
static void init_by_array64(
struct fx_random_ctx *context, unsigned long long init_key[],
unsigned long long key_length)
{
unsigned long long i, j, k;
init_genrand64(context, 19650218ULL);
i = 1;
j = 0;
k = (NN > key_length ? NN : key_length);
for (; k; k--) {
context->__mt19937.mt[i]
= (context->__mt19937.mt[i]
^ ((context->__mt19937.mt[i - 1]
^ (context->__mt19937.mt[i - 1] >> 62))
* 3935559000370003845ULL))
+ init_key[j] + j; /* non linear */
i++;
j++;
if (i >= NN) {
context->__mt19937.mt[0] = context->__mt19937.mt[NN - 1];
i = 1;
}
if (j >= key_length)
j = 0;
}
for (k = NN - 1; k; k--) {
context->__mt19937.mt[i]
= (context->__mt19937.mt[i]
^ ((context->__mt19937.mt[i - 1]
^ (context->__mt19937.mt[i - 1] >> 62))
* 2862933555777941757ULL))
- i; /* non linear */
i++;
if (i >= NN) {
context->__mt19937.mt[0] = context->__mt19937.mt[NN - 1];
i = 1;
}
}
context->__mt19937.mt[0]
= 1ULL << 63; /* MSB is 1; assuring non-zero initial array */
}
/* generates a random number on [0, 2^64-1]-interval */
static uint64_t genrand64_int64(struct fx_random_ctx *context)
{
#if 0
/* This is the original implementation. It is replaced by the alternate implementation, below. */
int i;
unsigned long long x;
static unsigned long long mag01[2]={0ULL, MATRIX_A};
if (mti >= NN) { /* generate NN words at one time */
/* if init_genrand64() has not been called, */
/* a default initial seed is used */
if (mti == NN+1)
init_genrand64(5489ULL);
for (i=0;i<NN-MM;i++) {
x = (mt[i]&UM)|(mt[i+1]&LM);
mt[i] = mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
}
for (;i<NN-1;i++) {
x = (mt[i]&UM)|(mt[i+1]&LM);
mt[i] = mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
}
x = (mt[NN-1]&UM)|(mt[0]&LM);
mt[NN-1] = mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
mti = 0;
}
x = mt[mti++];
x ^= (x >> 29) & 0x5555555555555555ULL;
x ^= (x << 17) & 0x71D67FFFEDA60000ULL;
x ^= (x << 37) & 0xFFF7EEE000000000ULL;
x ^= (x >> 43);
return x;
#else
/* This is the altered Cocoa with Love implementation. */
size_t i;
size_t j;
unsigned long long result;
if (context->__mt19937.mti >= NN) { /* generate NN words at one time */
size_t mid = NN / 2;
unsigned long long stateMid = context->__mt19937.mt[mid];
unsigned long long x;
unsigned long long y;
/* NOTE: this "untwist" code is modified from the original to
* improve performance, as described here:
* http://www.cocoawithlove.com/blog/2016/05/19/random-numbers.html
* These modifications are offered for use under the original
* icense at the top of this file.
*/
for (i = 0, j = mid; i != mid - 1; i++, j++) {
x = (context->__mt19937.mt[i] & UM)
| (context->__mt19937.mt[i + 1] & LM);
context->__mt19937.mt[i]
= context->__mt19937.mt[i + mid] ^ (x >> 1)
^ ((context->__mt19937.mt[i + 1] & 1) * MATRIX_A);
y = (context->__mt19937.mt[j] & UM)
| (context->__mt19937.mt[j + 1] & LM);
context->__mt19937.mt[j]
= context->__mt19937.mt[j - mid] ^ (y >> 1)
^ ((context->__mt19937.mt[j + 1] & 1) * MATRIX_A);
}
x = (context->__mt19937.mt[mid - 1] & UM) | (stateMid & LM);
context->__mt19937.mt[mid - 1] = context->__mt19937.mt[NN - 1]
^ (x >> 1)
^ ((stateMid & 1) * MATRIX_A);
y = (context->__mt19937.mt[NN - 1] & UM)
| (context->__mt19937.mt[0] & LM);
context->__mt19937.mt[NN - 1]
= context->__mt19937.mt[mid - 1] ^ (y >> 1)
^ ((context->__mt19937.mt[0] & 1) * MATRIX_A);
context->__mt19937.mti = 0;
}
result = context->__mt19937.mt[context->__mt19937.mti];
context->__mt19937.mti = context->__mt19937.mti + 1;
result ^= (result >> 29) & 0x5555555555555555ULL;
result ^= (result << 17) & 0x71D67FFFEDA60000ULL;
result ^= (result << 37) & 0xFFF7EEE000000000ULL;
result ^= (result >> 43);
return result;
#endif
}
#if FX_ENABLE_FLOATING_POINT == 1
/* generates a random number on [0,1]-real-interval */
double genrand64_real1(struct fx_random_ctx *context)
{
return (genrand64_int64(context) >> 11) * (1.0 / 9007199254740991.0);
}
/* generates a random number on [0,1)-real-interval */
double genrand64_real2(struct fx_random_ctx *context)
{
return (genrand64_int64(context) >> 11) * (1.0 / 9007199254740992.0);
}
/* generates a random number on (0,1)-real-interval */
double genrand64_real3(struct fx_random_ctx *context)
{
return ((genrand64_int64(context) >> 12) + 0.5)
* (1.0 / 4503599627370496.0);
}
#endif
struct fx_random_algorithm z__fx_gen_mt19937 = {
.gen_name = "mt19937",
.gen_init = init_genrand64,
.gen_getrand = genrand64_int64,
};
+219
View File
@@ -0,0 +1,219 @@
#include "object.h"
#include "type.h"
#include <assert.h>
#include <fx/core/class.h>
#include <fx/core/macros.h>
#include <fx/core/object.h>
#include <fx/core/stream.h>
#include <fx/core/thread.h>
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_object)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_object)
FX_TYPE_DEFINITION_BEGIN(fx_object)
FX_TYPE_ID(0x45f15a2c, 0x6831, 0x4bef, 0xb350, 0x15c650679211);
FX_TYPE_CLASS(fx_object_class);
FX_TYPE_DEFINITION_END(fx_object)
fx_result fx_object_instantiate(
struct fx_type_registration *type, struct _fx_object **out_object)
{
struct _fx_object *out = malloc(type->r_instance_size);
if (!out) {
return FX_RESULT_ERR(NO_MEMORY);
}
memset(out, 0x0, type->r_instance_size);
out->obj_magic = FX_OBJECT_MAGIC;
out->obj_type = type;
out->obj_ref = 1;
struct fx_queue_entry *entry = fx_queue_first(&type->r_class_hierarchy);
while (entry) {
struct fx_type_component *comp
= fx_unbox(struct fx_type_component, entry, c_entry);
const struct fx_type_info *class_info = comp->c_type->r_info;
void *private_data
= (char *)out + comp->c_instance_private_data_offset;
if (class_info->t_instance_init) {
class_info->t_instance_init(out, private_data);
}
if (comp->c_type == type) {
out->obj_main_priv_offset
= comp->c_instance_private_data_offset;
}
entry = fx_queue_next(entry);
}
*out_object = out;
return FX_RESULT_SUCCESS;
}
struct _fx_object *fx_object_create(fx_type type)
{
struct fx_type_registration *type_reg = fx_type_get_registration(type);
if (!type_reg) {
return NULL;
}
struct _fx_object *out = NULL;
fx_result result = fx_object_instantiate(type_reg, &out);
if (fx_result_is_error(result)) {
fx_error_discard(result);
return NULL;
}
return out;
}
void fx_object_to_string(const struct _fx_object *p, fx_stream *out)
{
FX_CLASS_DISPATCH_VIRTUAL_V(fx_object, FX_TYPE_OBJECT, to_string, p, out);
fx_stream_write_fmt(out, NULL, "<%s@%p>", p->obj_type->r_info->t_name, p);
}
bool fx_object_is_type(const struct _fx_object *p, fx_type type)
{
if (fx_type_id_compare(&p->obj_type->r_info->t_id, type) == 0) {
return true;
}
struct fx_type_component *comp
= fx_type_get_component(&p->obj_type->r_components, type);
return comp != NULL;
}
void *fx_object_get_private(const struct _fx_object *object, fx_type type)
{
if (!object) {
return NULL;
}
assert(object->obj_magic == FX_OBJECT_MAGIC);
if (fx_type_id_compare(&object->obj_type->r_info->t_id, type) == 0) {
return (char *)object + object->obj_main_priv_offset;
}
struct fx_type_component *comp
= fx_type_get_component(&object->obj_type->r_components, type);
if (!comp) {
return NULL;
}
return (char *)object + comp->c_instance_private_data_offset;
}
void *fx_object_get_protected(const struct _fx_object *object, fx_type type)
{
if (!object) {
return NULL;
}
assert(object->obj_magic == FX_OBJECT_MAGIC);
struct fx_type_component *comp
= fx_type_get_component(&object->obj_type->r_components, type);
if (!comp) {
return NULL;
}
return (char *)object + comp->c_instance_protected_data_offset;
}
void *fx_object_get_interface(const struct _fx_object *object, fx_type type)
{
if (!object) {
return NULL;
}
assert(object->obj_magic == FX_OBJECT_MAGIC);
return fx_class_get_interface(object->obj_type->r_class, type);
}
enum fx_status fx_object_get_data(
const struct _fx_object *object, fx_type type, void **priv, void **prot,
void **iface)
{
if (!object) {
return FX_ERR_INVALID_ARGUMENT;
}
assert(object->obj_magic == FX_OBJECT_MAGIC);
struct fx_type_component *comp
= fx_type_get_component(&object->obj_type->r_components, type);
if (!comp) {
return FX_ERR_INVALID_ARGUMENT;
}
if (priv) {
*priv = (char *)object + comp->c_instance_private_data_offset;
}
if (prot) {
*prot = (char *)object + comp->c_instance_protected_data_offset;
}
if (iface) {
*iface = (char *)object->obj_type->r_class
+ comp->c_class_data_offset;
}
return FX_SUCCESS;
}
struct _fx_object *fx_object_ref(struct _fx_object *p)
{
p->obj_ref++;
return p;
}
void fx_object_unref(struct _fx_object *p)
{
if (p->obj_ref > 1) {
p->obj_ref--;
return;
}
p->obj_ref = 0;
const struct fx_type_registration *type = p->obj_type;
struct fx_queue_entry *cur = fx_queue_last(&type->r_class_hierarchy);
while (cur) {
struct fx_type_component *comp
= fx_unbox(struct fx_type_component, cur, c_entry);
const struct fx_type_info *class_info = comp->c_type->r_info;
void *private_data
= (char *)p + comp->c_instance_private_data_offset;
if (class_info->t_instance_fini) {
class_info->t_instance_fini(p, private_data);
}
cur = fx_queue_prev(cur);
}
p->obj_magic = 0;
p->obj_type = NULL;
free(p);
}
struct _fx_object *fx_object_make_rvalue(struct _fx_object *p)
{
p->obj_ref = 0;
return p;
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef _OBJECT_H_
#define _OBJECT_H_
#include <fx/core/error.h>
#include <fx/core/misc.h>
#include <stdint.h>
struct fx_type_registration;
struct _fx_object {
uint64_t obj_magic;
const struct fx_type_registration *obj_type;
unsigned int obj_ref, obj_main_priv_offset;
};
extern fx_result fx_object_instantiate(
struct fx_type_registration *type, struct _fx_object **out);
#endif
+1638
View File
File diff suppressed because it is too large Load Diff
+161
View File
@@ -0,0 +1,161 @@
/**
* @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
* 2021-2023, Haifa, Palestine/Israel
* @author (c) Marco Paland (info@paland.com)
* 2014-2019, PALANDesign Hannover, Germany
*
* @note Others have made smaller contributions to this file: see the
* contributors page at https://github.com/eyalroz/printf/graphs/contributors
* or ask one of the authors.
*
* @brief Small stand-alone implementation of the printf family of functions
* (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems
* with a very limited resources.
*
* @note the implementations are thread-safe; re-entrant; use no functions from
* the standard library; and do not dynamically allocate any memory.
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef PRINTF_H_
#define PRINTF_H_
#ifdef __cplusplus
#include <cstdarg>
#include <cstddef>
extern "C" {
#else
#include <stdarg.h>
#include <stddef.h>
#endif
#ifdef __GNUC__
#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4)
#define ATTR_PRINTF(one_based_format_index, first_arg) \
__attribute__((format(gnu_printf, (one_based_format_index), (first_arg))))
#else
#define ATTR_PRINTF(one_based_format_index, first_arg) \
__attribute__((format(printf, (one_based_format_index), (first_arg))))
#endif
#define ATTR_VPRINTF(one_based_format_index) \
ATTR_PRINTF((one_based_format_index), 0)
#else
#define ATTR_PRINTF(one_based_format_index, first_arg)
#define ATTR_VPRINTF(one_based_format_index)
#endif
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT 0
#endif
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD 0
#endif
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
#define printf_ printf
#define sprintf_ sprintf
#define vsprintf_ vsprintf
#define snprintf_ snprintf
#define vsnprintf_ vsnprintf
#define vprintf_ vprintf
#endif
// If you want to include this implementation file directly rather than
// link against it, this will let you control the functions' visibility,
// e.g. make them static so as not to clash with other objects also
// using them.
#ifndef PRINTF_VISIBILITY
#define PRINTF_VISIBILITY
#endif
/**
* Prints/send a single character to some opaque output entity
*
* @note This function is not implemented by the library, only declared; you
* must provide an implementation if you wish to use the @ref printf / @ref
* vprintf function (and possibly for linking against the library, if your
* toolchain does not support discarding unused functions)
*
* @note The output could be as simple as a wrapper for the `write()` system
* call on a Unix-like * system, or even libc's @ref putchar , for replicating
* actual functionality of libc's @ref printf * function; but on an embedded
* system it may involve interaction with a special output device, like a UART,
* etc.
*
* @note in libc's @ref putchar, the parameter type is an int; this was intended
* to support the representation of either a proper character or EOF in a
* variable - but this is really not meaningful to pass into @ref putchar and is
* discouraged today. See further discussion in:
* @link https://stackoverflow.com/q/17452847/1593077
*
* @param c the single character to print
*/
PRINTF_VISIBILITY
void putchar_(char c);
/**
* printf/vprintf with user-specified output function
*
* An alternative to @ref printf_, in which the output function is specified
* dynamically (rather than @ref putchar_ being used)
*
* @param out An output function which takes one character and a type-erased
* additional parameters
* @param extra_arg The type-erased argument to pass to the output function @p
* out with each call
* @param format A string specifying the format of the output, with %-marked
* specifiers of how to interpret additional arguments.
* @param arg Additional arguments to the function, one for each specifier in
* @p format
* @return The number of characters for which the output f unction was invoked,
* not counting the terminating null character
*
*/
PRINTF_VISIBILITY
int z__fx_fctprintf(
void (*out)(char c, void *extra_arg), void *extra_arg,
const char *format, va_list arg) ATTR_VPRINTF(3);
#ifdef __cplusplus
} // extern "C"
#endif
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD
#undef printf_
#undef sprintf_
#undef vsprintf_
#undef snprintf_
#undef vsnprintf_
#undef vprintf_
#else
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT
#define printf printf_
#define sprintf sprintf_
#define vsprintf vsprintf_
#define snprintf snprintf_
#define vsnprintf vsnprintf_
#define vprintf vprintf_
#endif
#endif
#endif // PRINTF_H_
+245
View File
@@ -0,0 +1,245 @@
#include <fx/core/queue.h>
struct fx_queue_iterator_p {
size_t i;
fx_queue_entry *entry;
fx_queue *_q;
};
size_t fx_queue_length(const struct fx_queue *q)
{
size_t i = 0;
struct fx_queue_entry *x = q->q_first;
while (x) {
i++;
x = x->qe_next;
}
return i;
}
void fx_queue_insert_before(
struct fx_queue *q, struct fx_queue_entry *entry, struct fx_queue_entry *before)
{
struct fx_queue_entry *x = before->qe_prev;
if (x) {
x->qe_next = entry;
} else {
q->q_first = entry;
}
entry->qe_prev = x;
before->qe_prev = entry;
entry->qe_next = before;
}
void fx_queue_insert_after(
struct fx_queue *q, struct fx_queue_entry *entry, struct fx_queue_entry *after)
{
struct fx_queue_entry *x = after->qe_next;
if (x) {
x->qe_prev = entry;
} else {
q->q_last = entry;
}
entry->qe_next = x;
after->qe_next = entry;
entry->qe_prev = after;
}
void fx_queue_push_front(struct fx_queue *q, struct fx_queue_entry *entry)
{
if (q->q_first) {
q->q_first->qe_prev = entry;
}
entry->qe_next = q->q_first;
entry->qe_prev = NULL;
q->q_first = entry;
if (!q->q_last) {
q->q_last = entry;
}
}
void fx_queue_push_back(struct fx_queue *q, struct fx_queue_entry *entry)
{
if (q->q_last) {
q->q_last->qe_next = entry;
}
entry->qe_prev = q->q_last;
entry->qe_next = NULL;
q->q_last = entry;
if (!q->q_first) {
q->q_first = entry;
}
}
struct fx_queue_entry *fx_queue_pop_front(struct fx_queue *q)
{
struct fx_queue_entry *x = q->q_first;
if (x) {
fx_queue_delete(q, x);
}
return x;
}
struct fx_queue_entry *fx_queue_pop_back(struct fx_queue *q)
{
struct fx_queue_entry *x = q->q_last;
if (x) {
fx_queue_delete(q, x);
}
return x;
}
void fx_queue_move(fx_queue *q, fx_queue_entry *dest, fx_queue_entry *src)
{
if (src->qe_next) {
src->qe_next->qe_prev = dest;
}
if (src->qe_prev) {
src->qe_prev->qe_next = dest;
}
if (q->q_first == src) {
q->q_first = dest;
}
if (q->q_last == src) {
q->q_last = dest;
}
memmove(dest, src, sizeof *src);
}
void fx_queue_delete(struct fx_queue *q, struct fx_queue_entry *entry)
{
if (!entry) {
return;
}
if (entry == q->q_first) {
q->q_first = q->q_first->qe_next;
}
if (entry == q->q_last) {
q->q_last = q->q_last->qe_prev;
}
if (entry->qe_next) {
entry->qe_next->qe_prev = entry->qe_prev;
}
if (entry->qe_prev) {
entry->qe_prev->qe_next = entry->qe_next;
}
entry->qe_next = entry->qe_prev = NULL;
}
void fx_queue_delete_all(struct fx_queue *q)
{
struct fx_queue_entry *x = q->q_first;
while (x) {
struct fx_queue_entry *next = x->qe_next;
x->qe_next = x->qe_prev = NULL;
x = next;
}
q->q_first = q->q_last = NULL;
}
fx_iterator *fx_queue_begin(struct fx_queue *q)
{
fx_queue_iterator *it_obj = fx_object_create(FX_TYPE_QUEUE_ITERATOR);
struct fx_queue_iterator_p *it
= fx_object_get_private(it_obj, FX_TYPE_QUEUE_ITERATOR);
it->_q = (struct fx_queue *)q;
it->entry = q->q_first;
it->i = 0;
if (!it->entry) {
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
}
return it_obj;
}
static enum fx_status iterator_move_next(const fx_iterator *obj)
{
struct fx_queue_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_QUEUE_ITERATOR);
if (!it->entry) {
return FX_ERR_NO_DATA;
}
it->entry = it->entry->qe_next;
it->i++;
return (it->entry != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA;
}
static enum fx_status iterator_erase(fx_iterator *obj)
{
struct fx_queue_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_QUEUE_ITERATOR);
if (!it->entry) {
return FX_ERR_OUT_OF_BOUNDS;
}
struct fx_queue_entry *next = it->entry->qe_next;
fx_queue_delete(it->_q, it->entry);
it->entry = next;
return FX_SUCCESS;
}
static fx_iterator_value iterator_get_value(fx_iterator *obj)
{
struct fx_queue_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_QUEUE_ITERATOR);
return FX_ITERATOR_VALUE_PTR(it->entry);
}
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
{
struct fx_queue_iterator_p *it
= fx_object_get_private(obj, FX_TYPE_QUEUE_ITERATOR);
return FX_ITERATOR_VALUE_CPTR(it->entry);
}
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_queue_iterator)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
FX_TYPE_CLASS_DEFINITION_END(fx_queue_iterator)
FX_TYPE_DEFINITION_BEGIN(fx_queue_iterator)
FX_TYPE_ID(0x560dc263, 0xff98, 0x4812, 0x9b29, 0xa1218bd70881);
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
FX_TYPE_CLASS(fx_queue_iterator_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_queue_iterator_p);
FX_TYPE_DEFINITION_END(fx_queue_iterator)
+106
View File
@@ -0,0 +1,106 @@
#include "random.h"
#include <fx/core/random.h>
#define GET_ALGORITHM_ID(flags) ((flags) & 0xFF)
FX_API struct fx_random_algorithm z__fx_gen_mt19937;
static struct fx_random_algorithm *generators[] = {
[FX_RANDOM_MT19937] = &z__fx_gen_mt19937,
};
static size_t nr_generators = sizeof generators / sizeof generators[0];
static struct fx_random_ctx g_global_ctx = {0};
static void init_global_ctx(void)
{
fx_random_init(&g_global_ctx, FX_RANDOM_MT19937);
}
struct fx_random_ctx *fx_random_global_ctx(void)
{
if (!g_global_ctx.__f) {
init_global_ctx();
}
return &g_global_ctx;
}
fx_status fx_random_init(struct fx_random_ctx *ctx, fx_random_flags flags)
{
unsigned int algorithm_id = GET_ALGORITHM_ID(flags);
if (algorithm_id >= nr_generators || !generators[algorithm_id]) {
return FX_ERR_INVALID_ARGUMENT;
}
struct fx_random_algorithm *algorithm = generators[algorithm_id];
ctx->__f = flags;
ctx->__a = algorithm;
unsigned long long seed;
if (flags & FX_RANDOM_SECURE) {
seed = z__fx_platform_random_seed_secure();
} else {
seed = z__fx_platform_random_seed();
}
algorithm->gen_init(ctx, seed);
return FX_SUCCESS;
}
unsigned long long fx_random_next_int64(struct fx_random_ctx *ctx)
{
if (!ctx->__a || !ctx->__a->gen_getrand) {
return 0;
}
return ctx->__a->gen_getrand(ctx);
}
#if FX_ENABLE_FLOATING_POINT
double fx_random_next_double(struct fx_random_ctx *ctx)
{
unsigned long long v = fx_random_next_int64(ctx);
if (!v) {
return 0.0;
}
return (double)(v >> 11) * (1.0 / 9007199254740991.0);
}
#endif
void fx_random_next_bytes(
struct fx_random_ctx *ctx, unsigned char *out, size_t nbytes)
{
size_t n_qwords = 0;
n_qwords = nbytes >> 3;
if ((n_qwords << 3) < nbytes) {
n_qwords++;
}
size_t bytes_written = 0;
for (size_t i = 0; i < n_qwords; i++) {
uint64_t *dest = (uint64_t *)&out[bytes_written];
*dest = fx_random_next_int64(ctx);
bytes_written += 8;
}
if (bytes_written == nbytes) {
return;
}
uint64_t padding = fx_random_next_int64(ctx);
unsigned char *padding_bytes = (unsigned char *)&padding;
for (size_t i = 0; i < 8; i++) {
out[bytes_written++] = padding_bytes[i];
if (bytes_written == nbytes) {
break;
}
}
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef _FX_RANDOM_H_
#define _FX_RANDOM_H_
#include <stdint.h>
#include <fx/core/misc.h>
struct fx_random_ctx;
struct fx_random_algorithm {
const char *gen_name;
void(*gen_init)(struct fx_random_ctx *, unsigned long long seed);
uint64_t(*gen_getrand)(struct fx_random_ctx *);
};
FX_API uint64_t z__fx_platform_random_seed(void);
FX_API uint64_t z__fx_platform_random_seed_secure(void);
#endif
+442
View File
@@ -0,0 +1,442 @@
#include <fx/core/ringbuffer.h>
#include <stdlib.h>
#include <string.h>
#define BUF_LOCKED(buf) \
(((buf)->r_flags & (RINGBUFFER_READ_LOCKED | RINGBUFFER_WRITE_LOCKED)) \
!= 0)
/*** PRIVATE DATA *************************************************************/
enum ringbuffer_flags {
RINGBUFFER_BUFFER_MALLOC = 0x02u,
RINGBUFFER_READ_LOCKED = 0x04u,
RINGBUFFER_WRITE_LOCKED = 0x08u,
};
struct fx_ringbuffer_p {
enum ringbuffer_flags r_flags;
void *r_buf, *r_opened_buf;
unsigned long r_capacity, r_opened_capacity;
unsigned long r_write_ptr, r_read_ptr;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static enum fx_status ringbuffer_clear(struct fx_ringbuffer_p *buf)
{
if (BUF_LOCKED(buf)) {
return FX_ERR_BUSY;
}
buf->r_read_ptr = buf->r_write_ptr = 0;
return FX_SUCCESS;
}
static size_t ringbuffer_write_capacity_remaining(const struct fx_ringbuffer_p *buf)
{
if (buf->r_read_ptr > buf->r_write_ptr) {
return buf->r_read_ptr - buf->r_write_ptr - 1;
} else {
return buf->r_capacity - buf->r_write_ptr + buf->r_read_ptr - 1;
}
}
static size_t ringbuffer_available_data_remaining(const struct fx_ringbuffer_p *buf)
{
if (buf->r_read_ptr < buf->r_write_ptr) {
return buf->r_write_ptr - buf->r_read_ptr;
} else if (buf->r_read_ptr > buf->r_write_ptr) {
return buf->r_capacity - buf->r_read_ptr + buf->r_write_ptr;
} else {
return 0;
}
}
static enum fx_status ringbuffer_open_read_buffer(
struct fx_ringbuffer_p *buf, const void **ptr, size_t *length)
{
if (BUF_LOCKED(buf)) {
return FX_ERR_BUSY;
}
size_t contiguous_capacity = 0;
if (buf->r_read_ptr > buf->r_write_ptr) {
contiguous_capacity = buf->r_capacity - buf->r_read_ptr;
} else {
contiguous_capacity = buf->r_write_ptr - buf->r_read_ptr;
}
if (contiguous_capacity == 0) {
return FX_ERR_NO_DATA;
}
buf->r_opened_buf = (char *)buf->r_buf + buf->r_read_ptr;
buf->r_opened_capacity = contiguous_capacity;
buf->r_flags |= RINGBUFFER_READ_LOCKED;
*ptr = buf->r_opened_buf;
*length = contiguous_capacity;
return FX_SUCCESS;
}
static enum fx_status ringbuffer_close_read_buffer(
struct fx_ringbuffer_p *buf, const void **ptr, size_t nr_read)
{
if (!(buf->r_flags & RINGBUFFER_READ_LOCKED)) {
return FX_ERR_BAD_STATE;
}
if (*ptr != buf->r_opened_buf) {
return FX_ERR_INVALID_ARGUMENT;
}
if (nr_read > buf->r_opened_capacity) {
return FX_ERR_INVALID_ARGUMENT;
}
buf->r_read_ptr += nr_read;
if (buf->r_read_ptr >= buf->r_capacity) {
buf->r_read_ptr = 0;
}
if (buf->r_read_ptr == buf->r_write_ptr) {
/* the ringbuffer is now empty. set both pointers to 0.
* this ensures that the whole buffer will be available
* contiguously to the next call to open_write_buffer */
buf->r_read_ptr = 0;
buf->r_write_ptr = 0;
}
buf->r_opened_buf = NULL;
buf->r_opened_capacity = 0;
buf->r_flags &= ~RINGBUFFER_READ_LOCKED;
return FX_SUCCESS;
}
static enum fx_status ringbuffer_open_write_buffer(
struct fx_ringbuffer_p *buf, void **ptr, size_t *capacity)
{
if (BUF_LOCKED(buf)) {
return FX_ERR_BUSY;
}
size_t contiguous_capacity = 0;
if (buf->r_write_ptr >= buf->r_read_ptr) {
contiguous_capacity = buf->r_capacity - buf->r_write_ptr - 1;
if (buf->r_read_ptr > 0) {
contiguous_capacity++;
}
} else {
contiguous_capacity = buf->r_read_ptr - buf->r_write_ptr - 1;
}
if (contiguous_capacity == 0) {
return FX_ERR_NO_SPACE;
}
buf->r_opened_buf = (char *)buf->r_buf + buf->r_write_ptr;
buf->r_opened_capacity = contiguous_capacity;
buf->r_flags |= RINGBUFFER_WRITE_LOCKED;
*ptr = buf->r_opened_buf;
*capacity = contiguous_capacity;
return FX_SUCCESS;
}
static enum fx_status ringbuffer_close_write_buffer(
struct fx_ringbuffer_p *buf, void **ptr, size_t nr_written)
{
if (!(buf->r_flags & RINGBUFFER_WRITE_LOCKED)) {
return FX_ERR_BAD_STATE;
}
if (*ptr != buf->r_opened_buf) {
return FX_ERR_INVALID_ARGUMENT;
}
if (nr_written > buf->r_opened_capacity) {
return FX_ERR_INVALID_ARGUMENT;
}
buf->r_write_ptr += nr_written;
if (buf->r_write_ptr >= buf->r_capacity) {
buf->r_write_ptr = 0;
}
buf->r_opened_buf = NULL;
buf->r_opened_capacity = 0;
buf->r_flags &= ~RINGBUFFER_WRITE_LOCKED;
return FX_SUCCESS;
}
static enum fx_status ringbuffer_read(
struct fx_ringbuffer_p *buf, void *p, size_t count, size_t *nr_read)
{
if (BUF_LOCKED(buf)) {
return FX_ERR_BUSY;
}
size_t r = 0;
unsigned char *dest = p;
size_t remaining = count;
while (remaining > 0) {
const void *src;
size_t available;
enum fx_status status
= ringbuffer_open_read_buffer(buf, &src, &available);
if (status == FX_ERR_NO_DATA) {
break;
}
if (!FX_OK(status)) {
return status;
}
size_t to_copy = remaining;
if (to_copy > available) {
to_copy = available;
}
memcpy(dest, src, to_copy);
remaining -= to_copy;
dest += to_copy;
r += to_copy;
ringbuffer_close_read_buffer(buf, &src, to_copy);
}
*nr_read = r;
return FX_SUCCESS;
}
static enum fx_status ringbuffer_write(
struct fx_ringbuffer_p *buf, const void *p, size_t count, size_t *nr_written)
{
if (BUF_LOCKED(buf)) {
return FX_ERR_BUSY;
}
size_t w = 0;
const unsigned char *src = p;
size_t remaining = count;
while (remaining > 0) {
void *dest;
size_t available;
enum fx_status status
= ringbuffer_open_write_buffer(buf, &dest, &available);
if (status == FX_ERR_NO_SPACE) {
break;
}
if (!FX_OK(status)) {
return status;
}
size_t to_copy = remaining;
if (to_copy > available) {
to_copy = available;
}
memcpy(dest, src, to_copy);
remaining -= to_copy;
src += to_copy;
w += to_copy;
ringbuffer_close_write_buffer(buf, &dest, to_copy);
}
*nr_written = w;
return FX_SUCCESS;
}
static int ringbuffer_getc(struct fx_ringbuffer_p *buf)
{
size_t available = ringbuffer_available_data_remaining(buf);
if (available == 0) {
return -1;
}
char *p = buf->r_buf;
char c = p[buf->r_read_ptr++];
if (buf->r_read_ptr >= buf->r_capacity) {
buf->r_read_ptr = 0;
}
return c;
}
static enum fx_status ringbuffer_putc(struct fx_ringbuffer_p *buf, int c)
{
size_t available = ringbuffer_write_capacity_remaining(buf);
if (available == 0) {
return FX_ERR_NO_SPACE;
}
char *p = buf->r_buf;
p[buf->r_write_ptr++] = c;
if (buf->r_write_ptr >= buf->r_capacity) {
buf->r_write_ptr = 0;
}
return c;
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_ringbuffer *fx_ringbuffer_create(size_t capacity)
{
fx_ringbuffer *ringbuf = fx_object_create(FX_TYPE_RINGBUFFER);
if (!ringbuf) {
return NULL;
}
struct fx_ringbuffer_p *p
= fx_object_get_private(ringbuf, FX_TYPE_RINGBUFFER);
void *buffer = malloc(capacity);
if (!buffer) {
fx_ringbuffer_unref(ringbuf);
return NULL;
}
p->r_flags = RINGBUFFER_BUFFER_MALLOC;
p->r_buf = buffer;
p->r_capacity = capacity;
return ringbuf;
}
fx_ringbuffer *fx_ringbuffer_create_with_buffer(void *ptr, size_t capacity)
{
fx_ringbuffer *ringbuf = fx_object_create(FX_TYPE_RINGBUFFER);
if (!ringbuf) {
return NULL;
}
struct fx_ringbuffer_p *p
= fx_object_get_private(ringbuf, FX_TYPE_RINGBUFFER);
p->r_flags = 0;
p->r_buf = ptr;
p->r_capacity = capacity;
return ringbuf;
}
enum fx_status fx_ringbuffer_clear(fx_ringbuffer *buf)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_RINGBUFFER, ringbuffer_clear, buf);
}
enum fx_status fx_ringbuffer_read(
fx_ringbuffer *buf, void *p, size_t count, size_t *nr_read)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_RINGBUFFER, ringbuffer_read, buf, p, count, nr_read);
}
enum fx_status fx_ringbuffer_write(
fx_ringbuffer *buf, const void *p, size_t count, size_t *nr_written)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_RINGBUFFER, ringbuffer_write, buf, p, count, nr_written);
}
int fx_ringbuffer_getc(fx_ringbuffer *buf)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_RINGBUFFER, ringbuffer_getc, buf);
}
enum fx_status fx_ringbuffer_putc(fx_ringbuffer *buf, int c)
{
FX_CLASS_DISPATCH_STATIC(FX_TYPE_RINGBUFFER, ringbuffer_putc, buf, c);
}
size_t fx_ringbuffer_write_capacity_remaining(const fx_ringbuffer *buf)
{
FX_CLASS_DISPATCH_STATIC_0(
FX_TYPE_RINGBUFFER, ringbuffer_write_capacity_remaining, buf);
}
size_t fx_ringbuffer_available_data_remaining(const fx_ringbuffer *buf)
{
FX_CLASS_DISPATCH_STATIC_0(
FX_TYPE_RINGBUFFER, ringbuffer_available_data_remaining, buf);
}
enum fx_status fx_ringbuffer_open_read_buffer(
fx_ringbuffer *buf, const void **ptr, size_t *length)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_RINGBUFFER, ringbuffer_open_read_buffer, buf, ptr, length);
}
enum fx_status fx_ringbuffer_close_read_buffer(
fx_ringbuffer *buf, const void **ptr, size_t nr_read)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_RINGBUFFER, ringbuffer_close_read_buffer, buf, ptr, nr_read);
}
enum fx_status fx_ringbuffer_open_write_buffer(
fx_ringbuffer *buf, void **ptr, size_t *capacity)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_RINGBUFFER, ringbuffer_open_write_buffer, buf, ptr,
capacity);
}
enum fx_status fx_ringbuffer_close_write_buffer(
fx_ringbuffer *buf, void **ptr, size_t nr_written)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_RINGBUFFER, ringbuffer_close_write_buffer, buf, ptr,
nr_written);
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void ringbuffer_init(fx_object *obj, void *priv)
{
struct fx_ringbuffer_p *buf = priv;
}
static void ringbuffer_fini(fx_object *obj, void *priv)
{
struct fx_ringbuffer_p *buf = priv;
if (buf->r_flags & RINGBUFFER_BUFFER_MALLOC) {
free(buf->r_buf);
}
}
/*** CLASS DEFINITION *********************************************************/
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_ringbuffer)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_ringbuffer)
FX_TYPE_DEFINITION_BEGIN(fx_ringbuffer)
FX_TYPE_ID(0xb0493774, 0xef13, 0x4905, 0xa865, 0x1595607ccad9);
FX_TYPE_CLASS(fx_ringbuffer_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_ringbuffer_p);
FX_TYPE_INSTANCE_INIT(ringbuffer_init);
FX_TYPE_INSTANCE_FINI(ringbuffer_fini);
FX_TYPE_DEFINITION_END(fx_ringbuffer)
+275
View File
@@ -0,0 +1,275 @@
#include <fx/core/bstr.h>
#include <fx/core/rope.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void fx_rope_init_char(struct fx_rope *rope, char c)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = FX_ROPE_F_CHAR;
rope->r_len_left = rope->r_len_total = 1;
rope->r_v.v_char = c;
}
void fx_rope_init_cstr(struct fx_rope *rope, const char *s)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = FX_ROPE_F_CSTR;
rope->r_v.v_cstr.hash = fx_hash_cstr_ex(s, &rope->r_len_total);
rope->r_len_left = rope->r_len_total;
char *s2 = malloc(rope->r_len_total + 1);
if (!s2) {
return;
}
strcpy(s2, s);
s2[rope->r_len_total] = '\0';
rope->r_v.v_cstr.s = s2;
}
void fx_rope_init_cstr_borrowed(struct fx_rope *rope, const char *s)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = FX_ROPE_F_CSTR_BORROWED;
rope->r_v.v_cstr.s = s;
rope->r_v.v_cstr.hash = fx_hash_cstr_ex(s, &rope->r_len_total);
rope->r_len_left = rope->r_len_total;
}
void fx_rope_init_cstr_static(struct fx_rope *rope, const char *s)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = FX_ROPE_F_CSTR_STATIC;
rope->r_v.v_cstr.s = s;
rope->r_v.v_cstr.hash = fx_hash_cstr_ex(s, &rope->r_len_total);
rope->r_len_left = rope->r_len_total;
}
void fx_rope_init_int(struct fx_rope *rope, intptr_t v)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = FX_ROPE_F_INT;
rope->r_len_left = rope->r_len_total = fx_int_length(v);
rope->r_v.v_int = v;
}
void fx_rope_init_uint(struct fx_rope *rope, uintptr_t v)
{
memset(rope, 0x0, sizeof *rope);
rope->r_flags = FX_ROPE_F_UINT;
rope->r_len_left = rope->r_len_total = fx_uint_length(v);
rope->r_v.v_uint = v;
}
void fx_rope_destroy(struct fx_rope *rope)
{
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
switch (type) {
case FX_ROPE_F_CSTR:
free((char *)rope->r_v.v_cstr.s);
break;
case FX_ROPE_F_COMPOSITE:
fx_rope_destroy((struct fx_rope *)rope->r_v.v_composite.r_left);
fx_rope_destroy((struct fx_rope *)rope->r_v.v_composite.r_right);
break;
default:
break;
}
if (rope->r_flags & FX_ROPE_F_MALLOC) {
free(rope);
}
}
void fx_rope_iterate(
const struct fx_rope *rope, void (*func)(const fx_rope *, void *), void *arg)
{
if (FX_ROPE_TYPE(rope->r_flags) != FX_ROPE_F_COMPOSITE) {
func(rope, arg);
return;
}
if (rope->r_v.v_composite.r_left) {
fx_rope_iterate(rope->r_v.v_composite.r_left, func, arg);
}
if (rope->r_v.v_composite.r_right) {
fx_rope_iterate(rope->r_v.v_composite.r_right, func, arg);
}
}
size_t fx_rope_get_size(const struct fx_rope *rope)
{
return rope->r_len_total;
}
void fx_rope_concat(
struct fx_rope *result, const struct fx_rope *left, const struct fx_rope *right)
{
memset(result, 0x0, sizeof *result);
result->r_flags = FX_ROPE_F_COMPOSITE;
result->r_len_left = left->r_len_total;
result->r_len_total = left->r_len_total + right->r_len_total;
result->r_v.v_composite.r_left = left;
result->r_v.v_composite.r_right = right;
}
static struct fx_rope *create_composite_node(void)
{
struct fx_rope *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->r_flags = FX_ROPE_F_COMPOSITE | FX_ROPE_F_MALLOC;
return out;
}
void fx_rope_join(fx_rope *result, const fx_rope **ropes, size_t nr_ropes)
{
if (nr_ropes == 0) {
return;
}
if (nr_ropes == 1) {
*result = *ropes[0];
return;
}
struct fx_rope *prev = NULL;
for (size_t i = 0; i < nr_ropes - 1; i++) {
const struct fx_rope *left = ropes[i];
const struct fx_rope *right = ropes[i + 1];
if (prev) {
left = prev;
}
struct fx_rope *composite = create_composite_node();
if (!composite) {
return;
}
composite->r_len_left = left->r_len_total;
composite->r_len_total = left->r_len_total + right->r_len_total;
composite->r_v.v_composite.r_left = left;
composite->r_v.v_composite.r_right = right;
prev = composite;
}
*result = *prev;
result->r_flags &= ~FX_ROPE_F_MALLOC;
free(prev);
}
static void rope_iterate(
const struct fx_rope *rope,
void (*callback)(const struct fx_rope *, void *), void *arg)
{
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
switch (type) {
case FX_ROPE_F_CHAR:
case FX_ROPE_F_CSTR:
case FX_ROPE_F_CSTR_BORROWED:
case FX_ROPE_F_CSTR_STATIC:
case FX_ROPE_F_INT:
case FX_ROPE_F_UINT:
callback(rope, arg);
break;
case FX_ROPE_F_COMPOSITE:
rope_iterate(rope->r_v.v_composite.r_left, callback, arg);
rope_iterate(rope->r_v.v_composite.r_right, callback, arg);
break;
default:
break;
}
}
static void to_bstr(const struct fx_rope *rope, void *arg)
{
fx_bstr *str = arg;
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
switch (type) {
case FX_ROPE_F_CHAR:
fx_bstr_write_char(str, rope->r_v.v_char);
break;
case FX_ROPE_F_CSTR:
case FX_ROPE_F_CSTR_BORROWED:
case FX_ROPE_F_CSTR_STATIC:
fx_bstr_write_cstr(str, rope->r_v.v_cstr.s, NULL);
break;
case FX_ROPE_F_INT:
fx_bstr_write_fmt(str, NULL, "%" PRIdPTR, rope->r_v.v_int);
break;
case FX_ROPE_F_UINT:
fx_bstr_write_fmt(str, NULL, "%" PRIuPTR, rope->r_v.v_uint);
break;
default:
break;
}
}
static void to_stream(const struct fx_rope *rope, void *arg)
{
fx_stream *out = arg;
unsigned int type = FX_ROPE_TYPE(rope->r_flags);
switch (type) {
case FX_ROPE_F_CHAR:
fx_stream_write_char(out, rope->r_v.v_char);
break;
case FX_ROPE_F_CSTR:
case FX_ROPE_F_CSTR_BORROWED:
case FX_ROPE_F_CSTR_STATIC:
fx_stream_write_cstr(out, rope->r_v.v_cstr.s, NULL);
break;
case FX_ROPE_F_INT:
fx_stream_write_fmt(out, NULL, "%" PRIdPTR, rope->r_v.v_int);
break;
case FX_ROPE_F_UINT:
fx_stream_write_fmt(out, NULL, "%" PRIuPTR, rope->r_v.v_uint);
break;
default:
break;
}
}
fx_status fx_rope_to_cstr(const struct fx_rope *rope, char *out, size_t max)
{
fx_bstr str;
fx_bstr_begin(&str, out, max);
rope_iterate(rope, to_bstr, &str);
return FX_SUCCESS;
}
fx_status fx_rope_to_bstr(const struct fx_rope *rope, fx_bstr *str)
{
rope_iterate(rope, to_bstr, str);
return FX_SUCCESS;
}
fx_status fx_rope_to_string(const struct fx_rope *rope, fx_stream *out)
{
rope_iterate(rope, to_stream, out);
return FX_SUCCESS;
}
+60
View File
@@ -0,0 +1,60 @@
#include <fx/core/status.h>
#include <stddef.h>
#define ENUM_STR(s) \
case s: \
return #s;
#define ENUM_STR2(c, s) \
case c: \
return s;
const char *fx_status_to_string(fx_status status)
{
switch (status) {
ENUM_STR(FX_SUCCESS);
ENUM_STR(FX_ERR_NO_MEMORY);
ENUM_STR(FX_ERR_OUT_OF_BOUNDS);
ENUM_STR(FX_ERR_INVALID_ARGUMENT);
ENUM_STR(FX_ERR_NAME_EXISTS);
ENUM_STR(FX_ERR_NOT_SUPPORTED);
ENUM_STR(FX_ERR_BAD_STATE);
ENUM_STR(FX_ERR_NO_ENTRY);
ENUM_STR(FX_ERR_NO_DATA);
ENUM_STR(FX_ERR_NO_SPACE);
ENUM_STR(FX_ERR_UNKNOWN_FUNCTION);
ENUM_STR(FX_ERR_BAD_FORMAT);
ENUM_STR(FX_ERR_IO_FAILURE);
ENUM_STR(FX_ERR_IS_DIRECTORY);
ENUM_STR(FX_ERR_NOT_DIRECTORY);
ENUM_STR(FX_ERR_PERMISSION_DENIED);
ENUM_STR(FX_ERR_BUSY);
default:
return NULL;
}
}
const char *fx_status_description(fx_status status)
{
switch (status) {
ENUM_STR2(FX_SUCCESS, "Success");
ENUM_STR2(FX_ERR_NO_MEMORY, "Out of memory");
ENUM_STR2(FX_ERR_OUT_OF_BOUNDS, "Argument out of bounds");
ENUM_STR2(FX_ERR_INVALID_ARGUMENT, "Invalid argument");
ENUM_STR2(FX_ERR_NAME_EXISTS, "Name already exists");
ENUM_STR2(FX_ERR_NOT_SUPPORTED, "Operation not supported");
ENUM_STR2(FX_ERR_BAD_STATE, "Bad state");
ENUM_STR2(FX_ERR_NO_ENTRY, "No entry");
ENUM_STR2(FX_ERR_NO_DATA, "No data available");
ENUM_STR2(FX_ERR_NO_SPACE, "No space available");
ENUM_STR2(FX_ERR_UNKNOWN_FUNCTION, "Unknown function");
ENUM_STR2(FX_ERR_BAD_FORMAT, "Bad format");
ENUM_STR2(FX_ERR_IO_FAILURE, "I/O failure");
ENUM_STR2(FX_ERR_IS_DIRECTORY, "Object is a directory");
ENUM_STR2(FX_ERR_NOT_DIRECTORY, "Object is not a directory");
ENUM_STR2(FX_ERR_PERMISSION_DENIED, "Permission denied");
ENUM_STR2(FX_ERR_BUSY, "Resource busy or locked");
default:
return NULL;
}
}
+1232
View File
File diff suppressed because it is too large Load Diff
+301
View File
@@ -0,0 +1,301 @@
#include <fx/core/stringstream.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_CAPACITY 15
/*** PRIVATE DATA *************************************************************/
struct fx_stringstream_p {
char *ss_buf;
size_t ss_ptr;
size_t ss_len;
size_t ss_max;
unsigned char ss_alloc;
};
/*** PRIVATE FUNCTIONS ********************************************************/
static enum fx_status __getc(struct fx_stringstream_p *ss, fx_wchar *out)
{
size_t available = ss->ss_len - ss->ss_ptr;
const char *p = ss->ss_buf + ss->ss_ptr;
size_t to_copy = fx_wchar_utf8_codepoint_stride(p);
if (to_copy > available) {
return FX_ERR_BAD_STATE;
}
fx_wchar c = fx_wchar_utf8_codepoint_decode(p);
*out = c;
if (c == FX_WCHAR_INVALID) {
return FX_ERR_BAD_STATE;
}
ss->ss_ptr += to_copy;
return FX_SUCCESS;
}
static enum fx_status __gets(
struct fx_stringstream_p *ss, char *s, size_t len, size_t *nr_read)
{
size_t available = ss->ss_len - ss->ss_ptr;
size_t to_copy = len;
if (available < to_copy) {
to_copy = available;
}
memcpy(s, ss->ss_buf + ss->ss_ptr, to_copy);
ss->ss_ptr += to_copy;
if (nr_read) {
*nr_read = to_copy;
}
return FX_SUCCESS;
}
static enum fx_status __puts(
struct fx_stringstream_p *ss, const char *s, size_t len, size_t *nr_written)
{
size_t available = ss->ss_max - ss->ss_len;
size_t to_copy = len;
if (to_copy > available && ss->ss_alloc == 1) {
char *new_buf = realloc(ss->ss_buf, ss->ss_len + to_copy + 1);
if (!new_buf) {
return FX_ERR_NO_MEMORY;
}
ss->ss_buf = new_buf;
ss->ss_max = ss->ss_len + to_copy;
available = ss->ss_max - ss->ss_len;
}
if (available < to_copy) {
to_copy = available;
}
memcpy(ss->ss_buf + ss->ss_len, s, to_copy);
ss->ss_buf[ss->ss_len + to_copy] = 0;
/* increment the length by the full string length, even if only a
* portion was copied */
ss->ss_len += len;
if (nr_written) {
*nr_written = to_copy;
}
return FX_SUCCESS;
}
static enum fx_status stringstream_reset(struct fx_stringstream_p *ss)
{
ss->ss_len = 0;
if (ss->ss_buf) {
*ss->ss_buf = 0;
}
return FX_SUCCESS;
}
static enum fx_status stringstream_reset_with_buffer(
struct fx_stringstream_p *ss, char *buf, size_t max)
{
ss->ss_len = 0;
if (ss->ss_buf && ss->ss_alloc) {
free(ss->ss_buf);
}
ss->ss_buf = buf;
ss->ss_max = max;
ss->ss_alloc = 0;
return FX_SUCCESS;
}
static size_t stringstream_get_length(const struct fx_stringstream_p *strv)
{
return strv->ss_len;
}
static const char *stringstream_ptr(const struct fx_stringstream_p *ss)
{
return ss->ss_buf;
}
static char *stringstream_steal(struct fx_stringstream_p *ss)
{
char *out = ss->ss_buf;
memset(ss, 0x0, sizeof *ss);
ss->ss_alloc = 1;
return out;
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_stringstream *fx_stringstream_create_with_buffer(char *buf, size_t max)
{
fx_stringstream *s = fx_object_create(FX_TYPE_STRINGSTREAM);
if (!s) {
return NULL;
}
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
struct fx_stringstream_p *p
= fx_object_get_private(s, FX_TYPE_STRINGSTREAM);
cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | Z__FX_STREAM_STATIC;
p->ss_buf = buf;
p->ss_max = max;
p->ss_len = 0;
p->ss_alloc = 0;
return s;
}
fx_stringstream *fx_stringstream_create(void)
{
fx_stringstream *s = fx_object_create(FX_TYPE_STRINGSTREAM);
if (!s) {
return NULL;
}
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
struct fx_stringstream_p *p
= fx_object_get_private(s, FX_TYPE_STRINGSTREAM);
cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | Z__FX_STREAM_STATIC;
p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
if (!p->ss_buf) {
fx_stringstream_unref(s);
return NULL;
}
memset(p->ss_buf, 0x0, DEFAULT_CAPACITY + 1);
p->ss_max = DEFAULT_CAPACITY;
p->ss_len = 0;
p->ss_alloc = 1;
return s;
}
size_t fx_stringstream_get_length(const fx_stringstream *strv)
{
FX_CLASS_DISPATCH_STATIC_0(
FX_TYPE_STRINGSTREAM, stringstream_get_length, strv);
}
enum fx_status fx_stringstream_reset(fx_stringstream *strv)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_reset, strv);
}
enum fx_status fx_stringstream_reset_with_buffer(
fx_stringstream *strv, char *buf, size_t max)
{
FX_CLASS_DISPATCH_STATIC(
FX_TYPE_STRINGSTREAM, stringstream_reset_with_buffer, strv, buf,
max);
}
const char *fx_stringstream_ptr(const fx_stringstream *ss)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_ptr, ss);
}
char *fx_stringstream_steal(fx_stringstream *ss)
{
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_steal, ss);
}
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
/*** VIRTUAL FUNCTIONS ********************************************************/
static void stringstream_init(fx_object *obj, void *priv)
{
struct fx_stringstream_p *stream = priv;
}
static void stringstream_fini(fx_object *obj, void *priv)
{
struct fx_stringstream_p *stream = priv;
if (stream->ss_alloc && stream->ss_buf) {
free(stream->ss_buf);
}
}
enum fx_status stream_getc(fx_stream *stream, fx_wchar *c)
{
struct fx_stringstream_p *s
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
enum fx_status status = __getc(s, c);
return status;
}
enum fx_status stream_read(
fx_stream *stream, void *buf, size_t count, size_t *nr_read)
{
struct fx_stringstream_p *s
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
enum fx_status status = __gets(s, buf, count, nr_read);
return status;
}
enum fx_status stream_write(
fx_stream *stream, const void *buf, size_t count, size_t *nr_written)
{
struct fx_stringstream_p *s
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
enum fx_status status = __puts(s, (const char *)buf, count, nr_written);
return status;
}
/*** CLASS DEFINITION *********************************************************/
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_stringstream)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
FX_INTERFACE_ENTRY(s_close) = NULL;
FX_INTERFACE_ENTRY(s_seek) = NULL;
FX_INTERFACE_ENTRY(s_tell) = NULL;
FX_INTERFACE_ENTRY(s_getc) = stream_getc;
FX_INTERFACE_ENTRY(s_read) = stream_read;
FX_INTERFACE_ENTRY(s_write) = stream_write;
FX_INTERFACE_ENTRY(s_reserve) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
FX_TYPE_CLASS_DEFINITION_END(fx_stringstream)
FX_TYPE_DEFINITION_BEGIN(fx_stringstream)
FX_TYPE_ID(0x508a609a, 0xfac5, 0x4d31, 0x843a, 0x44b68ad329f3);
FX_TYPE_EXTENDS(FX_TYPE_STREAM);
FX_TYPE_CLASS(fx_stringstream_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_stringstream_p);
FX_TYPE_INSTANCE_INIT(stringstream_init);
FX_TYPE_INSTANCE_FINI(stringstream_fini);
FX_TYPE_DEFINITION_END(fx_stringstream)
+16
View File
@@ -0,0 +1,16 @@
#include <fx/core/bitop.h>
int fx_popcountl(long v)
{
return __builtin_popcountl(v);
}
int fx_ctzl(long v)
{
return __builtin_ctzl(v);
}
int fx_clzl(long v)
{
return __builtin_clzl(v);
}
+35
View File
@@ -0,0 +1,35 @@
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
uint64_t z__fx_platform_random_seed()
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd == -1) {
return (uint64_t)-1;
}
uint64_t v = 0;
if (read(fd, &v, sizeof v) != sizeof v) {
close(fd);
return (uint64_t)-1;
}
return v;
}
uint64_t z__fx_platform_random_seed_secure()
{
int fd = open("/dev/random", O_RDONLY);
if (fd == -1) {
return (uint64_t)-1;
}
uint64_t v = 0;
if (read(fd, &v, sizeof v) != sizeof v) {
close(fd);
return (uint64_t)-1;
}
return v;
}
+61
View File
@@ -0,0 +1,61 @@
#include <assert.h>
#include <fx/core/error.h>
#include <fx/core/thread.h>
#include <stdlib.h>
#include <string.h>
struct fx_thread {
pthread_t thr_p;
fx_result thr_result;
};
static fx_once thread_tls_init_once = FX_ONCE_INIT;
static pthread_key_t thread_tls_key = {0};
static void thread_dtor(void *p)
{
struct fx_thread *thread = p;
}
static void thread_tls_init()
{
pthread_key_create(&thread_tls_key, thread_dtor);
}
struct fx_thread *fx_thread_self(void)
{
if (fx_init_once(&thread_tls_init_once)) {
thread_tls_init();
}
struct fx_thread *thread = pthread_getspecific(thread_tls_key);
if (thread) {
return thread;
}
thread = malloc(sizeof *thread);
assert(thread);
memset(thread, 0x0, sizeof *thread);
thread->thr_p = pthread_self();
pthread_setspecific(thread_tls_key, thread);
return thread;
}
bool fx_mutex_lock(fx_mutex *mut)
{
return pthread_mutex_lock(mut) == 0;
}
bool fx_mutex_trylock(fx_mutex *mut)
{
return pthread_mutex_trylock(mut) == 0;
}
bool fx_mutex_unlock(fx_mutex *mut)
{
return pthread_mutex_unlock(mut) == 0;
}
+16
View File
@@ -0,0 +1,16 @@
#include <fx/core/bitop.h>
int fx_popcountl(long v)
{
return __builtin_popcountl(v);
}
int fx_ctzl(long v)
{
return __builtin_ctzl(v);
}
int fx_clzl(long v)
{
return __builtin_clzl(v);
}
+35
View File
@@ -0,0 +1,35 @@
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
uint64_t z__fx_platform_random_seed()
{
int fd = open("/dev/urandom", O_RDONLY);
if (fd == -1) {
return (uint64_t)-1;
}
uint64_t v = 0;
if (read(fd, &v, sizeof v) != sizeof v) {
close(fd);
return (uint64_t)-1;
}
return v;
}
uint64_t z__fx_platform_random_seed_secure()
{
int fd = open("/dev/random", O_RDONLY);
if (fd == -1) {
return (uint64_t)-1;
}
uint64_t v = 0;
if (read(fd, &v, sizeof v) != sizeof v) {
close(fd);
return (uint64_t)-1;
}
return v;
}
+16
View File
@@ -0,0 +1,16 @@
#include <fx/core/bitop.h>
int fx_popcountl(long v)
{
return __builtin_popcountl(v);
}
int fx_ctzl(long v)
{
return __builtin_ctzl(v);
}
int fx_clzl(long v)
{
return __builtin_clzl(v);
}
+13
View File
@@ -0,0 +1,13 @@
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
uint64_t z__fx_platform_random_seed()
{
return 0;
}
uint64_t z__fx_platform_random_seed_secure()
{
return 0;
}
+70
View File
@@ -0,0 +1,70 @@
#include <fx/core/bitop.h>
#include <intrin.h>
#include <assert.h>
#define CPU_FEATURE_YES 1
#define CPU_FEATURE_NO -1
#define CPU_FEATURE_UNKNOWN 0
static int cpu_supports_popcnt = CPU_FEATURE_UNKNOWN;
static int check_popcnt_support()
{
int d[4];
__cpuid(d, 0x00000001);
return (d[2] & 0x800000) ? CPU_FEATURE_YES : CPU_FEATURE_NO;
}
int fx_popcountl(long v)
{
if (cpu_supports_popcnt == CPU_FEATURE_UNKNOWN) {
cpu_supports_popcnt = check_popcnt_support();
}
if (cpu_supports_popcnt == CPU_FEATURE_YES) {
#if _M_AMD64 == 100
return __popcnt64(v);
#else
return __popcnt(v);
#endif
}
assert(0 && "CPU does not support popcount!");
return 0;
}
int fx_ctzl(long v)
{
unsigned long trailing_zero = 0;
#if _M_AMD64 == 100
int x = _BitScanForward64(&trailing_zero, v);
#else
int x = _BitScanForward(&trailing_zero, v);
#endif
if (x) {
return trailing_zero;
} else {
return 64;
}
}
int fx_clzl(long v)
{
unsigned long leading_zero = 0;
#if _M_AMD64 == 100
int x = _BitScanReverse64(&leading_zero, v);
#else
int x = _BitScanReverse(&leading_zero, v);
#endif
if (x) {
return 64 - leading_zero;
} else {
// Same remarks as above
return 64;
}
}
+30
View File
@@ -0,0 +1,30 @@
#include <fcntl.h>
#include <stdint.h>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <wincrypt.h>
uint64_t z__fx_platform_random_seed_secure(void)
{
BOOL status;
HCRYPTPROV hCryptProv;
status = CryptAcquireContext(
&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
if (status == FALSE) {
return (uint64_t)-1;
}
uint64_t v = 0;
status = CryptGenRandom(hCryptProv, sizeof v, (BYTE *)&v);
CryptReleaseContext(hCryptProv, 0);
return status == TRUE ? v : (uint64_t)-1;
}
uint64_t z__fx_platform_random_seed(void)
{
return z__fx_platform_random_seed_secure();
}
+319
View File
@@ -0,0 +1,319 @@
#include "type.h"
#include "class.h"
#include "object.h"
#include <fx/core/bst.h>
#include <fx/core/endian.h>
#include <fx/core/object.h>
#include <fx/core/type.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct fx_bst type_list = FX_BST_INIT;
static union fx_type zero_id = {0};
struct type_init_ctx {
size_t ctx_class_offset;
size_t ctx_instance_offset;
};
static inline int registration_compare(
const struct fx_type_registration *a, const struct fx_type_registration *b)
{
return fx_type_id_compare(&a->r_info->t_id, &b->r_info->t_id);
}
static inline int component_compare(
const struct fx_type_component *a, const struct fx_type_component *b)
{
return fx_type_id_compare(&a->c_type->r_info->t_id, &b->c_type->r_info->t_id);
}
FX_BST_DEFINE_INSERT(
struct fx_type_registration, r_node, r_info->r_id, put_type,
registration_compare)
FX_BST_DEFINE_INSERT(
struct fx_type_component, c_node, &c_type->r_info->t_id,
put_type_component, component_compare)
static struct fx_type_registration *get_type(
const fx_bst *tree, const union fx_type *key)
{
fx_bst_node *cur = tree->bst_root;
while (cur) {
struct fx_type_registration *cur_node
= fx_unbox(struct fx_type_registration, cur, r_node);
int cmp = fx_type_id_compare(key, &cur_node->r_info->t_id);
if (cmp > 0) {
cur = fx_bst_right(cur);
} else if (cmp < 0) {
cur = fx_bst_left(cur);
} else {
return cur_node;
}
}
return NULL;
}
struct fx_type_component *fx_type_get_component(
const fx_bst *tree, const union fx_type *key)
{
fx_bst_node *cur = tree->bst_root;
while (cur) {
struct fx_type_component *cur_node
= fx_unbox(struct fx_type_component, cur, c_node);
int cmp = fx_type_id_compare(key, &cur_node->c_type->r_info->t_id);
if (cmp > 0) {
cur = fx_bst_right(cur);
} else if (cmp < 0) {
cur = fx_bst_left(cur);
} else {
return cur_node;
}
}
return NULL;
}
static struct fx_type_component *create_type_component(
const struct fx_type_registration *type_reg)
{
struct fx_type_component *c = malloc(sizeof *c);
if (!c) {
return NULL;
}
memset(c, 0x0, sizeof *c);
c->c_type = type_reg;
return c;
}
void fx_type_id_init(
union fx_type *out, uint32_t a, uint16_t b, uint16_t c, uint16_t d,
uint64_t e)
{
fx_i32 x_a = fx_i32_htob(a);
fx_i16 x_b = fx_i16_htob(b);
fx_i16 x_c = fx_i16_htob(c);
fx_i16 x_d = fx_i16_htob(d);
fx_i64 x_e = fx_i64_htob(e);
memcpy(&out->b[0], x_a.i_bytes, sizeof x_a.i_bytes);
memcpy(&out->b[4], x_b.i_bytes, sizeof x_b.i_bytes);
memcpy(&out->b[6], x_c.i_bytes, sizeof x_c.i_bytes);
memcpy(&out->b[8], x_d.i_bytes, sizeof x_d.i_bytes);
memcpy(&out->b[10], &x_e.i_bytes[2], sizeof x_e.i_bytes - 2);
}
static void initialise_type_component(
struct fx_type_component *comp, const struct fx_type_info *info,
struct type_init_ctx *init_ctx)
{
comp->c_class_data_offset = init_ctx->ctx_class_offset;
comp->c_class_data_size = info->t_class_size;
init_ctx->ctx_class_offset += comp->c_class_data_size;
comp->c_instance_private_data_offset = init_ctx->ctx_instance_offset;
comp->c_instance_private_data_size = info->t_instance_private_size;
init_ctx->ctx_instance_offset += comp->c_instance_private_data_size;
comp->c_instance_protected_data_offset = init_ctx->ctx_instance_offset;
comp->c_instance_protected_data_size = info->t_instance_protected_size;
init_ctx->ctx_instance_offset += comp->c_instance_protected_data_size;
}
static fx_result locate_interface(
fx_type interface_id, struct fx_type_registration *dest,
struct type_init_ctx *init_ctx)
{
struct fx_type_component *interface_comp
= fx_type_get_component(&dest->r_components, interface_id);
if (interface_comp) {
return FX_RESULT_SUCCESS;
}
struct fx_type_registration *interface_reg
= get_type(&type_list, interface_id);
if (!interface_reg) {
return FX_RESULT_ERR(NO_ENTRY);
}
interface_comp = create_type_component(interface_reg);
if (!interface_comp) {
return FX_RESULT_ERR(NO_MEMORY);
}
initialise_type_component(interface_comp, interface_reg->r_info, init_ctx);
put_type_component(&dest->r_components, interface_comp);
return FX_RESULT_SUCCESS;
}
static fx_result locate_interfaces(
const union fx_type *interfaces, size_t nr_interfaces,
struct fx_type_registration *dest, struct type_init_ctx *init_ctx)
{
fx_result result = FX_RESULT_SUCCESS;
for (size_t i = 0; i < nr_interfaces; i++) {
fx_type interface_id = &interfaces[i];
result = locate_interface(interface_id, dest, init_ctx);
if (fx_result_is_error(result)) {
break;
}
}
return result;
}
static fx_result find_type_components(struct fx_type_registration *reg)
{
const struct fx_type_info *current = reg->r_info;
struct fx_type_component *comp = create_type_component(reg);
if (!comp) {
return FX_RESULT_ERR(NO_MEMORY);
}
struct type_init_ctx init_ctx = {
.ctx_instance_offset = sizeof(struct _fx_object),
.ctx_class_offset = sizeof(struct _fx_class),
};
put_type_component(&reg->r_components, comp);
fx_queue_push_front(&reg->r_class_hierarchy, &comp->c_entry);
fx_result result = locate_interfaces(
current->t_interfaces, current->t_nr_interfaces, reg, &init_ctx);
if (fx_result_is_error(result)) {
return result;
}
fx_type current_id = &current->t_parent_id;
if (!current_id || fx_type_id_compare(current_id, &zero_id) == 0) {
goto skip_class_hierarchy;
}
while (1) {
struct fx_type_registration *dep_class
= get_type(&type_list, current_id);
if (!dep_class) {
return FX_RESULT_ERR(NO_ENTRY);
}
comp = fx_type_get_component(&reg->r_components, current_id);
if (comp) {
/* circular class dependency */
// result = FX_RESULT_ERR(INVALID_ARGUMENT);
// break;
current_id = &dep_class->r_info->t_parent_id;
continue;
}
comp = create_type_component(dep_class);
result = locate_interfaces(
dep_class->r_info->t_interfaces,
dep_class->r_info->t_nr_interfaces, reg, &init_ctx);
if (fx_result_is_error(result)) {
break;
}
put_type_component(&reg->r_components, comp);
fx_queue_push_front(&reg->r_class_hierarchy, &comp->c_entry);
if (fx_type_id_compare(current_id, FX_TYPE_OBJECT) == 0) {
break;
}
current_id = &dep_class->r_info->t_parent_id;
}
fx_queue_entry *entry = fx_queue_first(&reg->r_class_hierarchy);
while (entry) {
comp = fx_unbox(struct fx_type_component, entry, c_entry);
initialise_type_component(comp, comp->c_type->r_info, &init_ctx);
entry = fx_queue_next(entry);
}
fx_bst_node *node = fx_bst_first(&reg->r_components);
while (node) {
comp = fx_unbox(struct fx_type_component, node, c_node);
if (comp->c_type->r_category == FX_TYPE_CLASS) {
/* this component was already initialised above */
node = fx_bst_next(node);
continue;
}
initialise_type_component(comp, comp->c_type->r_info, &init_ctx);
node = fx_bst_next(node);
}
skip_class_hierarchy:
reg->r_instance_size = init_ctx.ctx_instance_offset;
reg->r_class_size = init_ctx.ctx_class_offset;
return result;
}
static bool type_has_base_class(struct fx_type_info *info)
{
if (fx_type_id_compare(&info->t_id, FX_TYPE_OBJECT) == 0) {
return true;
}
return fx_type_id_compare(&info->t_parent_id, &zero_id) != 0;
}
fx_result fx_type_register(struct fx_type_info *info)
{
if (!type_has_base_class(info)) {
fx_type_id_copy(FX_TYPE_OBJECT, &info->t_parent_id);
}
struct fx_type_registration *r = get_type(&type_list, &info->t_id);
if (r) {
return FX_RESULT_ERR(NAME_EXISTS);
}
r = malloc(sizeof *r);
if (!r) {
return FX_RESULT_ERR(NO_MEMORY);
}
memset(r, 0x0, sizeof *r);
r->r_category = FX_TYPE_CLASS;
r->r_info = info;
fx_result result = find_type_components(r);
if (fx_result_is_error(result)) {
free(r);
return fx_result_propagate(result);
}
result = fx_class_instantiate(r, &r->r_class);
if (!r->r_class) {
free(r);
return fx_error_with_msg_template_caused_by_error(
FX_ERRORS_BUILTIN, FX_ERR_TYPE_REGISTRATION_FAILURE,
result, FX_MSG_TYPE_REGISTRATION_FAILURE,
FX_ERROR_PARAM("typename", info->t_name));
}
put_type(&type_list, r);
return FX_RESULT_SUCCESS;
}
struct fx_type_registration *fx_type_get_registration(fx_type id)
{
return get_type(&type_list, id);
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef _TYPE_H_
#define _TYPE_H_
#include <fx/core/bst.h>
#include <fx/core/queue.h>
#include <fx/core/type.h>
#include <stddef.h>
enum fx_type_category {
FX_TYPE_NONE = 0,
FX_TYPE_CLASS,
FX_TYPE_INTERFACE,
};
struct fx_type_component {
struct fx_bst_node c_node;
struct fx_queue_entry c_entry;
const struct fx_type_registration *c_type;
size_t c_class_data_offset, c_class_data_size;
size_t c_instance_private_data_offset, c_instance_private_data_size;
size_t c_instance_protected_data_offset, c_instance_protected_data_size;
};
struct fx_type_registration {
enum fx_type_category r_category;
struct fx_bst_node r_node;
const fx_type_info *r_info;
struct _fx_class *r_class;
struct fx_bst r_components;
struct fx_queue r_class_hierarchy;
size_t r_instance_size, r_class_size;
};
extern struct fx_type_registration *fx_type_get_registration(fx_type id);
extern struct fx_type_component *fx_type_get_component(
const fx_bst *tree, const union fx_type *key);
#endif