Compare commits

..

16 Commits

Author SHA1 Message Date
84df46489a meta: update clang-format config 2026-02-03 14:47:36 +00:00
0d5a186d80 test: core: add bstr tests; update rope tests 2026-02-03 14:47:25 +00:00
2632feac32 cmd: add support for dynamically generating command options at runtime 2026-02-03 14:46:40 +00:00
f5c4fa561f ds: uuid: convert uuid bytes struct to union 2026-02-03 14:45:30 +00:00
5639aefd61 ds: string: set iterator value to B_WCHAR_INVALID when end of string is reached 2026-02-03 14:44:36 +00:00
30a9db17dc ds: list: update iterator interface 2026-02-03 14:43:35 +00:00
ce50cfd18b ds: hashmap: update iterator interface 2026-02-03 14:43:17 +00:00
9b48fc2b45 ds: convert (stub) bitbuffer implementation to (stub) b_object sub-class 2026-02-03 14:42:05 +00:00
5889426478 core: rope: add bstr support 2026-02-03 14:39:33 +00:00
c13b7a7e3a core: stream: add bstr support
despite not being a b_object, the b_stream interface can now detect when
a b_bstr instance has been passed as a stream parameter and use the correct
functions to handle writing to it.

this allows any function that expects a b_stream parameter to be called
with a b_bstr instance instead, allowing complex stream-based I/O operations
to be directed towards bounded character arrays with no heap allocation
required.
2026-02-03 14:36:48 +00:00
23aba2a27f core: add bstr data structure
bstr is very similar to b_stringstream, with the key difference being it can be
stack-allocated. this allows you to write a complex formatted string to a
stack-allocated character buffer with no heap memory allocation required.
bstr also supports automatically-managed dynamic string buffers for unbounded
string construction.
2026-02-03 14:34:58 +00:00
bdcd4163c7 core: stringstream: added read-support
any characters written to a stringstream can be optionally read back again
using the b_stream read API.

this functions similar to a ringbuffer, with two key differences:
 1) the buffer is not circular, and will continuously expand to accomodate all incoming data.
 2) reading data from the stringstream does not remove it from the buffer.
2026-02-03 14:33:06 +00:00
add05ef478 core: iterator: added inline definition of is_valid() 2026-02-03 14:32:15 +00:00
68ab79fe2a core: hash: add support for hashing the contents of ropes 2026-02-03 14:31:35 +00:00
ce9195c130 core: queue: implement moving queue entries
this works exactly the same as moving btree nodes.
2026-02-03 14:30:53 +00:00
837a42e249 core: btree: implement moving btree nodes
moving a btree node is similar to simply using memmove() or memcpy(), with the added
bonus of updating the pointers in the wider data structure to the new node memory
and zeroing the old node memory so that it isn't used accidentally after the move
is complete.
2026-02-03 14:28:58 +00:00
30 changed files with 1179 additions and 166 deletions

View File

@@ -4,7 +4,6 @@ IndentWidth: 8
Language: Cpp
DerivePointerAlignment: false
PointerAlignment: Right
ReferenceAlignment: Left
ColumnLimit: 80
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: None
@@ -53,9 +52,67 @@ PenaltyBreakOpenParenthesis: 5
PenaltyBreakBeforeFirstCallParameter: 5
PenaltyIndentedWhitespace: 0
AttributeMacros:
- BLUE_API
- BLUELIB_API
ForEachMacros:
- b_btree_foreach
- b_queue_foreach
MacroBlockBegin: "^B_(TYPE|PARAM)_.*_BEGIN$"
MacroBlockEnd: "^B_(TYPE|PARAM)_.*_END$"
MacroBlockBegin: "B_TYPE_.*_BEGIN"
MacroBlockEnd: "B_TYPE_.*_END"
---
Language: ObjC
DerivePointerAlignment: false
PointerAlignment: Right
ColumnLimit: 80
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignEscapedNewlines: Right
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLambdasOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
ExperimentalAutoDetectBinPacking: false
BitFieldColonSpacing: Both
BreakBeforeBraces: Linux
BreakBeforeBinaryOperators: All
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakStringLiterals: true
ContinuationIndentWidth: 8
Cpp11BracedListStyle: true
IncludeBlocks: Regroup
SortIncludes: true
IndentRequires: true
NamespaceIndentation: Inner
ReflowComments: true
SpacesBeforeTrailingComments: 3
TabWidth: 8
UseTab: AlignWithSpaces
PenaltyReturnTypeOnItsOwnLine: 1000000
PenaltyExcessCharacter: 5
PenaltyBreakOpenParenthesis: 5
PenaltyBreakBeforeFirstCallParameter: 5
PenaltyIndentedWhitespace: 0
AttributeMacros:
- BLUELIB_API
ForEachMacros:
- b_btree_foreach
- b_queue_foreach
MacroBlockBegin: "B_TYPE_.*_BEGIN"
MacroBlockEnd: "B_TYPE_.*_END"

View File

@@ -282,6 +282,24 @@ struct b_command_usage *b_command_add_usage(struct b_command *cmd)
return usage;
}
const struct b_command_option *b_command_get_option(
const struct b_command *cmd, int id)
{
struct b_queue_entry *cur = b_queue_first(&cmd->b_opt);
while (cur) {
const struct b_command_option *opt
= b_unbox(struct b_command_option, cur, opt_entry);
if (opt->opt_id == id) {
return opt;
}
cur = b_queue_next(cur);
}
return NULL;
}
b_status b_command_usage_add_option(
struct b_command_usage *usage, struct b_command_option *opt)
{
@@ -335,9 +353,9 @@ b_status b_command_usage_add_command(b_command_usage *usage, unsigned int cmd_id
static void prepend_command_name(struct b_command *cmd, b_string *out)
{
int nr_names = 0;
cmd->b_name&& nr_names++;
cmd->b_long_name&& nr_names++;
cmd->b_short_name&& nr_names++;
cmd->b_name &&nr_names++;
cmd->b_long_name &&nr_names++;
cmd->b_short_name &&nr_names++;
if (nr_names > 1) {
b_string_prepend_cstr(out, "}");

View File

@@ -61,6 +61,12 @@
this_opt = opt_##id; \
if (this_opt)
#define B_COMMAND_OPTION_GEN(id) \
b_command_option *z__b_unique_name() \
= b_command_add_option(this_cmd, (id)); \
this_opt = z__b_unique_name(); \
if (this_opt)
#define B_COMMAND_HELP_OPTION() \
do { \
b_command_option *opt \
@@ -210,6 +216,11 @@ BLUE_API b_command_option *b_command_add_option(b_command *cmd, int id);
BLUE_API b_command_arg *b_command_add_arg(b_command *cmd, int id);
BLUE_API b_command_usage *b_command_add_usage(b_command *cmd);
BLUE_API const b_command_option *b_command_get_option(const b_command *cmd, int id);
BLUE_API const char *b_command_option_get_long_name(const b_command_option *opt);
BLUE_API char b_command_option_get_short_name(const b_command_option *opt);
BLUE_API const char *b_command_option_get_description(b_command_option *opt);
BLUE_API b_status b_command_option_set_long_name(
b_command_option *opt, const char *name);
BLUE_API b_status b_command_option_set_short_name(b_command_option *opt, char name);

View File

@@ -42,6 +42,21 @@ void b_command_option_destroy(struct b_command_option *opt)
free(opt);
}
const char *b_command_option_get_long_name(const struct b_command_option *opt)
{
return opt->opt_long_name;
}
char b_command_option_get_short_name(const struct b_command_option *opt)
{
return opt->opt_short_name;
}
const char *b_command_option_get_description(struct b_command_option *opt)
{
return opt->opt_description;
}
b_status b_command_option_set_long_name(
struct b_command_option *opt, const char *name)
{

375
core/bstr.c Normal file
View File

@@ -0,0 +1,375 @@
#include "printf.h"
#include <blue/core/bstr.h>
#include <blue/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, B_BSTR_F_ALLOC))
/* number of bytes that bstr_buf is extended by when required */
#define CAPACITY_STEP 32
void b_bstr_begin(struct b_bstr *str, char *buf, size_t max)
{
memset(str, 0x0, sizeof *str);
str->bstr_magic = B_BSTR_MAGIC;
str->bstr_buf = buf;
str->bstr_capacity = max;
str->bstr_len = 0;
str->bstr_flags = B_BSTR_F_NONE;
}
void b_bstr_begin_dynamic(struct b_bstr *str)
{
memset(str, 0x0, sizeof *str);
str->bstr_magic = B_BSTR_MAGIC;
str->bstr_buf = NULL;
str->bstr_capacity = 0;
str->bstr_len = 0;
str->bstr_flags = B_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 *b_bstr_end(struct b_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 b_status b_bstr_reserve(struct b_bstr *strv, size_t len)
{
if (!IS_DYNAMIC(strv)) {
return B_SUCCESS;
}
if (strv->bstr_capacity > 0 && strv->bstr_capacity - 1 >= len) {
return B_SUCCESS;
}
char *new_buf = realloc(strv->bstr_buf, len + 1);
if (!new_buf) {
return B_ERR_NO_MEMORY;
}
strv->bstr_buf = new_buf;
strv->bstr_capacity = len + 1;
strv->bstr_buf[strv->bstr_len] = '\0';
return B_SUCCESS;
}
static int current_indent(struct b_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 b_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, B_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 b_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 b_bstr *str = arg;
formatter_putchar(str, c);
}
static enum b_status bstr_putcs(
struct b_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 B_SUCCESS;
}
static enum b_status bstr_puts(struct b_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 B_SUCCESS;
}
enum b_status b_bstr_push_indent(struct b_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 B_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 B_SUCCESS;
}
enum b_status b_bstr_pop_indent(struct b_bstr *strv)
{
if (strv->bstr_istack_ptr > 0) {
strv->bstr_istack_ptr--;
}
return B_SUCCESS;
}
enum b_status b_bstr_write_char(struct b_bstr *str, char c)
{
formatter_putchar(str, c);
return B_SUCCESS;
}
enum b_status b_bstr_write_chars(
struct b_bstr *str, const char *s, size_t len, size_t *nr_written)
{
return bstr_putcs(str, s, len, nr_written);
}
enum b_status b_bstr_write_cstr(struct b_bstr *str, const char *s, size_t *nr_written)
{
return bstr_puts(str, s, nr_written);
}
enum b_status b_bstr_write_cstr_list(
struct b_bstr *str, const char **strs, size_t *nr_written)
{
size_t w = 0;
enum b_status status = B_SUCCESS;
for (size_t i = 0; strs[i]; i++) {
size_t tmp = 0;
status = bstr_puts(str, strs[i], &tmp);
w += tmp;
if (B_ERR(status)) {
break;
}
}
if (nr_written) {
*nr_written = w;
}
return status;
}
enum b_status b_bstr_write_cstr_array(
struct b_bstr *str, const char **strs, size_t count, size_t *nr_written)
{
enum b_status status = B_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 (B_ERR(status)) {
break;
}
}
if (nr_written) {
*nr_written = w;
}
return status;
}
enum b_status b_bstr_add_many(struct b_bstr *str, size_t *nr_written, ...)
{
va_list arg;
va_start(arg, nr_written);
const char *s = NULL;
size_t w = 0;
enum b_status status = B_SUCCESS;
while ((s = va_arg(arg, const char *))) {
size_t tmp = 0;
status = bstr_puts(str, s, &tmp);
w += tmp;
if (B_ERR(status)) {
break;
}
}
if (nr_written) {
*nr_written = w;
}
return status;
}
enum b_status b_bstr_write_rope(
b_bstr *strv, const struct b_rope *rope, size_t *nr_written)
{
size_t start = strv->bstr_len;
enum b_status status = b_rope_to_bstr(rope, strv);
size_t end = strv->bstr_len;
if (nr_written) {
*nr_written = end - start;
}
return status;
}
enum b_status b_bstr_write_fmt(
struct b_bstr *str, size_t *nr_written, const char *format, ...)
{
va_list arg;
va_start(arg, format);
enum b_status result = b_bstr_write_vfmt(str, nr_written, format, arg);
va_end(arg);
return result;
}
enum b_status b_bstr_write_vfmt(
struct b_bstr *str, size_t *nr_written, const char *format, va_list arg)
{
size_t start = str->bstr_len;
z__b_fctprintf(bstr_fctprintf, str, format, arg);
size_t end = str->bstr_len;
if (nr_written) {
*nr_written = end - start;
}
/* TODO update z__b_fctprintf to support propagating error codes */
return B_SUCCESS;
}
char *b_bstr_rope(const struct b_rope *rope, size_t *nr_written)
{
struct b_bstr str;
b_bstr_begin_dynamic(&str);
b_bstr_write_rope(&str, rope, nr_written);
return b_bstr_end(&str);
}
char *b_bstr_fmt(size_t *nr_written, const char *format, ...)
{
va_list arg;
va_start(arg, format);
char *s = b_bstr_vfmt(nr_written, format, arg);
va_end(arg);
return s;
}
char *b_bstr_vfmt(size_t *nr_written, const char *format, va_list arg)
{
struct b_bstr str;
b_bstr_begin_dynamic(&str);
b_bstr_write_vfmt(&str, nr_written, format, arg);
return b_bstr_end(&str);
}

View File

@@ -736,6 +736,32 @@ b_btree_node *b_btree_prev(const struct b_btree_node *node)
return prev_node(node, &d);
}
void b_btree_move(
struct b_btree *tree, struct b_btree_node *dest, struct b_btree_node *src)
{
if (src->b_parent) {
if (src->b_parent->b_left == src) {
src->b_parent->b_left = dest;
} else {
src->b_parent->b_right = dest;
}
}
if (src->b_left) {
src->b_left->b_parent = dest;
}
if (src->b_right) {
src->b_right->b_parent = dest;
}
if (tree->b_root == src) {
tree->b_root = dest;
}
memmove(dest, src, sizeof *src);
}
b_iterator *b_btree_begin(struct b_btree *tree)
{
b_iterator *it_obj = b_object_create(B_TYPE_BTREE_ITERATOR);

View File

@@ -1,6 +1,8 @@
#include "hash.h"
#include <blue/core/hash.h>
#include <blue/core/rope.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
@@ -116,6 +118,43 @@ enum b_status b_hash_ctx_update(struct b_hash_ctx *ctx, const void *p, size_t le
return B_SUCCESS;
}
static void update_rope(const b_rope *rope, void *arg)
{
struct b_hash_ctx *ctx = arg;
unsigned int type = B_ROPE_TYPE(rope->r_flags);
char tmp[64];
size_t len = 0;
switch (type) {
case B_ROPE_F_CHAR:
b_hash_ctx_update(ctx, &rope->r_v.v_char, sizeof rope->r_v.v_char);
break;
case B_ROPE_F_CSTR:
case B_ROPE_F_CSTR_BORROWED:
case B_ROPE_F_CSTR_STATIC:
b_hash_ctx_update(
ctx, rope->r_v.v_cstr.s, strlen(rope->r_v.v_cstr.s));
break;
case B_ROPE_F_INT:
len = snprintf(tmp, sizeof tmp, "%" PRIdPTR, rope->r_v.v_int);
b_hash_ctx_update(ctx, tmp, len);
break;
case B_ROPE_F_UINT:
len = snprintf(tmp, sizeof tmp, "%" PRIuPTR, rope->r_v.v_uint);
b_hash_ctx_update(ctx, tmp, len);
break;
default:
break;
}
}
enum b_status b_hash_ctx_update_rope(
struct b_hash_ctx *ctx, const struct b_rope *rope)
{
b_rope_iterate(rope, update_rope, ctx);
return B_SUCCESS;
}
enum b_status b_hash_ctx_finish(
struct b_hash_ctx *ctx, void *out_digest, size_t out_max)
{

View File

@@ -0,0 +1,71 @@
#ifndef BLUE_CORE_BSTR_H_
#define BLUE_CORE_BSTR_H_
#include <blue/core/misc.h>
#include <blue/core/status.h>
#include <stdarg.h>
#include <stddef.h>
#define B_BSTR_MAGIC 0x5005500550055005ULL
struct b_rope;
enum b_bstr_flags {
B_BSTR_F_NONE = 0x00u,
B_BSTR_F_ALLOC = 0x01u,
};
typedef struct b_bstr {
uint64_t bstr_magic;
enum b_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;
} b_bstr;
BLUE_API void b_bstr_begin(b_bstr *strv, char *buf, size_t max);
BLUE_API void b_bstr_begin_dynamic(b_bstr *strv);
BLUE_API char *b_bstr_end(b_bstr *strv);
BLUE_API b_status b_bstr_reserve(b_bstr *strv, size_t len);
static inline size_t b_bstr_get_size(const b_bstr *str)
{
return str->bstr_len;
}
static inline size_t b_bstr_get_capacity(const b_bstr *str)
{
return str->bstr_capacity;
}
BLUE_API b_status b_bstr_push_indent(b_bstr *strv, int indent);
BLUE_API b_status b_bstr_pop_indent(b_bstr *strv);
BLUE_API b_status b_bstr_write_char(b_bstr *strv, char c);
BLUE_API b_status b_bstr_write_chars(
b_bstr *strv, const char *cs, size_t len, size_t *nr_written);
BLUE_API b_status b_bstr_write_cstr(
b_bstr *strv, const char *str, size_t *nr_written);
BLUE_API b_status b_bstr_write_cstr_list(
b_bstr *strv, const char **strs, size_t *nr_written);
BLUE_API b_status b_bstr_write_cstr_array(
b_bstr *strv, const char **strs, size_t count, size_t *nr_written);
BLUE_API b_status b_bstr_write_cstr_varg(b_bstr *strv, size_t *nr_written, ...);
BLUE_API b_status b_bstr_write_rope(
b_bstr *strv, const struct b_rope *rope, size_t *nr_written);
BLUE_API b_status b_bstr_write_fmt(
b_bstr *strv, size_t *nr_written, const char *format, ...);
BLUE_API b_status b_bstr_write_vfmt(
b_bstr *strv, size_t *nr_written, const char *format, va_list arg);
BLUE_API char *b_bstr_rope(const struct b_rope *rope, size_t *nr_written);
BLUE_API char *b_bstr_fmt(size_t *nr_written, const char *format, ...);
BLUE_API char *b_bstr_vfmt(size_t *nr_written, const char *format, va_list arg);
#endif

View File

@@ -335,6 +335,8 @@ static inline b_btree_node *b_btree_parent(b_btree_node *node)
return node->b_parent;
}
BLUE_API void b_btree_move(b_btree *tree, b_btree_node *dest, b_btree_node *src);
/* get the height of `node`.
the height of a node is defined as the length of the longest path

View File

@@ -29,6 +29,7 @@
#define B_DIGEST_LENGTH_SHAKE256 B_DIGEST_LENGTH_256
struct b_hash_function_ops;
struct b_rope;
typedef enum b_hash_function {
B_HASH_NONE = 0,
@@ -103,6 +104,7 @@ BLUE_API uint64_t b_hash_cstr_ex(const char *s, size_t *len);
BLUE_API b_status b_hash_ctx_init(b_hash_ctx *ctx, b_hash_function func);
BLUE_API b_status b_hash_ctx_reset(b_hash_ctx *ctx);
BLUE_API b_status b_hash_ctx_update(b_hash_ctx *ctx, const void *p, size_t len);
BLUE_API b_status b_hash_ctx_update_rope(b_hash_ctx *ctx, const struct b_rope *rope);
BLUE_API b_status b_hash_ctx_finish(
b_hash_ctx *ctx, void *out_digest, size_t out_max);

View File

@@ -83,7 +83,10 @@ BLUE_API b_status b_iterator_move_next(const b_iterator *it);
BLUE_API b_iterator_value b_iterator_get_value(b_iterator *it);
BLUE_API const b_iterator_value b_iterator_get_cvalue(const b_iterator *it);
BLUE_API b_status b_iterator_erase(b_iterator *it);
BLUE_API b_status b_iterator_is_valid(const b_iterator *it);
static inline bool b_iterator_is_valid(const b_iterator *it)
{
return B_OK(b_iterator_get_status(it));
}
B_DECLS_END;

View File

@@ -35,24 +35,24 @@ static inline void b_queue_init(b_queue *q)
}
static inline bool b_queue_empty(const b_queue *q)
{
return q->q_first == NULL;
return q ? (q->q_first == NULL) : true;
}
static inline b_queue_entry *b_queue_first(const b_queue *q)
{
return q->q_first;
return q ? q->q_first : NULL;
}
static inline b_queue_entry *b_queue_last(const b_queue *q)
{
return q->q_last;
return q ? q->q_last : NULL;
}
static inline b_queue_entry *b_queue_next(const b_queue_entry *entry)
{
return entry->qe_next;
return entry ? entry->qe_next : NULL;
}
static inline b_queue_entry *b_queue_prev(const b_queue_entry *entry)
{
return entry->qe_prev;
return entry ? entry->qe_prev : NULL;
}
BLUE_API b_type b_queue_iterator_get_type(void);
@@ -70,6 +70,7 @@ BLUE_API void b_queue_push_back(b_queue *q, b_queue_entry *entry);
BLUE_API b_queue_entry *b_queue_pop_front(b_queue *q);
BLUE_API b_queue_entry *b_queue_pop_back(b_queue *q);
BLUE_API void b_queue_move(b_queue *q, b_queue_entry *dest, b_queue_entry *src);
BLUE_API void b_queue_delete(b_queue *q, b_queue_entry *entry);
BLUE_API void b_queue_delete_all(b_queue *q);

View File

@@ -3,10 +3,12 @@
#include <blue/core/hash.h>
#include <blue/core/misc.h>
#include <blue/core/stream.h>
#include <stdint.h>
#include <string.h>
struct b_string;
struct b_bstr;
#define B_ROPE_TYPE(f) ((f) & 0xFF)
@@ -17,7 +19,7 @@ struct b_string;
.r_v = {.v_char = (c) } \
}
#define B_ROPE_CSTR(str) \
#define B_ROPE_CSTR(str) \
{ \
.r_flags = B_ROPE_F_CSTR_BORROWED, \
.r_len_total = strlen(str), \
@@ -29,7 +31,7 @@ struct b_string;
}, \
}
#define B_ROPE_CSTR_STATIC(str) \
#define B_ROPE_CSTR_STATIC(str) \
{ \
.r_flags = B_ROPE_F_CSTR_STATIC, \
.r_len_total = strlen(str), \
@@ -94,10 +96,14 @@ BLUE_API void b_rope_init_uint(b_rope *rope, uintptr_t v);
BLUE_API void b_rope_destroy(b_rope *rope);
BLUE_API void b_rope_iterate(
const b_rope *rope, void (*func)(const b_rope *, void *), void *arg);
BLUE_API size_t b_rope_get_size(const b_rope *rope);
BLUE_API void b_rope_concat(b_rope *result, const b_rope *left, const b_rope *right);
BLUE_API void b_rope_join(b_rope *result, const b_rope **ropes, size_t nr_ropes);
BLUE_API void b_rope_to_cstr(const b_rope *rope, char *out, size_t max);
BLUE_API b_status b_rope_to_cstr(const b_rope *rope, char *out, size_t max);
BLUE_API b_status b_rope_to_bstr(const b_rope *rope, struct b_bstr *str);
BLUE_API b_status b_rope_to_string(const b_rope *rope, b_stream *out);
#endif

View File

@@ -30,20 +30,6 @@ BLUE_API char *b_stringstream_steal(b_stringstream *strv);
BLUE_API size_t b_stringstream_get_length(const b_stringstream *strv);
#if 0
BLUE_API void b_stringstream_push_indent(b_stringstream *strv, int indent);
BLUE_API void b_stringstream_pop_indent(b_stringstream *strv);
BLUE_API b_status b_stringstream_add(b_stringstream *strv, const char *str);
BLUE_API b_status b_stringstream_addf(b_stringstream *strv, const char *format, ...);
BLUE_API b_status b_stringstream_addv(b_stringstream *strv, const char **strs);
BLUE_API b_status b_stringstream_addvf(
b_stringstream *strv, const char *format, va_list arg);
BLUE_API b_status b_stringstream_addvl(
b_stringstream *strv, const char **strs, size_t count);
BLUE_API b_status b_stringstream_add_many(b_stringstream *strv, ...);
#endif
B_DECLS_END;
#endif

View File

@@ -102,6 +102,27 @@ struct b_queue_entry *b_queue_pop_back(struct b_queue *q)
return x;
}
void b_queue_move(b_queue *q, b_queue_entry *dest, b_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 b_queue_delete(struct b_queue *q, struct b_queue_entry *entry)
{
if (!entry) {

View File

@@ -1,3 +1,4 @@
#include <blue/core/bstr.h>
#include <blue/core/rope.h>
#include <inttypes.h>
#include <stdio.h>
@@ -86,6 +87,23 @@ void b_rope_destroy(struct b_rope *rope)
}
}
void b_rope_iterate(
const struct b_rope *rope, void (*func)(const b_rope *, void *), void *arg)
{
if (B_ROPE_TYPE(rope->r_flags) != B_ROPE_F_COMPOSITE) {
func(rope, arg);
return;
}
if (rope->r_v.v_composite.r_left) {
b_rope_iterate(rope->r_v.v_composite.r_left, func, arg);
}
if (rope->r_v.v_composite.r_right) {
b_rope_iterate(rope->r_v.v_composite.r_right, func, arg);
}
}
size_t b_rope_get_size(const struct b_rope *rope)
{
return rope->r_len_total;
@@ -181,56 +199,77 @@ static void rope_iterate(
}
}
struct to_cstr_args {
char *str;
size_t max;
size_t ptr;
};
static void to_cstr(const struct b_rope *rope, void *arg)
static void to_bstr(const struct b_rope *rope, void *arg)
{
struct to_cstr_args *str = arg;
if (str->ptr >= str->max) {
return;
}
b_bstr *str = arg;
unsigned int type = B_ROPE_TYPE(rope->r_flags);
char *dest = str->str + str->ptr;
size_t capacity = str->max - str->ptr;
size_t nr_written = 0;
switch (type) {
case B_ROPE_F_CHAR:
nr_written = snprintf(dest, capacity, "%c", rope->r_v.v_char);
b_bstr_write_char(str, rope->r_v.v_char);
break;
case B_ROPE_F_CSTR:
case B_ROPE_F_CSTR_BORROWED:
case B_ROPE_F_CSTR_STATIC:
nr_written = snprintf(dest, capacity, "%s", rope->r_v.v_cstr.s);
b_bstr_write_cstr(str, rope->r_v.v_cstr.s, NULL);
break;
case B_ROPE_F_INT:
nr_written
= snprintf(dest, capacity, "%" PRIdPTR, rope->r_v.v_int);
b_bstr_write_fmt(str, NULL, "%" PRIdPTR, rope->r_v.v_int);
break;
case B_ROPE_F_UINT:
nr_written
= snprintf(dest, capacity, "%" PRIuPTR, rope->r_v.v_uint);
b_bstr_write_fmt(str, NULL, "%" PRIuPTR, rope->r_v.v_uint);
break;
default:
break;
}
str->ptr += nr_written;
}
void b_rope_to_cstr(const struct b_rope *rope, char *out, size_t max)
static void to_stream(const struct b_rope *rope, void *arg)
{
struct to_cstr_args args = {
.str = out,
.max = max,
.ptr = 0,
};
b_stream *out = arg;
rope_iterate(rope, to_cstr, &args);
unsigned int type = B_ROPE_TYPE(rope->r_flags);
switch (type) {
case B_ROPE_F_CHAR:
b_stream_write_char(out, rope->r_v.v_char);
break;
case B_ROPE_F_CSTR:
case B_ROPE_F_CSTR_BORROWED:
case B_ROPE_F_CSTR_STATIC:
b_stream_write_string(out, rope->r_v.v_cstr.s, NULL);
break;
case B_ROPE_F_INT:
b_stream_write_fmt(out, NULL, "%" PRIdPTR, rope->r_v.v_int);
break;
case B_ROPE_F_UINT:
b_stream_write_fmt(out, NULL, "%" PRIuPTR, rope->r_v.v_uint);
break;
default:
break;
}
}
b_status b_rope_to_cstr(const struct b_rope *rope, char *out, size_t max)
{
b_bstr str;
b_bstr_begin(&str, out, max);
rope_iterate(rope, to_bstr, &str);
return B_SUCCESS;
}
b_status b_rope_to_bstr(const struct b_rope *rope, b_bstr *str)
{
rope_iterate(rope, to_bstr, str);
return B_SUCCESS;
}
b_status b_rope_to_string(const struct b_rope *rope, b_stream *out)
{
rope_iterate(rope, to_stream, out);
return B_SUCCESS;
}

View File

@@ -1,10 +1,14 @@
#include "printf.h"
#include <blue/core/bstr.h>
#include <blue/core/stream.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define READ_MAGIC(p) (*(uint64_t *)p)
#define IS_BSTR(p) (READ_MAGIC(p) == B_BSTR_MAGIC)
#define B_TYPE_STDIO_STREAM (b_stdio_stream_get_type())
#define STREAM_DISPATCH_VIRTUAL(func, stream, ...) \
@@ -369,6 +373,39 @@ static enum b_status stream_read_line_s(
return status;
}
static enum b_status stream_read_line_to_bstr(
struct stream_data *src, struct b_bstr *dest)
{
if (!(src->s_cfg->s_mode & B_STREAM_READ)) {
return B_ERR_NOT_SUPPORTED;
}
enum b_status status = B_SUCCESS;
size_t i = 0;
b_wchar c = 0;
while (1) {
status = stream_read_char(src, &c);
if (status != B_SUCCESS) {
break;
}
b_bstr_write_char(dest, c);
i++;
if (c == '\n') {
break;
}
}
if (status == B_ERR_NO_DATA && i > 0) {
status = B_SUCCESS;
}
return status;
}
static enum b_status stream_write_bytes(
struct stream_data *stream, const void *buf, size_t count, size_t *nr_written)
{
@@ -469,6 +506,57 @@ static enum b_status stream_read_all_bytes_s(
return status;
}
static enum b_status stream_read_all_bytes_to_bstr_s(
struct stream_data *src, struct b_bstr *dest,
struct b_stream_buffer_p *buffer, size_t *out_nr_read)
{
if (!(src->s_cfg->s_mode & B_STREAM_READ)) {
return B_ERR_NOT_SUPPORTED;
}
if (!buffer) {
return B_ERR_INVALID_ARGUMENT;
}
if (src->s_ops->s_seek) {
size_t offset = stream_cursor(src);
stream_seek(src, 0, B_STREAM_SEEK_END);
size_t length = stream_cursor(src);
stream_seek(src, offset, B_STREAM_SEEK_START);
b_bstr_reserve(dest, length);
}
enum b_status status = B_SUCCESS;
size_t nr_read = 0;
while (1) {
size_t r = 0, w = 0;
status = stream_read_bytes(
src, buffer->p_buf, buffer->p_buf_len, &r);
if (status != B_SUCCESS) {
break;
}
status = b_bstr_write_chars(dest, buffer->p_buf, r, &w);
nr_read += w;
if (status != B_SUCCESS || w != buffer->p_buf_len) {
break;
}
}
if (status == B_ERR_NO_DATA && nr_read > 0) {
status = B_SUCCESS;
}
if (out_nr_read) {
*out_nr_read = nr_read;
}
return status;
}
static enum b_status stream_write_string(
struct stream_data *stream, const char *s, size_t *nr_written)
{
@@ -642,6 +730,10 @@ b_stream *b_stream_open_fp(FILE *fp)
enum b_status b_stream_reserve(b_stream *stream, size_t len)
{
if (IS_BSTR(stream)) {
return B_ERR_NOT_SUPPORTED;
}
B_CLASS_DISPATCH_VIRTUAL(
b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_reserve, stream,
len);
@@ -650,6 +742,10 @@ enum b_status b_stream_reserve(b_stream *stream, size_t len)
enum b_status b_stream_seek(
b_stream *stream, long long offset, b_stream_seek_origin origin)
{
if (IS_BSTR(stream)) {
return B_ERR_NOT_SUPPORTED;
}
B_CLASS_DISPATCH_VIRTUAL(
b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_seek, stream,
offset, origin);
@@ -657,37 +753,65 @@ enum b_status b_stream_seek(
size_t b_stream_cursor(const b_stream *stream)
{
if (IS_BSTR(stream)) {
return b_bstr_get_size((b_bstr *)stream);
}
STREAM_DISPATCH_VIRTUAL_0(stream_cursor, stream);
}
enum b_status b_stream_push_indent(b_stream *strp, int indent)
{
if (IS_BSTR(strp)) {
return b_bstr_push_indent((b_bstr *)strp, indent);
}
STREAM_DISPATCH_VIRTUAL(stream_push_indent, strp, indent);
}
enum b_status b_stream_pop_indent(b_stream *strp)
{
if (IS_BSTR(strp)) {
return b_bstr_pop_indent((b_bstr *)strp);
}
STREAM_DISPATCH_VIRTUAL_0(stream_pop_indent, strp);
}
enum b_status b_stream_read_char(b_stream *strp, int *c)
{
if (IS_BSTR(strp)) {
return B_ERR_NOT_SUPPORTED;
}
STREAM_DISPATCH_VIRTUAL(stream_read_char, strp, c);
}
enum b_status b_stream_read_bytes(
b_stream *strp, void *buf, size_t count, size_t *nr_read)
{
if (IS_BSTR(strp)) {
return B_ERR_NOT_SUPPORTED;
}
STREAM_DISPATCH_VIRTUAL(stream_read_bytes, strp, buf, count, nr_read);
}
enum b_status b_stream_read_line(b_stream *strp, char *s, size_t max)
{
if (IS_BSTR(strp)) {
return B_ERR_NOT_SUPPORTED;
}
STREAM_DISPATCH_VIRTUAL(stream_read_line, strp, s, max);
}
enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest)
{
if (IS_BSTR(src)) {
return B_ERR_NOT_SUPPORTED;
}
enum b_status status;
struct stream_data src_p, dest_p;
@@ -696,6 +820,10 @@ enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest)
return status;
}
if (IS_BSTR(dest)) {
return stream_read_line_to_bstr(&src_p, (b_bstr *)dest);
}
status = stream_get_data(dest, &dest_p);
if (!B_OK(status)) {
return status;
@@ -707,12 +835,20 @@ enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest)
enum b_status b_stream_read_all_bytes(
b_stream *stream, void *p, size_t max, size_t *out_nr_read)
{
if (IS_BSTR(stream)) {
return B_ERR_NOT_SUPPORTED;
}
STREAM_DISPATCH_VIRTUAL(stream_read_all_bytes, stream, p, max, out_nr_read);
}
enum b_status b_stream_read_all_bytes_s(
b_stream *src, b_stream *dest, b_stream_buffer *buffer, size_t *out_nr_read)
{
if (IS_BSTR(src)) {
return B_ERR_NOT_SUPPORTED;
}
enum b_status status;
struct stream_data src_p, dest_p;
struct b_stream_buffer_p *buffer_p;
@@ -722,39 +858,66 @@ enum b_status b_stream_read_all_bytes_s(
return status;
}
status = stream_get_data(dest, &dest_p);
if (!B_OK(status)) {
return status;
}
buffer_p = b_object_get_private(buffer, B_TYPE_STREAM_BUFFER);
if (!buffer_p) {
return B_ERR_INVALID_ARGUMENT;
}
if (IS_BSTR(dest)) {
return stream_read_all_bytes_to_bstr_s(
&src_p, (b_bstr *)dest, buffer_p, out_nr_read);
}
status = stream_get_data(dest, &dest_p);
if (!B_OK(status)) {
return status;
}
return stream_read_all_bytes_s(&src_p, &dest_p, buffer_p, out_nr_read);
}
enum b_status b_stream_write_char(b_stream *stream, b_wchar c)
{
if (IS_BSTR(stream)) {
return b_bstr_write_char((b_bstr *)stream, c);
}
STREAM_DISPATCH_VIRTUAL(stream_write_char, stream, c);
}
enum b_status b_stream_write_string(
b_stream *stream, const char *s, size_t *nr_written)
{
if (IS_BSTR(stream)) {
return b_bstr_write_cstr((b_bstr *)stream, s, nr_written);
}
STREAM_DISPATCH_VIRTUAL(stream_write_string, stream, s, nr_written);
}
enum b_status b_stream_write_bytes(
b_stream *stream, const void *buf, size_t count, size_t *nr_written)
{
if (IS_BSTR(stream)) {
return b_bstr_write_chars((b_bstr *)stream, buf, count, nr_written);
}
STREAM_DISPATCH_VIRTUAL(stream_write_bytes, stream, buf, count, nr_written);
}
enum b_status b_stream_write_fmt(
b_stream *stream, size_t *nr_written, const char *format, ...)
{
if (IS_BSTR(stream)) {
va_list arg;
va_start(arg, format);
b_status w = b_bstr_write_vfmt(
(b_bstr *)stream, nr_written, format, arg);
va_end(arg);
return w;
}
struct stream_data p;
enum b_status status = stream_get_data(stream, &p);
@@ -773,6 +936,10 @@ enum b_status b_stream_write_fmt(
enum b_status b_stream_write_vfmt(
b_stream *stream, size_t *nr_written, const char *format, va_list arg)
{
if (IS_BSTR(stream)) {
return b_bstr_write_vfmt((b_bstr *)stream, nr_written, format, arg);
}
struct stream_data p;
enum b_status status = stream_get_data(stream, &p);

View File

@@ -10,6 +10,7 @@
struct b_stringstream_p {
char *ss_buf;
size_t ss_ptr;
size_t ss_len;
size_t ss_max;
unsigned char ss_alloc;
@@ -17,6 +18,50 @@ struct b_stringstream_p {
/*** PRIVATE FUNCTIONS ********************************************************/
static enum b_status __getc(struct b_stringstream_p *ss, b_wchar *out)
{
size_t available = ss->ss_len - ss->ss_ptr;
const char *p = ss->ss_buf + ss->ss_ptr;
size_t to_copy = b_wchar_utf8_codepoint_stride(p);
if (to_copy > available) {
return B_ERR_BAD_STATE;
}
b_wchar c = b_wchar_utf8_codepoint_decode(p);
*out = c;
if (c == B_WCHAR_INVALID) {
return B_ERR_BAD_STATE;
}
ss->ss_ptr += to_copy;
return B_SUCCESS;
}
static enum b_status __gets(
struct b_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 B_SUCCESS;
}
static enum b_status __puts(
struct b_stringstream_p *ss, const char *s, size_t len, size_t *nr_written)
{
@@ -111,7 +156,7 @@ b_stringstream *b_stringstream_create_with_buffer(char *buf, size_t max)
b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM);
struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM);
cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC;
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
p->ss_buf = buf;
p->ss_max = max;
@@ -131,7 +176,7 @@ b_stringstream *b_stringstream_create(void)
b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM);
struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM);
cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC;
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
if (!p->ss_buf) {
@@ -193,6 +238,26 @@ static void stringstream_fini(b_object *obj, void *priv)
}
}
enum b_status stream_getc(b_stream *stream, b_wchar *c)
{
struct b_stringstream_p *s
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
enum b_status status = __getc(s, c);
return status;
}
enum b_status stream_read(b_stream *stream, void *buf, size_t count, size_t *nr_read)
{
struct b_stringstream_p *s
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
enum b_status status = __gets(s, buf, count, nr_read);
return status;
}
enum b_status stream_write(
b_stream *stream, const void *buf, size_t count, size_t *nr_written)
{
@@ -215,8 +280,8 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_stringstream)
B_INTERFACE_ENTRY(s_close) = NULL;
B_INTERFACE_ENTRY(s_seek) = NULL;
B_INTERFACE_ENTRY(s_tell) = NULL;
B_INTERFACE_ENTRY(s_getc) = NULL;
B_INTERFACE_ENTRY(s_read) = NULL;
B_INTERFACE_ENTRY(s_getc) = stream_getc;
B_INTERFACE_ENTRY(s_read) = stream_read;
B_INTERFACE_ENTRY(s_write) = stream_write;
B_INTERFACE_ENTRY(s_reserve) = NULL;
B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM)

View File

@@ -0,0 +1,38 @@
#include <blue/ds/bitbuffer.h>
/*** PRIVATE DATA *************************************************************/
struct b_bitbuffer_p {
int x;
};
/*** PRIVATE FUNCTIONS ********************************************************/
/*** PUBLIC FUNCTIONS *********************************************************/
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
/*** VIRTUAL FUNCTIONS ********************************************************/
static void bitbuffer_init(b_object *obj, void *priv)
{
struct b_bitbuffer_p *bitbuffer = priv;
}
static void bitbuffer_fini(b_object *obj, void *priv)
{
struct b_bitbuffer_p *bitbuffer = priv;
}
/*** CLASS DEFINITION *********************************************************/
B_TYPE_CLASS_DEFINITION_BEGIN(b_bitbuffer)
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
B_INTERFACE_ENTRY(to_string) = NULL;
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
B_TYPE_CLASS_DEFINITION_END(b_bitbuffer)
B_TYPE_DEFINITION_BEGIN(b_bitbuffer)
B_TYPE_ID(0x628e33da, 0x3109, 0x4a5d, 0x98d5, 0xb0e4cb3ccb65);
B_TYPE_CLASS(b_bitbuffer_class);
B_TYPE_INSTANCE_PRIVATE(struct b_bitbuffer_p);
B_TYPE_INSTANCE_INIT(bitbuffer_init);
B_TYPE_INSTANCE_FINI(bitbuffer_fini);
B_TYPE_DEFINITION_END(b_bitbuffer)

View File

View File

@@ -366,6 +366,54 @@ bool b_hashmap_is_empty(const b_hashmap *hashmap)
B_CLASS_DISPATCH_STATIC_0(B_TYPE_HASHMAP, hashmap_is_empty, hashmap);
}
b_iterator *b_hashmap_begin(b_hashmap *hashmap)
{
b_hashmap_iterator *it_obj = b_object_create(B_TYPE_HASHMAP_ITERATOR);
struct b_hashmap_iterator_p *it
= b_object_get_private(it_obj, B_TYPE_HASHMAP_ITERATOR);
it->_h = hashmap;
it->_h_p = b_object_get_private(hashmap, B_TYPE_HASHMAP);
it->i = 0;
if (b_hashmap_is_empty(hashmap)) {
memset(&it->item, 0x0, sizeof it->item);
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return it_obj;
}
struct b_btree_node *first_node = b_btree_first(&it->_h_p->h_buckets);
struct b_hashmap_bucket *first_bucket
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
if (!first_bucket) {
memset(&it->item, 0x0, sizeof it->item);
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return it_obj;
}
struct b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
struct b_hashmap_bucket_item *first_item
= b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry);
if (!first_item) {
memset(&it->item, 0x0, sizeof it->item);
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return it_obj;
}
memcpy(&it->item.key, &first_item->bi_key, sizeof it->item.key);
memcpy(&it->item.value, &first_item->bi_value, sizeof it->item.value);
it->_cbn = first_node;
it->_cqe = first_entry;
return it_obj;
}
const b_iterator *b_hashmap_cbegin(const b_hashmap *hashmap)
{
return b_hashmap_begin((b_hashmap *)hashmap);
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void hashmap_init(b_object *obj, void *priv)
@@ -410,54 +458,6 @@ static void hashmap_fini(b_object *obj, void *priv)
/*** ITERATOR FUNCTIONS *******************************************************/
static b_iterator *iterable_begin(b_hashmap *hashmap)
{
b_hashmap_iterator *it_obj = b_object_create(B_TYPE_HASHMAP_ITERATOR);
struct b_hashmap_iterator_p *it
= b_object_get_private(it_obj, B_TYPE_HASHMAP_ITERATOR);
it->_h = hashmap;
it->_h_p = b_object_get_private(hashmap, B_TYPE_HASHMAP);
it->i = 0;
if (b_hashmap_is_empty(hashmap)) {
memset(&it->item, 0x0, sizeof it->item);
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return it_obj;
}
struct b_btree_node *first_node = b_btree_first(&it->_h_p->h_buckets);
struct b_hashmap_bucket *first_bucket
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
if (!first_bucket) {
memset(&it->item, 0x0, sizeof it->item);
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return it_obj;
}
struct b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
struct b_hashmap_bucket_item *first_item
= b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry);
if (!first_item) {
memset(&it->item, 0x0, sizeof it->item);
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
return it_obj;
}
memcpy(&it->item.key, &first_item->bi_key, sizeof it->item.key);
memcpy(&it->item.value, &first_item->bi_value, sizeof it->item.value);
it->_cbn = first_node;
it->_cqe = first_entry;
return 0;
}
static const b_iterator *iterable_cbegin(const b_hashmap *hashmap)
{
return iterable_begin((b_hashmap *)hashmap);
}
static enum b_status iterator_move_next(const b_iterator *obj)
{
struct b_hashmap_iterator_p *it
@@ -485,7 +485,7 @@ static enum b_status iterator_move_next(const b_iterator *obj)
it->_cbn = next_node;
it->_cqe = next_entry;
return true;
return B_SUCCESS;
}
static enum b_status iterator_erase(b_iterator *obj)
@@ -562,8 +562,8 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_hashmap)
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
B_INTERFACE_ENTRY(it_begin) = iterable_begin;
B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
B_INTERFACE_ENTRY(it_begin) = b_hashmap_begin;
B_INTERFACE_ENTRY(it_cbegin) = b_hashmap_cbegin;
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
B_TYPE_CLASS_DEFINITION_END(b_hashmap)

View File

@@ -1,22 +1,15 @@
#ifndef BLUE_OBJECT_BITBUFFER_H_
#define BLUE_OBJECT_BITBUFFER_H_
#ifndef BLUE_DS_BITBUFFER_H_
#define BLUE_DS_BITBUFFER_H_
#include <blue/ds/object.h>
#include <blue/core/macros.h>
#define B_BITBUFFER(p) ((b_bitbuffer *)(p))
B_DECLS_BEGIN;
typedef struct b_bitbuffer b_bitbuffer;
B_DECLARE_TYPE(b_bitbuffer);
BLUE_API b_bitbuffer *b_bitbuffer_create(void);
static inline b_bitbuffer *b_bitbuffer_retain(b_bitbuffer *buf)
{
return B_BITBUFFER(b_retain(B_DSREF(buf)));
}
static inline void b_bitbuffer_release(b_bitbuffer *buf)
{
b_release(B_DSREF(buf));
}
B_TYPE_CLASS_DECLARATION_BEGIN(b_bitbuffer)
;
B_TYPE_CLASS_DECLARATION_END(b_bitbuffer);
BLUE_API b_status b_bitbuffer_put_bit(b_bitbuffer *buf, int bit);
BLUE_API b_status b_bitbuffer_put_bool(b_bitbuffer *buf, bool b);
@@ -27,4 +20,6 @@ BLUE_API b_status b_bitbuffer_put_bytes(
BLUE_API b_status b_bitbuffer_put_string(
b_bitbuffer *buf, const char *p, size_t len, size_t bits_per_char);
B_DECLS_END;
#endif

View File

@@ -75,6 +75,9 @@ BLUE_API bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *k
BLUE_API size_t b_hashmap_get_size(const b_hashmap *hashmap);
BLUE_API bool b_hashmap_is_empty(const b_hashmap *hashmap);
BLUE_API b_iterator *b_hashmap_begin(b_hashmap *hashmap);
BLUE_API const b_iterator *b_hashmap_cbegin(const b_hashmap *hashmap);
B_DECLS_END;
#endif

View File

@@ -56,7 +56,7 @@ BLUE_API void b_list_delete_all(b_list *q);
BLUE_API void *b_list_entry_value(const b_list_entry *entry);
BLUE_API b_iterator *b_list_begin(b_list *q);
BLUE_API b_iterator *b_list_cbegin(const b_list *q);
BLUE_API const b_iterator *b_list_cbegin(const b_list *q);
B_DECLS_END;

View File

@@ -17,8 +17,11 @@ B_DECLARE_TYPE(b_uuid);
B_TYPE_CLASS_DECLARATION_BEGIN(b_uuid)
B_TYPE_CLASS_DECLARATION_END(b_uuid)
typedef struct b_uuid_bytes {
unsigned char uuid_bytes[B_UUID_NBYTES];
typedef union b_uuid_bytes {
uint8_t uuid_bytes[B_UUID_NBYTES];
uint16_t uuid_words[B_UUID_NBYTES / 2];
uint32_t uuid_dwords[B_UUID_NBYTES / 4];
uint64_t uuid_qwords[B_UUID_NBYTES / 8];
} b_uuid_bytes;
BLUE_API b_type b_uuid_get_type(void);

View File

@@ -365,22 +365,7 @@ void *b_list_entry_value(const struct b_list_entry *entry)
return entry ? entry->e_data : NULL;
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void list_init(b_object *obj, void *priv)
{
struct b_list_p *list = priv;
}
static void list_fini(b_object *obj, void *priv)
{
struct b_list_p *list = priv;
list_delete_all(list);
}
/*** ITERATOR FUNCTIONS *******************************************************/
static b_iterator *iterable_begin(b_list *q)
b_iterator *b_list_begin(b_list *q)
{
b_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR);
struct b_list_iterator_p *it
@@ -399,7 +384,7 @@ static b_iterator *iterable_begin(b_list *q)
return 0;
}
static const b_iterator *iterable_cbegin(const b_list *q)
const b_iterator *b_list_cbegin(const b_list *q)
{
b_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR);
struct b_list_iterator_p *it
@@ -418,6 +403,21 @@ static const b_iterator *iterable_cbegin(const b_list *q)
return 0;
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void list_init(b_object *obj, void *priv)
{
struct b_list_p *list = priv;
}
static void list_fini(b_object *obj, void *priv)
{
struct b_list_p *list = priv;
list_delete_all(list);
}
/*** ITERATOR FUNCTIONS *******************************************************/
static enum b_status iterator_move_next(const b_iterator *obj)
{
struct b_list_iterator_p *it
@@ -493,8 +493,8 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_list)
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
B_INTERFACE_ENTRY(it_begin) = iterable_begin;
B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
B_INTERFACE_ENTRY(it_begin) = b_list_begin;
B_INTERFACE_ENTRY(it_cbegin) = b_list_cbegin;
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
B_TYPE_CLASS_DEFINITION_END(b_list)

View File

@@ -8,7 +8,8 @@
#include <stdlib.h>
#include <string.h>
/* maximum length of string that can be stored inline, not including null-terminator */
/* maximum length of string that can be stored inline, not including
* null-terminator */
#define STRING_INLINE_CAPACITY 15
#define IS_VALID_UTF8_SCALAR(x) \
@@ -243,7 +244,8 @@ static int string_change_capacity(struct b_string_p *str, size_t capacity)
bool is_now_inline = capacity == STRING_INLINE_CAPACITY;
if (capacity == old_capacity) {
/* this also handles the case where the old and new capacity both fit into the inline buffer. */
/* this also handles the case where the old and new capacity
* both fit into the inline buffer. */
return 0;
}
@@ -1447,6 +1449,7 @@ static enum b_status chars_iterator_move_next(struct b_string_iterator_p *it)
it->codepoint_index += 1;
if (it->byte_index >= it->_s_p->s_len) {
it->char_value = B_WCHAR_INVALID;
return B_ERR_NO_DATA;
}

View File

@@ -9,7 +9,7 @@
/*** PRIVATE DATA *************************************************************/
struct b_uuid_p {
struct b_uuid_bytes uuid_bytes;
union b_uuid_bytes uuid_bytes;
};
/*** PRIVATE FUNCTIONS ********************************************************/
@@ -39,12 +39,12 @@ static void uuid_get_bytes(
}
static void uuid_get_uuid_bytes(
const struct b_uuid_p *uuid, struct b_uuid_bytes *bytes)
const struct b_uuid_p *uuid, union b_uuid_bytes *bytes)
{
memcpy(bytes, &uuid->uuid_bytes, sizeof *bytes);
}
static struct b_uuid_bytes *uuid_ptr(struct b_uuid_p *uuid)
static union b_uuid_bytes *uuid_ptr(struct b_uuid_p *uuid)
{
return &uuid->uuid_bytes;
}
@@ -101,7 +101,7 @@ b_uuid *b_uuid_create_from_bytev(const unsigned char bytes[B_UUID_NBYTES])
b_uuid *b_uuid_create_from_cstr(const char *str)
{
struct b_uuid_bytes bytes;
union b_uuid_bytes bytes;
bool valid = true;
bool is_guid = false;
@@ -169,19 +169,19 @@ void b_uuid_get_bytes(const b_uuid *uuid, unsigned char bytes[B_UUID_NBYTES])
B_CLASS_DISPATCH_STATIC(B_TYPE_UUID, uuid_get_bytes, uuid, bytes);
}
void b_uuid_get_uuid_bytes(const b_uuid *uuid, struct b_uuid_bytes *bytes)
void b_uuid_get_uuid_bytes(const b_uuid *uuid, union b_uuid_bytes *bytes)
{
B_CLASS_DISPATCH_STATIC(B_TYPE_UUID, uuid_get_uuid_bytes, uuid, bytes);
}
struct b_uuid_bytes *b_uuid_ptr(b_uuid *uuid)
union b_uuid_bytes *b_uuid_ptr(b_uuid *uuid)
{
B_CLASS_DISPATCH_STATIC_0(B_TYPE_UUID, uuid_ptr, uuid);
}
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
b_uuid *b_uuid_create_from_uuid_bytes(const struct b_uuid_bytes *bytes)
b_uuid *b_uuid_create_from_uuid_bytes(const union b_uuid_bytes *bytes)
{
return b_uuid_create_from_bytev(bytes->uuid_bytes);
}

View File

@@ -1,6 +1,60 @@
#include <blue/core/rope.h>
#include <inttypes.h>
#include <stdio.h>
static void print_rope(const struct b_rope *rope, int depth)
{
for (int i = 0; i < depth; i++) {
printf(" ");
}
printf("[%x:", rope->r_flags);
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_CHAR) && printf(" CHAR");
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_CSTR) && printf(" CSTR");
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_CSTR_BORROWED)
&& printf(" CSTR_BORROWED");
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_CSTR_STATIC)
&& printf(" CSTR_STATIC");
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_INT) && printf(" INT");
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_UINT) && printf(" UINT");
(B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_COMPOSITE)
&& printf(" COMPOSITE");
(rope->r_flags & B_ROPE_F_MALLOC) && printf(" MALLOC");
printf("] ");
switch (B_ROPE_TYPE(rope->r_flags)) {
case B_ROPE_F_CHAR:
printf("%c", rope->r_v.v_char);
break;
case B_ROPE_F_CSTR:
case B_ROPE_F_CSTR_BORROWED:
case B_ROPE_F_CSTR_STATIC:
printf("%s", rope->r_v.v_cstr.s);
break;
case B_ROPE_F_INT:
printf("%" PRIdPTR, rope->r_v.v_int);
break;
case B_ROPE_F_UINT:
printf("%" PRIuPTR, rope->r_v.v_uint);
break;
default:
break;
}
printf("\n");
if (B_ROPE_TYPE(rope->r_flags) == B_ROPE_F_COMPOSITE) {
if (rope->r_v.v_composite.r_left) {
print_rope(rope->r_v.v_composite.r_left, depth + 1);
}
if (rope->r_v.v_composite.r_right) {
print_rope(rope->r_v.v_composite.r_right, depth + 1);
}
}
}
int main(void)
{
b_rope a = B_ROPE_CHAR('a');
@@ -19,6 +73,8 @@ int main(void)
b_rope_join(&str, ropes, sizeof ropes / sizeof ropes[0]);
print_rope(&str, 0);
char cstr[1024];
b_rope_to_cstr(&str, cstr, sizeof cstr);
b_rope_destroy(&str);

View File

@@ -1,3 +1,4 @@
#include <blue/core/bstr.h>
#include <blue/core/stream.h>
#include <stdio.h>
@@ -6,5 +7,15 @@ int main(void)
b_stream_read_line_s(b_stdin, b_stdout);
b_stream_write_char(b_stdout, '\n');
char s[16];
b_bstr str;
b_bstr_begin(&str, s, sizeof s);
b_stream_read_line_s(b_stdin, (b_stream *)&str);
b_stream_write_char((b_stream *)&str, '\n');
const char *e = b_bstr_end(&str);
fputs(e, stdout);
return 0;
}