meta: rename core module to fx namespace
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
include(../cmake/Templates.cmake)
|
||||
|
||||
add_fx_module(
|
||||
NAME core
|
||||
SUBDIRS hash)
|
||||
@@ -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)
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+213
@@ -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
File diff suppressed because it is too large
Load Diff
+37
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
@@ -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,
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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)
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+161
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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(®->r_components, comp);
|
||||
fx_queue_push_front(®->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 = ¤t->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(®->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(®->r_components, comp);
|
||||
fx_queue_push_front(®->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(®->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(®->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);
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user