From 61b02adc50603fce6f4d9af486eda8ca5add1898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Sj=C3=B6berg?= Date: Wed, 10 Nov 2021 15:46:34 +0100 Subject: [PATCH 0001/1258] Do not filter test procedures when filter is empty If `build_context.test_names` is empty, we do not need to perform any filtering. --- src/checker.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/checker.cpp b/src/checker.cpp index cffaad348..695606a38 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4773,6 +4773,10 @@ void check_unchecked_bodies(Checker *c) { } void check_test_procedures(Checker *c) { + if (build_context.test_names.entries.count == 0) { + return; + } + AstPackage *pkg = c->info.init_package; Scope *s = pkg->scope; From a75dc9d86d25a061bec0bfe79b2d8ce45e0c1357 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 13 Nov 2021 19:07:16 +0000 Subject: [PATCH 0002/1258] Fix minor issue with unmarshal for booleans --- core/encoding/json/unmarshal.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index 23518d8d0..fe3137b7e 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -222,6 +222,7 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { advance_token(p) return case .False, .True: + advance_token(p) if assign_bool(v, token.kind == .True) { return } From b9701340b8faff107fe6a515d5de429141508f48 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 13 Nov 2021 19:15:37 +0000 Subject: [PATCH 0003/1258] Add `linalg.matrix4_look_at_from_fru` --- core/math/linalg/specific.odin | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/core/math/linalg/specific.odin b/core/math/linalg/specific.odin index 3729b0954..5cb68e3a8 100644 --- a/core/math/linalg/specific.odin +++ b/core/math/linalg/specific.odin @@ -2033,6 +2033,55 @@ matrix4_look_at :: proc{ } +matrix4_look_at_from_fru_f16 :: proc(eye, f, r, u: Vector3f16, flip_z_axis := true) -> (m: Matrix4f16) { + f, s, u := f, r, u + f = normalize(f) + s = normalize(s) + u = normalize(u) + fe := dot(f, eye) + + return { + {+s.x, +u.x, -f.x, 0}, + {+s.y, +u.y, -f.y, 0}, + {+s.z, +u.z, -f.z, 0}, + {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + } +} +matrix4_look_at_from_fru_f32 :: proc(eye, f, r, u: Vector3f32, flip_z_axis := true) -> (m: Matrix4f32) { + f, s, u := f, r, u + f = normalize(f) + s = normalize(s) + u = normalize(u) + fe := dot(f, eye) + + return { + {+s.x, +u.x, -f.x, 0}, + {+s.y, +u.y, -f.y, 0}, + {+s.z, +u.z, -f.z, 0}, + {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + } +} +matrix4_look_at_from_fru_f64 :: proc(eye, f, r, u: Vector3f64, flip_z_axis := true) -> (m: Matrix4f64) { + f, s, u := f, r, u + f = normalize(f) + s = normalize(s) + u = normalize(u) + fe := dot(f, eye) + + return { + {+s.x, +u.x, -f.x, 0}, + {+s.y, +u.y, -f.y, 0}, + {+s.z, +u.z, -f.z, 0}, + {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + } +} +matrix4_look_at_from_fru :: proc{ + matrix4_look_at_from_fru_f16, + matrix4_look_at_from_fru_f32, + matrix4_look_at_from_fru_f64, +} + + matrix4_perspective_f16 :: proc(fovy, aspect, near, far: f16, flip_z_axis := true) -> (m: Matrix4f16) { tan_half_fovy := math.tan(0.5 * fovy) m[0][0] = 1 / (aspect*tan_half_fovy) From 3f038428a7f282468011415db76da4bf08ddb67c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Nov 2021 15:12:37 +0000 Subject: [PATCH 0004/1258] Begin minimizing `Ast` size --- src/check_expr.cpp | 6 +++--- src/check_stmt.cpp | 2 +- src/check_type.cpp | 5 +++-- src/checker.cpp | 2 +- src/llvm_backend.cpp | 6 +++--- src/llvm_backend_debug.cpp | 12 ++++++------ src/llvm_backend_proc.cpp | 4 ++-- src/llvm_backend_stmt.cpp | 5 +++-- src/parser.cpp | 20 ++++++++++++-------- src/parser.hpp | 27 +++++++++++++++++---------- 10 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7a0273805..96ca2d308 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8413,14 +8413,14 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (check_is_assignable_to(c, &z, first_type)) { // NOTE(bill): AST GENERATION HACK! Token op = {Token_Pointer}; - first_arg = ast_deref_expr(first_arg->file, first_arg, op); + first_arg = ast_deref_expr(first_arg->file(), first_arg, op); } else if (y.mode == Addressing_Variable) { Operand w = y; w.type = alloc_type_pointer(y.type); if (check_is_assignable_to(c, &w, first_type)) { // NOTE(bill): AST GENERATION HACK! Token op = {Token_And}; - first_arg = ast_unary_expr(first_arg->file, op, first_arg); + first_arg = ast_unary_expr(first_arg->file(), op, first_arg); } } } @@ -8443,7 +8443,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } if (!fail && first_is_field_value) { Token op = {Token_Eq}; - AstFile *f = first_arg->file; + AstFile *f = first_arg->file(); first_arg = ast_field_value(f, ast_ident(f, make_token_ident(first_arg_name)), first_arg, op); } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 24ad0eec1..b5e3d8c88 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1616,7 +1616,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } Operand lhs = {Addressing_Invalid}; Operand rhs = {Addressing_Invalid}; - Ast *binary_expr = alloc_ast_node(node->file, Ast_BinaryExpr); + Ast *binary_expr = alloc_ast_node(node->file(), Ast_BinaryExpr); ast_node(be, BinaryExpr, binary_expr); be->op = op; be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add)); diff --git a/src/check_type.cpp b/src/check_type.cpp index 398967af8..b7feb562d 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1939,8 +1939,9 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, error(proc_type_node, "A procedure type with the #optional_second tag requires 2 return values, got %td", result_count); } else { bool ok = false; - if (proc_type_node->file && proc_type_node->file->pkg) { - ok = proc_type_node->file->pkg->scope == ctx->info->runtime_package->scope; + AstFile *file = proc_type_node->file(); + if (file && file->pkg) { + ok = file->pkg->scope == ctx->info->runtime_package->scope; } if (!ok) { diff --git a/src/checker.cpp b/src/checker.cpp index cffaad348..4ae8fd456 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3712,7 +3712,7 @@ String path_to_entity_name(String name, String fullpath, bool strip_extension=tr #if 1 void add_import_dependency_node(Checker *c, Ast *decl, PtrMap *M) { - AstPackage *parent_pkg = decl->file->pkg; + AstPackage *parent_pkg = decl->file()->pkg; switch (decl->kind) { case_ast_node(id, ImportDecl, decl); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index e468f3032..5acd2a80f 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -454,7 +454,7 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A token.kind = Token_Ident; token.string = name; Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags); - e->file = expr->file; + e->file = expr->file(); e->decl_info = pl->decl; e->code_gen_module = m; e->flags |= EntityFlag_ProcBodyChecked; @@ -1278,8 +1278,8 @@ void lb_generate_code(lbGenerator *gen) { if (Entity *entry_point = m->info->entry_point) { if (Ast *ident = entry_point->identifier.load()) { - if (ident->file) { - init_file = ident->file; + if (ident->file_id) { + init_file = ident->file(); } } } diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index a890c56ef..7a2b00fe9 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -18,7 +18,7 @@ LLVMMetadataRef lb_get_llvm_file_metadata_from_node(lbModule *m, Ast *node) { if (node == nullptr) { return nullptr; } - return lb_get_llvm_metadata(m, node->file); + return lb_get_llvm_metadata(m, node->file()); } LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) { @@ -660,7 +660,7 @@ void lb_debug_complete_types(lbModule *m) { case Type_Struct: if (file == nullptr) { if (bt->Struct.node) { - file = lb_get_llvm_metadata(m, bt->Struct.node->file); + file = lb_get_llvm_metadata(m, bt->Struct.node->file()); line_number = cast(unsigned)ast_token(bt->Struct.node).pos.line; } } @@ -741,7 +741,7 @@ void lb_debug_complete_types(lbModule *m) { { if (file == nullptr) { GB_ASSERT(bt->Union.node != nullptr); - file = lb_get_llvm_metadata(m, bt->Union.node->file); + file = lb_get_llvm_metadata(m, bt->Union.node->file()); line_number = cast(unsigned)ast_token(bt->Union.node).pos.line; } @@ -801,7 +801,7 @@ void lb_debug_complete_types(lbModule *m) { { if (file == nullptr) { GB_ASSERT(bt->BitSet.node != nullptr); - file = lb_get_llvm_metadata(m, bt->BitSet.node->file); + file = lb_get_llvm_metadata(m, bt->BitSet.node->file()); line_number = cast(unsigned)ast_token(bt->BitSet.node).pos.line; } @@ -929,7 +929,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T } - AstFile *file = p->body->file; + AstFile *file = p->body->file(); LLVMMetadataRef llvm_scope = lb_get_current_debug_scope(p); LLVMMetadataRef llvm_file = lb_get_llvm_metadata(m, file); @@ -975,7 +975,7 @@ void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) { } TokenPos pos = {}; - pos.file_id = p->body->file ? p->body->file->id : 0; + pos.file_id = p->body->file_id; pos.line = LLVMDILocationGetLine(loc); pos.column = LLVMDILocationGetColumn(loc); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 8b8559cae..25b27ee47 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -258,8 +258,8 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) if (entity->file != nullptr) { file = lb_get_llvm_metadata(m, entity->file); scope = file; - } else if (ident != nullptr && ident->file != nullptr) { - file = lb_get_llvm_metadata(m, ident->file); + } else if (ident != nullptr && ident->file_id != 0) { + file = lb_get_llvm_metadata(m, ident->file()); scope = file; } else if (entity->scope != nullptr) { file = lb_get_llvm_metadata(m, entity->scope->file); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9d3d2c949..ec8ded7fa 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -212,8 +212,9 @@ void lb_open_scope(lbProcedure *p, Scope *s) { unsigned column = cast(unsigned)token.pos.column; LLVMMetadataRef file = nullptr; - if (s->node->file != nullptr) { - file = lb_get_llvm_metadata(m, s->node->file); + AstFile *ast_file = s->node->file(); + if (ast_file != nullptr) { + file = lb_get_llvm_metadata(m, ast_file); } LLVMMetadataRef scope = nullptr; if (p->scope_stack.count > 0) { diff --git a/src/parser.cpp b/src/parser.cpp index 12888a52d..ba5df1f27 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -65,7 +65,7 @@ Ast *alloc_ast_node(AstFile *f, AstKind kind) { Ast *node = cast(Ast *)gb_alloc(a, size); node->kind = kind; - node->file = f; + node->file_id = f ? f->id : 0; return node; } @@ -95,7 +95,8 @@ Ast *clone_ast(Ast *node) { if (node == nullptr) { return nullptr; } - Ast *n = alloc_ast_node(node->file, node->kind); + AstFile *f = get_ast_file_from_id(node->file_id); + Ast *n = alloc_ast_node(f, node->kind); gb_memmove(n, node, ast_node_size(node->kind)); switch (n->kind) { @@ -399,8 +400,9 @@ void error(Ast *node, char const *fmt, ...) { va_start(va, fmt); error_va(token.pos, end_pos, fmt, va); va_end(va); - if (node != nullptr && node->file != nullptr) { - node->file->error_count += 1; + if (node != nullptr && node->file_id != 0) { + AstFile *f = get_ast_file_from_id(node->file_id); + f->error_count += 1; } } @@ -413,8 +415,9 @@ void error_no_newline(Ast *node, char const *fmt, ...) { va_start(va, fmt); error_no_newline_va(token.pos, fmt, va); va_end(va); - if (node != nullptr && node->file != nullptr) { - node->file->error_count += 1; + if (node != nullptr && node->file_id != 0) { + AstFile *f = get_ast_file_from_id(node->file_id); + f->error_count += 1; } } @@ -442,8 +445,9 @@ void syntax_error(Ast *node, char const *fmt, ...) { va_start(va, fmt); syntax_error_va(token.pos, end_pos, fmt, va); va_end(va); - if (node != nullptr && node->file != nullptr) { - node->file->error_count += 1; + if (node != nullptr && node->file_id != 0) { + AstFile *f = get_ast_file_from_id(node->file_id); + f->error_count += 1; } } diff --git a/src/parser.hpp b/src/parser.hpp index 418d035c4..76ae33b21 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -255,14 +255,14 @@ ProcCallingConvention default_calling_convention(void) { return ProcCC_Odin; } -enum StateFlag : u16 { +enum StateFlag : u8 { StateFlag_bounds_check = 1<<0, StateFlag_no_bounds_check = 1<<1, - StateFlag_BeenHandled = 1<<15, + StateFlag_BeenHandled = 1<<7, }; -enum ViralStateFlag : u16 { +enum ViralStateFlag : u8 { ViralStateFlag_ContainsDeferredProcedure = 1<<0, }; @@ -666,7 +666,7 @@ AST_KIND(_TypeBegin, "", bool) \ }) \ AST_KIND(_TypeEnd, "", bool) -enum AstKind { +enum AstKind : u16 { Ast_Invalid, #define AST_KIND(_kind_name_, ...) GB_JOIN2(Ast_, _kind_name_), AST_KINDS @@ -696,18 +696,18 @@ isize const ast_variant_sizes[] = { struct AstCommonStuff { AstKind kind; - u16 state_flags; - u16 viral_state_flags; - AstFile * file; + u8 state_flags; + u8 viral_state_flags; + i32 file_id; Scope * scope; TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size }; struct Ast { AstKind kind; - u16 state_flags; - u16 viral_state_flags; - AstFile * file; + u8 state_flags; + u8 viral_state_flags; + i32 file_id; Scope * scope; TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size @@ -717,6 +717,13 @@ struct Ast { AST_KINDS #undef AST_KIND }; + + + // NOTE(bill): I know I dislike methods but this is hopefully a temporary thing + // for refactoring purposes + AstFile *file() const { + return get_ast_file_from_id(this->file_id); + } }; From f47311f2f6c59856efd64c56101cc004d1b15bc2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Nov 2021 15:22:40 +0000 Subject: [PATCH 0005/1258] Remove `scope` field from `Ast` --- src/check_decl.cpp | 3 --- src/check_stmt.cpp | 14 ++++++------- src/checker.cpp | 41 +++++++++++++++++++++++++++++++++++---- src/checker.hpp | 1 - src/llvm_backend_stmt.cpp | 16 +++++++-------- src/parser.hpp | 22 +++++++++++++++------ 6 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 134dbb35b..42f68203c 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1302,9 +1302,6 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty Type *t = base_type(type_deref(e->type)); if (t->kind == Type_Struct) { Scope *scope = t->Struct.scope; - if (scope == nullptr) { - scope = scope_of_node(t->Struct.node); - } GB_ASSERT(scope != nullptr); for_array(i, scope->elements.entries) { Entity *f = scope->elements.entries[i].value; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index b5e3d8c88..1a424240c 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -635,10 +635,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b bool is_ptr = is_type_pointer(e->type); Type *t = base_type(type_deref(e->type)); if (t->kind == Type_Struct) { - Scope *found = scope_of_node(t->Struct.node); - if (found == nullptr) { - found = t->Struct.scope; - } + Scope *found = t->Struct.scope; GB_ASSERT(found != nullptr); for_array(i, found->elements.entries) { Entity *f = found->elements.entries[i].value; @@ -1399,9 +1396,9 @@ void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { ast_node(bs, BlockStmt, body); // NOTE(bill, 2020-09-23): This logic is prevent common erros with block statements // e.g. if cond { x := 123; } // this is an error - if (body->scope != nullptr && body->scope->elements.entries.count > 0) { - if (body->scope->parent->node != nullptr) { - switch (body->scope->parent->node->kind) { + if (bs->scope != nullptr && bs->scope->elements.entries.count > 0) { + if (bs->scope->parent->node != nullptr) { + switch (bs->scope->parent->node->kind) { case Ast_IfStmt: case Ast_ForStmt: case Ast_RangeStmt: @@ -2339,7 +2336,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } else if (is_type_struct(t) || is_type_raw_union(t)) { ERROR_BLOCK(); - Scope *scope = scope_of_node(t->Struct.node); + Scope *scope = t->Struct.scope; + GB_ASSERT(scope != nullptr); for_array(i, scope->elements.entries) { Entity *f = scope->elements.entries[i].value; if (f->kind == Entity_Variable) { diff --git a/src/checker.cpp b/src/checker.cpp index 4ae8fd456..3caed256a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -318,7 +318,43 @@ void add_scope(CheckerContext *c, Ast *node, Scope *scope) { GB_ASSERT(node != nullptr); GB_ASSERT(scope != nullptr); scope->node = node; - node->scope = scope; + switch (node->kind) { + case Ast_BlockStmt: node->BlockStmt.scope = scope; break; + case Ast_IfStmt: node->IfStmt.scope = scope; break; + case Ast_ForStmt: node->ForStmt.scope = scope; break; + case Ast_RangeStmt: node->RangeStmt.scope = scope; break; + case Ast_UnrollRangeStmt: node->UnrollRangeStmt.scope = scope; break; + case Ast_CaseClause: node->CaseClause.scope = scope; break; + case Ast_SwitchStmt: node->SwitchStmt.scope = scope; break; + case Ast_TypeSwitchStmt: node->TypeSwitchStmt.scope = scope; break; + case Ast_ProcType: node->ProcType.scope = scope; break; + case Ast_StructType: node->StructType.scope = scope; break; + case Ast_UnionType: node->UnionType.scope = scope; break; + case Ast_EnumType: node->EnumType.scope = scope; break; + default: GB_PANIC("Invalid node for add_scope: %.*s", LIT(ast_strings[node->kind])); + } +} + +Scope *scope_of_node(Ast *node) { + if (node == nullptr) { + return nullptr; + } + switch (node->kind) { + case Ast_BlockStmt: return node->BlockStmt.scope; + case Ast_IfStmt: return node->IfStmt.scope; + case Ast_ForStmt: return node->ForStmt.scope; + case Ast_RangeStmt: return node->RangeStmt.scope; + case Ast_UnrollRangeStmt: return node->UnrollRangeStmt.scope; + case Ast_CaseClause: return node->CaseClause.scope; + case Ast_SwitchStmt: return node->SwitchStmt.scope; + case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.scope; + case Ast_ProcType: return node->ProcType.scope; + case Ast_StructType: return node->StructType.scope; + case Ast_UnionType: return node->UnionType.scope; + case Ast_EnumType: return node->EnumType.scope; + } + GB_PANIC("Invalid node for add_scope: %.*s", LIT(ast_strings[node->kind])); + return nullptr; } @@ -1081,9 +1117,6 @@ AstFile *ast_file_of_filename(CheckerInfo *i, String filename) { } return nullptr; } -Scope *scope_of_node(Ast *node) { - return node->scope; -} ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) { if (c->untyped != nullptr) { ExprInfo **found = map_get(c->untyped, expr); diff --git a/src/checker.hpp b/src/checker.hpp index 6511dad32..74435c1d4 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -410,7 +410,6 @@ gb_global AstPackage *config_pkg = nullptr; TypeAndValue type_and_value_of_expr (Ast *expr); Type * type_of_expr (Ast *expr); Entity * implicit_entity_of_node(Ast *clause); -Scope * scope_of_node (Ast *node); DeclInfo * decl_info_of_ident (Ast *ident); DeclInfo * decl_info_of_entity (Entity * e); AstFile * ast_file_of_filename (CheckerInfo *i, String filename); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index ec8ded7fa..c2ff0dfe1 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1625,7 +1625,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice const &return_results) { void lb_build_if_stmt(lbProcedure *p, Ast *node) { ast_node(is, IfStmt, node); - lb_open_scope(p, node->scope); // Scope #1 + lb_open_scope(p, is->scope); // Scope #1 defer (lb_close_scope(p, lbDeferExit_Default, nullptr)); if (is->init != nullptr) { @@ -1675,7 +1675,7 @@ void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_emit_jump(p, else_); lb_start_block(p, else_); - lb_open_scope(p, is->else_stmt->scope); + lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); lb_close_scope(p, lbDeferExit_Default, nullptr); } @@ -1692,7 +1692,7 @@ void lb_build_if_stmt(lbProcedure *p, Ast *node) { if (is->else_stmt != nullptr) { lb_start_block(p, else_); - lb_open_scope(p, is->else_stmt->scope); + lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); lb_close_scope(p, lbDeferExit_Default, nullptr); @@ -1710,7 +1710,7 @@ void lb_build_if_stmt(lbProcedure *p, Ast *node) { void lb_build_for_stmt(lbProcedure *p, Ast *node) { ast_node(fs, ForStmt, node); - lb_open_scope(p, node->scope); // Open Scope here + lb_open_scope(p, fs->scope); // Open Scope here if (fs->init != nullptr) { #if 1 @@ -2056,7 +2056,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { tl->is_block = true; } - lb_open_scope(p, node->scope); + lb_open_scope(p, bs->scope); lb_build_stmt_list(p, bs->stmts); lb_close_scope(p, lbDeferExit_Default, nullptr); @@ -2137,15 +2137,15 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { case_end; case_ast_node(rs, RangeStmt, node); - lb_build_range_stmt(p, rs, node->scope); + lb_build_range_stmt(p, rs, rs->scope); case_end; case_ast_node(rs, UnrollRangeStmt, node); - lb_build_unroll_range_stmt(p, rs, node->scope); + lb_build_unroll_range_stmt(p, rs, rs->scope); case_end; case_ast_node(ss, SwitchStmt, node); - lb_build_switch_stmt(p, ss, node->scope); + lb_build_switch_stmt(p, ss, ss->scope); case_end; case_ast_node(ss, TypeSwitchStmt, node); diff --git a/src/parser.hpp b/src/parser.hpp index 76ae33b21..b1518533e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -424,11 +424,13 @@ AST_KIND(_StmtBegin, "", bool) \ }) \ AST_KIND(_ComplexStmtBegin, "", bool) \ AST_KIND(BlockStmt, "block statement", struct { \ + Scope *scope; \ Slice stmts; \ Ast *label; \ Token open, close; \ }) \ AST_KIND(IfStmt, "if statement", struct { \ + Scope *scope; \ Token token; \ Ast *label; \ Ast * init; \ @@ -449,6 +451,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Slice results; \ }) \ AST_KIND(ForStmt, "for statement", struct { \ + Scope *scope; \ Token token; \ Ast *label; \ Ast *init; \ @@ -457,6 +460,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Ast *body; \ }) \ AST_KIND(RangeStmt, "range statement", struct { \ + Scope *scope; \ Token token; \ Ast *label; \ Slice vals; \ @@ -465,6 +469,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Ast *body; \ }) \ AST_KIND(UnrollRangeStmt, "#unroll range statement", struct { \ + Scope *scope; \ Token unroll_token; \ Token for_token; \ Ast *val0; \ @@ -474,12 +479,14 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Ast *body; \ }) \ AST_KIND(CaseClause, "case clause", struct { \ + Scope *scope; \ Token token; \ Slice list; \ Slice stmts; \ Entity *implicit_entity; \ }) \ AST_KIND(SwitchStmt, "switch statement", struct { \ + Scope *scope; \ Token token; \ Ast *label; \ Ast *init; \ @@ -488,6 +495,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ bool partial; \ }) \ AST_KIND(TypeSwitchStmt, "type switch statement", struct { \ + Scope *scope; \ Token token; \ Ast *label; \ Ast *tag; \ @@ -589,6 +597,7 @@ AST_KIND(_TypeBegin, "", bool) \ Ast * specialization; \ }) \ AST_KIND(ProcType, "procedure type", struct { \ + Scope *scope; \ Token token; \ Ast *params; \ Ast *results; \ @@ -621,6 +630,7 @@ AST_KIND(_TypeBegin, "", bool) \ Ast *tag; \ }) \ AST_KIND(StructType, "struct type", struct { \ + Scope *scope; \ Token token; \ Slice fields; \ isize field_count; \ @@ -632,6 +642,7 @@ AST_KIND(_TypeBegin, "", bool) \ bool is_raw_union; \ }) \ AST_KIND(UnionType, "union type", struct { \ + Scope *scope; \ Token token; \ Slice variants; \ Ast *polymorphic_params; \ @@ -642,6 +653,7 @@ AST_KIND(_TypeBegin, "", bool) \ Slice where_clauses; \ }) \ AST_KIND(EnumType, "enum type", struct { \ + Scope *scope; \ Token token; \ Ast * base_type; \ Slice fields; /* FieldValue */ \ @@ -695,21 +707,19 @@ isize const ast_variant_sizes[] = { }; struct AstCommonStuff { - AstKind kind; + AstKind kind; // u16 u8 state_flags; u8 viral_state_flags; i32 file_id; - Scope * scope; - TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size + TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size }; struct Ast { - AstKind kind; + AstKind kind; // u16 u8 state_flags; u8 viral_state_flags; i32 file_id; - Scope * scope; - TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size + TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size // IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant union { From f55fc4cd08dba25730fa1c74d31611cf27ef2155 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Nov 2021 17:25:29 +0000 Subject: [PATCH 0006/1258] Add `complex32` and `quaternion64` for the 16-bit float types to `fmt` --- core/fmt/fmt.odin | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 06cb6703f..a9ff6ca47 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2076,9 +2076,11 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case f32be: fmt_float(fi, f64(a), 32, verb) case f64be: fmt_float(fi, f64(a), 64, verb) + case complex32: fmt_complex(fi, complex128(a), 32, verb) case complex64: fmt_complex(fi, complex128(a), 64, verb) case complex128: fmt_complex(fi, a, 128, verb) + case quaternion64: fmt_quaternion(fi, quaternion256(a), 64, verb) case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb) case quaternion256: fmt_quaternion(fi, a, 256, verb) From e814a3693f9efbdd00113de4dd5937acd97bc486 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Nov 2021 17:26:01 +0000 Subject: [PATCH 0007/1258] Improve usage of `file_id` --- src/check_builtin.cpp | 4 +-- src/checker.cpp | 4 +-- src/common.cpp | 63 ++++++++++++++++++++++++++++++++++--------- src/docs_writer.cpp | 2 +- src/parser.cpp | 12 ++++----- src/parser.hpp | 8 ++++-- src/ptr_set.cpp | 4 ++- src/thread_pool.cpp | 2 +- src/tokenizer.cpp | 6 ++--- 9 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d910314fb..f93cf9886 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -446,9 +446,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } else if (hash_kind == "fnv64") { hash_value = gb_fnv64(data, file_size); } else if (hash_kind == "fnv32a") { - hash_value = gb_fnv32a(data, file_size); + hash_value = fnv32a(data, file_size); } else if (hash_kind == "fnv64a") { - hash_value = gb_fnv64a(data, file_size); + hash_value = fnv64a(data, file_size); } else if (hash_kind == "murmur32") { hash_value = gb_murmur32(data, file_size); } else if (hash_kind == "murmur64") { diff --git a/src/checker.cpp b/src/checker.cpp index 3caed256a..fa74c23ed 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -225,8 +225,8 @@ bool decl_info_has_init(DeclInfo *d) { Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) { Scope *s = gb_alloc_item(permanent_allocator(), Scope); s->parent = parent; - string_map_init(&s->elements, heap_allocator(), init_elements_capacity); - ptr_set_init(&s->imported, heap_allocator(), 0); + string_map_init(&s->elements, permanent_allocator(), init_elements_capacity); + ptr_set_init(&s->imported, permanent_allocator(), 0); mutex_init(&s->mutex); if (parent != nullptr && parent != builtin_pkg->scope) { diff --git a/src/common.cpp b/src/common.cpp index cca478421..ab2a46118 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -83,9 +83,20 @@ int i32_cmp(i32 x, i32 y) { u32 fnv32a(void const *data, isize len) { u8 const *bytes = cast(u8 const *)data; u32 h = 0x811c9dc5; - for (isize i = 0; i < len; i++) { - u32 b = cast(u32)bytes[i]; - h = (h ^ b) * 0x01000193; + + for (; len >= 8; len -= 8, bytes += 8) { + h = (h ^ bytes[0]) * 0x01000193; + h = (h ^ bytes[1]) * 0x01000193; + h = (h ^ bytes[2]) * 0x01000193; + h = (h ^ bytes[3]) * 0x01000193; + h = (h ^ bytes[4]) * 0x01000193; + h = (h ^ bytes[5]) * 0x01000193; + h = (h ^ bytes[6]) * 0x01000193; + h = (h ^ bytes[7]) * 0x01000193; + } + + while (len--) { + h = (h ^ *bytes++) * 0x01000193; } return h; } @@ -93,20 +104,48 @@ u32 fnv32a(void const *data, isize len) { u64 fnv64a(void const *data, isize len) { u8 const *bytes = cast(u8 const *)data; u64 h = 0xcbf29ce484222325ull; - for (isize i = 0; i < len; i++) { - u64 b = cast(u64)bytes[i]; - h = (h ^ b) * 0x100000001b3ull; + + for (; len >= 8; len -= 8, bytes += 8) { + h = (h ^ bytes[0]) * 0x100000001b3ull; + h = (h ^ bytes[1]) * 0x100000001b3ull; + h = (h ^ bytes[2]) * 0x100000001b3ull; + h = (h ^ bytes[3]) * 0x100000001b3ull; + h = (h ^ bytes[4]) * 0x100000001b3ull; + h = (h ^ bytes[5]) * 0x100000001b3ull; + h = (h ^ bytes[6]) * 0x100000001b3ull; + h = (h ^ bytes[7]) * 0x100000001b3ull; + } + + while (len--) { + h = (h ^ *bytes++) * 0x100000001b3ull; } return h; } u64 u64_digit_value(Rune r) { - if ('0' <= r && r <= '9') { - return r - '0'; - } else if ('a' <= r && r <= 'f') { - return r - 'a' + 10; - } else if ('A' <= r && r <= 'F') { - return r - 'A' + 10; + switch (r) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': return 10; + case 'b': return 11; + case 'c': return 12; + case 'd': return 13; + case 'e': return 14; + case 'f': return 15; + case 'A': return 10; + case 'B': return 11; + case 'C': return 12; + case 'D': return 13; + case 'E': return 14; + case 'F': return 15; } return 16; // NOTE(bill): Larger than highest possible } diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index e7254e16b..430e26782 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -257,7 +257,7 @@ OdinDocArray odin_write_item_as_slice(OdinDocWriter *w, T data) { OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos const &pos) { OdinDocFileIndex file_index = 0; if (pos.file_id != 0) { - AstFile *file = get_ast_file_from_id(pos.file_id); + AstFile *file = global_files[pos.file_id]; if (file != nullptr) { OdinDocFileIndex *file_index_found = map_get(&w->file_cache, file); GB_ASSERT(file_index_found != nullptr); diff --git a/src/parser.cpp b/src/parser.cpp index ba5df1f27..cbd4d61d5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -11,7 +11,7 @@ Token token_end_of_line(AstFile *f, Token tok) { } gbString get_file_line_as_string(TokenPos const &pos, i32 *offset_) { - AstFile *file = get_ast_file_from_id(pos.file_id); + AstFile *file = thread_safe_get_ast_file_from_id(pos.file_id); if (file == nullptr) { return nullptr; } @@ -95,7 +95,7 @@ Ast *clone_ast(Ast *node) { if (node == nullptr) { return nullptr; } - AstFile *f = get_ast_file_from_id(node->file_id); + AstFile *f = node->thread_safe_file(); Ast *n = alloc_ast_node(f, node->kind); gb_memmove(n, node, ast_node_size(node->kind)); @@ -401,7 +401,7 @@ void error(Ast *node, char const *fmt, ...) { error_va(token.pos, end_pos, fmt, va); va_end(va); if (node != nullptr && node->file_id != 0) { - AstFile *f = get_ast_file_from_id(node->file_id); + AstFile *f = node->thread_safe_file(); f->error_count += 1; } } @@ -416,7 +416,7 @@ void error_no_newline(Ast *node, char const *fmt, ...) { error_no_newline_va(token.pos, fmt, va); va_end(va); if (node != nullptr && node->file_id != 0) { - AstFile *f = get_ast_file_from_id(node->file_id); + AstFile *f = node->thread_safe_file(); f->error_count += 1; } } @@ -446,7 +446,7 @@ void syntax_error(Ast *node, char const *fmt, ...) { syntax_error_va(token.pos, end_pos, fmt, va); va_end(va); if (node != nullptr && node->file_id != 0) { - AstFile *f = get_ast_file_from_id(node->file_id); + AstFile *f = node->thread_safe_file(); f->error_count += 1; } } @@ -4669,7 +4669,7 @@ ParseFileError init_ast_file(AstFile *f, String fullpath, TokenPos *err_pos) { GB_ASSERT(f != nullptr); f->fullpath = string_trim_whitespace(fullpath); // Just in case set_file_path_string(f->id, fullpath); - set_ast_file_from_id(f->id, f); + thread_safe_set_ast_file_from_id(f->id, f); if (!string_ends_with(f->fullpath, str_lit(".odin"))) { return ParseFile_WrongExtension; } diff --git a/src/parser.hpp b/src/parser.hpp index b1518533e..b83822cbf 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -731,8 +731,12 @@ struct Ast { // NOTE(bill): I know I dislike methods but this is hopefully a temporary thing // for refactoring purposes - AstFile *file() const { - return get_ast_file_from_id(this->file_id); + gb_inline AstFile *file() const { + // NOTE(bill): This doesn't need to call get_ast_file_from_id which + return global_files[this->file_id]; + } + gb_inline AstFile *thread_safe_file() const { + return thread_safe_get_ast_file_from_id(this->file_id); } }; diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index 8dd3cb4dc..ca7df3b53 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -24,7 +24,9 @@ template void ptr_set_reserve(PtrSet *h, isize cap); template void ptr_set_init(PtrSet *s, gbAllocator a, isize capacity) { - capacity = next_pow2_isize(gb_max(16, capacity)); + if (capacity != 0) { + capacity = next_pow2_isize(gb_max(16, capacity)); + } slice_init(&s->hashes, a, capacity); array_init(&s->entries, a, 0, capacity); diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index fc65110fe..727cdcdda 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -95,7 +95,7 @@ bool thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) { thread_pool_queue_push(pool, task); GB_ASSERT(pool->ready >= 0); pool->ready++; - condition_signal(&pool->task_cond); + condition_broadcast(&pool->task_cond); mutex_unlock(&pool->mutex); return true; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 10b4494d7..b7ade9d89 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -192,7 +192,7 @@ gb_global Array global_file_path_strings; // index is file id gb_global Array global_files; // index is file id String get_file_path_string(i32 index); -struct AstFile *get_ast_file_from_id(i32 index); +struct AstFile *thread_safe_get_ast_file_from_id(i32 index); struct TokenPos { i32 file_id; @@ -318,7 +318,7 @@ bool set_file_path_string(i32 index, String const &path) { return ok; } -bool set_ast_file_from_id(i32 index, AstFile *file) { +bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) { bool ok = false; GB_ASSERT(index >= 0); mutex_lock(&global_error_collector.string_mutex); @@ -349,7 +349,7 @@ String get_file_path_string(i32 index) { return path; } -AstFile *get_ast_file_from_id(i32 index) { +AstFile *thread_safe_get_ast_file_from_id(i32 index) { GB_ASSERT(index >= 0); mutex_lock(&global_error_collector.string_mutex); From 1ec0b79345f05d6cdd84707768e1fd6e66004699 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Nov 2021 22:10:31 +0000 Subject: [PATCH 0008/1258] Allow both `-help` and `--help` if passed as `init_filename` --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 61288f3c4..5371393d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2541,7 +2541,8 @@ int main(int arg_count, char const **arg_ptr) { return 1; } - if (init_filename == "-help") { + if (init_filename == "-help" || + init_filename == "--help") { build_context.show_help = true; } From 1823b0cead9530aea5f6694a95f28e1ddac5efac Mon Sep 17 00:00:00 2001 From: cybermancer Date: Tue, 16 Nov 2021 15:15:21 +1100 Subject: [PATCH 0009/1258] Improve compiler help output with regard to command specific help. --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5371393d1..7896756d4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -545,8 +545,8 @@ void usage(String argv0) { print_usage_line(1, "version print version"); print_usage_line(1, "report print information useful to reporting a bug"); print_usage_line(0, ""); - print_usage_line(0, "For more information of flags, apply the flag to see what is possible"); - print_usage_line(1, "-help"); + print_usage_line(0, "For further details on a command, use -help or --help after the command name"); + print_usage_line(1, "e.g. odin build -help"); } From 6a101e69a26c09d6a0c8c5ebd6ed27a8ab89d5ee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 14:04:49 +0000 Subject: [PATCH 0010/1258] Implement `ldexp` and `frexp` in native Odin --- core/math/big/rat.odin | 2 +- core/math/math.odin | 174 +++++++++++++++++++++++++++++++------- core/math/math_basic.odin | 7 -- core/math/math_js.odin | 6 +- 4 files changed, 144 insertions(+), 45 deletions(-) diff --git a/core/math/big/rat.odin b/core/math/big/rat.odin index 8acd8c2c6..121f0ab50 100644 --- a/core/math/big/rat.odin +++ b/core/math/big/rat.odin @@ -436,7 +436,7 @@ internal_rat_to_float :: proc($T: typeid, z: ^Rat, allocator := context.allocato mantissa >>= 1 - f = T(math.ldexp(f64(mantissa), i32(exp-MSIZE1))) + f = T(math.ldexp(f64(mantissa), exp-MSIZE1)) if math.is_inf(f, 0) { exact = false } diff --git a/core/math/math.odin b/core/math/math.odin index 512577906..f966ed11f 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -120,13 +120,60 @@ exp :: proc{ exp_f64, exp_f64le, exp_f64be, } -ldexp_f16le :: proc "contextless" (val: f16le, exp: i32) -> f16le { return #force_inline f16le(ldexp_f16(f16(val), exp)) } -ldexp_f16be :: proc "contextless" (val: f16be, exp: i32) -> f16be { return #force_inline f16be(ldexp_f16(f16(val), exp)) } -ldexp_f32le :: proc "contextless" (val: f32le, exp: i32) -> f32le { return #force_inline f32le(ldexp_f32(f32(val), exp)) } -ldexp_f32be :: proc "contextless" (val: f32be, exp: i32) -> f32be { return #force_inline f32be(ldexp_f32(f32(val), exp)) } -ldexp_f64le :: proc "contextless" (val: f64le, exp: i32) -> f64le { return #force_inline f64le(ldexp_f64(f64(val), exp)) } -ldexp_f64be :: proc "contextless" (val: f64be, exp: i32) -> f64be { return #force_inline f64be(ldexp_f64(f64(val), exp)) } -ldexp :: proc{ + + +ldexp_f64 :: proc "contextless" (val: f64, exp: int) -> f64 { + mask :: F64_MASK + shift :: F64_SHIFT + bias :: F64_BIAS + + switch { + case val == 0: + return val + case is_inf(val) || is_nan(val): + return val + } + exp := exp + frac, e := normalize_f64(val) + exp += e + x := transmute(u64)frac + exp += int(x>>shift)&mask - bias + if exp < -1075 { // underflow + return copy_sign(0, frac) + } else if exp > 1023 { // overflow + if frac < 0 { + return inf_f64(-1) + } + return inf_f64(+1) + } + + m: f64 = 1 + if exp < -1022 { // denormal + exp += 53 + m = 1.0 / (1<<53) + } + x &~= mask << shift + x |= u64(exp+bias) << shift + return m * transmute(f64)x +} +ldexp_f16 :: proc "contextless" (val: f16, exp: int) -> f16 { return f16(ldexp_f64(f64(val), exp)) } +ldexp_f32 :: proc "contextless" (val: f32, exp: int) -> f32 { return f32(ldexp_f64(f64(val), exp)) } +ldexp_f16le :: proc "contextless" (val: f16le, exp: int) -> f16le { return #force_inline f16le(ldexp_f16(f16(val), exp)) } +ldexp_f16be :: proc "contextless" (val: f16be, exp: int) -> f16be { return #force_inline f16be(ldexp_f16(f16(val), exp)) } +ldexp_f32le :: proc "contextless" (val: f32le, exp: int) -> f32le { return #force_inline f32le(ldexp_f32(f32(val), exp)) } +ldexp_f32be :: proc "contextless" (val: f32be, exp: int) -> f32be { return #force_inline f32be(ldexp_f32(f32(val), exp)) } +ldexp_f64le :: proc "contextless" (val: f64le, exp: int) -> f64le { return #force_inline f64le(ldexp_f64(f64(val), exp)) } +ldexp_f64be :: proc "contextless" (val: f64be, exp: int) -> f64be { return #force_inline f64be(ldexp_f64(f64(val), exp)) } +// ldexp is the inverse of frexp +// it returns val * 2**exp. +// +// Special cases: +// ldexp(+0, exp) = +0 +// ldexp(-0, exp) = -0 +// ldexp(+inf, exp) = +inf +// ldexp(-inf, exp) = -inf +// ldexp(NaN, exp) = NaN +ldexp :: proc{ ldexp_f16, ldexp_f16le, ldexp_f16be, ldexp_f32, ldexp_f32le, ldexp_f32be, ldexp_f64, ldexp_f64le, ldexp_f64be, @@ -351,9 +398,9 @@ to_degrees :: proc{ trunc_f16 :: proc "contextless" (x: f16) -> f16 { trunc_internal :: proc "contextless" (f: f16) -> f16 { - mask :: 0x1f - shift :: 16 - 6 - bias :: 0xf + mask :: F16_MASK + shift :: F16_SHIFT + bias :: F16_BIAS if f < 1 { switch { @@ -383,9 +430,9 @@ trunc_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16 trunc_f32 :: proc "contextless" (x: f32) -> f32 { trunc_internal :: proc "contextless" (f: f32) -> f32 { - mask :: 0xff - shift :: 32 - 9 - bias :: 0x7f + mask :: F32_MASK + shift :: F32_SHIFT + bias :: F32_BIAS if f < 1 { switch { @@ -415,9 +462,9 @@ trunc_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32 trunc_f64 :: proc "contextless" (x: f64) -> f64 { trunc_internal :: proc "contextless" (f: f64) -> f64 { - mask :: 0x7ff - shift :: 64 - 12 - bias :: 0x3ff + mask :: F64_MASK + shift :: F64_SHIFT + bias :: F64_BIAS if f < 1 { switch { @@ -752,6 +799,44 @@ lcm :: proc "contextless" (x, y: $T) -> T return x / gcd(x, y) * y } +normalize_f16 :: proc "contextless" (x: f16) -> (y: f16, exponent: int) { + if abs(x) < F16_MIN { + return x * (1< (y: f32, exponent: int) { + if abs(x) < F32_MIN { + return x * (1< (y: f64, exponent: int) { + if abs(x) < F64_MIN { + return x * (1< (y: f16le, exponent: int) { y0, e := normalize_f16(f16(x)); return f16le(y0), e } +normalize_f16be :: proc "contextless" (x: f16be) -> (y: f16be, exponent: int) { y0, e := normalize_f16(f16(x)); return f16be(y0), e } +normalize_f32le :: proc "contextless" (x: f32le) -> (y: f32le, exponent: int) { y0, e := normalize_f32(f32(x)); return f32le(y0), e } +normalize_f32be :: proc "contextless" (x: f32be) -> (y: f32be, exponent: int) { y0, e := normalize_f32(f32(x)); return f32be(y0), e } +normalize_f64le :: proc "contextless" (x: f64le) -> (y: f64le, exponent: int) { y0, e := normalize_f64(f64(x)); return f64le(y0), e } +normalize_f64be :: proc "contextless" (x: f64be) -> (y: f64be, exponent: int) { y0, e := normalize_f64(f64(x)); return f64be(y0), e } + +normalize :: proc{ + normalize_f16, + normalize_f32, + normalize_f64, + normalize_f16le, + normalize_f16be, + normalize_f32le, + normalize_f32be, + normalize_f64le, + normalize_f64be, +} + frexp_f16 :: proc "contextless" (x: f16) -> (significand: f16, exponent: int) { f, e := frexp_f64(f64(x)) return f16(f), e @@ -776,24 +861,25 @@ frexp_f32be :: proc "contextless" (x: f32be) -> (significand: f32be, exponent: i f, e := frexp_f64(f64(x)) return f32be(f), e } -frexp_f64 :: proc "contextless" (x: f64) -> (significand: f64, exponent: int) { +frexp_f64 :: proc "contextless" (f: f64) -> (significand: f64, exponent: int) { + mask :: F64_MASK + shift :: F64_SHIFT + bias :: F64_BIAS + switch { - case x == 0: + case f == 0: return 0, 0 - case x < 0: - significand, exponent = frexp(-x) - return -significand, exponent - } - ex := trunc(log2(x)) - exponent = int(ex) - significand = x / pow(2.0, ex) - if abs(significand) >= 1 { - exponent += 1 - significand /= 2 - } - if exponent == 1024 && significand == 0 { - significand = 0.99999999999999988898 + case is_inf(f) || is_nan(f): + return f, 0 } + f := f + + f, exponent = normalize_f64(f) + x := transmute(u64)f + exponent += int((x>>shift)&mask) - bias + 1 + x &~= mask << shift + x |= (-1 + bias) << shift + significand = transmute(f64)x return } frexp_f64le :: proc "contextless" (x: f64le) -> (significand: f64le, exponent: int) { @@ -804,7 +890,18 @@ frexp_f64be :: proc "contextless" (x: f64be) -> (significand: f64be, exponent: i f, e := frexp_f64(f64(x)) return f64be(f), e } -frexp :: proc{ + +// frexp breaks the value into a normalized fraction, and an integral power of two +// It returns a significand and exponent satisfying x == significand * 2**exponent +// with the absolute value of significand in the intervalue of [0.5, 1). +// +// Special cases: +// frexp(+0) = +0, 0 +// frexp(-0) = -0, 0 +// frexp(+inf) = +inf, 0 +// frexp(-inf) = -inf, 0 +// frexp(NaN) = NaN, 0 +frexp :: proc{ frexp_f16, frexp_f16le, frexp_f16be, frexp_f32, frexp_f32le, frexp_f32be, frexp_f64, frexp_f64le, frexp_f64be, @@ -1349,3 +1446,16 @@ F64_MIN_10_EXP :: -307 // min decimal exponent F64_MIN_EXP :: -1021 // min binary exponent F64_RADIX :: 2 // exponent radix F64_ROUNDS :: 1 // addition rounding: near + + +F16_MASK :: 0x1f +F16_SHIFT :: 16 - 6 +F16_BIAS :: 0xf + +F32_MASK :: 0xff +F32_SHIFT :: 32 - 9 +F32_BIAS :: 0x7f + +F64_MASK :: 0x7ff +F64_SHIFT :: 64 - 12 +F64_BIAS :: 0x3ff \ No newline at end of file diff --git a/core/math/math_basic.odin b/core/math/math_basic.odin index 26bf4691d..4995ac9e3 100644 --- a/core/math/math_basic.odin +++ b/core/math/math_basic.odin @@ -51,11 +51,4 @@ foreign _ { exp_f32 :: proc(x: f32) -> f32 --- @(link_name="llvm.exp.f64") exp_f64 :: proc(x: f64) -> f64 --- - - @(link_name="llvm.ldexp.f16") - ldexp_f16 :: proc(val: f16, exp: i32) -> f16 --- - @(link_name="llvm.ldexp.f32") - ldexp_f32 :: proc(val: f32, exp: i32) -> f32 --- - @(link_name="llvm.ldexp.f64") - ldexp_f64 :: proc(val: f64, exp: i32) -> f64 --- } diff --git a/core/math/math_js.odin b/core/math/math_js.odin index c2ac1bedf..4d91b440c 100644 --- a/core/math/math_js.odin +++ b/core/math/math_js.odin @@ -19,8 +19,6 @@ foreign odin_env { ln_f64 :: proc(x: f64) -> f64 --- @(link_name="exp") exp_f64 :: proc(x: f64) -> f64 --- - @(link_name="ldexp") - ldexp_f64 :: proc(val: f64, exp: i32) -> f64 --- } @@ -31,7 +29,6 @@ pow_f16 :: proc "c" (x, power: f16) -> f16 { return f16(pow_f64(f64(x), fmuladd_f16 :: proc "c" (a, b, c: f16) -> f16 { return f16(fmuladd_f64(f64(a), f64(a), f64(c))) } ln_f16 :: proc "c" (x: f16) -> f16 { return f16(ln_f64(f64(x))) } exp_f16 :: proc "c" (x: f16) -> f16 { return f16(exp_f64(f64(x))) } -ldexp_f16 :: proc "c" (val: f16, exp: i32) -> f16 { return f16(ldexp_f64(f64(val), exp) ) } sqrt_f32 :: proc "c" (x: f32) -> f32 { return f32(sqrt_f64(f64(x))) } sin_f32 :: proc "c" (θ: f32) -> f32 { return f32(sin_f64(f64(θ))) } @@ -39,5 +36,4 @@ cos_f32 :: proc "c" (θ: f32) -> f32 { return f32(cos_f64(f64(θ pow_f32 :: proc "c" (x, power: f32) -> f32 { return f32(pow_f64(f64(x), f64(power))) } fmuladd_f32 :: proc "c" (a, b, c: f32) -> f32 { return f32(fmuladd_f64(f64(a), f64(a), f64(c))) } ln_f32 :: proc "c" (x: f32) -> f32 { return f32(ln_f64(f64(x))) } -exp_f32 :: proc "c" (x: f32) -> f32 { return f32(exp_f64(f64(x))) } -ldexp_f32 :: proc "c" (val: f32, exp: i32) -> f32 { return f32(ldexp_f64(f64(val), exp) ) } \ No newline at end of file +exp_f32 :: proc "c" (x: f32) -> f32 { return f32(exp_f64(f64(x))) } \ No newline at end of file From 91949b09929707ee969a5be778973e044d22d85c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 14:11:20 +0000 Subject: [PATCH 0011/1258] Implement `math.sqrt` with `intrinsics.sqrt` --- core/math/math_basic.odin | 19 ++++++++++++------- core/math/math_js.odin | 7 +++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/core/math/math_basic.odin b/core/math/math_basic.odin index 4995ac9e3..fe7b07d98 100644 --- a/core/math/math_basic.odin +++ b/core/math/math_basic.odin @@ -1,15 +1,10 @@ //+build !js package math +import "core:intrinsics" + @(default_calling_convention="none") foreign _ { - @(link_name="llvm.sqrt.f16") - sqrt_f16 :: proc(x: f16) -> f16 --- - @(link_name="llvm.sqrt.f32") - sqrt_f32 :: proc(x: f32) -> f32 --- - @(link_name="llvm.sqrt.f64") - sqrt_f64 :: proc(x: f64) -> f64 --- - @(link_name="llvm.sin.f16") sin_f16 :: proc(θ: f16) -> f16 --- @(link_name="llvm.sin.f32") @@ -52,3 +47,13 @@ foreign _ { @(link_name="llvm.exp.f64") exp_f64 :: proc(x: f64) -> f64 --- } + +sqrt_f16 :: proc "contextless" (x: f16) -> f16 { + return intrinsics.sqrt(x) +} +sqrt_f32 :: proc "contextless" (x: f32) -> f32 { + return intrinsics.sqrt(x) +} +sqrt_f64 :: proc "contextless" (x: f64) -> f64 { + return intrinsics.sqrt(x) +} diff --git a/core/math/math_js.odin b/core/math/math_js.odin index 4d91b440c..06c8b636d 100644 --- a/core/math/math_js.odin +++ b/core/math/math_js.odin @@ -1,12 +1,12 @@ //+build js package math +import "core:intrinsics" + foreign import "odin_env" @(default_calling_convention="c") foreign odin_env { - @(link_name="sqrt") - sqrt_f64 :: proc(x: f64) -> f64 --- @(link_name="sin") sin_f64 :: proc(θ: f64) -> f64 --- @(link_name="cos") @@ -21,6 +21,9 @@ foreign odin_env { exp_f64 :: proc(x: f64) -> f64 --- } +sqrt_f64 :: proc "contextless" (x: f64) -> f64 { + return intrinsics.sqrt(x) +} sqrt_f16 :: proc "c" (x: f16) -> f16 { return f16(sqrt_f64(f64(x))) } sin_f16 :: proc "c" (θ: f16) -> f16 { return f16(sin_f64(f64(θ))) } From 880af47ae72078ee894772b13477902aeb4e132b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 14:26:04 +0000 Subject: [PATCH 0012/1258] Rename math_js.odin to math_basic_js.odin --- core/math/{math_js.odin => math_basic_js.odin} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/math/{math_js.odin => math_basic_js.odin} (100%) diff --git a/core/math/math_js.odin b/core/math/math_basic_js.odin similarity index 100% rename from core/math/math_js.odin rename to core/math/math_basic_js.odin From eb8b0d7a03ab2fb3a066c9135c429b97e7bad346 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 14:26:43 +0000 Subject: [PATCH 0013/1258] Add `log1p`, `erf`, `erfc`, `ilogb` `logb` (implemented based of FreeBSD's) --- core/math/math.odin | 190 ++++++++++++++++-- core/math/math_erf.odin | 410 ++++++++++++++++++++++++++++++++++++++ core/math/math_log1p.odin | 198 ++++++++++++++++++ 3 files changed, 778 insertions(+), 20 deletions(-) create mode 100644 core/math/math_erf.odin create mode 100644 core/math/math_log1p.odin diff --git a/core/math/math.odin b/core/math/math.odin index f966ed11f..97fd4bd16 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -197,22 +197,16 @@ log :: proc{ log_f64, log_f64le, log_f64be, } -log2_f16 :: proc "contextless" (x: f16) -> f16 { return ln(x)/LN2 } -log2_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log2_f16(f16(x))) } -log2_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log2_f16(f16(x))) } - -log2_f32 :: proc "contextless" (x: f32) -> f32 { return ln(x)/LN2 } -log2_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log2_f32(f32(x))) } -log2_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log2_f32(f32(x))) } - -log2_f64 :: proc "contextless" (x: f64) -> f64 { return ln(x)/LN2 } -log2_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log2_f64(f64(x))) } -log2_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log2_f64(f64(x))) } -log2 :: proc{ - log2_f16, log2_f16le, log2_f16be, - log2_f32, log2_f32le, log2_f32be, - log2_f64, log2_f64le, log2_f64be, -} +log2_f16 :: logb_f16 +log2_f16le :: logb_f16le +log2_f16be :: logb_f16be +log2_f32 :: logb_f32 +log2_f32le :: logb_f32le +log2_f32be :: logb_f32be +log2_f64 :: logb_f64 +log2_f64le :: logb_f64le +log2_f64be :: logb_f64be +log2 :: logb log10_f16 :: proc "contextless" (x: f16) -> f16 { return ln(x)/LN10 } log10_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log10_f16(f16(x))) } @@ -1394,18 +1388,174 @@ tanh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { return (t - 1) / (t + 1) } -asinh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { - return ln(x + sqrt(x*x + 1)) +asinh :: proc "contextless" (y: $T) -> T where intrinsics.type_is_float(T) { + // The original C code, the long comment, and the constants + // below are from FreeBSD's /usr/src/lib/msun/src/s_asinh.c + // and came with this notice. + // + // ==================================================== + // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + // + // Developed at SunPro, a Sun Microsystems, Inc. business. + // Permission to use, copy, modify, and distribute this + // software is freely granted, provided that this notice + // is preserved. + // ==================================================== + + LN2 :: 0h3FE62E42FEFA39EF + NEAR_ZERO :: 1.0 / (1 << 28) + LARGE :: 1 << 28 + + x := f64(y) + + if is_nan(x) || is_inf(x) { + return T(x) + } + sign := false + if x < 0 { + x = -x + sign = true + } + temp: f64 + switch { + case x > LARGE: + temp = ln(x) + LN2 + case x > 2: + temp = ln(2*x + 1/(sqrt(x*x + 1) + x)) + case x < NEAR_ZERO: + temp = x + case: + temp = log1p(x + x*x/(1 + sqrt(1 + x*x))) + } + + if sign { + temp = -temp + } + return T(temp) } -acosh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { - return ln(x + sqrt(x*x - 1)) +acosh :: proc "contextless" (y: $T) -> T where intrinsics.type_is_float(T) { + // The original C code, the long comment, and the constants + // below are from FreeBSD's /usr/src/lib/msun/src/e_acosh.c + // and came with this notice. + // + // ==================================================== + // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + // + // Developed at SunPro, a Sun Microsystems, Inc. business. + // Permission to use, copy, modify, and distribute this + // software is freely granted, provided that this notice + // is preserved. + // ==================================================== + + LARGE :: 1<<28 + LN2 :: 0h3FE62E42FEFA39EF + x := f64(y) + switch { + case x < 1 || is_nan(x): + return T(nan_f64()) + case x == 1: + return 0 + case x >= LARGE: + return T(ln(x) + LN2) + case x > 2: + return T(ln(2*x - 1/(x+sqrt(x*x-1)))) + } + t := x-1 + return T(log1p(t + sqrt(2*t + t*t))) } atanh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { return 0.5*ln((1+x)/(1-x)) } +ilogb_f16 :: proc "contextless" (val: f16) -> int { + switch { + case val == 0: return int(min(i32)) + case is_nan(val): return int(max(i32)) + case is_inf(val): return int(max(i32)) + } + x, exp := normalize_f16(val) + return int(((transmute(u16)x)>>F16_SHIFT)&F16_MASK) - F16_BIAS + exp +} +ilogb_f32 :: proc "contextless" (val: f32) -> int { + switch { + case val == 0: return int(min(i32)) + case is_nan(val): return int(max(i32)) + case is_inf(val): return int(max(i32)) + } + x, exp := normalize_f32(val) + return int(((transmute(u32)x)>>F32_SHIFT)&F32_MASK) - F32_BIAS + exp +} +ilogb_f64 :: proc "contextless" (val: f64) -> int { + switch { + case val == 0: return int(min(i32)) + case is_nan(val): return int(max(i32)) + case is_inf(val): return int(max(i32)) + } + x, exp := normalize_f64(val) + return int(((transmute(u64)x)>>F64_SHIFT)&F64_MASK) - F64_BIAS + exp +} +ilogb_f16le :: proc "contextless" (value: f16le) -> int { return ilogb_f16(f16(value)) } +ilogb_f16be :: proc "contextless" (value: f16be) -> int { return ilogb_f16(f16(value)) } +ilogb_f32le :: proc "contextless" (value: f32le) -> int { return ilogb_f32(f32(value)) } +ilogb_f32be :: proc "contextless" (value: f32be) -> int { return ilogb_f32(f32(value)) } +ilogb_f64le :: proc "contextless" (value: f64le) -> int { return ilogb_f64(f64(value)) } +ilogb_f64be :: proc "contextless" (value: f64be) -> int { return ilogb_f64(f64(value)) } +ilogb :: proc { + ilogb_f16, + ilogb_f32, + ilogb_f64, + ilogb_f16le, + ilogb_f16be, + ilogb_f32le, + ilogb_f32be, + ilogb_f64le, + ilogb_f64be, +} + +logb_f16 :: proc "contextless" (val: f16) -> f16 { + switch { + case val == 0: return inf_f16(-1) + case is_inf(val): return inf_f16(+1) + case is_nan(val): return val + } + return f16(ilogb(val)) +} +logb_f32 :: proc "contextless" (val: f32) -> f32 { + switch { + case val == 0: return inf_f32(-1) + case is_inf(val): return inf_f32(+1) + case is_nan(val): return val + } + return f32(ilogb(val)) +} +logb_f64 :: proc "contextless" (val: f64) -> f64 { + switch { + case val == 0: return inf_f64(-1) + case is_inf(val): return inf_f64(+1) + case is_nan(val): return val + } + return f64(ilogb(val)) +} +logb_f16le :: proc "contextless" (value: f16le) -> f16le { return f16le(logb_f16(f16(value))) } +logb_f16be :: proc "contextless" (value: f16be) -> f16be { return f16be(logb_f16(f16(value))) } +logb_f32le :: proc "contextless" (value: f32le) -> f32le { return f32le(logb_f32(f32(value))) } +logb_f32be :: proc "contextless" (value: f32be) -> f32be { return f32be(logb_f32(f32(value))) } +logb_f64le :: proc "contextless" (value: f64le) -> f64le { return f64le(logb_f64(f64(value))) } +logb_f64be :: proc "contextless" (value: f64be) -> f64be { return f64be(logb_f64(f64(value))) } +logb :: proc { + logb_f16, + logb_f32, + logb_f64, + logb_f16le, + logb_f16be, + logb_f32le, + logb_f32be, + logb_f64le, + logb_f64be, +} + F16_DIG :: 3 F16_EPSILON :: 0.00097656 F16_GUARD :: 0 diff --git a/core/math/math_erf.odin b/core/math/math_erf.odin new file mode 100644 index 000000000..cdade59c5 --- /dev/null +++ b/core/math/math_erf.odin @@ -0,0 +1,410 @@ +package math + +// The original C code and the long comment below are +// from FreeBSD's /usr/src/lib/msun/src/s_erf.c and +// came with this notice. +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== +// +// +// double erf(double x) +// double erfc(double x) +// x +// 2 |\ +// erf(x) = --------- | exp(-t*t)dt +// sqrt(pi) \| +// 0 +// +// erfc(x) = 1-erf(x) +// Note that +// erf(-x) = -erf(x) +// erfc(-x) = 2 - erfc(x) +// +// Method: +// 1. For |x| in [0, 0.84375] +// erf(x) = x + x*R(x**2) +// erfc(x) = 1 - erf(x) if x in [-.84375,0.25] +// = 0.5 + ((0.5-x)-x*R) if x in [0.25,0.84375] +// where R = P/Q where P is an odd poly of degree 8 and +// Q is an odd poly of degree 10. +// -57.90 +// | R - (erf(x)-x)/x | <= 2 +// +// +// Remark. The formula is derived by noting +// erf(x) = (2/sqrt(pi))*(x - x**3/3 + x**5/10 - x**7/42 + ....) +// and that +// 2/sqrt(pi) = 1.128379167095512573896158903121545171688 +// is close to one. The interval is chosen because the fix +// point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is +// near 0.6174), and by some experiment, 0.84375 is chosen to +// guarantee the error is less than one ulp for erf. +// +// 2. For |x| in [0.84375,1.25], let s = |x| - 1, and +// c = 0.84506291151 rounded to single (24 bits) +// erf(x) = sign(x) * (c + P1(s)/Q1(s)) +// erfc(x) = (1-c) - P1(s)/Q1(s) if x > 0 +// 1+(c+P1(s)/Q1(s)) if x < 0 +// |P1/Q1 - (erf(|x|)-c)| <= 2**-59.06 +// Remark: here we use the taylor series expansion at x=1. +// erf(1+s) = erf(1) + s*Poly(s) +// = 0.845.. + P1(s)/Q1(s) +// That is, we use rational approximation to approximate +// erf(1+s) - (c = (single)0.84506291151) +// Note that |P1/Q1|< 0.078 for x in [0.84375,1.25] +// where +// P1(s) = degree 6 poly in s +// Q1(s) = degree 6 poly in s +// +// 3. For x in [1.25,1/0.35(~2.857143)], +// erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1) +// erf(x) = 1 - erfc(x) +// where +// R1(z) = degree 7 poly in z, (z=1/x**2) +// S1(z) = degree 8 poly in z +// +// 4. For x in [1/0.35,28] +// erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0 +// = 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6 x >= 28 +// erf(x) = sign(x) *(1 - tiny) (raise inexact) +// erfc(x) = tiny*tiny (raise underflow) if x > 0 +// = 2 - tiny if x<0 +// +// 7. Special case: +// erf(0) = 0, erf(inf) = 1, erf(-inf) = -1, +// erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, +// erfc/erf(NaN) is NaN + +erf :: proc{ + erf_f16, + erf_f16le, + erf_f16be, + erf_f32, + erf_f32le, + erf_f32be, + erf_f64, +} + +erf_f16 :: proc "contextless" (x: f16) -> f16 { return f16(erf_f64(f64(x))) } +erf_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erf_f64(f64(x))) } +erf_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erf_f64(f64(x))) } +erf_f32 :: proc "contextless" (x: f32) -> f32 { return f32(erf_f64(f64(x))) } +erf_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erf_f64(f64(x))) } +erf_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erf_f64(f64(x))) } + +erf_f64 :: proc "contextless" (x: f64) -> f64 { + erx :: 0h3FEB0AC160000000 + // Coefficients for approximation to erf in [0, 0.84375] + efx :: 0h3FC06EBA8214DB69 + efx8 :: 0h3FF06EBA8214DB69 + pp0 :: 0h3FC06EBA8214DB68 + pp1 :: 0hBFD4CD7D691CB913 + pp2 :: 0hBF9D2A51DBD7194F + pp3 :: 0hBF77A291236668E4 + pp4 :: 0hBEF8EAD6120016AC + qq1 :: 0h3FD97779CDDADC09 + qq2 :: 0h3FB0A54C5536CEBA + qq3 :: 0h3F74D022C4D36B0F + qq4 :: 0h3F215DC9221C1A10 + qq5 :: 0hBED09C4342A26120 + // Coefficients for approximation to erf in [0.84375, 1.25] + pa0 :: 0hBF6359B8BEF77538 + pa1 :: 0h3FDA8D00AD92B34D + pa2 :: 0hBFD7D240FBB8C3F1 + pa3 :: 0h3FD45FCA805120E4 + pa4 :: 0hBFBC63983D3E28EC + pa5 :: 0h3FA22A36599795EB + pa6 :: 0hBF61BF380A96073F + qa1 :: 0h3FBB3E6618EEE323 + qa2 :: 0h3FE14AF092EB6F33 + qa3 :: 0h3FB2635CD99FE9A7 + qa4 :: 0h3FC02660E763351F + qa5 :: 0h3F8BEDC26B51DD1C + qa6 :: 0h3F888B545735151D + // Coefficients for approximation to erfc in [1.25, 1/0.35] + ra0 :: 0hBF843412600D6435 + ra1 :: 0hBFE63416E4BA7360 + ra2 :: 0hC0251E0441B0E726 + ra3 :: 0hC04F300AE4CBA38D + ra4 :: 0hC0644CB184282266 + ra5 :: 0hC067135CEBCCABB2 + ra6 :: 0hC054526557E4D2F2 + ra7 :: 0hC023A0EFC69AC25C + sa1 :: 0h4033A6B9BD707687 + sa2 :: 0h4061350C526AE721 + sa3 :: 0h407B290DD58A1A71 + sa4 :: 0h40842B1921EC2868 + sa5 :: 0h407AD02157700314 + sa6 :: 0h405B28A3EE48AE2C + sa7 :: 0h401A47EF8E484A93 + sa8 :: 0hBFAEEFF2EE749A62 + // Coefficients for approximation to erfc in [1/.35, 28] + rb0 :: 0hBF84341239E86F4A + rb1 :: 0hBFE993BA70C285DE + rb2 :: 0hC031C209555F995A + rb3 :: 0hC064145D43C5ED98 + rb4 :: 0hC083EC881375F228 + rb5 :: 0hC09004616A2E5992 + rb6 :: 0hC07E384E9BDC383F + sb1 :: 0h403E568B261D5190 + sb2 :: 0h40745CAE221B9F0A + sb3 :: 0h409802EB189D5118 + sb4 :: 0h40A8FFB7688C246A + sb5 :: 0h40A3F219CEDF3BE6 + sb6 :: 0h407DA874E79FE763 + sb7 :: 0hC03670E242712D62 + + + VERY_TINY :: 0h0080000000000000 + SMALL :: 1.0 / (1 << 28) // 2**-28 + + // special cases + switch { + case is_nan(x): + return nan_f64() + case is_inf(x, 1): + return 1 + case is_inf(x, -1): + return -1 + } + x := x + sign := false + if x < 0 { + x = -x + sign = true + } + if x < 0.84375 { // |x| < 0.84375 + temp: f64 + if x < SMALL { // |x| < 2**-28 + if x < VERY_TINY { + temp = 0.125 * (8.0*x + efx8*x) // avoid underflow + } else { + temp = x + efx*x + } + } else { + z := x * x + r := pp0 + z*(pp1+z*(pp2+z*(pp3+z*pp4))) + s := 1 + z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))) + y := r / s + temp = x + x*y + } + if sign { + return -temp + } + return temp + } + if x < 1.25 { // 0.84375 <= |x| < 1.25 + s := x - 1 + P := pa0 + s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))) + Q := 1 + s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))) + if sign { + return -erx - P/Q + } + return erx + P/Q + } + if x >= 6 { // inf > |x| >= 6 + if sign { + return -1 + } + return 1 + } + s := 1 / (x * x) + R, S: f64 + if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143 + R = ra0 + s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(ra5+s*(ra6+s*ra7)))))) + S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8))))))) + } else { // |x| >= 1 / 0.35 ~ 2.857143 + R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6))))) + S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7)))))) + } + z := transmute(f64)(0xffffffff00000000 & transmute(u64)x) // pseudo-single (20-bit) precision x + r := exp(-z*z-0.5625) * exp((z-x)*(z+x)+R/S) + if sign { + return r/x - 1 + } + return 1 - r/x +} + + +erfc :: proc{ + erfc_f16, + erfc_f16le, + erfc_f16be, + erfc_f32, + erfc_f32le, + erfc_f32be, + erfc_f64, +} + +erfc_f16 :: proc "contextless" (x: f16) -> f16 { return f16(erfc_f64(f64(x))) } +erfc_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(erfc_f64(f64(x))) } +erfc_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(erfc_f64(f64(x))) } +erfc_f32 :: proc "contextless" (x: f32) -> f32 { return f32(erfc_f64(f64(x))) } +erfc_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(erfc_f64(f64(x))) } +erfc_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(erfc_f64(f64(x))) } + +erfc_f64 :: proc "contextless" (x: f64) -> f64 { + erx :: 0h3FEB0AC160000000 + // Coefficients for approximation to erf in [0, 0.84375] + efx :: 0h3FC06EBA8214DB69 + efx8 :: 0h3FF06EBA8214DB69 + pp0 :: 0h3FC06EBA8214DB68 + pp1 :: 0hBFD4CD7D691CB913 + pp2 :: 0hBF9D2A51DBD7194F + pp3 :: 0hBF77A291236668E4 + pp4 :: 0hBEF8EAD6120016AC + qq1 :: 0h3FD97779CDDADC09 + qq2 :: 0h3FB0A54C5536CEBA + qq3 :: 0h3F74D022C4D36B0F + qq4 :: 0h3F215DC9221C1A10 + qq5 :: 0hBED09C4342A26120 + // Coefficients for approximation to erf in [0.84375, 1.25] + pa0 :: 0hBF6359B8BEF77538 + pa1 :: 0h3FDA8D00AD92B34D + pa2 :: 0hBFD7D240FBB8C3F1 + pa3 :: 0h3FD45FCA805120E4 + pa4 :: 0hBFBC63983D3E28EC + pa5 :: 0h3FA22A36599795EB + pa6 :: 0hBF61BF380A96073F + qa1 :: 0h3FBB3E6618EEE323 + qa2 :: 0h3FE14AF092EB6F33 + qa3 :: 0h3FB2635CD99FE9A7 + qa4 :: 0h3FC02660E763351F + qa5 :: 0h3F8BEDC26B51DD1C + qa6 :: 0h3F888B545735151D + // Coefficients for approximation to erfc in [1.25, 1/0.35] + ra0 :: 0hBF843412600D6435 + ra1 :: 0hBFE63416E4BA7360 + ra2 :: 0hC0251E0441B0E726 + ra3 :: 0hC04F300AE4CBA38D + ra4 :: 0hC0644CB184282266 + ra5 :: 0hC067135CEBCCABB2 + ra6 :: 0hC054526557E4D2F2 + ra7 :: 0hC023A0EFC69AC25C + sa1 :: 0h4033A6B9BD707687 + sa2 :: 0h4061350C526AE721 + sa3 :: 0h407B290DD58A1A71 + sa4 :: 0h40842B1921EC2868 + sa5 :: 0h407AD02157700314 + sa6 :: 0h405B28A3EE48AE2C + sa7 :: 0h401A47EF8E484A93 + sa8 :: 0hBFAEEFF2EE749A62 + // Coefficients for approximation to erfc in [1/.35, 28] + rb0 :: 0hBF84341239E86F4A + rb1 :: 0hBFE993BA70C285DE + rb2 :: 0hC031C209555F995A + rb3 :: 0hC064145D43C5ED98 + rb4 :: 0hC083EC881375F228 + rb5 :: 0hC09004616A2E5992 + rb6 :: 0hC07E384E9BDC383F + sb1 :: 0h403E568B261D5190 + sb2 :: 0h40745CAE221B9F0A + sb3 :: 0h409802EB189D5118 + sb4 :: 0h40A8FFB7688C246A + sb5 :: 0h40A3F219CEDF3BE6 + sb6 :: 0h407DA874E79FE763 + sb7 :: 0hC03670E242712D62 + + TINY :: 1.0 / (1 << 56) // 2**-56 + // special cases + switch { + case is_nan(x): + return nan_f64() + case is_inf(x, 1): + return 0 + case is_inf(x, -1): + return 2 + } + x := x + sign := false + if x < 0 { + x = -x + sign = true + } + if x < 0.84375 { // |x| < 0.84375 + temp: f64 + if x < TINY { // |x| < 2**-56 + temp = x + } else { + z := x * x + r := pp0 + z*(pp1+z*(pp2+z*(pp3+z*pp4))) + s := 1 + z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5)))) + y := r / s + if x < 0.25 { // |x| < 1/4 + temp = x + x*y + } else { + temp = 0.5 + (x*y + (x - 0.5)) + } + } + if sign { + return 1 + temp + } + return 1 - temp + } + if x < 1.25 { // 0.84375 <= |x| < 1.25 + s := x - 1 + P := pa0 + s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6))))) + Q := 1 + s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6))))) + if sign { + return 1 + erx + P/Q + } + return 1 - erx - P/Q + + } + if x < 28 { // |x| < 28 + s := 1 / (x * x) + R, S: f64 + if x < 1/0.35 { // |x| < 1 / 0.35 ~ 2.857143 + R = ra0 + s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(ra5+s*(ra6+s*ra7)))))) + S = 1 + s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(sa5+s*(sa6+s*(sa7+s*sa8))))))) + } else { // |x| >= 1 / 0.35 ~ 2.857143 + if sign && x > 6 { + return 2 // x < -6 + } + R = rb0 + s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(rb5+s*rb6))))) + S = 1 + s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(sb5+s*(sb6+s*sb7)))))) + } + z := transmute(f64)(0xffffffff00000000 & transmute(u64)x) // pseudo-single (20-bit) precision x + r := exp(-z*z-0.5625) * exp((z-x)*(z+x)+R/S) + if sign { + return 2 - r/x + } + return r / x + } + if sign { + return 2 + } + return 0 +} \ No newline at end of file diff --git a/core/math/math_log1p.odin b/core/math/math_log1p.odin new file mode 100644 index 000000000..07e790666 --- /dev/null +++ b/core/math/math_log1p.odin @@ -0,0 +1,198 @@ +package math + +// The original C code, the long comment, and the constants +// below are from FreeBSD's /usr/src/lib/msun/src/s_log1p.c +// and came with this notice. The go code is a simplified +// version of the original C. +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== +// +// +// double log1p(double x) +// +// Method : +// 1. Argument Reduction: find k and f such that +// 1+x = 2**k * (1+f), +// where sqrt(2)/2 < 1+f < sqrt(2) . +// +// Note. If k=0, then f=x is exact. However, if k!=0, then f +// may not be representable exactly. In that case, a correction +// term is need. Let u=1+x rounded. Let c = (1+x)-u, then +// log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u), +// and add back the correction term c/u. +// (Note: when x > 2**53, one can simply return log(x)) +// +// 2. Approximation of log1p(f). +// Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) +// = 2s + 2/3 s**3 + 2/5 s**5 + ....., +// = 2s + s*R +// We use a special Reme algorithm on [0,0.1716] to generate +// a polynomial of degree 14 to approximate R The maximum error +// of this polynomial approximation is bounded by 2**-58.45. In +// other words, +// 2 4 6 8 10 12 14 +// R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s +// (the values of Lp1 to Lp7 are listed in the program) +// and +// | 2 14 | -58.45 +// | Lp1*s +...+Lp7*s - R(z) | <= 2 +// | | +// Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. +// In order to guarantee error in log below 1ulp, we compute log +// by +// log1p(f) = f - (hfsq - s*(hfsq+R)). +// +// 3. Finally, log1p(x) = k*ln2 + log1p(f). +// = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo))) +// Here ln2 is split into two floating point number: +// ln2_hi + ln2_lo, +// where n*ln2_hi is always exact for |n| < 2000. +// +// Special cases: +// log1p(x) is NaN with signal if x < -1 (including -INF) ; +// log1p(+INF) is +INF; log1p(-1) is -INF with signal; +// log1p(NaN) is that NaN with no signal. +// +// Accuracy: +// according to an error analysis, the error is always less than +// 1 ulp (unit in the last place). +// +// Constants: +// The hexadecimal values are the intended ones for the following +// constants. The decimal values may be used, provided that the +// compiler will convert from decimal to binary accurately enough +// to produce the hexadecimal values shown. +// +// Note: Assuming log() return accurate answer, the following +// algorithm can be used to compute log1p(x) to within a few ULP: +// +// u = 1+x; +// if(u==1.0) return x ; else +// return log(u)*(x/(u-1.0)); +// +// See HP-15C Advanced Functions Handbook, p.193. + +log1p :: proc { + log1p_f16, + log1p_f32, + log1p_f64, + log1p_f16le, + log1p_f16be, + log1p_f32le, + log1p_f32be, + log1p_f64le, + log1p_f64be, +} +log1p_f16 :: proc "contextless" (x: f16) -> f16 { return f16(log1p_f64(f64(x))) } +log1p_f32 :: proc "contextless" (x: f32) -> f32 { return f32(log1p_f64(f64(x))) } +log1p_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log1p_f64(f64(x))) } +log1p_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log1p_f64(f64(x))) } +log1p_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log1p_f64(f64(x))) } +log1p_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log1p_f64(f64(x))) } +log1p_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log1p_f64(f64(x))) } +log1p_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log1p_f64(f64(x))) } + +log1p_f64 :: proc "contextless" (x: f64) -> f64 { + SQRT2_M1 :: 0h3fda827999fcef34 // Sqrt(2)-1 + SQRT2_HALF_M1 :: 0hbfd2bec333018866 // Sqrt(2)/2-1 + SMALL :: 0h3e20000000000000 // 2**-29 + TINY :: 1.0 / (1 << 54) // 2**-54 + TWO53 :: 1 << 53 // 2**53 + LN2HI :: 0h3fe62e42fee00000 + LN2LO :: 0h3dea39ef35793c76 + LP1 :: 0h3FE5555555555593 + LP2 :: 0h3FD999999997FA04 + LP3 :: 0h3FD2492494229359 + LP4 :: 0h3FCC71C51D8E78AF + LP5 :: 0h3FC7466496CB03DE + LP6 :: 0h3FC39A09D078C69F + LP7 :: 0h3FC2F112DF3E5244 + + switch { + case x < -1 || is_nan(x): + return nan_f64() + case x == -1: + return inf_f64(-1) + case is_inf(x, 1): + return inf_f64(+1) + } + absx := abs(x) + + f: f64 + iu: u64 + k := 1 + if absx < SQRT2_M1 { // |x| < Sqrt(2)-1 + if absx < SMALL { // |x| < 2**-29 + if absx < TINY { // |x| < 2**-54 + return x + } + return x - x*x*0.5 + } + if x > SQRT2_HALF_M1 { // Sqrt(2)/2-1 < x + // (Sqrt(2)/2-1) < x < (Sqrt(2)-1) + k = 0 + f = x + iu = 1 + } + } + c: f64 + if k != 0 { + u: f64 + if absx < TWO53 { // 1<<53 + u = 1.0 + x + iu = transmute(u64)u + k = int((iu >> 52) - 1023) + // correction term + if k > 0 { + c = 1.0 - (u - x) + } else { + c = x - (u - 1.0) + } + c /= u + } else { + u = x + iu = transmute(u64)u + k = int((iu >> 52) - 1023) + c = 0 + } + iu &= 0x000fffffffffffff + if iu < 0x0006a09e667f3bcd { // mantissa of Sqrt(2) + u = transmute(f64)(iu | 0x3ff0000000000000) // normalize u + } else { + k += 1 + u = transmute(f64)(iu | 0x3fe0000000000000) // normalize u/2 + iu = (0x0010000000000000 - iu) >> 2 + } + f = u - 1.0 // Sqrt(2)/2 < u < Sqrt(2) + } + hfsq := 0.5 * f * f + s, R, z: f64 + if iu == 0 { // |f| < 2**-20 + if f == 0 { + if k == 0 { + return 0 + } + c += f64(k) * LN2LO + return f64(k)*LN2HI + c + } + R = hfsq * (1.0 - 0.66666666666666666*f) // avoid division + if k == 0 { + return f - R + } + return f64(k)*LN2HI - ((R - (f64(k)*LN2LO + c)) - f) + } + s = f / (2.0 + f) + z = s * s + R = z * (LP1 + z*(LP2+z*(LP3+z*(LP4+z*(LP5+z*(LP6+z*LP7)))))) + if k == 0 { + return f - (hfsq - s*(hfsq+R)) + } + return f64(k)*LN2HI - ((hfsq - (s*(hfsq+R) + (f64(k)*LN2LO + c))) - f) +} From 91408cb21f5ad7d04f5dc63dc350f727fe93d920 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 14:58:59 +0000 Subject: [PATCH 0014/1258] Implement `atanh` based on FreeBSD's /usr/src/lib/msun/src/e_atanh.c --- core/math/math.odin | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/core/math/math.odin b/core/math/math.odin index 97fd4bd16..f63a0644b 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -1465,8 +1465,48 @@ acosh :: proc "contextless" (y: $T) -> T where intrinsics.type_is_float(T) { return T(log1p(t + sqrt(2*t + t*t))) } -atanh :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { - return 0.5*ln((1+x)/(1-x)) +atanh :: proc "contextless" (y: $T) -> T where intrinsics.type_is_float(T) { + // The original C code, the long comment, and the constants + // below are from FreeBSD's /usr/src/lib/msun/src/e_atanh.c + // and came with this notice. + // + // ==================================================== + // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + // + // Developed at SunPro, a Sun Microsystems, Inc. business. + // Permission to use, copy, modify, and distribute this + // software is freely granted, provided that this notice + // is preserved. + // ==================================================== + NEAR_ZERO :: 1.0 / (1 << 28) + x := f64(y) + switch { + case x < -1 || x > 1 || is_nan(x): + return T(nan_f64()) + case x == 1: + return T(inf_f64(1)) + case x == -1: + return T(inf_f64(-1)) + } + sign := false + if x < 0 { + x = -x + sign = true + } + temp: f64 + switch { + case x < NEAR_ZERO: + temp = x + case x < 0.5: + temp = x + x + temp = 0.5 * log1p(temp + temp*x/(1-x)) + case: + temp = 0.5 * log1p((x+x)/(1-x)) + } + if sign { + temp = -temp + } + return T(temp) } ilogb_f16 :: proc "contextless" (val: f16) -> int { From e721f26a76facc8d0d9b5f2fccdb171c3857a327 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 15:05:04 +0000 Subject: [PATCH 0015/1258] Implement `ln` based off FreeBSD's /usr/src/lib/msun/src/e_log.c --- core/math/math.odin | 12 ---- core/math/math_basic.odin | 124 +++++++++++++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 19 deletions(-) diff --git a/core/math/math.odin b/core/math/math.odin index f63a0644b..5dd8f3732 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -96,18 +96,6 @@ fmuladd :: proc{ fmuladd_f64, fmuladd_f64le, fmuladd_f64be, } -ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f16(f16(x))) } -ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f16(f16(x))) } -ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f32(f32(x))) } -ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f32(f32(x))) } -ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) } -ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) } -ln :: proc{ - ln_f16, ln_f16le, ln_f16be, - ln_f32, ln_f32le, ln_f32be, - ln_f64, ln_f64le, ln_f64be, -} - exp_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(exp_f16(f16(x))) } exp_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(exp_f16(f16(x))) } exp_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(exp_f32(f32(x))) } diff --git a/core/math/math_basic.odin b/core/math/math_basic.odin index fe7b07d98..27c9bb366 100644 --- a/core/math/math_basic.odin +++ b/core/math/math_basic.odin @@ -33,13 +33,6 @@ foreign _ { @(link_name="llvm.fmuladd.f64") fmuladd_f64 :: proc(a, b, c: f64) -> f64 --- - @(link_name="llvm.log.f16") - ln_f16 :: proc(x: f16) -> f16 --- - @(link_name="llvm.log.f32") - ln_f32 :: proc(x: f32) -> f32 --- - @(link_name="llvm.log.f64") - ln_f64 :: proc(x: f64) -> f64 --- - @(link_name="llvm.exp.f16") exp_f16 :: proc(x: f16) -> f16 --- @(link_name="llvm.exp.f32") @@ -57,3 +50,120 @@ sqrt_f32 :: proc "contextless" (x: f32) -> f32 { sqrt_f64 :: proc "contextless" (x: f64) -> f64 { return intrinsics.sqrt(x) } + + + +ln_f64 :: proc "contextless" (x: f64) -> f64 { + // The original C code, the long comment, and the constants + // below are from FreeBSD's /usr/src/lib/msun/src/e_log.c + // and came with this notice. + // + // ==================================================== + // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + // + // Developed at SunPro, a Sun Microsystems, Inc. business. + // Permission to use, copy, modify, and distribute this + // software is freely granted, provided that this notice + // is preserved. + // ==================================================== + // + // __ieee754_log(x) + // Return the logarithm of x + // + // Method : + // 1. Argument Reduction: find k and f such that + // x = 2**k * (1+f), + // where sqrt(2)/2 < 1+f < sqrt(2) . + // + // 2. Approximation of log(1+f). + // Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) + // = 2s + 2/3 s**3 + 2/5 s**5 + ....., + // = 2s + s*R + // We use a special Reme algorithm on [0,0.1716] to generate + // a polynomial of degree 14 to approximate R. The maximum error + // of this polynomial approximation is bounded by 2**-58.45. In + // other words, + // 2 4 6 8 10 12 14 + // R(z) ~ L1*s +L2*s +L3*s +L4*s +L5*s +L6*s +L7*s + // (the values of L1 to L7 are listed in the program) and + // | 2 14 | -58.45 + // | L1*s +...+L7*s - R(z) | <= 2 + // | | + // Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. + // In order to guarantee error in log below 1ulp, we compute log by + // log(1+f) = f - s*(f - R) (if f is not too large) + // log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) + // + // 3. Finally, log(x) = k*Ln2 + log(1+f). + // = k*Ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*Ln2_lo))) + // Here Ln2 is split into two floating point number: + // Ln2_hi + Ln2_lo, + // where n*Ln2_hi is always exact for |n| < 2000. + // + // Special cases: + // log(x) is NaN with signal if x < 0 (including -INF) ; + // log(+INF) is +INF; log(0) is -INF with signal; + // log(NaN) is that NaN with no signal. + // + // Accuracy: + // according to an error analysis, the error is always less than + // 1 ulp (unit in the last place). + // + // Constants: + // The hexadecimal values are the intended ones for the following + // constants. The decimal values may be used, provided that the + // compiler will convert from decimal to binary accurately enough + // to produce the hexadecimal values shown. + + LN2_HI :: 0h3fe62e42_fee00000 // 6.93147180369123816490e-01 + LN2_LO :: 0h3dea39ef_35793c76 // 1.90821492927058770002e-10 + L1 :: 0h3fe55555_55555593 // 6.666666666666735130e-01 + L2 :: 0h3fd99999_9997fa04 // 3.999999999940941908e-01 + L3 :: 0h3fd24924_94229359 // 2.857142874366239149e-01 + L4 :: 0h3fcc71c5_1d8e78af // 2.222219843214978396e-01 + L5 :: 0h3fc74664_96cb03de // 1.818357216161805012e-01 + L6 :: 0h3fc39a09_d078c69f // 1.531383769920937332e-01 + L7 :: 0h3fc2f112_df3e5244 // 1.479819860511658591e-01 + + switch { + case is_nan(x) || is_inf(x, 1): + return x + case x < 0: + return nan_f64() + case x == 0: + return inf_f64(-1) + } + + // reduce + f1, ki := frexp(x) + if f1 < SQRT_TWO/2 { + f1 *= 2 + ki -= 1 + } + f := f1 - 1 + k := f64(ki) + + // compute + s := f / (2 + f) + s2 := s * s + s4 := s2 * s2 + t1 := s2 * (L1 + s4*(L3+s4*(L5+s4*L7))) + t2 := s4 * (L2 + s4*(L4+s4*L6)) + R := t1 + t2 + hfsq := 0.5 * f * f + return k*Ln2Hi_ - ((hfsq - (s*(hfsq+R) + k*LN2_LO)) - f) +} + +ln_f16 :: proc "contextless" (x: f16) -> f16 { return #force_inline f16(ln_f64(f64(x))) } +ln_f32 :: proc "contextless" (x: f32) -> f32 { return #force_inline f32(ln_f64(f64(x))) } +ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) } +ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) } +ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) } +ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) } +ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) } +ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) } +ln :: proc{ + ln_f16, ln_f16le, ln_f16be, + ln_f32, ln_f32le, ln_f32be, + ln_f64, ln_f64le, ln_f64be, +} \ No newline at end of file From d2327961495a95f1a92f8630bd9346eb748889ca Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 15:09:47 +0000 Subject: [PATCH 0016/1258] Fix typo --- core/math/math_basic.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/math/math_basic.odin b/core/math/math_basic.odin index 27c9bb366..c9d2e632d 100644 --- a/core/math/math_basic.odin +++ b/core/math/math_basic.odin @@ -151,7 +151,7 @@ ln_f64 :: proc "contextless" (x: f64) -> f64 { t2 := s4 * (L2 + s4*(L4+s4*L6)) R := t1 + t2 hfsq := 0.5 * f * f - return k*Ln2Hi_ - ((hfsq - (s*(hfsq+R) + k*LN2_LO)) - f) + return k*LN2_HI - ((hfsq - (s*(hfsq+R) + k*LN2_LO)) - f) } ln_f16 :: proc "contextless" (x: f16) -> f16 { return #force_inline f16(ln_f64(f64(x))) } From b530ca9a5e64643b11f5ddb67e15e8aacf0af2fa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 15:12:01 +0000 Subject: [PATCH 0017/1258] Add `math.nextafter` --- core/math/math.odin | 59 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/core/math/math.odin b/core/math/math.odin index 5dd8f3732..577536972 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -1584,6 +1584,65 @@ logb :: proc { logb_f64be, } +nextafter_f16 :: proc "contextless" (x, y: f16) -> (r: f16) { + switch { + case is_nan(x) || is_nan(y): + r = nan_f16() + case x == y: + r = x + case x == 0: + r = copy_sign_f16(1, y) + case (y > x) == (x > 0): + r = transmute(f16)(transmute(u16)x + 1) + case: + r = transmute(f16)(transmute(u16)x - 1) + } + return +} +nextafter_f32 :: proc "contextless" (x, y: f32) -> (r: f32) { + switch { + case is_nan(x) || is_nan(y): + r = nan_f32() + case x == y: + r = x + case x == 0: + r = copy_sign_f32(1, y) + case (y > x) == (x > 0): + r = transmute(f32)(transmute(u32)x + 1) + case: + r = transmute(f32)(transmute(u32)x - 1) + } + return +} +nextafter_f64 :: proc "contextless" (x, y: f64) -> (r: f64) { + switch { + case is_nan(x) || is_nan(y): + r = nan_f64() + case x == y: + r = x + case x == 0: + r = copy_sign_f64(1, y) + case (y > x) == (x > 0): + r = transmute(f64)(transmute(u64)x + 1) + case: + r = transmute(f64)(transmute(u64)x - 1) + } + return +} +nextafter_f16le :: proc "contextless" (x, y: f16le) -> (r: f16le) { return f16le(nextafter_f16(f16(x), f16(y))) } +nextafter_f16be :: proc "contextless" (x, y: f16be) -> (r: f16be) { return f16be(nextafter_f16(f16(x), f16(y))) } +nextafter_f32le :: proc "contextless" (x, y: f32le) -> (r: f32le) { return f32le(nextafter_f32(f32(x), f32(y))) } +nextafter_f32be :: proc "contextless" (x, y: f32be) -> (r: f32be) { return f32be(nextafter_f32(f32(x), f32(y))) } +nextafter_f64le :: proc "contextless" (x, y: f64le) -> (r: f64le) { return f64le(nextafter_f64(f64(x), f64(y))) } +nextafter_f64be :: proc "contextless" (x, y: f64be) -> (r: f64be) { return f64be(nextafter_f64(f64(x), f64(y))) } + +nextafter :: proc{ + nextafter_f16, nextafter_f16le, nextafter_f16be, + nextafter_f32, nextafter_f32le, nextafter_f32be, + nextafter_f64, nextafter_f64le, nextafter_f64be, +} + + F16_DIG :: 3 F16_EPSILON :: 0.00097656 F16_GUARD :: 0 From 2b546a598c34ff1319df000af2dbc496f2fe4f3b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 15:23:19 +0000 Subject: [PATCH 0018/1258] Add `math.signbit`; Add `math.gamma` based on http://netlib.sandia.gov/cephes/cprob/gamma.c --- core/math/math.odin | 22 ++++ core/math/math_gamma.odin | 226 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 core/math/math_gamma.odin diff --git a/core/math/math.odin b/core/math/math.odin index 577536972..ef89562c9 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -1642,6 +1642,28 @@ nextafter :: proc{ nextafter_f64, nextafter_f64le, nextafter_f64be, } +signbit_f16 :: proc "contextless" (x: f16) -> bool { + return (transmute(u16)x)&(1<<15) != 0 +} +signbit_f32 :: proc "contextless" (x: f32) -> bool { + return (transmute(u32)x)&(1<<31) != 0 +} +signbit_f64 :: proc "contextless" (x: f64) -> bool { + return (transmute(u64)x)&(1<<63) != 0 +} +signbit_f16le :: proc "contextless" (x: f16le) -> bool { return signbit_f16(f16(x)) } +signbit_f32le :: proc "contextless" (x: f32le) -> bool { return signbit_f32(f32(x)) } +signbit_f64le :: proc "contextless" (x: f64le) -> bool { return signbit_f64(f64(x)) } +signbit_f16be :: proc "contextless" (x: f16be) -> bool { return signbit_f16(f16(x)) } +signbit_f32be :: proc "contextless" (x: f32be) -> bool { return signbit_f32(f32(x)) } +signbit_f64be :: proc "contextless" (x: f64be) -> bool { return signbit_f64(f64(x)) } + +signbit :: proc{ + signbit_f16, signbit_f16le, signbit_f16be, + signbit_f32, signbit_f32le, signbit_f32be, + signbit_f64, signbit_f64le, signbit_f64be, +} + F16_DIG :: 3 F16_EPSILON :: 0.00097656 diff --git a/core/math/math_gamma.odin b/core/math/math_gamma.odin new file mode 100644 index 000000000..0a6188a9f --- /dev/null +++ b/core/math/math_gamma.odin @@ -0,0 +1,226 @@ +package math + +// The original C code, the long comment, and the constants +// below are from http://netlib.sandia.gov/cephes/cprob/gamma.c. +// +// tgamma.c +// +// Gamma function +// +// SYNOPSIS: +// +// double x, y, tgamma(); +// extern int signgam; +// +// y = tgamma( x ); +// +// DESCRIPTION: +// +// Returns gamma function of the argument. The result is +// correctly signed, and the sign (+1 or -1) is also +// returned in a global (extern) variable named signgam. +// This variable is also filled in by the logarithmic gamma +// function lgamma(). +// +// Arguments |x| <= 34 are reduced by recurrence and the function +// approximated by a rational function of degree 6/7 in the +// interval (2,3). Large arguments are handled by Stirling's +// formula. Large negative arguments are made positive using +// a reflection formula. +// +// ACCURACY: +// +// Relative error: +// arithmetic domain # trials peak rms +// DEC -34, 34 10000 1.3e-16 2.5e-17 +// IEEE -170,-33 20000 2.3e-15 3.3e-16 +// IEEE -33, 33 20000 9.4e-16 2.2e-16 +// IEEE 33, 171.6 20000 2.3e-15 3.2e-16 +// +// Error for arguments outside the test range will be larger +// owing to error amplification by the exponential function. +// +// Cephes Math Library Release 2.8: June, 2000 +// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +// +// The readme file at http://netlib.sandia.gov/cephes/ says: +// Some software in this archive may be from the book _Methods and +// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster +// International, 1989) or from the Cephes Mathematical Library, a +// commercial product. In either event, it is copyrighted by the author. +// What you see here may be used freely but it comes with no support or +// guarantee. +// +// The two known misprints in the book are repaired here in the +// source listings for the gamma function and the incomplete beta +// integral. +// +// Stephen L. Moshier +// moshier@na-net.ornl.gov + +// Gamma function computed by Stirling's formula. +// The pair of results must be multiplied together to get the actual answer. +// The multiplication is left to the caller so that, if careful, the caller can avoid +// infinity for 172 <= x <= 180. +// The polynomial is valid for 33 <= x <= 172; larger values are only used +// in reciprocal and produce denormalized floats. The lower precision there +// masks any imprecision in the polynomial. +@(private="file") +stirling :: proc "contextless" (x: f64) -> (f64, f64) { + @(static) gamS := [?]f64{ + 7.87311395793093628397e-04, + -2.29549961613378126380e-04, + -2.68132617805781232825e-03, + 3.47222221605458667310e-03, + 8.33333333333482257126e-02, + } + + if x > 200 { + return inf_f64(1), 1 + } + SQRT_TWO_PI :: 2.506628274631000502417 + MAX_STIRLING :: 143.01608 + w := 1 / x + w = 1 + w*((((gamS[0]*w+gamS[1])*w+gamS[2])*w+gamS[3])*w+gamS[4]) + y1 := exp(x) + y2 := 1.0 + if x > MAX_STIRLING { // avoid pow() overflow + v := pow(x, 0.5*x-0.25) + y1, y2 = v, v/y1 + } else { + y1 = pow(x, x-0.5) / y1 + } + return y1, SQRT_TWO_PI * w * y2 +} + +gamma_f64 :: proc "contextless" (x: f64) -> f64 { + is_neg_int :: proc "contextless" (x: f64) -> bool { + if x < 0 { + _, xf := modf(x) + return xf == 0 + } + return false + } + + @(static) gamP := [?]f64{ + 1.60119522476751861407e-04, + 1.19135147006586384913e-03, + 1.04213797561761569935e-02, + 4.76367800457137231464e-02, + 2.07448227648435975150e-01, + 4.94214826801497100753e-01, + 9.99999999999999996796e-01, + } + @(static) gamQ := [?]f64{ + -2.31581873324120129819e-05, + 5.39605580493303397842e-04, + -4.45641913851797240494e-03, + 1.18139785222060435552e-02, + 3.58236398605498653373e-02, + -2.34591795718243348568e-01, + 7.14304917030273074085e-02, + 1.00000000000000000320e+00, + } + + + EULER :: 0.57721566490153286060651209008240243104215933593992 // A001620 + + switch { + case is_neg_int(x) || is_inf(x, -1) || is_nan(x): + return nan_f64() + case is_inf(x, 1): + return inf_f64(1) + case x == 0: + if signbit(x) { + return inf_f64(-1) + } + return inf_f64(1) + } + + x := x + q := abs(x) + p := floor(q) + if q > 33 { + if x >= 0 { + y1, y2 := stirling(x) + return y1 * y2 + } + // Note: x is negative but (checked above) not a negative integer, + // so x must be small enough to be in range for conversion to i64. + // If |x| were >= 2⁶³ it would have to be an integer. + signgam := 1 + if ip := i64(p); ip&1 == 0 { + signgam = -1 + } + z := q - p + if z > 0.5 { + p = p + 1 + z = q - p + } + z = q * sin(PI*z) + if z == 0 { + return inf_f64(signgam) + } + sq1, sq2 := stirling(q) + absz := abs(z) + d := absz * sq1 * sq2 + if is_inf(d, 0) { + z = PI / absz / sq1 / sq2 + } else { + z = PI / d + } + return f64(signgam) * z + } + + // Reduce argument + z := 1.0 + for x >= 3 { + x = x - 1 + z = z * x + } + for x < 0 { + if x > -1e-09 { + if x == 0 { + return inf_f64(1) + } + return z / ((1 + EULER*x) * x) + } + z = z / x + x = x + 1 + } + for x < 2 { + if x < 1e-09 { + if x == 0 { + return inf_f64(1) + } + return z / ((1 + EULER*x) * x) + } + z = z / x + x = x + 1 + } + + if x == 2 { + return z + } + + x = x - 2 + p = (((((x*gamP[0]+gamP[1])*x+gamP[2])*x+gamP[3])*x+gamP[4])*x+gamP[5])*x + gamP[6] + q = ((((((x*gamQ[0]+gamQ[1])*x+gamQ[2])*x+gamQ[3])*x+gamQ[4])*x+gamQ[5])*x+gamQ[6])*x + gamQ[7] + return z * p / q +} + + +gamma_f16 :: proc "contextless" (x: f16) -> f16 { return f16(gamma_f64(f64(x))) } +gamma_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(gamma_f64(f64(x))) } +gamma_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(gamma_f64(f64(x))) } +gamma_f32 :: proc "contextless" (x: f32) -> f32 { return f32(gamma_f64(f64(x))) } +gamma_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(gamma_f64(f64(x))) } +gamma_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(gamma_f64(f64(x))) } +gamma_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(gamma_f64(f64(x))) } +gamma_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(gamma_f64(f64(x))) } + +gamma :: proc{ + gamma_f16, gamma_f16le, gamma_f16be, + gamma_f32, gamma_f32le, gamma_f32be, + gamma_f64, gamma_f64le, gamma_f64be, +} \ No newline at end of file From 1b28226a6788d095c66925276c7a28041f8bb2de Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 15:32:32 +0000 Subject: [PATCH 0019/1258] Add `math.lgamma` based off FreeBSD's `/usr/src/lib/msun/src/e_lgamma_r.c` --- core/math/math_lgamma.odin | 361 +++++++++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 core/math/math_lgamma.odin diff --git a/core/math/math_lgamma.odin b/core/math/math_lgamma.odin new file mode 100644 index 000000000..e6cbdf6cd --- /dev/null +++ b/core/math/math_lgamma.odin @@ -0,0 +1,361 @@ +package math + +// The original C code and the long comment below are +// from FreeBSD's /usr/src/lib/msun/src/e_lgamma_r.c and +// came with this notice. +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== +// +// __ieee754_lgamma_r(x, signgamp) +// Reentrant version of the logarithm of the Gamma function +// with user provided pointer for the sign of Gamma(x). +// +// Method: +// 1. Argument Reduction for 0 < x <= 8 +// Since gamma(1+s)=s*gamma(s), for x in [0,8], we may +// reduce x to a number in [1.5,2.5] by +// lgamma(1+s) = log(s) + lgamma(s) +// for example, +// lgamma(7.3) = log(6.3) + lgamma(6.3) +// = log(6.3*5.3) + lgamma(5.3) +// = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) +// 2. Polynomial approximation of lgamma around its +// minimum (ymin=1.461632144968362245) to maintain monotonicity. +// On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use +// Let z = x-ymin; +// lgamma(x) = -1.214862905358496078218 + z**2*poly(z) +// poly(z) is a 14 degree polynomial. +// 2. Rational approximation in the primary interval [2,3] +// We use the following approximation: +// s = x-2.0; +// lgamma(x) = 0.5*s + s*P(s)/Q(s) +// with accuracy +// |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 +// Our algorithms are based on the following observation +// +// zeta(2)-1 2 zeta(3)-1 3 +// lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... +// 2 3 +// +// where Euler = 0.5772156649... is the Euler constant, which +// is very close to 0.5. +// +// 3. For x>=8, we have +// lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... +// (better formula: +// lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) +// Let z = 1/x, then we approximation +// f(z) = lgamma(x) - (x-0.5)(log(x)-1) +// by +// 3 5 11 +// w = w0 + w1*z + w2*z + w3*z + ... + w6*z +// where +// |w - f(z)| < 2**-58.74 +// +// 4. For negative x, since (G is gamma function) +// -x*G(-x)*G(x) = pi/sin(pi*x), +// we have +// G(x) = pi/(sin(pi*x)*(-x)*G(-x)) +// since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 +// Hence, for x<0, signgam = sign(sin(pi*x)) and +// lgamma(x) = log(|Gamma(x)|) +// = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); +// Note: one should avoid computing pi*(-x) directly in the +// computation of sin(pi*(-x)). +// +// 5. Special Cases +// lgamma(2+s) ~ s*(1-Euler) for tiny s +// lgamma(1)=lgamma(2)=0 +// lgamma(x) ~ -log(x) for tiny x +// lgamma(0) = lgamma(inf) = inf +// lgamma(-integer) = +-inf +// +// + + +lgamma_f64 :: proc "contextless" (x: f64) -> (lgamma: f64, sign: int) { + sin_pi :: proc "contextless" (x: f64) -> f64 { + if x < 0.25 { + return -sin(PI * x) + } + x := x + + // argument reduction + z := floor(x) + n: int + if z != x { // inexact + x = mod(x, 2) + n = int(x * 4) + } else { + if x >= TWO_53 { // x must be even + x = 0 + n = 0 + } else { + if x < TWO_52 { + z = x + TWO_52 // exact + } + n = int(1 & transmute(u64)z) + x = f64(n) + n <<= 2 + } + } + switch n { + case 0: + x = sin(PI * x) + case 1, 2: + x = cos(PI * (0.5 - x)) + case 3, 4: + x = sin(PI * (1 - x)) + case 5, 6: + x = -cos(PI * (x - 1.5)) + case: + x = sin(PI * (x - 2)) + } + return -x + } + + @static lgamA := [?]f64{ + 0h3FB3C467E37DB0C8, + 0h3FD4A34CC4A60FAD, + 0h3FB13E001A5562A7, + 0h3F951322AC92547B, + 0h3F7E404FB68FEFE8, + 0h3F67ADD8CCB7926B, + 0h3F538A94116F3F5D, + 0h3F40B6C689B99C00, + 0h3F2CF2ECED10E54D, + 0h3F1C5088987DFB07, + 0h3EFA7074428CFA52, + 0h3F07858E90A45837, + } + @static lgamR := [?]f64{ + 1.0, + 0h3FF645A762C4AB74, + 0h3FE71A1893D3DCDC, + 0h3FC601EDCCFBDF27, + 0h3F9317EA742ED475, + 0h3F497DDACA41A95B, + 0h3EDEBAF7A5B38140, + } + @static lgamS := [?]f64{ + 0hBFB3C467E37DB0C8, + 0h3FCB848B36E20878, + 0h3FD4D98F4F139F59, + 0h3FC2BB9CBEE5F2F7, + 0h3F9B481C7E939961, + 0h3F5E26B67368F239, + 0h3F00BFECDD17E945, + } + @static lgamT := [?]f64{ + 0h3FDEF72BC8EE38A2, + 0hBFC2E4278DC6C509, + 0h3FB08B4294D5419B, + 0hBFA0C9A8DF35B713, + 0h3F9266E7970AF9EC, + 0hBF851F9FBA91EC6A, + 0h3F78FCE0E370E344, + 0hBF6E2EFFB3E914D7, + 0h3F6282D32E15C915, + 0hBF56FE8EBF2D1AF1, + 0h3F4CDF0CEF61A8E9, + 0hBF41A6109C73E0EC, + 0h3F34AF6D6C0EBBF7, + 0hBF347F24ECC38C38, + 0h3F35FD3EE8C2D3F4, + } + @static lgamU := [?]f64{ + 0hBFB3C467E37DB0C8, + 0h3FE4401E8B005DFF, + 0h3FF7475CD119BD6F, + 0h3FEF497644EA8450, + 0h3FCD4EAEF6010924, + 0h3F8B678BBF2BAB09, + } + @static lgamV := [?]f64{ + 1.0, + 0h4003A5D7C2BD619C, + 0h40010725A42B18F5, + 0h3FE89DFBE45050AF, + 0h3FBAAE55D6537C88, + 0h3F6A5ABB57D0CF61, + } + @static lgamW := [?]f64{ + 0h3FDACFE390C97D69, + 0h3FB555555555553B, + 0hBF66C16C16B02E5C, + 0h3F4A019F98CF38B6, + 0hBF4380CB8C0FE741, + 0h3F4B67BA4CDAD5D1, + 0hBF5AB89D0B9E43E4, + } + + + Y_MIN :: 1.461632144968362245 + TWO_52 :: 0h4330000000000000 // ~4.5036e+15 + TWO_53 :: 0h4340000000000000 // ~9.0072e+15 + TWO_58 :: 0h4390000000000000 // ~2.8823e+17 + TINY :: 0h3b90000000000000 // ~8.47033e-22 + Tc :: 0h3FF762D86356BE3F + Tf :: 0hBFBF19B9BCC38A42 + Tt :: 0hBC50C7CAA48A971F + + // special cases + sign = 1 + switch { + case is_nan(x): + lgamma = x + return + case is_inf(x): + lgamma = x + return + case x == 0: + lgamma = inf_f64(1) + return + } + + x := x + neg := false + if x < 0 { + x = -x + neg = true + } + + if x < TINY { // if |x| < 2**-70, return -log(|x|) + if neg { + sign = -1 + } + lgamma = -ln(x) + return + } + nadj: f64 + if neg { + if x >= TWO_52 { // |x| >= 2**52, must be -integer + lgamma = inf_f64(1) + return + } + t := sin_pi(x) + if t == 0 { + lgamma = inf_f64(1) // -integer + return + } + nadj = ln(PI / abs(t*x)) + if t < 0 { + sign = -1 + } + } + + switch { + case x == 1 || x == 2: // purge off 1 and 2 + lgamma = 0 + return + case x < 2: // use lgamma(x) = lgamma(x+1) - log(x) + y: f64 + i: int + if x <= 0.9 { + lgamma = -ln(x) + switch { + case x >= (Y_MIN - 1 + 0.27): // 0.7316 <= x <= 0.9 + y = 1 - x + i = 0 + case x >= (Y_MIN - 1 - 0.27): // 0.2316 <= x < 0.7316 + y = x - (Tc - 1) + i = 1 + case: // 0 < x < 0.2316 + y = x + i = 2 + } + } else { + lgamma = 0 + switch { + case x >= (Y_MIN + 0.27): // 1.7316 <= x < 2 + y = 2 - x + i = 0 + case x >= (Y_MIN - 0.27): // 1.2316 <= x < 1.7316 + y = x - Tc + i = 1 + case: // 0.9 < x < 1.2316 + y = x - 1 + i = 2 + } + } + switch i { + case 0: + z := y * y + p1 := lgamA[0] + z*(lgamA[2]+z*(lgamA[4]+z*(lgamA[6]+z*(lgamA[8]+z*lgamA[10])))) + p2 := z * (lgamA[1] + z*(+lgamA[3]+z*(lgamA[5]+z*(lgamA[7]+z*(lgamA[9]+z*lgamA[11]))))) + p := y*p1 + p2 + lgamma += (p - 0.5*y) + case 1: + z := y * y + w := z * y + p1 := lgamT[0] + w*(lgamT[3]+w*(lgamT[6]+w*(lgamT[9]+w*lgamT[12]))) // parallel comp + p2 := lgamT[1] + w*(lgamT[4]+w*(lgamT[7]+w*(lgamT[10]+w*lgamT[13]))) + p3 := lgamT[2] + w*(lgamT[5]+w*(lgamT[8]+w*(lgamT[11]+w*lgamT[14]))) + p := z*p1 - (Tt - w*(p2+y*p3)) + lgamma += (Tf + p) + case 2: + p1 := y * (lgamU[0] + y*(lgamU[1]+y*(lgamU[2]+y*(lgamU[3]+y*(lgamU[4]+y*lgamU[5]))))) + p2 := 1 + y*(lgamV[1]+y*(lgamV[2]+y*(lgamV[3]+y*(lgamV[4]+y*lgamV[5])))) + lgamma += (-0.5*y + p1/p2) + } + case x < 8: // 2 <= x < 8 + i := int(x) + y := x - f64(i) + p := y * (lgamS[0] + y*(lgamS[1]+y*(lgamS[2]+y*(lgamS[3]+y*(lgamS[4]+y*(lgamS[5]+y*lgamS[6])))))) + q := 1 + y*(lgamR[1]+y*(lgamR[2]+y*(lgamR[3]+y*(lgamR[4]+y*(lgamR[5]+y*lgamR[6]))))) + lgamma = 0.5*y + p/q + z := 1.0 // lgamma(1+s) = ln(s) + lgamma(s) + switch i { + case 7: + z *= (y + 6) + fallthrough + case 6: + z *= (y + 5) + fallthrough + case 5: + z *= (y + 4) + fallthrough + case 4: + z *= (y + 3) + fallthrough + case 3: + z *= (y + 2) + lgamma += ln(z) + } + case x < TWO_58: // 8 <= x < 2**58 + t := ln(x) + z := 1 / x + y := z * z + w := lgamW[0] + z*(lgamW[1]+y*(lgamW[2]+y*(lgamW[3]+y*(lgamW[4]+y*(lgamW[5]+y*lgamW[6]))))) + lgamma = (x-0.5)*(t-1) + w + case: // 2**58 <= x <= Inf + lgamma = x * (ln(x) - 1) + } + if neg { + lgamma = nadj - lgamma + } + return +} + + +lgamma_f16 :: proc "contextless" (x: f16) -> (lgamma: f16, sign: int) { r, s := lgamma_f64(f64(x)); return f16(r), s } +lgamma_f32 :: proc "contextless" (x: f32) -> (lgamma: f32, sign: int) { r, s := lgamma_f64(f64(x)); return f32(r), s } +lgamma_f16le :: proc "contextless" (x: f16le) -> (lgamma: f16le, sign: int) { r, s := lgamma_f64(f64(x)); return f16le(r), s } +lgamma_f16be :: proc "contextless" (x: f16be) -> (lgamma: f16be, sign: int) { r, s := lgamma_f64(f64(x)); return f16be(r), s } +lgamma_f32le :: proc "contextless" (x: f32le) -> (lgamma: f32le, sign: int) { r, s := lgamma_f64(f64(x)); return f32le(r), s } +lgamma_f32be :: proc "contextless" (x: f32be) -> (lgamma: f32be, sign: int) { r, s := lgamma_f64(f64(x)); return f32be(r), s } +lgamma_f64le :: proc "contextless" (x: f64le) -> (lgamma: f64le, sign: int) { r, s := lgamma_f64(f64(x)); return f64le(r), s } +lgamma_f64be :: proc "contextless" (x: f64be) -> (lgamma: f64be, sign: int) { r, s := lgamma_f64(f64(x)); return f64be(r), s } + +lgamma :: proc{ + lgamma_f16, lgamma_f16le, lgamma_f16be, + lgamma_f32, lgamma_f32le, lgamma_f32be, + lgamma_f64, lgamma_f64le, lgamma_f64be, +} \ No newline at end of file From bb7703fcec792904621bc0fc023abbb13af888a3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 16:08:20 +0000 Subject: [PATCH 0020/1258] Improve `ptr_map_hash_key` --- src/ptr_map.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp index 3d6be1d44..43e793b8a 100644 --- a/src/ptr_map.cpp +++ b/src/ptr_map.cpp @@ -28,11 +28,13 @@ struct PtrMap { u32 ptr_map_hash_key(uintptr key) { #if defined(GB_ARCH_64_BIT) - u64 x = (u64)key; - u8 count = (u8)(x >> 59); - x ^= x >> (5 + count); - x *= 12605985483714917081ull; - return (u32)(x ^ (x >> 43)); + key = (~key) + (key << 21); + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); + key = key ^ (key << 28); + return cast(u32)key; #elif defined(GB_ARCH_32_BIT) u32 state = ((u32)key) * 747796405u + 2891336453u; u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; From f09638318f4e2ef0966ed4c074026ba1a7c0cee8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Nov 2021 21:19:08 +0000 Subject: [PATCH 0021/1258] Add support for darwin to `core:c/libc` --- core/c/libc/complex.odin | 2 ++ core/c/libc/ctype.odin | 2 ++ core/c/libc/errno.odin | 16 ++++++++++++++++ core/c/libc/math.odin | 2 ++ core/c/libc/setjmp.odin | 3 ++- core/c/libc/signal.odin | 17 ++++++++++++++++- core/c/libc/stdio.odin | 34 +++++++++++++++++++++++++++++++++- core/c/libc/stdlib.odin | 20 +++++++++++++++++++- core/c/libc/string.odin | 2 ++ core/c/libc/threads.odin | 5 +++++ core/c/libc/time.odin | 8 +++++--- core/c/libc/uchar.odin | 2 ++ core/c/libc/wchar.odin | 2 ++ core/c/libc/wctype.odin | 9 ++++++++- 14 files changed, 116 insertions(+), 8 deletions(-) diff --git a/core/c/libc/complex.odin b/core/c/libc/complex.odin index e91d39023..62b28f0cd 100644 --- a/core/c/libc/complex.odin +++ b/core/c/libc/complex.odin @@ -4,6 +4,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } diff --git a/core/c/libc/ctype.odin b/core/c/libc/ctype.odin index 9e4b31208..05d9dcd37 100644 --- a/core/c/libc/ctype.odin +++ b/core/c/libc/ctype.odin @@ -2,6 +2,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin index dd17ce515..8ebe2f734 100644 --- a/core/c/libc/errno.odin +++ b/core/c/libc/errno.odin @@ -4,6 +4,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } @@ -38,6 +40,20 @@ when ODIN_OS == "windows" { ERANGE :: 34 } +when ODIN_OS == "darwin" { + @(private="file") + @(default_calling_convention="c") + foreign libc { + @(link_name="__error") + _get_errno :: proc() -> ^int --- + } + + // Unknown + EDOM :: 33 + EILSEQ :: 92 + ERANGE :: 34 +} + // Odin has no way to make an identifier "errno" behave as a function call to // read the value, or to produce an lvalue such that you can assign a different // error value to errno. To work around this, just expose it as a function like diff --git a/core/c/libc/math.odin b/core/c/libc/math.odin index c1c51fa25..ee702b82e 100644 --- a/core/c/libc/math.odin +++ b/core/c/libc/math.odin @@ -6,6 +6,8 @@ import "core:intrinsics" when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } diff --git a/core/c/libc/setjmp.odin b/core/c/libc/setjmp.odin index 4f3ae3aa3..dcd4a9c64 100644 --- a/core/c/libc/setjmp.odin +++ b/core/c/libc/setjmp.odin @@ -4,10 +4,11 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } - when ODIN_OS == "windows" { @(default_calling_convention="c") foreign libc { diff --git a/core/c/libc/signal.odin b/core/c/libc/signal.odin index ad007287e..e1044dc02 100644 --- a/core/c/libc/signal.odin +++ b/core/c/libc/signal.odin @@ -4,6 +4,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } @@ -32,7 +34,20 @@ when ODIN_OS == "windows" { SIGTERM :: 15 } -when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" { +when ODIN_OS == "linux" || ODIN_OS == "freebsd" { + SIG_ERR :: rawptr(~uintptr(0)) + SIG_DFL :: rawptr(uintptr(0)) + SIG_IGN :: rawptr(uintptr(1)) + + SIGABRT :: 6 + SIGFPE :: 8 + SIGILL :: 4 + SIGINT :: 2 + SIGSEGV :: 11 + SIGTERM :: 15 +} + +when ODIN_OS == "darwin" { SIG_ERR :: rawptr(~uintptr(0)) SIG_DFL :: rawptr(uintptr(0)) SIG_IGN :: rawptr(uintptr(1)) diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index 89891f82e..4a39c22e9 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -2,6 +2,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } @@ -67,7 +69,7 @@ when ODIN_OS == "linux" { SEEK_CUR :: 1 SEEK_END :: 2 - TMP_MAX :: 10000 + TMP_MAX :: 308915776 foreign libc { stderr: ^FILE @@ -76,6 +78,36 @@ when ODIN_OS == "linux" { } } +when ODIN_OS == "darwin" { + fpos_t :: distinct i64 + + _IOFBF :: 0 + _IOLBF :: 1 + _IONBF :: 2 + + BUFSIZ :: 1024 + + EOF :: int(-1) + + FOPEN_MAX :: 20 + + FILENAME_MAX :: 1024 + + L_tmpnam :: 1024 + + SEEK_SET :: 0 + SEEK_CUR :: 1 + SEEK_END :: 2 + + TMP_MAX :: 308915776 + + foreign libc { + @(link_name="__stderrp") stderr: ^FILE + @(link_name="__stdinp") stdin: ^FILE + @(link_name="__stdoutp") stdout: ^FILE + } +} + @(default_calling_convention="c") foreign libc { // 7.21.4 Operations on files diff --git a/core/c/libc/stdlib.odin b/core/c/libc/stdlib.odin index 0e24b0d5c..b368c0cee 100644 --- a/core/c/libc/stdlib.odin +++ b/core/c/libc/stdlib.odin @@ -4,6 +4,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } @@ -33,7 +35,23 @@ when ODIN_OS == "linux" { } MB_CUR_MAX :: #force_inline proc() -> size_t { - return __ctype_get_mb_cur_max() + return size_t(__ctype_get_mb_cur_max()) + } +} + + +when ODIN_OS == "darwin" { + RAND_MAX :: 0x7fffffff + + // GLIBC and MUSL only + @(private="file") + @(default_calling_convention="c") + foreign libc { + ___mb_cur_max :: proc() -> int --- + } + + MB_CUR_MAX :: #force_inline proc() -> size_t { + return size_t(___mb_cur_max()) } } diff --git a/core/c/libc/string.odin b/core/c/libc/string.odin index cd577237c..c91124dcb 100644 --- a/core/c/libc/string.odin +++ b/core/c/libc/string.odin @@ -6,6 +6,8 @@ import "core:runtime" when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } diff --git a/core/c/libc/threads.odin b/core/c/libc/threads.odin index 630216d06..ad305b517 100644 --- a/core/c/libc/threads.odin +++ b/core/c/libc/threads.odin @@ -136,3 +136,8 @@ when ODIN_OS == "linux" { tss_set :: proc(key: tss_t, val: rawptr) -> int --- } } + + +when ODIN_OS == "darwin" { + // TODO: find out what this is meant to be! +} diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin index 7cc677bff..96e80e216 100644 --- a/core/c/libc/time.odin +++ b/core/c/libc/time.odin @@ -4,6 +4,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } @@ -43,7 +45,7 @@ when ODIN_OS == "windows" { } } -when ODIN_OS == "linux" || ODIN_OS == "freebsd" { +when ODIN_OS == "linux" || ODIN_OS == "freebsd" || ODIN_OS == "darwin" { @(default_calling_convention="c") foreign libc { // 7.27.2 Time manipulation functions @@ -75,7 +77,7 @@ when ODIN_OS == "linux" || ODIN_OS == "freebsd" { tm :: struct { tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday, tm_isdst: int, - _: long, - _: rawptr, + tm_gmtoff: long, + tm_zone: rawptr, } } diff --git a/core/c/libc/uchar.odin b/core/c/libc/uchar.odin index 978d9b7bf..e49c29e51 100644 --- a/core/c/libc/uchar.odin +++ b/core/c/libc/uchar.odin @@ -4,6 +4,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } diff --git a/core/c/libc/wchar.odin b/core/c/libc/wchar.odin index d88a49dd9..fc206e494 100644 --- a/core/c/libc/wchar.odin +++ b/core/c/libc/wchar.odin @@ -4,6 +4,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin index 24af30c97..47f17e0b4 100644 --- a/core/c/libc/wctype.odin +++ b/core/c/libc/wctype.odin @@ -4,6 +4,8 @@ package libc when ODIN_OS == "windows" { foreign import libc "system:libucrt.lib" +} else when ODIN_OS == "darwin" { + foreign import libc "system:System.framework" } else { foreign import libc "system:c" } @@ -14,10 +16,15 @@ when ODIN_OS == "windows" { } when ODIN_OS == "linux" { - wctrans_t :: distinct rawptr + wctrans_t :: distinct intptr_t wctype_t :: distinct ulong } +when ODIN_OS == "darwin" { + wctrans_t :: distinct int + wctype_t :: distinct u32 +} + @(default_calling_convention="c") foreign libc { // 7.30.2.1 Wide character classification functions From e8775250730b78cdaac36e90decca473081978d0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 17 Nov 2021 10:40:55 +0000 Subject: [PATCH 0022/1258] Keep `-vet` happy for -no-crt and wasm targets --- core/runtime/procs.odin | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/runtime/procs.odin b/core/runtime/procs.odin index fe37c7e7d..961f6376f 100644 --- a/core/runtime/procs.odin +++ b/core/runtime/procs.odin @@ -42,7 +42,6 @@ when ODIN_NO_CRT && ODIN_OS == "windows" { memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr { if dst != src { d, s := ([^]byte)(dst), ([^]byte)(src) - d_end, s_end := d[len:], s[len:] for i := len-1; i >= 0; i -= 1 { d[i] = s[i] } @@ -54,7 +53,6 @@ when ODIN_NO_CRT && ODIN_OS == "windows" { memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr { if dst != src { d, s := ([^]byte)(dst), ([^]byte)(src) - d_end, s_end := d[len:], s[len:] for i := len-1; i >= 0; i -= 1 { d[i] = s[i] } From 9be0d18e5df63895e66782bb07484ee242e7028c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 17 Nov 2021 11:02:11 +0000 Subject: [PATCH 0023/1258] Correct `x in ptr` logic --- src/llvm_backend_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7f162856c..a23d60894 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1369,7 +1369,7 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { Type *rt = base_type(right.type); if (is_type_pointer(rt)) { right = lb_emit_load(p, right); - rt = type_deref(rt); + rt = base_type(type_deref(rt)); } switch (rt->kind) { From d1e76ee4f299fa2a47306c3dc8a4929abfdd4886 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sat, 6 Nov 2021 02:36:30 +0000 Subject: [PATCH 0024/1258] core/crypto: Add constant-time memory comparison routines Using a constant-time comparison is required when comparing things like MACs, password digests, and etc to avoid exposing sensitive data via trivial timing attacks. These routines could also live under core:mem, but they are somewhat specialized, and are likely only useful for cryptographic applications. --- core/crypto/crypto.odin | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 core/crypto/crypto.odin diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin new file mode 100644 index 000000000..ddcc5d367 --- /dev/null +++ b/core/crypto/crypto.odin @@ -0,0 +1,41 @@ +package crypto + +import "core:mem" + +// compare_constant_time returns 1 iff a and b are equal, 0 otherwise. +// +// The execution time of this routine is constant regardless of the contents +// of the slices being compared, as long as the length of the slices is equal. +// If the length of the two slices is different, it will early-return 0. +compare_constant_time :: proc "contextless" (a, b: []byte) -> int { + // If the length of the slices is different, early return. + // + // This leaks the fact that the slices have a different length, + // but the routine is primarily intended for comparing things + // like MACS and password digests. + n := len(a) + if n != len(b) { + return 0 + } + + return compare_byte_ptrs_constant_time(raw_data(a), raw_data(b), n) +} + +// compare_byte_ptrs_constant_time returns 1 iff the bytes pointed to by +// a and b are equal, 0 otherwise. +// +// The execution time of this routine is constant regardless of the +// contents of the memory being compared. +compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> int { + x := mem.slice_ptr(a, n) + y := mem.slice_ptr(b, n) + + v: byte + for i in 0..> 31) +} From 1a7a6a9116c7d9ed0e9ced208d0373ea62ad46c3 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sat, 6 Nov 2021 04:21:24 +0000 Subject: [PATCH 0025/1258] core/crypto: Add x25519 This package implements the X25519 key agreement scheme as specified in RFC 7748, using routines taken from fiat-crypto and Monocypher. --- core/crypto/_fiat/README.md | 35 + core/crypto/_fiat/fiat.odin | 24 + core/crypto/_fiat/field_curve25519/field.odin | 138 ++++ .../_fiat/field_curve25519/field51.odin | 616 ++++++++++++++++++ core/crypto/x25519/x25519.odin | 126 ++++ tests/core/crypto/test_core_crypto.odin | 5 + .../core/crypto/test_core_crypto_modern.odin | 95 +++ 7 files changed, 1039 insertions(+) create mode 100644 core/crypto/_fiat/README.md create mode 100644 core/crypto/_fiat/fiat.odin create mode 100644 core/crypto/_fiat/field_curve25519/field.odin create mode 100644 core/crypto/_fiat/field_curve25519/field51.odin create mode 100644 core/crypto/x25519/x25519.odin create mode 100644 tests/core/crypto/test_core_crypto_modern.odin diff --git a/core/crypto/_fiat/README.md b/core/crypto/_fiat/README.md new file mode 100644 index 000000000..cd510d442 --- /dev/null +++ b/core/crypto/_fiat/README.md @@ -0,0 +1,35 @@ +# fiat + +This package contains low level arithmetic required to implement certain +cryptographic primitives, ported from the [fiat-crypto project][1] +along with some higher-level helpers. + +## Notes + +fiat-crypto gives the choice of 3 licenses for derived works. The 1-Clause +BSD license is chosen as it is compatible with Odin's existing licensing. + +The routines are intended to be timing-safe, as long as the underlying +integer arithmetic is constant time. This is true on most systems commonly +used today, with the notable exception of WASM. + +While fiat-crypto provides both output targeting both 32-bit and 64-bit +architectures, only the 64-bit versions were used, as 32-bit architectures +are becoming increasingly uncommon and irrelevant. + +With the current Odin syntax, the Go output is trivially ported in most +cases and was used as the basis of the port. + +In the future, it would be better to auto-generate Odin either directly +by adding an appropriate code-gen backend written in Coq, or perhaps by +parsing the JSON output. + +As this is a port rather than autogenerated output, none of fiat-crypto's +formal verification guarantees apply, unless it is possible to prove binary +equivalence. + +For the most part, alterations to the base fiat-crypto generated code was +kept to a minimum, to aid auditability. This results in a somewhat +ideosyncratic style, and in some cases minor performance penalties. + +[1]: https://github.com/mit-plv/fiat-crypto diff --git a/core/crypto/_fiat/fiat.odin b/core/crypto/_fiat/fiat.odin new file mode 100644 index 000000000..ae9727149 --- /dev/null +++ b/core/crypto/_fiat/fiat.odin @@ -0,0 +1,24 @@ +package fiat + +// This package provides various helpers and types common to all of the +// fiat-crypto derived backends. + +// This code only works on a two's complement system. +#assert((-1 & 3) == 3) + +u1 :: distinct u8 +i1 :: distinct i8 + +cmovznz_u64 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u64) -> (out1: u64) { + x1 := (u64(arg1) * 0xffffffffffffffff) + x2 := ((x1 & arg3) | ((~x1) & arg2)) + out1 = x2 + return +} + +cmovznz_u32 :: #force_inline proc "contextless" (arg1: u1, arg2, arg3: u32) -> (out1: u32) { + x1 := (u32(arg1) * 0xffffffff) + x2 := ((x1 & arg3) | ((~x1) & arg2)) + out1 = x2 + return +} diff --git a/core/crypto/_fiat/field_curve25519/field.odin b/core/crypto/_fiat/field_curve25519/field.odin new file mode 100644 index 000000000..faf8ae3f7 --- /dev/null +++ b/core/crypto/_fiat/field_curve25519/field.odin @@ -0,0 +1,138 @@ +package field_curve25519 + +import "core:crypto" +import "core:mem" + +fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element { + return transmute(^Loose_Field_Element)(arg1) +} + +fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) -> ^Tight_Field_Element { + return transmute(^Tight_Field_Element)(arg1) +} + +fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) { + // Ignore the unused bit by copying the input and masking the bit off + // prior to deserialization. + tmp1: [32]byte = --- + copy_slice(tmp1[:], arg1[:]) + tmp1[31] &= 127 + + _fe_from_bytes(out1, &tmp1) + + mem.zero_explicit(&tmp1, size_of(tmp1)) +} + +fe_equal :: proc "contextless" (arg1, arg2: ^Tight_Field_Element) -> int { + tmp2: [32]byte = --- + + fe_to_bytes(&tmp2, arg2) + ret := fe_equal_bytes(arg1, &tmp2) + + mem.zero_explicit(&tmp2, size_of(tmp2)) + + return ret +} + +fe_equal_bytes :: proc "contextless" (arg1: ^Tight_Field_Element, arg2: ^[32]byte) -> int { + tmp1: [32]byte = --- + + fe_to_bytes(&tmp1, arg1) + + ret := crypto.compare_constant_time(tmp1[:], arg2[:]) + + mem.zero_explicit(&tmp1, size_of(tmp1)) + + return ret +} + +fe_carry_pow2k :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element, arg2: uint) { + // Special case: `arg1^(2 * 0) = 1`, though this should never happen. + if arg2 == 0 { + fe_one(out1) + return + } + + fe_carry_square(out1, arg1) + for _ in 1.. int { + // Inverse square root taken from Monocypher. + + tmp1, tmp2, tmp3: Tight_Field_Element = ---, ---, --- + + // t0 = x^((p-5)/8) + // Can be achieved with a simple double & add ladder, + // but it would be slower. + fe_carry_pow2k(&tmp1, arg1, 1) + fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 2) + fe_carry_mul(&tmp2, arg1, fe_relax_cast(&tmp2)) + fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), fe_relax_cast(&tmp2)) + fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 1) + fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1)) + fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 5) + fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1)) + fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 10) + fe_carry_mul(&tmp2, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1)) + fe_carry_pow2k(&tmp3, fe_relax_cast(&tmp2), 20) + fe_carry_mul(&tmp2, fe_relax_cast(&tmp3), fe_relax_cast(&tmp2)) + fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp2), 10) + fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1)) + fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp1), 50) + fe_carry_mul(&tmp2, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1)) + fe_carry_pow2k(&tmp3, fe_relax_cast(&tmp2), 100) + fe_carry_mul(&tmp2, fe_relax_cast(&tmp3), fe_relax_cast(&tmp2)) + fe_carry_pow2k(&tmp2, fe_relax_cast(&tmp2), 50) + fe_carry_mul(&tmp1, fe_relax_cast(&tmp2), fe_relax_cast(&tmp1)) + fe_carry_pow2k(&tmp1, fe_relax_cast(&tmp1), 2) + fe_carry_mul(&tmp1, fe_relax_cast(&tmp1), arg1) + + // quartic = x^((p-1)/4) + quartic := &tmp2 + fe_carry_square(quartic, fe_relax_cast(&tmp1)) + fe_carry_mul(quartic, fe_relax_cast(quartic), arg1) + + // Serialize quartic once to save on repeated serialization/sanitization. + quartic_buf: [32]byte = --- + fe_to_bytes(&quartic_buf, quartic) + check := &tmp3 + + fe_one(check) + p1 := fe_equal_bytes(check, &quartic_buf) + fe_carry_opp(check, check) + m1 := fe_equal_bytes(check, &quartic_buf) + fe_carry_opp(check, &SQRT_M1) + ms := fe_equal_bytes(check, &quartic_buf) + + // if quartic == -1 or sqrt(-1) + // then isr = x^((p-1)/4) * sqrt(-1) + // else isr = x^((p-1)/4) + fe_carry_mul(out1, fe_relax_cast(&tmp1), fe_relax_cast(&SQRT_M1)) + fe_cond_assign(out1, &tmp1, (m1|ms) ~ 1) + + mem.zero_explicit(&tmp1, size_of(tmp1)) + mem.zero_explicit(&tmp2, size_of(tmp2)) + mem.zero_explicit(&tmp3, size_of(tmp3)) + mem.zero_explicit(&quartic_buf, size_of(quartic_buf)) + + return p1 | m1 +} + +fe_carry_inv :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { + tmp1: Tight_Field_Element + + fe_carry_square(&tmp1, arg1) + _ = fe_carry_invsqrt(&tmp1, fe_relax_cast(&tmp1)) + fe_carry_square(&tmp1, fe_relax_cast(&tmp1)) + fe_carry_mul(out1, fe_relax_cast(&tmp1), arg1) + + mem.zero_explicit(&tmp1, size_of(tmp1)) +} diff --git a/core/crypto/_fiat/field_curve25519/field51.odin b/core/crypto/_fiat/field_curve25519/field51.odin new file mode 100644 index 000000000..e4ca98b57 --- /dev/null +++ b/core/crypto/_fiat/field_curve25519/field51.odin @@ -0,0 +1,616 @@ +// The BSD 1-Clause License (BSD-1-Clause) +// +// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +// 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. +// +// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "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 Berkeley Software Design, +// Inc. 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. + +package field_curve25519 + +// The file provides arithmetic on the field Z/(2^255-19) using +// unsaturated 64-bit integer arithmetic. It is derived primarily +// from the machine generated Golang output from the fiat-crypto project. +// +// While the base implementation is provably correct, this implementation +// makes no such claims as the port and optimizations were done by hand. +// At some point, it may be worth adding support to fiat-crypto for +// generating Odin output. +// +// TODO: +// * When fiat-crypto supports it, using a saturated 64-bit limbs +// instead of 51-bit limbs will be faster, though the gains are +// minimal unless adcx/adox/mulx are used. + +import fiat "core:crypto/_fiat" +import "core:math/bits" + +Loose_Field_Element :: distinct [5]u64 +Tight_Field_Element :: distinct [5]u64 + +SQRT_M1 := Tight_Field_Element{ + 1718705420411056, + 234908883556509, + 2233514472574048, + 2117202627021982, + 765476049583133, +} + +_addcarryx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { + x1 := ((u64(arg1) + arg2) + arg3) + x2 := (x1 & 0x7ffffffffffff) + x3 := fiat.u1((x1 >> 51)) + out1 = x2 + out2 = x3 + return +} + +_subborrowx_u51 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { + x1 := ((i64(arg2) - i64(arg1)) - i64(arg3)) + x2 := fiat.i1((x1 >> 51)) + x3 := (u64(x1) & 0x7ffffffffffff) + out1 = x3 + out2 = (0x0 - fiat.u1(x2)) + return +} + +fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) { + x2, x1 := bits.mul_u64(arg1[4], (arg2[4] * 0x13)) + x4, x3 := bits.mul_u64(arg1[4], (arg2[3] * 0x13)) + x6, x5 := bits.mul_u64(arg1[4], (arg2[2] * 0x13)) + x8, x7 := bits.mul_u64(arg1[4], (arg2[1] * 0x13)) + x10, x9 := bits.mul_u64(arg1[3], (arg2[4] * 0x13)) + x12, x11 := bits.mul_u64(arg1[3], (arg2[3] * 0x13)) + x14, x13 := bits.mul_u64(arg1[3], (arg2[2] * 0x13)) + x16, x15 := bits.mul_u64(arg1[2], (arg2[4] * 0x13)) + x18, x17 := bits.mul_u64(arg1[2], (arg2[3] * 0x13)) + x20, x19 := bits.mul_u64(arg1[1], (arg2[4] * 0x13)) + x22, x21 := bits.mul_u64(arg1[4], arg2[0]) + x24, x23 := bits.mul_u64(arg1[3], arg2[1]) + x26, x25 := bits.mul_u64(arg1[3], arg2[0]) + x28, x27 := bits.mul_u64(arg1[2], arg2[2]) + x30, x29 := bits.mul_u64(arg1[2], arg2[1]) + x32, x31 := bits.mul_u64(arg1[2], arg2[0]) + x34, x33 := bits.mul_u64(arg1[1], arg2[3]) + x36, x35 := bits.mul_u64(arg1[1], arg2[2]) + x38, x37 := bits.mul_u64(arg1[1], arg2[1]) + x40, x39 := bits.mul_u64(arg1[1], arg2[0]) + x42, x41 := bits.mul_u64(arg1[0], arg2[4]) + x44, x43 := bits.mul_u64(arg1[0], arg2[3]) + x46, x45 := bits.mul_u64(arg1[0], arg2[2]) + x48, x47 := bits.mul_u64(arg1[0], arg2[1]) + x50, x49 := bits.mul_u64(arg1[0], arg2[0]) + x51, x52 := bits.add_u64(x13, x7, u64(0x0)) + x53, _ := bits.add_u64(x14, x8, u64(fiat.u1(x52))) + x55, x56 := bits.add_u64(x17, x51, u64(0x0)) + x57, _ := bits.add_u64(x18, x53, u64(fiat.u1(x56))) + x59, x60 := bits.add_u64(x19, x55, u64(0x0)) + x61, _ := bits.add_u64(x20, x57, u64(fiat.u1(x60))) + x63, x64 := bits.add_u64(x49, x59, u64(0x0)) + x65, _ := bits.add_u64(x50, x61, u64(fiat.u1(x64))) + x67 := ((x63 >> 51) | ((x65 << 13) & 0xffffffffffffffff)) + x68 := (x63 & 0x7ffffffffffff) + x69, x70 := bits.add_u64(x23, x21, u64(0x0)) + x71, _ := bits.add_u64(x24, x22, u64(fiat.u1(x70))) + x73, x74 := bits.add_u64(x27, x69, u64(0x0)) + x75, _ := bits.add_u64(x28, x71, u64(fiat.u1(x74))) + x77, x78 := bits.add_u64(x33, x73, u64(0x0)) + x79, _ := bits.add_u64(x34, x75, u64(fiat.u1(x78))) + x81, x82 := bits.add_u64(x41, x77, u64(0x0)) + x83, _ := bits.add_u64(x42, x79, u64(fiat.u1(x82))) + x85, x86 := bits.add_u64(x25, x1, u64(0x0)) + x87, _ := bits.add_u64(x26, x2, u64(fiat.u1(x86))) + x89, x90 := bits.add_u64(x29, x85, u64(0x0)) + x91, _ := bits.add_u64(x30, x87, u64(fiat.u1(x90))) + x93, x94 := bits.add_u64(x35, x89, u64(0x0)) + x95, _ := bits.add_u64(x36, x91, u64(fiat.u1(x94))) + x97, x98 := bits.add_u64(x43, x93, u64(0x0)) + x99, _ := bits.add_u64(x44, x95, u64(fiat.u1(x98))) + x101, x102 := bits.add_u64(x9, x3, u64(0x0)) + x103, _ := bits.add_u64(x10, x4, u64(fiat.u1(x102))) + x105, x106 := bits.add_u64(x31, x101, u64(0x0)) + x107, _ := bits.add_u64(x32, x103, u64(fiat.u1(x106))) + x109, x110 := bits.add_u64(x37, x105, u64(0x0)) + x111, _ := bits.add_u64(x38, x107, u64(fiat.u1(x110))) + x113, x114 := bits.add_u64(x45, x109, u64(0x0)) + x115, _ := bits.add_u64(x46, x111, u64(fiat.u1(x114))) + x117, x118 := bits.add_u64(x11, x5, u64(0x0)) + x119, _ := bits.add_u64(x12, x6, u64(fiat.u1(x118))) + x121, x122 := bits.add_u64(x15, x117, u64(0x0)) + x123, _ := bits.add_u64(x16, x119, u64(fiat.u1(x122))) + x125, x126 := bits.add_u64(x39, x121, u64(0x0)) + x127, _ := bits.add_u64(x40, x123, u64(fiat.u1(x126))) + x129, x130 := bits.add_u64(x47, x125, u64(0x0)) + x131, _ := bits.add_u64(x48, x127, u64(fiat.u1(x130))) + x133, x134 := bits.add_u64(x67, x129, u64(0x0)) + x135 := (u64(fiat.u1(x134)) + x131) + x136 := ((x133 >> 51) | ((x135 << 13) & 0xffffffffffffffff)) + x137 := (x133 & 0x7ffffffffffff) + x138, x139 := bits.add_u64(x136, x113, u64(0x0)) + x140 := (u64(fiat.u1(x139)) + x115) + x141 := ((x138 >> 51) | ((x140 << 13) & 0xffffffffffffffff)) + x142 := (x138 & 0x7ffffffffffff) + x143, x144 := bits.add_u64(x141, x97, u64(0x0)) + x145 := (u64(fiat.u1(x144)) + x99) + x146 := ((x143 >> 51) | ((x145 << 13) & 0xffffffffffffffff)) + x147 := (x143 & 0x7ffffffffffff) + x148, x149 := bits.add_u64(x146, x81, u64(0x0)) + x150 := (u64(fiat.u1(x149)) + x83) + x151 := ((x148 >> 51) | ((x150 << 13) & 0xffffffffffffffff)) + x152 := (x148 & 0x7ffffffffffff) + x153 := (x151 * 0x13) + x154 := (x68 + x153) + x155 := (x154 >> 51) + x156 := (x154 & 0x7ffffffffffff) + x157 := (x155 + x137) + x158 := fiat.u1((x157 >> 51)) + x159 := (x157 & 0x7ffffffffffff) + x160 := (u64(x158) + x142) + out1[0] = x156 + out1[1] = x159 + out1[2] = x160 + out1[3] = x147 + out1[4] = x152 +} + +fe_carry_square :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { + x1 := (arg1[4] * 0x13) + x2 := (x1 * 0x2) + x3 := (arg1[4] * 0x2) + x4 := (arg1[3] * 0x13) + x5 := (x4 * 0x2) + x6 := (arg1[3] * 0x2) + x7 := (arg1[2] * 0x2) + x8 := (arg1[1] * 0x2) + x10, x9 := bits.mul_u64(arg1[4], x1) + x12, x11 := bits.mul_u64(arg1[3], x2) + x14, x13 := bits.mul_u64(arg1[3], x4) + x16, x15 := bits.mul_u64(arg1[2], x2) + x18, x17 := bits.mul_u64(arg1[2], x5) + x20, x19 := bits.mul_u64(arg1[2], arg1[2]) + x22, x21 := bits.mul_u64(arg1[1], x2) + x24, x23 := bits.mul_u64(arg1[1], x6) + x26, x25 := bits.mul_u64(arg1[1], x7) + x28, x27 := bits.mul_u64(arg1[1], arg1[1]) + x30, x29 := bits.mul_u64(arg1[0], x3) + x32, x31 := bits.mul_u64(arg1[0], x6) + x34, x33 := bits.mul_u64(arg1[0], x7) + x36, x35 := bits.mul_u64(arg1[0], x8) + x38, x37 := bits.mul_u64(arg1[0], arg1[0]) + x39, x40 := bits.add_u64(x21, x17, u64(0x0)) + x41, _ := bits.add_u64(x22, x18, u64(fiat.u1(x40))) + x43, x44 := bits.add_u64(x37, x39, u64(0x0)) + x45, _ := bits.add_u64(x38, x41, u64(fiat.u1(x44))) + x47 := ((x43 >> 51) | ((x45 << 13) & 0xffffffffffffffff)) + x48 := (x43 & 0x7ffffffffffff) + x49, x50 := bits.add_u64(x23, x19, u64(0x0)) + x51, _ := bits.add_u64(x24, x20, u64(fiat.u1(x50))) + x53, x54 := bits.add_u64(x29, x49, u64(0x0)) + x55, _ := bits.add_u64(x30, x51, u64(fiat.u1(x54))) + x57, x58 := bits.add_u64(x25, x9, u64(0x0)) + x59, _ := bits.add_u64(x26, x10, u64(fiat.u1(x58))) + x61, x62 := bits.add_u64(x31, x57, u64(0x0)) + x63, _ := bits.add_u64(x32, x59, u64(fiat.u1(x62))) + x65, x66 := bits.add_u64(x27, x11, u64(0x0)) + x67, _ := bits.add_u64(x28, x12, u64(fiat.u1(x66))) + x69, x70 := bits.add_u64(x33, x65, u64(0x0)) + x71, _ := bits.add_u64(x34, x67, u64(fiat.u1(x70))) + x73, x74 := bits.add_u64(x15, x13, u64(0x0)) + x75, _ := bits.add_u64(x16, x14, u64(fiat.u1(x74))) + x77, x78 := bits.add_u64(x35, x73, u64(0x0)) + x79, _ := bits.add_u64(x36, x75, u64(fiat.u1(x78))) + x81, x82 := bits.add_u64(x47, x77, u64(0x0)) + x83 := (u64(fiat.u1(x82)) + x79) + x84 := ((x81 >> 51) | ((x83 << 13) & 0xffffffffffffffff)) + x85 := (x81 & 0x7ffffffffffff) + x86, x87 := bits.add_u64(x84, x69, u64(0x0)) + x88 := (u64(fiat.u1(x87)) + x71) + x89 := ((x86 >> 51) | ((x88 << 13) & 0xffffffffffffffff)) + x90 := (x86 & 0x7ffffffffffff) + x91, x92 := bits.add_u64(x89, x61, u64(0x0)) + x93 := (u64(fiat.u1(x92)) + x63) + x94 := ((x91 >> 51) | ((x93 << 13) & 0xffffffffffffffff)) + x95 := (x91 & 0x7ffffffffffff) + x96, x97 := bits.add_u64(x94, x53, u64(0x0)) + x98 := (u64(fiat.u1(x97)) + x55) + x99 := ((x96 >> 51) | ((x98 << 13) & 0xffffffffffffffff)) + x100 := (x96 & 0x7ffffffffffff) + x101 := (x99 * 0x13) + x102 := (x48 + x101) + x103 := (x102 >> 51) + x104 := (x102 & 0x7ffffffffffff) + x105 := (x103 + x85) + x106 := fiat.u1((x105 >> 51)) + x107 := (x105 & 0x7ffffffffffff) + x108 := (u64(x106) + x90) + out1[0] = x104 + out1[1] = x107 + out1[2] = x108 + out1[3] = x95 + out1[4] = x100 +} + +fe_carry :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { + x1 := arg1[0] + x2 := ((x1 >> 51) + arg1[1]) + x3 := ((x2 >> 51) + arg1[2]) + x4 := ((x3 >> 51) + arg1[3]) + x5 := ((x4 >> 51) + arg1[4]) + x6 := ((x1 & 0x7ffffffffffff) + ((x5 >> 51) * 0x13)) + x7 := (u64(fiat.u1((x6 >> 51))) + (x2 & 0x7ffffffffffff)) + x8 := (x6 & 0x7ffffffffffff) + x9 := (x7 & 0x7ffffffffffff) + x10 := (u64(fiat.u1((x7 >> 51))) + (x3 & 0x7ffffffffffff)) + x11 := (x4 & 0x7ffffffffffff) + x12 := (x5 & 0x7ffffffffffff) + out1[0] = x8 + out1[1] = x9 + out1[2] = x10 + out1[3] = x11 + out1[4] = x12 +} + +fe_add :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) { + x1 := (arg1[0] + arg2[0]) + x2 := (arg1[1] + arg2[1]) + x3 := (arg1[2] + arg2[2]) + x4 := (arg1[3] + arg2[3]) + x5 := (arg1[4] + arg2[4]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 +} + +fe_sub :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) { + x1 := ((0xfffffffffffda + arg1[0]) - arg2[0]) + x2 := ((0xffffffffffffe + arg1[1]) - arg2[1]) + x3 := ((0xffffffffffffe + arg1[2]) - arg2[2]) + x4 := ((0xffffffffffffe + arg1[3]) - arg2[3]) + x5 := ((0xffffffffffffe + arg1[4]) - arg2[4]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 +} + +fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) { + x1 := (0xfffffffffffda - arg1[0]) + x2 := (0xffffffffffffe - arg1[1]) + x3 := (0xffffffffffffe - arg1[2]) + x4 := (0xffffffffffffe - arg1[3]) + x5 := (0xffffffffffffe - arg1[4]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 +} + +fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: int) { + x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) + x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) + x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) + x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3]) + x5 := fiat.cmovznz_u64(fiat.u1(arg2), out1[4], arg1[4]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 +} + +fe_to_bytes :: proc "contextless" (out1: ^[32]byte, arg1: ^Tight_Field_Element) { + x1, x2 := _subborrowx_u51(0x0, arg1[0], 0x7ffffffffffed) + x3, x4 := _subborrowx_u51(x2, arg1[1], 0x7ffffffffffff) + x5, x6 := _subborrowx_u51(x4, arg1[2], 0x7ffffffffffff) + x7, x8 := _subborrowx_u51(x6, arg1[3], 0x7ffffffffffff) + x9, x10 := _subborrowx_u51(x8, arg1[4], 0x7ffffffffffff) + x11 := fiat.cmovznz_u64(x10, u64(0x0), 0xffffffffffffffff) + x12, x13 := _addcarryx_u51(0x0, x1, (x11 & 0x7ffffffffffed)) + x14, x15 := _addcarryx_u51(x13, x3, (x11 & 0x7ffffffffffff)) + x16, x17 := _addcarryx_u51(x15, x5, (x11 & 0x7ffffffffffff)) + x18, x19 := _addcarryx_u51(x17, x7, (x11 & 0x7ffffffffffff)) + x20, _ := _addcarryx_u51(x19, x9, (x11 & 0x7ffffffffffff)) + x22 := (x20 << 4) + x23 := (x18 * u64(0x2)) + x24 := (x16 << 6) + x25 := (x14 << 3) + x26 := (u8(x12) & 0xff) + x27 := (x12 >> 8) + x28 := (u8(x27) & 0xff) + x29 := (x27 >> 8) + x30 := (u8(x29) & 0xff) + x31 := (x29 >> 8) + x32 := (u8(x31) & 0xff) + x33 := (x31 >> 8) + x34 := (u8(x33) & 0xff) + x35 := (x33 >> 8) + x36 := (u8(x35) & 0xff) + x37 := u8((x35 >> 8)) + x38 := (x25 + u64(x37)) + x39 := (u8(x38) & 0xff) + x40 := (x38 >> 8) + x41 := (u8(x40) & 0xff) + x42 := (x40 >> 8) + x43 := (u8(x42) & 0xff) + x44 := (x42 >> 8) + x45 := (u8(x44) & 0xff) + x46 := (x44 >> 8) + x47 := (u8(x46) & 0xff) + x48 := (x46 >> 8) + x49 := (u8(x48) & 0xff) + x50 := u8((x48 >> 8)) + x51 := (x24 + u64(x50)) + x52 := (u8(x51) & 0xff) + x53 := (x51 >> 8) + x54 := (u8(x53) & 0xff) + x55 := (x53 >> 8) + x56 := (u8(x55) & 0xff) + x57 := (x55 >> 8) + x58 := (u8(x57) & 0xff) + x59 := (x57 >> 8) + x60 := (u8(x59) & 0xff) + x61 := (x59 >> 8) + x62 := (u8(x61) & 0xff) + x63 := (x61 >> 8) + x64 := (u8(x63) & 0xff) + x65 := fiat.u1((x63 >> 8)) + x66 := (x23 + u64(x65)) + x67 := (u8(x66) & 0xff) + x68 := (x66 >> 8) + x69 := (u8(x68) & 0xff) + x70 := (x68 >> 8) + x71 := (u8(x70) & 0xff) + x72 := (x70 >> 8) + x73 := (u8(x72) & 0xff) + x74 := (x72 >> 8) + x75 := (u8(x74) & 0xff) + x76 := (x74 >> 8) + x77 := (u8(x76) & 0xff) + x78 := u8((x76 >> 8)) + x79 := (x22 + u64(x78)) + x80 := (u8(x79) & 0xff) + x81 := (x79 >> 8) + x82 := (u8(x81) & 0xff) + x83 := (x81 >> 8) + x84 := (u8(x83) & 0xff) + x85 := (x83 >> 8) + x86 := (u8(x85) & 0xff) + x87 := (x85 >> 8) + x88 := (u8(x87) & 0xff) + x89 := (x87 >> 8) + x90 := (u8(x89) & 0xff) + x91 := u8((x89 >> 8)) + out1[0] = x26 + out1[1] = x28 + out1[2] = x30 + out1[3] = x32 + out1[4] = x34 + out1[5] = x36 + out1[6] = x39 + out1[7] = x41 + out1[8] = x43 + out1[9] = x45 + out1[10] = x47 + out1[11] = x49 + out1[12] = x52 + out1[13] = x54 + out1[14] = x56 + out1[15] = x58 + out1[16] = x60 + out1[17] = x62 + out1[18] = x64 + out1[19] = x67 + out1[20] = x69 + out1[21] = x71 + out1[22] = x73 + out1[23] = x75 + out1[24] = x77 + out1[25] = x80 + out1[26] = x82 + out1[27] = x84 + out1[28] = x86 + out1[29] = x88 + out1[30] = x90 + out1[31] = x91 +} + +_fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) { + x1 := (u64(arg1[31]) << 44) + x2 := (u64(arg1[30]) << 36) + x3 := (u64(arg1[29]) << 28) + x4 := (u64(arg1[28]) << 20) + x5 := (u64(arg1[27]) << 12) + x6 := (u64(arg1[26]) << 4) + x7 := (u64(arg1[25]) << 47) + x8 := (u64(arg1[24]) << 39) + x9 := (u64(arg1[23]) << 31) + x10 := (u64(arg1[22]) << 23) + x11 := (u64(arg1[21]) << 15) + x12 := (u64(arg1[20]) << 7) + x13 := (u64(arg1[19]) << 50) + x14 := (u64(arg1[18]) << 42) + x15 := (u64(arg1[17]) << 34) + x16 := (u64(arg1[16]) << 26) + x17 := (u64(arg1[15]) << 18) + x18 := (u64(arg1[14]) << 10) + x19 := (u64(arg1[13]) << 2) + x20 := (u64(arg1[12]) << 45) + x21 := (u64(arg1[11]) << 37) + x22 := (u64(arg1[10]) << 29) + x23 := (u64(arg1[9]) << 21) + x24 := (u64(arg1[8]) << 13) + x25 := (u64(arg1[7]) << 5) + x26 := (u64(arg1[6]) << 48) + x27 := (u64(arg1[5]) << 40) + x28 := (u64(arg1[4]) << 32) + x29 := (u64(arg1[3]) << 24) + x30 := (u64(arg1[2]) << 16) + x31 := (u64(arg1[1]) << 8) + x32 := arg1[0] + x33 := (x31 + u64(x32)) + x34 := (x30 + x33) + x35 := (x29 + x34) + x36 := (x28 + x35) + x37 := (x27 + x36) + x38 := (x26 + x37) + x39 := (x38 & 0x7ffffffffffff) + x40 := u8((x38 >> 51)) + x41 := (x25 + u64(x40)) + x42 := (x24 + x41) + x43 := (x23 + x42) + x44 := (x22 + x43) + x45 := (x21 + x44) + x46 := (x20 + x45) + x47 := (x46 & 0x7ffffffffffff) + x48 := u8((x46 >> 51)) + x49 := (x19 + u64(x48)) + x50 := (x18 + x49) + x51 := (x17 + x50) + x52 := (x16 + x51) + x53 := (x15 + x52) + x54 := (x14 + x53) + x55 := (x13 + x54) + x56 := (x55 & 0x7ffffffffffff) + x57 := u8((x55 >> 51)) + x58 := (x12 + u64(x57)) + x59 := (x11 + x58) + x60 := (x10 + x59) + x61 := (x9 + x60) + x62 := (x8 + x61) + x63 := (x7 + x62) + x64 := (x63 & 0x7ffffffffffff) + x65 := u8((x63 >> 51)) + x66 := (x6 + u64(x65)) + x67 := (x5 + x66) + x68 := (x4 + x67) + x69 := (x3 + x68) + x70 := (x2 + x69) + x71 := (x1 + x70) + out1[0] = x39 + out1[1] = x47 + out1[2] = x56 + out1[3] = x64 + out1[4] = x71 +} + +fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + x4 := arg1[3] + x5 := arg1[4] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 +} + +fe_carry_scmul_121666 :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { + x2, x1 := bits.mul_u64(0x1db42, arg1[4]) + x4, x3 := bits.mul_u64(0x1db42, arg1[3]) + x6, x5 := bits.mul_u64(0x1db42, arg1[2]) + x8, x7 := bits.mul_u64(0x1db42, arg1[1]) + x10, x9 := bits.mul_u64(0x1db42, arg1[0]) + x11 := ((x9 >> 51) | ((x10 << 13) & 0xffffffffffffffff)) + x12 := (x9 & 0x7ffffffffffff) + x13, x14 := bits.add_u64(x11, x7, u64(0x0)) + x15 := (u64(fiat.u1(x14)) + x8) + x16 := ((x13 >> 51) | ((x15 << 13) & 0xffffffffffffffff)) + x17 := (x13 & 0x7ffffffffffff) + x18, x19 := bits.add_u64(x16, x5, u64(0x0)) + x20 := (u64(fiat.u1(x19)) + x6) + x21 := ((x18 >> 51) | ((x20 << 13) & 0xffffffffffffffff)) + x22 := (x18 & 0x7ffffffffffff) + x23, x24 := bits.add_u64(x21, x3, u64(0x0)) + x25 := (u64(fiat.u1(x24)) + x4) + x26 := ((x23 >> 51) | ((x25 << 13) & 0xffffffffffffffff)) + x27 := (x23 & 0x7ffffffffffff) + x28, x29 := bits.add_u64(x26, x1, u64(0x0)) + x30 := (u64(fiat.u1(x29)) + x2) + x31 := ((x28 >> 51) | ((x30 << 13) & 0xffffffffffffffff)) + x32 := (x28 & 0x7ffffffffffff) + x33 := (x31 * 0x13) + x34 := (x12 + x33) + x35 := fiat.u1((x34 >> 51)) + x36 := (x34 & 0x7ffffffffffff) + x37 := (u64(x35) + x17) + x38 := fiat.u1((x37 >> 51)) + x39 := (x37 & 0x7ffffffffffff) + x40 := (u64(x38) + x22) + out1[0] = x36 + out1[1] = x39 + out1[2] = x40 + out1[3] = x27 + out1[4] = x32 +} + +// The following routines were added by hand, and do not come from fiat-crypto. + +fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) { + out1[0] = 0 + out1[1] = 0 + out1[2] = 0 + out1[3] = 0 + out1[4] = 0 +} + +fe_one :: proc "contextless" (out1: ^Tight_Field_Element) { + out1[0] = 1 + out1[1] = 0 + out1[2] = 0 + out1[3] = 0 + out1[4] = 0 +} + +fe_set :: proc "contextless" (out1, arg1: ^Tight_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + x4 := arg1[3] + x5 := arg1[4] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 +} + +fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) { + mask := -u64(arg1) + x := (out1[0] ~ out2[0]) & mask + x1, y1 := out1[0] ~ x, out2[0] ~ x + x = (out1[1] ~ out2[1]) & mask + x2, y2 := out1[1] ~ x, out2[1] ~ x + x = (out1[2] ~ out2[2]) & mask + x3, y3 := out1[2] ~ x, out2[2] ~ x + x = (out1[3] ~ out2[3]) & mask + x4, y4 := out1[3] ~ x, out2[3] ~ x + x = (out1[4] ~ out2[4]) & mask + x5, y5 := out1[4] ~ x, out2[4] ~ x + out1[0], out2[0] = x1, y1 + out1[1], out2[1] = x2, y2 + out1[2], out2[2] = x3, y3 + out1[3], out2[3] = x4, y4 + out1[4], out2[4] = x5, y5 +} diff --git a/core/crypto/x25519/x25519.odin b/core/crypto/x25519/x25519.odin new file mode 100644 index 000000000..dfc8daa47 --- /dev/null +++ b/core/crypto/x25519/x25519.odin @@ -0,0 +1,126 @@ +package x25519 + +import field "core:crypto/_fiat/field_curve25519" +import "core:mem" + +SCALAR_SIZE :: 32 +POINT_SIZE :: 32 + +_BASE_POINT: [32]byte = {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +_scalar_bit :: #force_inline proc "contextless" (s: ^[32]byte, i: int) -> u8 { + if i < 0 { + return 0 + } + return (s[i>>3] >> uint(i&7)) & 1 +} + +_scalarmult :: proc (out, scalar, point: ^[32]byte) { + // Montgomery pseduo-multiplication taken from Monocypher. + + // computes the scalar product + x1: field.Tight_Field_Element = --- + field.fe_from_bytes(&x1, point) + + // computes the actual scalar product (the result is in x2 and z2) + x2, x3, z2, z3: field.Tight_Field_Element = ---, ---, ---, --- + t0, t1: field.Loose_Field_Element = ---, --- + + // Montgomery ladder + // In projective coordinates, to avoid divisions: x = X / Z + // We don't care about the y coordinate, it's only 1 bit of information + field.fe_one(&x2) // "zero" point + field.fe_zero(&z2) + field.fe_set(&x3, &x1) // "one" point + field.fe_one(&z3) + + swap: int + for pos := 255-1; pos >= 0; pos = pos - 1 { + // constant time conditional swap before ladder step + b := int(_scalar_bit(scalar, pos)) + swap ~= b // xor trick avoids swapping at the end of the loop + field.fe_cond_swap(&x2, &x3, swap) + field.fe_cond_swap(&z2, &z3, swap) + swap = b // anticipates one last swap after the loop + + // Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3) + // with differential addition + // + // Note: This deliberately omits reductions after add/sub operations + // if the result is only ever used as the input to a mul/square since + // the implementations of those can deal with non-reduced inputs. + // + // fe_tighten_cast is only used to store a fully reduced + // output in a Loose_Field_Element, or to provide such a + // Loose_Field_Element as a Tight_Field_Element argument. + field.fe_sub(&t0, &x3, &z3) + field.fe_sub(&t1, &x2, &z2) + field.fe_add(field.fe_relax_cast(&x2), &x2, &z2) // x2 - unreduced + field.fe_add(field.fe_relax_cast(&z2), &x3, &z3) // z2 - unreduced + field.fe_carry_mul(&z3, &t0, field.fe_relax_cast(&x2)) + field.fe_carry_mul(&z2, field.fe_relax_cast(&z2), &t1) // z2 - reduced + field.fe_carry_square(field.fe_tighten_cast(&t0), &t1) // t0 - reduced + field.fe_carry_square(field.fe_tighten_cast(&t1), field.fe_relax_cast(&x2)) // t1 - reduced + field.fe_add(field.fe_relax_cast(&x3), &z3, &z2) // x3 - unreduced + field.fe_sub(field.fe_relax_cast(&z2), &z3, &z2) // z2 - unreduced + field.fe_carry_mul(&x2, &t1, &t0) // x2 - reduced + field.fe_sub(&t1, field.fe_tighten_cast(&t1), field.fe_tighten_cast(&t0)) // safe - t1/t0 is reduced + field.fe_carry_square(&z2, field.fe_relax_cast(&z2)) // z2 - reduced + field.fe_carry_scmul_121666(&z3, &t1) + field.fe_carry_square(&x3, field.fe_relax_cast(&x3)) // x3 - reduced + field.fe_add(&t0, field.fe_tighten_cast(&t0), &z3) // safe - t0 is reduced + field.fe_carry_mul(&z3, field.fe_relax_cast(&x1), field.fe_relax_cast(&z2)) + field.fe_carry_mul(&z2, &t1, &t0) + } + // last swap is necessary to compensate for the xor trick + // Note: after this swap, P3 == P2 + P1. + field.fe_cond_swap(&x2, &x3, swap) + field.fe_cond_swap(&z2, &z3, swap) + + // normalises the coordinates: x == X / Z + field.fe_carry_inv(&z2, field.fe_relax_cast(&z2)) + field.fe_carry_mul(&x2, field.fe_relax_cast(&x2), field.fe_relax_cast(&z2)) + field.fe_to_bytes(out, &x2) + + mem.zero_explicit(&x1, size_of(x1)) + mem.zero_explicit(&x2, size_of(x2)) + mem.zero_explicit(&x3, size_of(x3)) + mem.zero_explicit(&z2, size_of(z2)) + mem.zero_explicit(&z3, size_of(z3)) + mem.zero_explicit(&t0, size_of(t0)) + mem.zero_explicit(&t1, size_of(t1)) +} + +scalarmult :: proc (dst, scalar, point: []byte) { + if len(scalar) != SCALAR_SIZE { + panic("crypto/x25519: invalid scalar size") + } + if len(point) != POINT_SIZE { + panic("crypto/x25519: invalid point size") + } + if len(dst) != POINT_SIZE { + panic("crypto/x25519: invalid destination point size") + } + + // "clamp" the scalar + e: [32]byte = --- + copy_slice(e[:], scalar) + e[0] &= 248 + e[31] &= 127 + e[31] |= 64 + + p: [32]byte = --- + copy_slice(p[:], point) + + d: [32]byte = --- + _scalarmult(&d, &e, &p) + copy_slice(dst, d[:]) + + mem.zero_explicit(&e, size_of(e)) + mem.zero_explicit(&d, size_of(d)) +} + +scalarmult_basepoint :: proc (dst, scalar: []byte) { + // TODO/perf: Switch to using a precomputed table. + scalarmult(dst, scalar, _BASE_POINT[:]) +} diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index df9920552..768ba242f 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -115,6 +115,11 @@ main :: proc() { test_haval_224(&t) test_haval_256(&t) + // "modern" crypto tests + test_x25519(&t) + + bench_modern(&t) + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } diff --git a/tests/core/crypto/test_core_crypto_modern.odin b/tests/core/crypto/test_core_crypto_modern.odin new file mode 100644 index 000000000..4d7f08bb1 --- /dev/null +++ b/tests/core/crypto/test_core_crypto_modern.odin @@ -0,0 +1,95 @@ +package test_core_crypto + +import "core:testing" +import "core:fmt" +import "core:time" + +import "core:crypto/x25519" + +_digit_value :: proc(r: rune) -> int { + ri := int(r) + v: int = 16 + switch r { + case '0'..='9': v = ri-'0' + case 'a'..='z': v = ri-'a'+10 + case 'A'..='Z': v = ri-'A'+10 + } + return v +} + +_decode_hex32 :: proc(s: string) -> [32]byte{ + b: [32]byte + for i := 0; i < len(s); i = i + 2 { + hi := _digit_value(rune(s[i])) + lo := _digit_value(rune(s[i+1])) + b[i/2] = byte(hi << 4 | lo) + } + return b +} + +TestECDH :: struct { + scalar: string, + point: string, + product: string, +} + +@(test) +test_x25519 :: proc(t: ^testing.T) { + log(t, "Testing X25519") + + test_vectors := [?]TestECDH { + // Test vectors from RFC 7748 + TestECDH{ + "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", + "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c", + "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552", + }, + TestECDH{ + "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", + "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493", + "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957", + }, + } + for v, _ in test_vectors { + scalar := _decode_hex32(v.scalar) + point := _decode_hex32(v.point) + + derived_point: [x25519.POINT_SIZE]byte + x25519.scalarmult(derived_point[:], scalar[:], point[:]) + derived_point_str := hex_string(derived_point[:]) + + expect(t, derived_point_str == v.product, fmt.tprintf("Expected %s for %s * %s, but got %s instead", v.product, v.scalar, v.point, derived_point_str)) + + // Abuse the test vectors to sanity-check the scalar-basepoint multiply. + p1, p2: [x25519.POINT_SIZE]byte + x25519.scalarmult_basepoint(p1[:], scalar[:]) + x25519.scalarmult(p2[:], scalar[:], x25519._BASE_POINT[:]) + p1_str, p2_str := hex_string(p1[:]), hex_string(p2[:]) + expect(t, p1_str == p2_str, fmt.tprintf("Expected %s for %s * basepoint, but got %s instead", p2_str, v.scalar, p1_str)) + } + + // TODO/tests: Run the wycheproof test vectors, once I figure out + // how to work with JSON. +} + +@(test) +bench_modern :: proc(t: ^testing.T) { + fmt.println("Starting benchmarks:") + + bench_x25519(t) +} + +bench_x25519 :: proc(t: ^testing.T) { + point := _decode_hex32("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") + scalar := _decode_hex32("cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe") + out: [x25519.POINT_SIZE]byte = --- + + iters :: 10000 + start := time.now() + for i := 0; i < iters; i = i + 1 { + x25519.scalarmult(out[:], scalar[:], point[:]) + } + elapsed := time.since(start) + + log(t, fmt.tprintf("x25519.scalarmult: ~%f us/op", time.duration_microseconds(elapsed) / iters)) +} From 64db286582dc6007317bc5c74d7f5e156f22f855 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sat, 6 Nov 2021 07:38:04 +0000 Subject: [PATCH 0026/1258] core/crypto: Add poly1305 This package implements the Poly1305 MAC algorithm as specified in RFC 8439, using routines taked from fiat-crypto and poly1305-donna. --- core/crypto/_fiat/field_poly1305/field.odin | 45 +++ .../_fiat/field_poly1305/field4344.odin | 356 ++++++++++++++++++ core/crypto/poly1305/poly1305.odin | 163 ++++++++ tests/core/crypto/test_core_crypto.odin | 1 + .../core/crypto/test_core_crypto_modern.odin | 131 +++++++ 5 files changed, 696 insertions(+) create mode 100644 core/crypto/_fiat/field_poly1305/field.odin create mode 100644 core/crypto/_fiat/field_poly1305/field4344.odin create mode 100644 core/crypto/poly1305/poly1305.odin diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin new file mode 100644 index 000000000..642949b02 --- /dev/null +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -0,0 +1,45 @@ +package field_poly1305 + +import "core:crypto/util" +import "core:mem" + +fe_relax_cast :: #force_inline proc "contextless" (arg1: ^Tight_Field_Element) -> ^Loose_Field_Element { + return transmute(^Loose_Field_Element)(arg1) +} + +fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) -> ^Tight_Field_Element { + return transmute(^Tight_Field_Element)(arg1) +} + +fe_from_bytes :: proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte, sanitize: bool = true) { + // fiat-crypto's deserialization routine wants 256-bits of input, but + // r/s are 128-bits long, and block processing works on 128-bits plus a + // final bit. + // + // This is more ergonomic, and while the copy is unfortunate, this avoids + // having to alter the fiat-crypto derived code. + + assert(len(arg1) == 16) + + tmp: [32]byte + copy_slice(tmp[0:16], arg1[:]) + tmp[16] = arg2 + + _fe_from_bytes(out1, &tmp) + + // Need to sanitize the temporary buffer when deserializing `s`. + if sanitize { + mem.zero_explicit(&tmp, size_of(tmp)) + } +} + +fe_from_u64s :: proc "contextless" (out1: ^Tight_Field_Element, lo, hi: u64) { + tmp: [32]byte + util.PUT_U64_LE(tmp[0:8], lo) + util.PUT_U64_LE(tmp[8:16], hi) + + _fe_from_bytes(out1, &tmp) + + // This routine is only used to deserialize `r` which is confidential. + mem.zero_explicit(&tmp, size_of(tmp)) +} diff --git a/core/crypto/_fiat/field_poly1305/field4344.odin b/core/crypto/_fiat/field_poly1305/field4344.odin new file mode 100644 index 000000000..ba9bc2694 --- /dev/null +++ b/core/crypto/_fiat/field_poly1305/field4344.odin @@ -0,0 +1,356 @@ +// The BSD 1-Clause License (BSD-1-Clause) +// +// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +// 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. +// +// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "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 Berkeley Software Design, +// Inc. 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. + +package field_poly1305 + +// This file provides arithmetic on the field Z/(2^130 - 5) using +// unsaturated 64-bit integer arithmetic. It is derived primarily +// from the machine generate Golang output from the fiat-crypto project. +// +// While the base implementation is provably correct, this implementation +// makes no such claims as the port and optimizations were done by hand. +// At some point, it may be worth adding support to fiat-crypto for +// generating Odin output. + +import fiat "core:crypto/_fiat" +import "core:math/bits" + +Loose_Field_Element :: distinct [3]u64 +Tight_Field_Element :: distinct [3]u64 + +_addcarryx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { + x1 := ((u64(arg1) + arg2) + arg3) + x2 := (x1 & 0xfffffffffff) + x3 := fiat.u1((x1 >> 44)) + out1 = x2 + out2 = x3 + return +} + +_subborrowx_u44 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { + x1 := ((i64(arg2) - i64(arg1)) - i64(arg3)) + x2 := fiat.i1((x1 >> 44)) + x3 := (u64(x1) & 0xfffffffffff) + out1 = x3 + out2 = (0x0 - fiat.u1(x2)) + return +} + +_addcarryx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { + x1 := ((u64(arg1) + arg2) + arg3) + x2 := (x1 & 0x7ffffffffff) + x3 := fiat.u1((x1 >> 43)) + out1 = x2 + out2 = x3 + return +} + +_subborrowx_u43 :: #force_inline proc "contextless" (arg1: fiat.u1, arg2, arg3: u64) -> (out1: u64, out2: fiat.u1) { + x1 := ((i64(arg2) - i64(arg1)) - i64(arg3)) + x2 := fiat.i1((x1 >> 43)) + x3 := (u64(x1) & 0x7ffffffffff) + out1 = x3 + out2 = (0x0 - fiat.u1(x2)) + return +} + +fe_carry_mul :: proc (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) { + x2, x1 := bits.mul_u64(arg1[2], (arg2[2] * 0x5)) + x4, x3 := bits.mul_u64(arg1[2], (arg2[1] * 0xa)) + x6, x5 := bits.mul_u64(arg1[1], (arg2[2] * 0xa)) + x8, x7 := bits.mul_u64(arg1[2], arg2[0]) + x10, x9 := bits.mul_u64(arg1[1], (arg2[1] * 0x2)) + x12, x11 := bits.mul_u64(arg1[1], arg2[0]) + x14, x13 := bits.mul_u64(arg1[0], arg2[2]) + x16, x15 := bits.mul_u64(arg1[0], arg2[1]) + x18, x17 := bits.mul_u64(arg1[0], arg2[0]) + x19, x20 := bits.add_u64(x5, x3, u64(0x0)) + x21, _ := bits.add_u64(x6, x4, u64(fiat.u1(x20))) + x23, x24 := bits.add_u64(x17, x19, u64(0x0)) + x25, _ := bits.add_u64(x18, x21, u64(fiat.u1(x24))) + x27 := ((x23 >> 44) | ((x25 << 20) & 0xffffffffffffffff)) + x28 := (x23 & 0xfffffffffff) + x29, x30 := bits.add_u64(x9, x7, u64(0x0)) + x31, _ := bits.add_u64(x10, x8, u64(fiat.u1(x30))) + x33, x34 := bits.add_u64(x13, x29, u64(0x0)) + x35, _ := bits.add_u64(x14, x31, u64(fiat.u1(x34))) + x37, x38 := bits.add_u64(x11, x1, u64(0x0)) + x39, _ := bits.add_u64(x12, x2, u64(fiat.u1(x38))) + x41, x42 := bits.add_u64(x15, x37, u64(0x0)) + x43, _ := bits.add_u64(x16, x39, u64(fiat.u1(x42))) + x45, x46 := bits.add_u64(x27, x41, u64(0x0)) + x47 := (u64(fiat.u1(x46)) + x43) + x48 := ((x45 >> 43) | ((x47 << 21) & 0xffffffffffffffff)) + x49 := (x45 & 0x7ffffffffff) + x50, x51 := bits.add_u64(x48, x33, u64(0x0)) + x52 := (u64(fiat.u1(x51)) + x35) + x53 := ((x50 >> 43) | ((x52 << 21) & 0xffffffffffffffff)) + x54 := (x50 & 0x7ffffffffff) + x55 := (x53 * 0x5) + x56 := (x28 + x55) + x57 := (x56 >> 44) + x58 := (x56 & 0xfffffffffff) + x59 := (x57 + x49) + x60 := fiat.u1((x59 >> 43)) + x61 := (x59 & 0x7ffffffffff) + x62 := (u64(x60) + x54) + out1[0] = x58 + out1[1] = x61 + out1[2] = x62 +} + +fe_carry_square :: proc (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { + x1 := (arg1[2] * 0x5) + x2 := (x1 * 0x2) + x3 := (arg1[2] * 0x2) + x4 := (arg1[1] * 0x2) + x6, x5 := bits.mul_u64(arg1[2], x1) + x8, x7 := bits.mul_u64(arg1[1], (x2 * 0x2)) + x10, x9 := bits.mul_u64(arg1[1], (arg1[1] * 0x2)) + x12, x11 := bits.mul_u64(arg1[0], x3) + x14, x13 := bits.mul_u64(arg1[0], x4) + x16, x15 := bits.mul_u64(arg1[0], arg1[0]) + x17, x18 := bits.add_u64(x15, x7, u64(0x0)) + x19, _ := bits.add_u64(x16, x8, u64(fiat.u1(x18))) + x21 := ((x17 >> 44) | ((x19 << 20) & 0xffffffffffffffff)) + x22 := (x17 & 0xfffffffffff) + x23, x24 := bits.add_u64(x11, x9, u64(0x0)) + x25, _ := bits.add_u64(x12, x10, u64(fiat.u1(x24))) + x27, x28 := bits.add_u64(x13, x5, u64(0x0)) + x29, _ := bits.add_u64(x14, x6, u64(fiat.u1(x28))) + x31, x32 := bits.add_u64(x21, x27, u64(0x0)) + x33 := (u64(fiat.u1(x32)) + x29) + x34 := ((x31 >> 43) | ((x33 << 21) & 0xffffffffffffffff)) + x35 := (x31 & 0x7ffffffffff) + x36, x37 := bits.add_u64(x34, x23, u64(0x0)) + x38 := (u64(fiat.u1(x37)) + x25) + x39 := ((x36 >> 43) | ((x38 << 21) & 0xffffffffffffffff)) + x40 := (x36 & 0x7ffffffffff) + x41 := (x39 * 0x5) + x42 := (x22 + x41) + x43 := (x42 >> 44) + x44 := (x42 & 0xfffffffffff) + x45 := (x43 + x35) + x46 := fiat.u1((x45 >> 43)) + x47 := (x45 & 0x7ffffffffff) + x48 := (u64(x46) + x40) + out1[0] = x44 + out1[1] = x47 + out1[2] = x48 +} + +fe_carry :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { + x1 := arg1[0] + x2 := ((x1 >> 44) + arg1[1]) + x3 := ((x2 >> 43) + arg1[2]) + x4 := ((x1 & 0xfffffffffff) + ((x3 >> 43) * 0x5)) + x5 := (u64(fiat.u1((x4 >> 44))) + (x2 & 0x7ffffffffff)) + x6 := (x4 & 0xfffffffffff) + x7 := (x5 & 0x7ffffffffff) + x8 := (u64(fiat.u1((x5 >> 43))) + (x3 & 0x7ffffffffff)) + out1[0] = x6 + out1[1] = x7 + out1[2] = x8 +} + +fe_add :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) { + x1 := (arg1[0] + arg2[0]) + x2 := (arg1[1] + arg2[1]) + x3 := (arg1[2] + arg2[2]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 +} + +fe_sub :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) { + x1 := ((0x1ffffffffff6 + arg1[0]) - arg2[0]) + x2 := ((0xffffffffffe + arg1[1]) - arg2[1]) + x3 := ((0xffffffffffe + arg1[2]) - arg2[2]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 +} + +fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) { + x1 := (0x1ffffffffff6 - arg1[0]) + x2 := (0xffffffffffe - arg1[1]) + x3 := (0xffffffffffe - arg1[2]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 +} + +fe_cond_assign :: proc "contextless" (out1, arg1: ^Tight_Field_Element, arg2: bool) { + x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) + x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) + x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 +} + +fe_to_bytes :: proc "contextless" (out1: ^[32]byte, arg1: ^Tight_Field_Element) { + x1, x2 := _subborrowx_u44(0x0, arg1[0], 0xffffffffffb) + x3, x4 := _subborrowx_u43(x2, arg1[1], 0x7ffffffffff) + x5, x6 := _subborrowx_u43(x4, arg1[2], 0x7ffffffffff) + x7 := fiat.cmovznz_u64(x6, u64(0x0), 0xffffffffffffffff) + x8, x9 := _addcarryx_u44(0x0, x1, (x7 & 0xffffffffffb)) + x10, x11 := _addcarryx_u43(x9, x3, (x7 & 0x7ffffffffff)) + x12, _ := _addcarryx_u43(x11, x5, (x7 & 0x7ffffffffff)) + x14 := (x12 << 7) + x15 := (x10 << 4) + x16 := (u8(x8) & 0xff) + x17 := (x8 >> 8) + x18 := (u8(x17) & 0xff) + x19 := (x17 >> 8) + x20 := (u8(x19) & 0xff) + x21 := (x19 >> 8) + x22 := (u8(x21) & 0xff) + x23 := (x21 >> 8) + x24 := (u8(x23) & 0xff) + x25 := u8((x23 >> 8)) + x26 := (x15 + u64(x25)) + x27 := (u8(x26) & 0xff) + x28 := (x26 >> 8) + x29 := (u8(x28) & 0xff) + x30 := (x28 >> 8) + x31 := (u8(x30) & 0xff) + x32 := (x30 >> 8) + x33 := (u8(x32) & 0xff) + x34 := (x32 >> 8) + x35 := (u8(x34) & 0xff) + x36 := u8((x34 >> 8)) + x37 := (x14 + u64(x36)) + x38 := (u8(x37) & 0xff) + x39 := (x37 >> 8) + x40 := (u8(x39) & 0xff) + x41 := (x39 >> 8) + x42 := (u8(x41) & 0xff) + x43 := (x41 >> 8) + x44 := (u8(x43) & 0xff) + x45 := (x43 >> 8) + x46 := (u8(x45) & 0xff) + x47 := (x45 >> 8) + x48 := (u8(x47) & 0xff) + x49 := u8((x47 >> 8)) + out1[0] = x16 + out1[1] = x18 + out1[2] = x20 + out1[3] = x22 + out1[4] = x24 + out1[5] = x27 + out1[6] = x29 + out1[7] = x31 + out1[8] = x33 + out1[9] = x35 + out1[10] = x38 + out1[11] = x40 + out1[12] = x42 + out1[13] = x44 + out1[14] = x46 + out1[15] = x48 + out1[16] = x49 +} + +_fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[32]byte) { + x1 := (u64(arg1[16]) << 41) + x2 := (u64(arg1[15]) << 33) + x3 := (u64(arg1[14]) << 25) + x4 := (u64(arg1[13]) << 17) + x5 := (u64(arg1[12]) << 9) + x6 := (u64(arg1[11]) * u64(0x2)) + x7 := (u64(arg1[10]) << 36) + x8 := (u64(arg1[9]) << 28) + x9 := (u64(arg1[8]) << 20) + x10 := (u64(arg1[7]) << 12) + x11 := (u64(arg1[6]) << 4) + x12 := (u64(arg1[5]) << 40) + x13 := (u64(arg1[4]) << 32) + x14 := (u64(arg1[3]) << 24) + x15 := (u64(arg1[2]) << 16) + x16 := (u64(arg1[1]) << 8) + x17 := arg1[0] + x18 := (x16 + u64(x17)) + x19 := (x15 + x18) + x20 := (x14 + x19) + x21 := (x13 + x20) + x22 := (x12 + x21) + x23 := (x22 & 0xfffffffffff) + x24 := u8((x22 >> 44)) + x25 := (x11 + u64(x24)) + x26 := (x10 + x25) + x27 := (x9 + x26) + x28 := (x8 + x27) + x29 := (x7 + x28) + x30 := (x29 & 0x7ffffffffff) + x31 := fiat.u1((x29 >> 43)) + x32 := (x6 + u64(x31)) + x33 := (x5 + x32) + x34 := (x4 + x33) + x35 := (x3 + x34) + x36 := (x2 + x35) + x37 := (x1 + x36) + out1[0] = x23 + out1[1] = x30 + out1[2] = x37 +} + +fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 +} + +// The following routines were added by hand, and do not come from fiat-crypto. + +fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) { + out1[0] = 0 + out1[1] = 0 + out1[2] = 0 +} + +fe_set :: #force_inline proc "contextless" (out1, arg1: ^Tight_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 +} + +fe_cond_swap :: proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: bool) { + mask := -u64(arg1) + x := (out1[0] ~ out2[0]) & mask + x1, y1 := out1[0] ~ x, out2[0] ~ x + x = (out1[1] ~ out2[1]) & mask + x2, y2 := out1[1] ~ x, out2[1] ~ x + x = (out1[2] ~ out2[2]) & mask + x3, y3 := out1[2] ~ x, out2[2] ~ x + out1[0], out2[0] = x1, y1 + out1[1], out2[1] = x2, y2 + out1[2], out2[2] = x3, y3 +} diff --git a/core/crypto/poly1305/poly1305.odin b/core/crypto/poly1305/poly1305.odin new file mode 100644 index 000000000..8986be879 --- /dev/null +++ b/core/crypto/poly1305/poly1305.odin @@ -0,0 +1,163 @@ +package poly1305 + +import "core:crypto" +import "core:crypto/util" +import field "core:crypto/_fiat/field_poly1305" +import "core:mem" + +KEY_SIZE :: 32 +TAG_SIZE :: 16 + +_BLOCK_SIZE :: 16 + +sum :: proc (dst, msg, key: []byte) { + ctx: Context = --- + + init(&ctx, key) + update(&ctx, msg) + final(&ctx, dst) +} + +verify :: proc (tag, msg, key: []byte) -> bool { + ctx: Context = --- + derived_tag: [16]byte = --- + + if len(tag) != TAG_SIZE { + panic("crypto/poly1305: invalid tag size") + } + + init(&ctx, key) + update(&ctx, msg) + final(&ctx, derived_tag[:]) + + return crypto.compare_constant_time(derived_tag[:], tag) == 1 +} + +Context :: struct { + _r: field.Tight_Field_Element, + _a: field.Tight_Field_Element, + _s: field.Tight_Field_Element, + + _buffer: [_BLOCK_SIZE]byte, + _leftover: int, + + _is_initialized: bool, +} + +init :: proc (ctx: ^Context, key: []byte) { + if len(key) != KEY_SIZE { + panic("crypto/poly1305: invalid key size") + } + + // r = le_bytes_to_num(key[0..15]) + // r = clamp(r) (r &= 0xffffffc0ffffffc0ffffffc0fffffff) + tmp_lo := util.U64_LE(key[0:8]) & 0x0ffffffc0fffffff + tmp_hi := util.U64_LE(key[8:16]) & 0xffffffc0ffffffc + field.fe_from_u64s(&ctx._r, tmp_lo, tmp_hi) + + // s = le_bytes_to_num(key[16..31]) + field.fe_from_bytes(&ctx._s, key[16:32], 0) + + // a = 0 + field.fe_zero(&ctx._a) + + // No leftover in buffer + ctx._leftover = 0 + + ctx._is_initialized = true +} + +update :: proc (ctx: ^Context, data: []byte) { + assert(ctx._is_initialized) + + msg := data + msg_len := len(data) + + // Handle leftover + if ctx._leftover > 0 { + want := min(_BLOCK_SIZE - ctx._leftover, msg_len) + copy_slice(ctx._buffer[ctx._leftover:], msg[:want]) + msg_len = msg_len - want + msg = msg[want:] + ctx._leftover = ctx._leftover + want + if ctx._leftover < _BLOCK_SIZE { + return + } + _blocks(ctx, ctx._buffer[:]) + ctx._leftover = 0 + } + + // Process full blocks + if msg_len >= _BLOCK_SIZE { + want := msg_len & (~int(_BLOCK_SIZE - 1)) + _blocks(ctx, msg[:want]) + msg = msg[want:] + msg_len = msg_len - want + } + + // Store leftover + if msg_len > 0 { + // TODO: While -donna does it this way, I'm fairly sure that + // `ctx._leftover == 0` is an invariant at this point. + copy(ctx._buffer[ctx._leftover:], msg) + ctx._leftover = ctx._leftover + msg_len + } +} + +final :: proc (ctx: ^Context, dst: []byte) { + assert(ctx._is_initialized) + + if len(dst) != TAG_SIZE { + panic("poly1305: invalid destination tag size") + } + + // Process remaining block + if ctx._leftover > 0 { + ctx._buffer[ctx._leftover] = 1 + for i := ctx._leftover + 1; i < _BLOCK_SIZE; i = i + 1 { + ctx._buffer[i] = 0 + } + _blocks(ctx, ctx._buffer[:], true) + } + + // a += s + field.fe_add(field.fe_relax_cast(&ctx._a), &ctx._a, &ctx._s) // _a unreduced + field.fe_carry(&ctx._a, field.fe_relax_cast(&ctx._a)) // _a reduced + + // return num_to_16_le_bytes(a) + tmp: [32]byte = --- + field.fe_to_bytes(&tmp, &ctx._a) + copy_slice(dst, tmp[0:16]) + + reset(ctx) +} + +reset :: proc (ctx: ^Context) { + mem.zero_explicit(&ctx._r, size_of(ctx._r)) + mem.zero_explicit(&ctx._a, size_of(ctx._a)) + mem.zero_explicit(&ctx._s, size_of(ctx._s)) + mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer)) + + ctx._is_initialized = false +} + +_blocks :: proc (ctx: ^Context, msg: []byte, final := false) { + n: field.Tight_Field_Element = --- + final_byte := byte(!final) + + data := msg + data_len := len(data) + for data_len >= _BLOCK_SIZE { + // n = le_bytes_to_num(msg[((i-1)*16)..*i*16] | [0x01]) + field.fe_from_bytes(&n, data[:_BLOCK_SIZE], final_byte, false) + + // a += n + field.fe_add(field.fe_relax_cast(&ctx._a), &ctx._a, &n) // _a unreduced + + // a = (r * a) % p + field.fe_carry_mul(&ctx._a, field.fe_relax_cast(&ctx._a), field.fe_relax_cast(&ctx._r)) // _a reduced + + data = data[_BLOCK_SIZE:] + data_len = data_len - _BLOCK_SIZE + } +} diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 768ba242f..c27b5c6bc 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -116,6 +116,7 @@ main :: proc() { test_haval_256(&t) // "modern" crypto tests + test_poly1305(&t) test_x25519(&t) bench_modern(&t) diff --git a/tests/core/crypto/test_core_crypto_modern.odin b/tests/core/crypto/test_core_crypto_modern.odin index 4d7f08bb1..f4f07928e 100644 --- a/tests/core/crypto/test_core_crypto_modern.odin +++ b/tests/core/crypto/test_core_crypto_modern.odin @@ -4,6 +4,7 @@ import "core:testing" import "core:fmt" import "core:time" +import "core:crypto/poly1305" import "core:crypto/x25519" _digit_value :: proc(r: rune) -> int { @@ -27,6 +28,70 @@ _decode_hex32 :: proc(s: string) -> [32]byte{ return b } +@(test) +test_poly1305 :: proc(t: ^testing.T) { + log(t, "Testing poly1305") + + // Test cases taken from poly1305-donna. + key := [poly1305.KEY_SIZE]byte{ + 0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91, + 0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25, + 0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65, + 0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80, + } + + msg := [131]byte{ + 0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73, + 0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce, + 0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4, + 0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a, + 0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b, + 0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72, + 0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2, + 0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38, + 0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a, + 0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae, + 0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea, + 0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda, + 0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde, + 0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3, + 0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6, + 0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74, + 0xe3,0x55,0xa5, + } + + tag := [poly1305.TAG_SIZE]byte{ + 0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5, + 0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9, + } + tag_str := hex_string(tag[:]) + + // Verify - oneshot + compare + ok := poly1305.verify(tag[:], msg[:], key[:]) + expect(t, ok, "oneshot verify call failed") + + // Sum - oneshot + derived_tag: [poly1305.TAG_SIZE]byte + poly1305.sum(derived_tag[:], msg[:], key[:]) + derived_tag_str := hex_string(derived_tag[:]) + expect(t, derived_tag_str == tag_str, fmt.tprintf("Expected %s for sum(msg, key), but got %s instead", tag_str, derived_tag_str)) + + // Incremental + mem.zero(&derived_tag, size_of(derived_tag)) + ctx: poly1305.Context = --- + poly1305.init(&ctx, key[:]) + read_lengths := [11]int{32, 64, 16, 8, 4, 2, 1, 1, 1, 1, 1} + off := 0 + for read_length in read_lengths { + to_read := msg[off:off+read_length] + poly1305.update(&ctx, to_read) + off = off + read_length + } + poly1305.final(&ctx, derived_tag[:]) + derived_tag_str = hex_string(derived_tag[:]) + expect(t, derived_tag_str == tag_str, fmt.tprintf("Expected %s for init/update/final - incremental, but got %s instead", tag_str, derived_tag_str)) +} + TestECDH :: struct { scalar: string, point: string, @@ -76,9 +141,75 @@ test_x25519 :: proc(t: ^testing.T) { bench_modern :: proc(t: ^testing.T) { fmt.println("Starting benchmarks:") + bench_poly1305(t) bench_x25519(t) } +_setup_poly1305 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + assert(options != nil) + + options.input = make([]u8, options.bytes, allocator) + return nil if len(options.input) == options.bytes else .Allocation_Error +} + +_teardown_poly1305 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + assert(options != nil) + + delete(options.input) + return nil +} + +_benchmark_poly1305 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + key := [poly1305.KEY_SIZE]byte{ + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + + tag: [poly1305.TAG_SIZE]byte = --- + for _ in 0..=options.rounds { + poly1305.sum(tag[:], buf, key[:]) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + //options.hash = u128(h) + return nil +} + +benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) { + fmt.printf("\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", + name, + options.rounds, + options.processed, + time.duration_nanoseconds(options.duration), + options.rounds_per_second, + options.megabytes_per_second, + ) +} + +bench_poly1305 :: proc(t: ^testing.T) { + name := "Poly1305 64 zero bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 64, + setup = _setup_poly1305, + bench = _benchmark_poly1305, + teardown = _teardown_poly1305, + } + + err := time.benchmark(options, context.allocator) + expect(t, err == nil, name) + benchmark_print(name, options) + + name = "Poly1305 1024 zero bytes" + options.bytes = 1024 + err = time.benchmark(options, context.allocator) + expect(t, err == nil, name) + benchmark_print(name, options) +} + bench_x25519 :: proc(t: ^testing.T) { point := _decode_hex32("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") scalar := _decode_hex32("cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe") From 4647081f4953ad22810b3ff120d4c499f4240701 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Mon, 8 Nov 2021 04:47:42 +0000 Subject: [PATCH 0027/1258] core/crypto/poly1305: Triple performance on amd64 with -o:speed --- core/crypto/_fiat/field_poly1305/field.odin | 47 +++++++++++++++------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index 642949b02..bfb7cf1f9 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -11,25 +11,46 @@ fe_tighten_cast :: #force_inline proc "contextless" (arg1: ^Loose_Field_Element) return transmute(^Tight_Field_Element)(arg1) } -fe_from_bytes :: proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte, sanitize: bool = true) { - // fiat-crypto's deserialization routine wants 256-bits of input, but - // r/s are 128-bits long, and block processing works on 128-bits plus a - // final bit. +fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, arg2: byte, sanitize: bool = true) { + // fiat-crypto's deserialization routine effectively processes a + // single byte at a time, and wants 256-bits of input for a value + // that will be 128-bits or 129-bits. // - // This is more ergonomic, and while the copy is unfortunate, this avoids - // having to alter the fiat-crypto derived code. + // This is somewhat cumbersome to use, so at a minimum a wrapper + // makes implementing the actual MAC block processing considerably + // neater. assert(len(arg1) == 16) - tmp: [32]byte - copy_slice(tmp[0:16], arg1[:]) - tmp[16] = arg2 + when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" { + // While it may be unwise to do deserialization here on our + // own when fiat-crypto provides equivalent functionality, + // doing it this way provides a little under 3x performance + // improvement when optimization is enabled. + src_p := transmute(^[2]u64)(&arg1[0]) + lo := src_p[0] + hi := src_p[1] - _fe_from_bytes(out1, &tmp) + // This is inspired by poly1305-donna, though adjustments were + // made since a Tight_Field_Element's limbs are 44-bits, 43-bits, + // and 43-bits wide. + // + // Note: This could be transplated into fe_from_u64s, but that + // code is called once per MAC, and is non-criticial path. + hibit := u64(arg2) << 41 // arg2 << 128 + out1[0] = lo & 0xfffffffffff + out1[1] = ((lo >> 44) | (hi << 20)) & 0x7ffffffffff + out1[2] = ((hi >> 23) & 0x7ffffffffff) | hibit + } else { + tmp: [32]byte + copy_slice(tmp[0:16], arg1[:]) + tmp[16] = arg2 - // Need to sanitize the temporary buffer when deserializing `s`. - if sanitize { - mem.zero_explicit(&tmp, size_of(tmp)) + _fe_from_bytes(out1, &tmp) + if sanitize { + // This is used to deserialize `s` which is confidential. + mem.zero_explicit(&tmp, size_of(tmp)) + } } } From 7bed3176360df79d88e1e6022e62b985d3648579 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Sat, 6 Nov 2021 23:15:50 +0000 Subject: [PATCH 0028/1258] core/crypto: Add chacha20 This package implements the ChaCha20 stream cipher as specified in RFC 8439, and the somewhat non-standard XChaCha20 variant that supports a 192-bit nonce. While an IETF draft for XChaCha20 standardization exists, implementations that pre-date the draft use a 64-bit counter, instead of the IETF-style 32-bit one. This implementation opts for the latter as compatibility with libsodium is more important than compatibility with an expired IETF draft. --- core/crypto/chacha20/chacha20.odin | 581 ++++++++++++++++++ tests/core/crypto/test_core_crypto.odin | 1 + .../core/crypto/test_core_crypto_modern.odin | 150 ++++- 3 files changed, 728 insertions(+), 4 deletions(-) create mode 100644 core/crypto/chacha20/chacha20.odin diff --git a/core/crypto/chacha20/chacha20.odin b/core/crypto/chacha20/chacha20.odin new file mode 100644 index 000000000..f6f551692 --- /dev/null +++ b/core/crypto/chacha20/chacha20.odin @@ -0,0 +1,581 @@ +package chacha20 + +import "core:crypto/util" +import "core:math/bits" +import "core:mem" + +KEY_SIZE :: 32 +NONCE_SIZE :: 12 +XNONCE_SIZE :: 24 + +_MAX_CTR_IETF :: 0xffffffff + +_BLOCK_SIZE :: 64 +_STATE_SIZE_U32 :: 16 +_ROUNDS :: 20 + +_SIGMA_0 : u32 : 0x61707865 +_SIGMA_1 : u32 : 0x3320646e +_SIGMA_2 : u32 : 0x79622d32 +_SIGMA_3 : u32 : 0x6b206574 + +Context :: struct { + _s: [_STATE_SIZE_U32]u32, + + _buffer: [_BLOCK_SIZE]byte, + _off: int, + + _is_ietf_flavor: bool, + _is_initialized: bool, +} + +init :: proc (ctx: ^Context, key, nonce: []byte) { + if len(key) != KEY_SIZE { + panic("crypto/chacha20: invalid ChaCha20 key size") + } + if n_len := len(nonce); n_len != NONCE_SIZE && n_len != XNONCE_SIZE { + panic("crypto/chacha20: invalid (X)ChaCha20 nonce size") + } + + k, n := key, nonce + + // Derive the XChaCha20 subkey and sub-nonce via HChaCha20. + is_xchacha := len(nonce) == XNONCE_SIZE + if is_xchacha { + sub_key := ctx._buffer[:KEY_SIZE] + _hchacha20(sub_key, k, n) + k = sub_key + n = n[16:24] + } + + ctx._s[0] = _SIGMA_0 + ctx._s[1] = _SIGMA_1 + ctx._s[2] = _SIGMA_2 + ctx._s[3] = _SIGMA_3 + ctx._s[4] = util.U32_LE(k[0:4]) + ctx._s[5] = util.U32_LE(k[4:8]) + ctx._s[6] = util.U32_LE(k[8:12]) + ctx._s[7] = util.U32_LE(k[12:16]) + ctx._s[8] = util.U32_LE(k[16:20]) + ctx._s[9] = util.U32_LE(k[20:24]) + ctx._s[10] = util.U32_LE(k[24:28]) + ctx._s[11] = util.U32_LE(k[28:32]) + ctx._s[12] = 0 + if !is_xchacha { + ctx._s[13] = util.U32_LE(n[0:4]) + ctx._s[14] = util.U32_LE(n[4:8]) + ctx._s[15] = util.U32_LE(n[8:12]) + } else { + ctx._s[13] = 0 + ctx._s[14] = util.U32_LE(n[0:4]) + ctx._s[15] = util.U32_LE(n[4:8]) + + // The sub-key is stored in the keystream buffer. While + // this will be overwritten in most circumstances, explicitly + // clear it out early. + mem.zero_explicit(&ctx._buffer, KEY_SIZE) + } + + ctx._off = _BLOCK_SIZE + ctx._is_ietf_flavor = !is_xchacha + ctx._is_initialized = true +} + +seek :: proc (ctx: ^Context, block_nr: u64) { + assert(ctx._is_initialized) + + if ctx._is_ietf_flavor { + if block_nr > _MAX_CTR_IETF { + panic("crypto/chacha20: attempted to seek past maximum counter") + } + } else { + ctx._s[13] = u32(block_nr >> 32) + } + ctx._s[12] = u32(block_nr) + ctx._off = _BLOCK_SIZE +} + +xor_bytes :: proc (ctx: ^Context, dst, src: []byte) { + assert(ctx._is_initialized) + + // TODO: Enforcing that dst and src alias exactly or not at all + // is a good idea, though odd aliasing should be extremely uncommon. + + src, dst := src, dst + if dst_len := len(dst); dst_len < len(src) { + src = src[:dst_len] + } + + for remaining := len(src); remaining > 0; { + // Process multiple blocks at once + if ctx._off == _BLOCK_SIZE { + if nr_blocks := remaining / _BLOCK_SIZE; nr_blocks > 0 { + direct_bytes := nr_blocks * _BLOCK_SIZE + _do_blocks(ctx, dst, src, nr_blocks) + remaining -= direct_bytes + if remaining == 0 { + return + } + dst = dst[direct_bytes:] + src = src[direct_bytes:] + } + + // If there is a partial block, generate and buffer 1 block + // worth of keystream. + _do_blocks(ctx, ctx._buffer[:], nil, 1) + ctx._off = 0 + } + + // Process partial blocks from the buffered keystream. + to_xor := min(_BLOCK_SIZE - ctx._off, remaining) + buffered_keystream := ctx._buffer[ctx._off:] + for i := 0; i < to_xor; i = i + 1 { + dst[i] = buffered_keystream[i] ~ src[i] + } + ctx._off += to_xor + dst = dst[to_xor:] + src = src[to_xor:] + remaining -= to_xor + } +} + +keystream_bytes :: proc (ctx: ^Context, dst: []byte) { + assert(ctx._is_initialized) + + dst := dst + for remaining := len(dst); remaining > 0; { + // Process multiple blocks at once + if ctx._off == _BLOCK_SIZE { + if nr_blocks := remaining / _BLOCK_SIZE; nr_blocks > 0 { + direct_bytes := nr_blocks * _BLOCK_SIZE + _do_blocks(ctx, dst, nil, nr_blocks) + remaining -= direct_bytes + if remaining == 0 { + return + } + dst = dst[direct_bytes:] + } + + // If there is a partial block, generate and buffer 1 block + // worth of keystream. + _do_blocks(ctx, ctx._buffer[:], nil, 1) + ctx._off = 0 + } + + // Process partial blocks from the buffered keystream. + to_copy := min(_BLOCK_SIZE - ctx._off, remaining) + buffered_keystream := ctx._buffer[ctx._off:] + copy(dst[:to_copy], buffered_keystream[:to_copy]) + ctx._off += to_copy + dst = dst[to_copy:] + remaining -= to_copy + } +} + +reset :: proc (ctx: ^Context) { + mem.zero_explicit(&ctx._s, size_of(ctx._s)) + mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer)) + + ctx._is_initialized = false +} + +_do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) { + // Enforce the maximum consumed keystream per nonce. + // + // While all modern "standard" definitions of ChaCha20 use + // the IETF 32-bit counter, for XChaCha20 most common + // implementations allow for a 64-bit counter. + // + // Honestly, the answer here is "use a MRAE primitive", but + // go with common practice in the case of XChaCha20. + if ctx._is_ietf_flavor { + if u64(ctx._s[12]) + u64(nr_blocks) > 0xffffffff { + panic("crypto/chacha20: maximum ChaCha20 keystream per nonce reached") + } + } else { + ctr := (u64(ctx._s[13]) << 32) | u64(ctx._s[12]) + if _, carry := bits.add_u64(ctr, u64(nr_blocks), 0); carry != 0 { + panic("crypto/chacha20: maximum XChaCha20 keystream per nonce reached") + } + } + + dst, src := dst, src + x := &ctx._s + for n := 0; n < nr_blocks; n = n + 1 { + x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3 + x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15] + + for i := _ROUNDS; i > 0; i = i - 2 { + // Even when forcing inlining manually inlining all of + // these is decently faster. + + // quarterround(x, 0, 4, 8, 12) + x0 += x4 + x12 ~= x0 + x12 = util.ROTL32(x12, 16) + x8 += x12 + x4 ~= x8 + x4 = util.ROTL32(x4, 12) + x0 += x4 + x12 ~= x0 + x12 = util.ROTL32(x12, 8) + x8 += x12 + x4 ~= x8 + x4 = util.ROTL32(x4, 7) + + // quarterround(x, 1, 5, 9, 13) + x1 += x5 + x13 ~= x1 + x13 = util.ROTL32(x13, 16) + x9 += x13 + x5 ~= x9 + x5 = util.ROTL32(x5, 12) + x1 += x5 + x13 ~= x1 + x13 = util.ROTL32(x13, 8) + x9 += x13 + x5 ~= x9 + x5 = util.ROTL32(x5, 7) + + // quarterround(x, 2, 6, 10, 14) + x2 += x6 + x14 ~= x2 + x14 = util.ROTL32(x14, 16) + x10 += x14 + x6 ~= x10 + x6 = util.ROTL32(x6, 12) + x2 += x6 + x14 ~= x2 + x14 = util.ROTL32(x14, 8) + x10 += x14 + x6 ~= x10 + x6 = util.ROTL32(x6, 7) + + // quarterround(x, 3, 7, 11, 15) + x3 += x7 + x15 ~= x3 + x15 = util.ROTL32(x15, 16) + x11 += x15 + x7 ~= x11 + x7 = util.ROTL32(x7, 12) + x3 += x7 + x15 ~= x3 + x15 = util.ROTL32(x15, 8) + x11 += x15 + x7 ~= x11 + x7 = util.ROTL32(x7, 7) + + // quarterround(x, 0, 5, 10, 15) + x0 += x5 + x15 ~= x0 + x15 = util.ROTL32(x15, 16) + x10 += x15 + x5 ~= x10 + x5 = util.ROTL32(x5, 12) + x0 += x5 + x15 ~= x0 + x15 = util.ROTL32(x15, 8) + x10 += x15 + x5 ~= x10 + x5 = util.ROTL32(x5, 7) + + // quarterround(x, 1, 6, 11, 12) + x1 += x6 + x12 ~= x1 + x12 = util.ROTL32(x12, 16) + x11 += x12 + x6 ~= x11 + x6 = util.ROTL32(x6, 12) + x1 += x6 + x12 ~= x1 + x12 = util.ROTL32(x12, 8) + x11 += x12 + x6 ~= x11 + x6 = util.ROTL32(x6, 7) + + // quarterround(x, 2, 7, 8, 13) + x2 += x7 + x13 ~= x2 + x13 = util.ROTL32(x13, 16) + x8 += x13 + x7 ~= x8 + x7 = util.ROTL32(x7, 12) + x2 += x7 + x13 ~= x2 + x13 = util.ROTL32(x13, 8) + x8 += x13 + x7 ~= x8 + x7 = util.ROTL32(x7, 7) + + // quarterround(x, 3, 4, 9, 14) + x3 += x4 + x14 ~= x3 + x14 = util.ROTL32(x14, 16) + x9 += x14 + x4 ~= x9 + x4 = util.ROTL32(x4, 12) + x3 += x4 + x14 ~= x3 + x14 = util.ROTL32(x14, 8) + x9 += x14 + x4 ~= x9 + x4 = util.ROTL32(x4, 7) + } + + x0 += _SIGMA_0 + x1 += _SIGMA_1 + x2 += _SIGMA_2 + x3 += _SIGMA_3 + x4 += x[4] + x5 += x[5] + x6 += x[6] + x7 += x[7] + x8 += x[8] + x9 += x[9] + x10 += x[10] + x11 += x[11] + x12 += x[12] + x13 += x[13] + x14 += x[14] + x15 += x[15] + + // While the "correct" answer to getting more performance out of + // this is "use vector operations", support for that is currently + // a work in progress/to be designed. + // + // Until dedicated assembly can be written leverage the fact that + // the callers of this routine ensure that src/dst are valid. + + when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" { + // util.PUT_U32_LE/util.U32_LE are not required on little-endian + // systems that also happen to not be strict about aligned + // memory access. + + dst_p := transmute(^[16]u32)(&dst[0]) + if src != nil { + src_p := transmute(^[16]u32)(&src[0]) + dst_p[0] = src_p[0] ~ x0 + dst_p[1] = src_p[1] ~ x1 + dst_p[2] = src_p[2] ~ x2 + dst_p[3] = src_p[3] ~ x3 + dst_p[4] = src_p[4] ~ x4 + dst_p[5] = src_p[5] ~ x5 + dst_p[6] = src_p[6] ~ x6 + dst_p[7] = src_p[7] ~ x7 + dst_p[8] = src_p[8] ~ x8 + dst_p[9] = src_p[9] ~ x9 + dst_p[10] = src_p[10] ~ x10 + dst_p[11] = src_p[11] ~ x11 + dst_p[12] = src_p[12] ~ x12 + dst_p[13] = src_p[13] ~ x13 + dst_p[14] = src_p[14] ~ x14 + dst_p[15] = src_p[15] ~ x15 + src = src[_BLOCK_SIZE:] + } else { + dst_p[0] = x0 + dst_p[1] = x1 + dst_p[2] = x2 + dst_p[3] = x3 + dst_p[4] = x4 + dst_p[5] = x5 + dst_p[6] = x6 + dst_p[7] = x7 + dst_p[8] = x8 + dst_p[9] = x9 + dst_p[10] = x10 + dst_p[11] = x11 + dst_p[12] = x12 + dst_p[13] = x13 + dst_p[14] = x14 + dst_p[15] = x15 + } + dst = dst[_BLOCK_SIZE:] + } else { + #no_bounds_check { + if src != nil { + util.PUT_U32_LE(dst[0:4], util.U32_LE(src[0:4]) ~ x0) + util.PUT_U32_LE(dst[4:8], util.U32_LE(src[4:8]) ~ x1) + util.PUT_U32_LE(dst[8:12], util.U32_LE(src[8:12]) ~ x2) + util.PUT_U32_LE(dst[12:16], util.U32_LE(src[12:16]) ~ x3) + util.PUT_U32_LE(dst[16:20], util.U32_LE(src[16:20]) ~ x4) + util.PUT_U32_LE(dst[20:24], util.U32_LE(src[20:24]) ~ x5) + util.PUT_U32_LE(dst[24:28], util.U32_LE(src[24:28]) ~ x6) + util.PUT_U32_LE(dst[28:32], util.U32_LE(src[28:32]) ~ x7) + util.PUT_U32_LE(dst[32:36], util.U32_LE(src[32:36]) ~ x8) + util.PUT_U32_LE(dst[36:40], util.U32_LE(src[36:40]) ~ x9) + util.PUT_U32_LE(dst[40:44], util.U32_LE(src[40:44]) ~ x10) + util.PUT_U32_LE(dst[44:48], util.U32_LE(src[44:48]) ~ x11) + util.PUT_U32_LE(dst[48:52], util.U32_LE(src[48:52]) ~ x12) + util.PUT_U32_LE(dst[52:56], util.U32_LE(src[52:56]) ~ x13) + util.PUT_U32_LE(dst[56:60], util.U32_LE(src[56:60]) ~ x14) + util.PUT_U32_LE(dst[60:64], util.U32_LE(src[60:64]) ~ x15) + src = src[_BLOCK_SIZE:] + } else { + util.PUT_U32_LE(dst[0:4], x0) + util.PUT_U32_LE(dst[4:8], x1) + util.PUT_U32_LE(dst[8:12], x2) + util.PUT_U32_LE(dst[12:16], x3) + util.PUT_U32_LE(dst[16:20], x4) + util.PUT_U32_LE(dst[20:24], x5) + util.PUT_U32_LE(dst[24:28], x6) + util.PUT_U32_LE(dst[28:32], x7) + util.PUT_U32_LE(dst[32:36], x8) + util.PUT_U32_LE(dst[36:40], x9) + util.PUT_U32_LE(dst[40:44], x10) + util.PUT_U32_LE(dst[44:48], x11) + util.PUT_U32_LE(dst[48:52], x12) + util.PUT_U32_LE(dst[52:56], x13) + util.PUT_U32_LE(dst[56:60], x14) + util.PUT_U32_LE(dst[60:64], x15) + } + dst = dst[_BLOCK_SIZE:] + } + } + + // Increment the counter. Overflow checking is done upon + // entry into the routine, so a 64-bit increment safely + // covers both cases. + new_ctr := ((u64(ctx._s[13]) << 32) | u64(ctx._s[12])) + 1 + x[12] = u32(new_ctr) + x[13] = u32(new_ctr >> 32) + } +} + +_hchacha20 :: proc (dst, key, nonce: []byte) { + x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3 + x4 := util.U32_LE(key[0:4]) + x5 := util.U32_LE(key[4:8]) + x6 := util.U32_LE(key[8:12]) + x7 := util.U32_LE(key[12:16]) + x8 := util.U32_LE(key[16:20]) + x9 := util.U32_LE(key[20:24]) + x10 := util.U32_LE(key[24:28]) + x11 := util.U32_LE(key[28:32]) + x12 := util.U32_LE(nonce[0:4]) + x13 := util.U32_LE(nonce[4:8]) + x14 := util.U32_LE(nonce[8:12]) + x15 := util.U32_LE(nonce[12:16]) + + for i := _ROUNDS; i > 0; i = i - 2 { + // quarterround(x, 0, 4, 8, 12) + x0 += x4 + x12 ~= x0 + x12 = util.ROTL32(x12, 16) + x8 += x12 + x4 ~= x8 + x4 = util.ROTL32(x4, 12) + x0 += x4 + x12 ~= x0 + x12 = util.ROTL32(x12, 8) + x8 += x12 + x4 ~= x8 + x4 = util.ROTL32(x4, 7) + + // quarterround(x, 1, 5, 9, 13) + x1 += x5 + x13 ~= x1 + x13 = util.ROTL32(x13, 16) + x9 += x13 + x5 ~= x9 + x5 = util.ROTL32(x5, 12) + x1 += x5 + x13 ~= x1 + x13 = util.ROTL32(x13, 8) + x9 += x13 + x5 ~= x9 + x5 = util.ROTL32(x5, 7) + + // quarterround(x, 2, 6, 10, 14) + x2 += x6 + x14 ~= x2 + x14 = util.ROTL32(x14, 16) + x10 += x14 + x6 ~= x10 + x6 = util.ROTL32(x6, 12) + x2 += x6 + x14 ~= x2 + x14 = util.ROTL32(x14, 8) + x10 += x14 + x6 ~= x10 + x6 = util.ROTL32(x6, 7) + + // quarterround(x, 3, 7, 11, 15) + x3 += x7 + x15 ~= x3 + x15 = util.ROTL32(x15, 16) + x11 += x15 + x7 ~= x11 + x7 = util.ROTL32(x7, 12) + x3 += x7 + x15 ~= x3 + x15 = util.ROTL32(x15, 8) + x11 += x15 + x7 ~= x11 + x7 = util.ROTL32(x7, 7) + + // quarterround(x, 0, 5, 10, 15) + x0 += x5 + x15 ~= x0 + x15 = util.ROTL32(x15, 16) + x10 += x15 + x5 ~= x10 + x5 = util.ROTL32(x5, 12) + x0 += x5 + x15 ~= x0 + x15 = util.ROTL32(x15, 8) + x10 += x15 + x5 ~= x10 + x5 = util.ROTL32(x5, 7) + + // quarterround(x, 1, 6, 11, 12) + x1 += x6 + x12 ~= x1 + x12 = util.ROTL32(x12, 16) + x11 += x12 + x6 ~= x11 + x6 = util.ROTL32(x6, 12) + x1 += x6 + x12 ~= x1 + x12 = util.ROTL32(x12, 8) + x11 += x12 + x6 ~= x11 + x6 = util.ROTL32(x6, 7) + + // quarterround(x, 2, 7, 8, 13) + x2 += x7 + x13 ~= x2 + x13 = util.ROTL32(x13, 16) + x8 += x13 + x7 ~= x8 + x7 = util.ROTL32(x7, 12) + x2 += x7 + x13 ~= x2 + x13 = util.ROTL32(x13, 8) + x8 += x13 + x7 ~= x8 + x7 = util.ROTL32(x7, 7) + + // quarterround(x, 3, 4, 9, 14) + x3 += x4 + x14 ~= x3 + x14 = util.ROTL32(x14, 16) + x9 += x14 + x4 ~= x9 + x4 = util.ROTL32(x4, 12) + x3 += x4 + x14 ~= x3 + x14 = util.ROTL32(x14, 8) + x9 += x14 + x4 ~= x9 + x4 = util.ROTL32(x4, 7) + } + + util.PUT_U32_LE(dst[0:4], x0) + util.PUT_U32_LE(dst[4:8], x1) + util.PUT_U32_LE(dst[8:12], x2) + util.PUT_U32_LE(dst[12:16], x3) + util.PUT_U32_LE(dst[16:20], x12) + util.PUT_U32_LE(dst[20:24], x13) + util.PUT_U32_LE(dst[24:28], x14) + util.PUT_U32_LE(dst[28:32], x15) +} diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index c27b5c6bc..b73a191ad 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -116,6 +116,7 @@ main :: proc() { test_haval_256(&t) // "modern" crypto tests + test_chacha20(&t) test_poly1305(&t) test_x25519(&t) diff --git a/tests/core/crypto/test_core_crypto_modern.odin b/tests/core/crypto/test_core_crypto_modern.odin index f4f07928e..45ec8b339 100644 --- a/tests/core/crypto/test_core_crypto_modern.odin +++ b/tests/core/crypto/test_core_crypto_modern.odin @@ -2,8 +2,10 @@ package test_core_crypto import "core:testing" import "core:fmt" +import "core:mem" import "core:time" +import "core:crypto/chacha20" import "core:crypto/poly1305" import "core:crypto/x25519" @@ -28,6 +30,94 @@ _decode_hex32 :: proc(s: string) -> [32]byte{ return b } +@(test) +test_chacha20 :: proc(t: ^testing.T) { + log(t, "Testing (X)ChaCha20") + + // Test cases taken from RFC 8439, and draft-irtf-cfrg-xchacha-03 + plaintext_str := "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." + plaintext := transmute([]byte)(plaintext_str) + + key := [chacha20.KEY_SIZE]byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + } + + nonce := [chacha20.NONCE_SIZE]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x00, + } + + ciphertext := [114]byte{ + 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, + 0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81, + 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2, + 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, + 0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab, + 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57, + 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, + 0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8, + 0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61, + 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e, + 0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06, + 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36, + 0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6, + 0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42, + 0x87, 0x4d, + } + ciphertext_str := hex_string(ciphertext[:]) + + derived_ciphertext: [114]byte + ctx: chacha20.Context = --- + chacha20.init(&ctx, key[:], nonce[:]) + chacha20.seek(&ctx, 1) // The test vectors start the counter at 1. + chacha20.xor_bytes(&ctx, derived_ciphertext[:], plaintext[:]) + + derived_ciphertext_str := hex_string(derived_ciphertext[:]) + expect(t, derived_ciphertext_str == ciphertext_str, fmt.tprintf("Expected %s for xor_bytes(plaintext_str), but got %s instead", ciphertext_str, derived_ciphertext_str)) + + xkey := [chacha20.KEY_SIZE]byte{ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + } + + xnonce := [chacha20.XNONCE_SIZE]byte{ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + } + + xciphertext := [114]byte{ + 0xbd, 0x6d, 0x17, 0x9d, 0x3e, 0x83, 0xd4, 0x3b, + 0x95, 0x76, 0x57, 0x94, 0x93, 0xc0, 0xe9, 0x39, + 0x57, 0x2a, 0x17, 0x00, 0x25, 0x2b, 0xfa, 0xcc, + 0xbe, 0xd2, 0x90, 0x2c, 0x21, 0x39, 0x6c, 0xbb, + 0x73, 0x1c, 0x7f, 0x1b, 0x0b, 0x4a, 0xa6, 0x44, + 0x0b, 0xf3, 0xa8, 0x2f, 0x4e, 0xda, 0x7e, 0x39, + 0xae, 0x64, 0xc6, 0x70, 0x8c, 0x54, 0xc2, 0x16, + 0xcb, 0x96, 0xb7, 0x2e, 0x12, 0x13, 0xb4, 0x52, + 0x2f, 0x8c, 0x9b, 0xa4, 0x0d, 0xb5, 0xd9, 0x45, + 0xb1, 0x1b, 0x69, 0xb9, 0x82, 0xc1, 0xbb, 0x9e, + 0x3f, 0x3f, 0xac, 0x2b, 0xc3, 0x69, 0x48, 0x8f, + 0x76, 0xb2, 0x38, 0x35, 0x65, 0xd3, 0xff, 0xf9, + 0x21, 0xf9, 0x66, 0x4c, 0x97, 0x63, 0x7d, 0xa9, + 0x76, 0x88, 0x12, 0xf6, 0x15, 0xc6, 0x8b, 0x13, + 0xb5, 0x2e, + } + xciphertext_str := hex_string(xciphertext[:]) + + chacha20.init(&ctx, xkey[:], xnonce[:]) + chacha20.seek(&ctx, 1) + chacha20.xor_bytes(&ctx, derived_ciphertext[:], plaintext[:]) + + derived_ciphertext_str = hex_string(derived_ciphertext[:]) + expect(t, derived_ciphertext_str == xciphertext_str, fmt.tprintf("Expected %s for xor_bytes(plaintext_str), but got %s instead", xciphertext_str, derived_ciphertext_str)) +} + @(test) test_poly1305 :: proc(t: ^testing.T) { log(t, "Testing poly1305") @@ -141,24 +231,49 @@ test_x25519 :: proc(t: ^testing.T) { bench_modern :: proc(t: ^testing.T) { fmt.println("Starting benchmarks:") + bench_chacha20(t) bench_poly1305(t) bench_x25519(t) } -_setup_poly1305 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { +_setup_sized_buf :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { assert(options != nil) options.input = make([]u8, options.bytes, allocator) return nil if len(options.input) == options.bytes else .Allocation_Error } -_teardown_poly1305 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { +_teardown_sized_buf :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { assert(options != nil) delete(options.input) return nil } +_benchmark_chacha20 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + key := [chacha20.KEY_SIZE]byte{ + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + nonce := [chacha20.NONCE_SIZE]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + } + + ctx: chacha20.Context = --- + chacha20.init(&ctx, key[:], nonce[:]) + + for _ in 0..=options.rounds { + chacha20.xor_bytes(&ctx, buf, buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + return nil +} + _benchmark_poly1305 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { buf := options.input key := [poly1305.KEY_SIZE]byte{ @@ -189,14 +304,41 @@ benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) { ) } +bench_chacha20 :: proc(t: ^testing.T) { + name := "ChaCha20 64 bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 64, + setup = _setup_sized_buf, + bench = _benchmark_chacha20, + teardown = _teardown_sized_buf, + } + + err := time.benchmark(options, context.allocator) + expect(t, err == nil, name) + benchmark_print(name, options) + + name = "ChaCha20 1024 bytes" + options.bytes = 1024 + err = time.benchmark(options, context.allocator) + expect(t, err == nil, name) + benchmark_print(name, options) + + name = "ChaCha20 65536 bytes" + options.bytes = 65536 + err = time.benchmark(options, context.allocator) + expect(t, err == nil, name) + benchmark_print(name, options) +} + bench_poly1305 :: proc(t: ^testing.T) { name := "Poly1305 64 zero bytes" options := &time.Benchmark_Options{ rounds = 1_000, bytes = 64, - setup = _setup_poly1305, + setup = _setup_sized_buf, bench = _benchmark_poly1305, - teardown = _teardown_poly1305, + teardown = _teardown_sized_buf, } err := time.benchmark(options, context.allocator) From 6c4c9aef618dcf3932be88ca6df65164145b7cea Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Tue, 9 Nov 2021 07:22:41 +0000 Subject: [PATCH 0029/1258] core/crypto: Add chacha20poly1305 This package implements the chacha20poly1305 AEAD construct as specified in RFC 8439. --- .../chacha20poly1305/chacha20poly1305.odin | 146 ++++++++++++++++++ tests/core/crypto/test_core_crypto.odin | 1 + .../core/crypto/test_core_crypto_modern.odin | 131 +++++++++++++++- 3 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 core/crypto/chacha20poly1305/chacha20poly1305.odin diff --git a/core/crypto/chacha20poly1305/chacha20poly1305.odin b/core/crypto/chacha20poly1305/chacha20poly1305.odin new file mode 100644 index 000000000..67d89df56 --- /dev/null +++ b/core/crypto/chacha20poly1305/chacha20poly1305.odin @@ -0,0 +1,146 @@ +package chacha20poly1305 + +import "core:crypto" +import "core:crypto/chacha20" +import "core:crypto/poly1305" +import "core:crypto/util" +import "core:mem" + +KEY_SIZE :: chacha20.KEY_SIZE +NONCE_SIZE :: chacha20.NONCE_SIZE +TAG_SIZE :: poly1305.TAG_SIZE + +_P_MAX :: 64 * 0xffffffff // 64 * (2^32-1) + +_validate_common_slice_sizes :: proc (tag, key, nonce, aad, text: []byte) { + if len(tag) != TAG_SIZE { + panic("crypto/chacha20poly1305: invalid destination tag size") + } + if len(key) != KEY_SIZE { + panic("crypto/chacha20poly1305: invalid key size") + } + if len(nonce) != NONCE_SIZE { + panic("crypto/chacha20poly1305: invalid nonce size") + } + + #assert(size_of(int) == 8 || size_of(int) <= 4) + when size_of(int) == 8 { + // A_MAX = 2^64 - 1 due to the length field limit. + // P_MAX = 64 * (2^32 - 1) due to the IETF ChaCha20 counter limit. + // + // A_MAX is limited by size_of(int), so there is no need to + // enforce it. P_MAX only needs to be checked on 64-bit targets, + // for reasons that should be obvious. + if text_len := len(text); text_len > _P_MAX { + panic("crypto/chacha20poly1305: oversized src data") + } + } +} + +_PAD: [16]byte +_update_mac_pad16 :: #force_inline proc (ctx: ^poly1305.Context, x_len: int) { + if pad_len := 16 - (x_len & (16-1)); pad_len != 16 { + poly1305.update(ctx, _PAD[:pad_len]) + } +} + +encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) { + _validate_common_slice_sizes(tag, key, nonce, aad, plaintext) + if len(ciphertext) != len(plaintext) { + panic("crypto/chacha20poly1305: invalid destination ciphertext size") + } + + stream_ctx: chacha20.Context = --- + chacha20.init(&stream_ctx, key, nonce) + + // otk = poly1305_key_gen(key, nonce) + otk: [poly1305.KEY_SIZE]byte = --- + chacha20.keystream_bytes(&stream_ctx, otk[:]) + mac_ctx: poly1305.Context = --- + poly1305.init(&mac_ctx, otk[:]) + mem.zero_explicit(&otk, size_of(otk)) + + aad_len, ciphertext_len := len(aad), len(ciphertext) + + // There is nothing preventing aad and ciphertext from overlapping + // so auth the AAD before encrypting (slightly different from the + // RFC, since the RFC encrypts into a new buffer). + // + // mac_data = aad | pad16(aad) + poly1305.update(&mac_ctx, aad) + _update_mac_pad16(&mac_ctx, aad_len) + + // ciphertext = chacha20_encrypt(key, 1, nonce, plaintext) + chacha20.seek(&stream_ctx, 1) + chacha20.xor_bytes(&stream_ctx, ciphertext, plaintext) + chacha20.reset(&stream_ctx) // Don't need the stream context anymore. + + // mac_data |= ciphertext | pad16(ciphertext) + poly1305.update(&mac_ctx, ciphertext) + _update_mac_pad16(&mac_ctx, ciphertext_len) + + // mac_data |= num_to_8_le_bytes(aad.length) + // mac_data |= num_to_8_le_bytes(ciphertext.length) + l_buf := otk[0:16] // Reuse the scratch buffer. + util.PUT_U64_LE(l_buf[0:8], u64(aad_len)) + util.PUT_U64_LE(l_buf[8:16], u64(ciphertext_len)) + poly1305.update(&mac_ctx, l_buf) + + // tag = poly1305_mac(mac_data, otk) + poly1305.final(&mac_ctx, tag) // Implicitly sanitizes context. +} + +decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool { + _validate_common_slice_sizes(tag, key, nonce, aad, ciphertext) + if len(ciphertext) != len(plaintext) { + panic("crypto/chacha20poly1305: invalid destination plaintext size") + } + + // Note: Unlike encrypt, this can fail early, so use defer for + // sanitization rather than assuming control flow reaches certain + // points where needed. + + stream_ctx: chacha20.Context = --- + chacha20.init(&stream_ctx, key, nonce) + + // otk = poly1305_key_gen(key, nonce) + otk: [poly1305.KEY_SIZE]byte = --- + chacha20.keystream_bytes(&stream_ctx, otk[:]) + defer chacha20.reset(&stream_ctx) + + mac_ctx: poly1305.Context = --- + poly1305.init(&mac_ctx, otk[:]) + defer mem.zero_explicit(&otk, size_of(otk)) + + aad_len, ciphertext_len := len(aad), len(ciphertext) + + // mac_data = aad | pad16(aad) + // mac_data |= ciphertext | pad16(ciphertext) + // mac_data |= num_to_8_le_bytes(aad.length) + // mac_data |= num_to_8_le_bytes(ciphertext.length) + poly1305.update(&mac_ctx, aad) + _update_mac_pad16(&mac_ctx, aad_len) + poly1305.update(&mac_ctx, ciphertext) + _update_mac_pad16(&mac_ctx, ciphertext_len) + l_buf := otk[0:16] // Reuse the scratch buffer. + util.PUT_U64_LE(l_buf[0:8], u64(aad_len)) + util.PUT_U64_LE(l_buf[8:16], u64(ciphertext_len)) + poly1305.update(&mac_ctx, l_buf) + + // tag = poly1305_mac(mac_data, otk) + derived_tag := otk[0:poly1305.TAG_SIZE] // Reuse the scratch buffer again. + poly1305.final(&mac_ctx, derived_tag) // Implicitly sanitizes context. + + // Validate the tag in constant time. + if crypto.compare_constant_time(tag, derived_tag) != 1 { + // Zero out the plaintext, as a defense in depth measure. + mem.zero_explicit(raw_data(plaintext), ciphertext_len) + return false + } + + // plaintext = chacha20_decrypt(key, 1, nonce, ciphertext) + chacha20.seek(&stream_ctx, 1) + chacha20.xor_bytes(&stream_ctx, plaintext, ciphertext) + + return true +} diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index b73a191ad..731833096 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -118,6 +118,7 @@ main :: proc() { // "modern" crypto tests test_chacha20(&t) test_poly1305(&t) + test_chacha20poly1305(&t) test_x25519(&t) bench_modern(&t) diff --git a/tests/core/crypto/test_core_crypto_modern.odin b/tests/core/crypto/test_core_crypto_modern.odin index 45ec8b339..b3d9e47fd 100644 --- a/tests/core/crypto/test_core_crypto_modern.odin +++ b/tests/core/crypto/test_core_crypto_modern.odin @@ -6,6 +6,7 @@ import "core:mem" import "core:time" import "core:crypto/chacha20" +import "core:crypto/chacha20poly1305" import "core:crypto/poly1305" import "core:crypto/x25519" @@ -30,13 +31,14 @@ _decode_hex32 :: proc(s: string) -> [32]byte{ return b } +_PLAINTEXT_SUNSCREEN_STR := "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." + @(test) test_chacha20 :: proc(t: ^testing.T) { log(t, "Testing (X)ChaCha20") // Test cases taken from RFC 8439, and draft-irtf-cfrg-xchacha-03 - plaintext_str := "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." - plaintext := transmute([]byte)(plaintext_str) + plaintext := transmute([]byte)(_PLAINTEXT_SUNSCREEN_STR) key := [chacha20.KEY_SIZE]byte{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, @@ -182,6 +184,80 @@ test_poly1305 :: proc(t: ^testing.T) { expect(t, derived_tag_str == tag_str, fmt.tprintf("Expected %s for init/update/final - incremental, but got %s instead", tag_str, derived_tag_str)) } +@(test) +test_chacha20poly1305 :: proc(t: ^testing.T) { + log(t, "Testing chacha20poly1205") + + plaintext := transmute([]byte)(_PLAINTEXT_SUNSCREEN_STR) + + aad := [12]byte{ + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, + } + + key := [chacha20poly1305.KEY_SIZE]byte{ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + } + + nonce := [chacha20poly1305.NONCE_SIZE]byte{ + 0x07, 0x00, 0x00, 0x00, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + } + + ciphertext := [114]byte{ + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, + 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, + 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, + 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, + 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, + 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, + 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, + 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16, + } + ciphertext_str := hex_string(ciphertext[:]) + + tag := [chacha20poly1305.TAG_SIZE]byte{ + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, + 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91, + } + tag_str := hex_string(tag[:]) + + derived_tag: [chacha20poly1305.TAG_SIZE]byte + derived_ciphertext: [114]byte + + chacha20poly1305.encrypt(derived_ciphertext[:], derived_tag[:], key[:], nonce[:], aad[:], plaintext) + + derived_ciphertext_str := hex_string(derived_ciphertext[:]) + expect(t, derived_ciphertext_str == ciphertext_str, fmt.tprintf("Expected ciphertext %s for encrypt(aad, plaintext), but got %s instead", ciphertext_str, derived_ciphertext_str)) + + derived_tag_str := hex_string(derived_tag[:]) + expect(t, derived_tag_str == tag_str, fmt.tprintf("Expected tag %s for encrypt(aad, plaintext), but got %s instead", tag_str, derived_tag_str)) + + derived_plaintext: [114]byte + ok := chacha20poly1305.decrypt(derived_plaintext[:], tag[:], key[:], nonce[:], aad[:], ciphertext[:]) + derived_plaintext_str := string(derived_plaintext[:]) + expect(t, ok, "Expected true for decrypt(tag, aad, ciphertext)") + expect(t, derived_plaintext_str == _PLAINTEXT_SUNSCREEN_STR, fmt.tprintf("Expected plaintext %s for decrypt(tag, aad, ciphertext), but got %s instead", _PLAINTEXT_SUNSCREEN_STR, derived_plaintext_str)) + + derived_ciphertext[0] ~= 0xa5 + ok = chacha20poly1305.decrypt(derived_plaintext[:], tag[:], key[:], nonce[:], aad[:], derived_ciphertext[:]) + expect(t, !ok, "Expected false for decrypt(tag, aad, corrupted_ciphertext)") + + aad[0] ~= 0xa5 + ok = chacha20poly1305.decrypt(derived_plaintext[:], tag[:], key[:], nonce[:], aad[:], ciphertext[:]) + expect(t, !ok, "Expected false for decrypt(tag, corrupted_aad, ciphertext)") +} + TestECDH :: struct { scalar: string, point: string, @@ -233,6 +309,7 @@ bench_modern :: proc(t: ^testing.T) { bench_chacha20(t) bench_poly1305(t) + bench_chacha20poly1305(t) bench_x25519(t) } @@ -293,6 +370,29 @@ _benchmark_poly1305 :: proc(options: ^time.Benchmark_Options, allocator := conte return nil } +_benchmark_chacha20poly1305 :: proc(options: ^time.Benchmark_Options, allocator := context.allocator) -> (err: time.Benchmark_Error) { + buf := options.input + key := [chacha20.KEY_SIZE]byte{ + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + nonce := [chacha20.NONCE_SIZE]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + } + + tag: [chacha20poly1305.TAG_SIZE]byte = --- + + for _ in 0..=options.rounds { + chacha20poly1305.encrypt(buf,tag[:], key[:], nonce[:], nil, buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + return nil +} + benchmark_print :: proc(name: string, options: ^time.Benchmark_Options) { fmt.printf("\t[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", name, @@ -352,6 +452,33 @@ bench_poly1305 :: proc(t: ^testing.T) { benchmark_print(name, options) } +bench_chacha20poly1305 :: proc(t: ^testing.T) { + name := "chacha20poly1305 64 bytes" + options := &time.Benchmark_Options{ + rounds = 1_000, + bytes = 64, + setup = _setup_sized_buf, + bench = _benchmark_chacha20poly1305, + teardown = _teardown_sized_buf, + } + + err := time.benchmark(options, context.allocator) + expect(t, err == nil, name) + benchmark_print(name, options) + + name = "chacha20poly1305 1024 bytes" + options.bytes = 1024 + err = time.benchmark(options, context.allocator) + expect(t, err == nil, name) + benchmark_print(name, options) + + name = "chacha20poly1305 65536 bytes" + options.bytes = 65536 + err = time.benchmark(options, context.allocator) + expect(t, err == nil, name) + benchmark_print(name, options) +} + bench_x25519 :: proc(t: ^testing.T) { point := _decode_hex32("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") scalar := _decode_hex32("cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe") From 61c581baeb94ac73cbb25e93af2710d12e15f25c Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 12 Nov 2021 06:22:17 +0000 Subject: [PATCH 0030/1258] core/sys/unix: Add syscalls_linux.odin Linux is in the unfortunate situation where the system call number is architecture specific. This consolidates the system call number definitions in a single location, adds some wrappers, and hopefully fixes the existing non-portable invocations of the syscall intrinsic. --- core/mem/virtual/virtual_linux.odin | 76 ++++++++++++--------------- core/os/os_linux.odin | 5 +- core/sync/sync2/futex_linux.odin | 3 +- core/sync/sync2/primitives_linux.odin | 5 +- core/sync/sync_linux.odin | 4 +- core/sys/unix/syscalls_linux.odin | 60 +++++++++++++++++++++ 6 files changed, 101 insertions(+), 52 deletions(-) create mode 100644 core/sys/unix/syscalls_linux.odin diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin index c4dd564ee..71a56e499 100644 --- a/core/mem/virtual/virtual_linux.odin +++ b/core/mem/virtual/virtual_linux.odin @@ -4,64 +4,56 @@ package mem_virtual import "core:c" import "core:intrinsics" +import "core:sys/unix" -when ODIN_ARCH == "amd64" { - SYS_mmap :: 9 - SYS_mprotect :: 10 - SYS_munmap :: 11 - SYS_madvise :: 28 - - PROT_NONE :: 0x0 - PROT_READ :: 0x1 - PROT_WRITE :: 0x2 - PROT_EXEC :: 0x4 - PROT_GROWSDOWN :: 0x01000000 - PROT_GROWSUP :: 0x02000000 +PROT_NONE :: 0x0 +PROT_READ :: 0x1 +PROT_WRITE :: 0x2 +PROT_EXEC :: 0x4 +PROT_GROWSDOWN :: 0x01000000 +PROT_GROWSUP :: 0x02000000 - MAP_FIXED :: 0x1 - MAP_PRIVATE :: 0x2 - MAP_SHARED :: 0x4 - MAP_ANONYMOUS :: 0x20 - - MADV_NORMAL :: 0 - MADV_RANDOM :: 1 - MADV_SEQUENTIAL :: 2 - MADV_WILLNEED :: 3 - MADV_DONTNEED :: 4 - MADV_FREE :: 8 - MADV_REMOVE :: 9 - MADV_DONTFORK :: 10 - MADV_DOFORK :: 11 - MADV_MERGEABLE :: 12 - MADV_UNMERGEABLE :: 13 - MADV_HUGEPAGE :: 14 - MADV_NOHUGEPAGE :: 15 - MADV_DONTDUMP :: 16 - MADV_DODUMP :: 17 - MADV_WIPEONFORK :: 18 - MADV_KEEPONFORK :: 19 - MADV_HWPOISON :: 100 -} else { - #panic("Unsupported architecture") -} +MAP_FIXED :: 0x1 +MAP_PRIVATE :: 0x2 +MAP_SHARED :: 0x4 +MAP_ANONYMOUS :: 0x20 + +MADV_NORMAL :: 0 +MADV_RANDOM :: 1 +MADV_SEQUENTIAL :: 2 +MADV_WILLNEED :: 3 +MADV_DONTNEED :: 4 +MADV_FREE :: 8 +MADV_REMOVE :: 9 +MADV_DONTFORK :: 10 +MADV_DOFORK :: 11 +MADV_MERGEABLE :: 12 +MADV_UNMERGEABLE :: 13 +MADV_HUGEPAGE :: 14 +MADV_NOHUGEPAGE :: 15 +MADV_DONTDUMP :: 16 +MADV_DODUMP :: 17 +MADV_WIPEONFORK :: 18 +MADV_KEEPONFORK :: 19 +MADV_HWPOISON :: 100 mmap :: proc "contextless" (addr: rawptr, length: uint, prot: c.int, flags: c.int, fd: c.int, offset: uintptr) -> rawptr { - res := intrinsics.syscall(SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset) + res := intrinsics.syscall(unix.SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset) return rawptr(res) } munmap :: proc "contextless" (addr: rawptr, length: uint) -> c.int { - res := intrinsics.syscall(SYS_munmap, uintptr(addr), uintptr(length)) + res := intrinsics.syscall(unix.SYS_munmap, uintptr(addr), uintptr(length)) return c.int(res) } mprotect :: proc "contextless" (addr: rawptr, length: uint, prot: c.int) -> c.int { - res := intrinsics.syscall(SYS_mprotect, uintptr(addr), uintptr(length), uint(prot)) + res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uint(prot)) return c.int(res) } madvise :: proc "contextless" (addr: rawptr, length: uint, advice: c.int) -> c.int { - res := intrinsics.syscall(SYS_madvise, uintptr(addr), uintptr(length), uintptr(advice)) + res := intrinsics.syscall(unix.SYS_madvise, uintptr(addr), uintptr(length), uintptr(advice)) return c.int(res) } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index bc4717b44..260a051ce 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -8,6 +8,7 @@ import "core:strings" import "core:c" import "core:strconv" import "core:intrinsics" +import "core:sys/unix" Handle :: distinct i32 File_Time :: distinct u64 @@ -265,8 +266,6 @@ X_OK :: 1 // Test for execute permission W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission -SYS_GETTID :: 186 - foreign libc { @(link_name="__errno_location") __errno_location :: proc() -> ^int --- @@ -594,7 +593,7 @@ exit :: proc "contextless" (code: int) -> ! { } current_thread_id :: proc "contextless" () -> int { - return cast(int)intrinsics.syscall(SYS_GETTID) + return unix.sys_gettid() } dlopen :: proc(filename: string, flags: int) -> rawptr { diff --git a/core/sync/sync2/futex_linux.odin b/core/sync/sync2/futex_linux.odin index 1bd41c7cf..fca28cace 100644 --- a/core/sync/sync2/futex_linux.odin +++ b/core/sync/sync2/futex_linux.odin @@ -5,6 +5,7 @@ package sync2 import "core:c" import "core:time" import "core:intrinsics" +import "core:sys/unix" FUTEX_WAIT :: 0 FUTEX_WAKE :: 1 @@ -34,7 +35,7 @@ get_errno :: proc(r: int) -> int { } internal_futex :: proc(f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int { - code := int(intrinsics.syscall(202, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0)) + code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0)) return get_errno(code) } diff --git a/core/sync/sync2/primitives_linux.odin b/core/sync/sync2/primitives_linux.odin index 4c81295bd..89ed97985 100644 --- a/core/sync/sync2/primitives_linux.odin +++ b/core/sync/sync2/primitives_linux.odin @@ -2,9 +2,8 @@ //+private package sync2 -import "core:intrinsics" +import "core:sys/unix" _current_thread_id :: proc "contextless" () -> int { - SYS_GETTID :: 186 - return int(intrinsics.syscall(SYS_GETTID)) + return unix.sys_gettid() } diff --git a/core/sync/sync_linux.odin b/core/sync/sync_linux.odin index fe856df94..340437c11 100644 --- a/core/sync/sync_linux.odin +++ b/core/sync/sync_linux.odin @@ -1,11 +1,9 @@ package sync import "core:sys/unix" -import "core:intrinsics" current_thread_id :: proc "contextless" () -> int { - SYS_GETTID :: 186 - return int(intrinsics.syscall(SYS_GETTID)) + return unix.sys_gettid() } diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin new file mode 100644 index 000000000..659eedfbb --- /dev/null +++ b/core/sys/unix/syscalls_linux.odin @@ -0,0 +1,60 @@ +package unix + +import "core:intrinsics" + +// Linux has inconsistent system call numbering across architectures, +// for largely historical reasons. This attempts to provide a unified +// Odin-side interface for system calls that are required for the core +// library to work. + +// For authorative system call numbers, the following files in the kernel +// source can be used: +// +// amd64: arch/x86/entry/syscalls/syscall_64.tbl +// arm64: include/uapi/asm-generic/unistd.h +// 386: arch/x86/entry/syscalls/sycall_32.tbl +// arm: arch/arm/tools/syscall.tbl + +when ODIN_ARCH == "amd64" { + SYS_mmap : uintptr : 9 + SYS_mprotect : uintptr : 10 + SYS_munmap : uintptr : 11 + SYS_madvise : uintptr : 28 + SYS_futex : uintptr : 202 + SYS_gettid : uintptr : 186 + SYS_getrandom : uintptr : 318 +} else when ODIN_ARCH == "arm64" { + SYS_mmap : uintptr : 222 + SYS_mprotect : uintptr : 226 + SYS_munmap : uintptr : 215 + SYS_madvise : uintptr : 233 + SYS_futex : uintptr : 98 + SYS_gettid : uintptr : 178 + SYS_getrandom : uintptr : 278 +} else when ODIN_ARCH == "386" { + SYS_mmap : uintptr : 192 // 90 is "sys_old_mmap", we want mmap2 + SYS_mprotect : uintptr : 125 + SYS_munmap : uintptr : 91 + SYS_madvise : uintptr : 219 + SYS_futex : uintptr : 240 + SYS_gettid : uintptr : 224 + SYS_getrandom : uintptr : 355 +} else when ODIN_ARCH == "arm" { + SYS_mmap : uintptr : 192 // 90 is "sys_old_mmap", we want mmap2 + SYS_mprotect : uintptr : 125 + SYS_munmap: uintptr : 91 + SYS_madvise: uintptr : 220 + SYS_futex : uintptr : 240 + SYS_gettid : uintptr: 224 + SYS_getrandom : uintptr : 384 +} else { + #panic("Unsupported architecture") +} + +sys_gettid :: proc "contextless" () -> int { + return cast(int)intrinsics.syscall(SYS_gettid) +} + +sys_getrandom :: proc "contextless" (buf: ^byte, buflen: int, flags: uint) -> int { + return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags)) +} From 6bafa21bee56ccfbdf74f88bf7937a900a7d22d9 Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 11 Nov 2021 07:59:45 +0000 Subject: [PATCH 0031/1258] crypto: Add rand_bytes This adds `rand_bytes(dst: []byte)` which fills the destination buffer with entropy from the cryptographic random number generator. This takes the "simple is best" approach and just directly returns the OS CSPRNG output instead of doing anything fancy (a la OpenBSD's arc4random). --- core/crypto/crypto.odin | 11 +++++ core/crypto/rand_generic.odin | 7 ++++ core/crypto/rand_linux.odin | 37 +++++++++++++++++ tests/core/crypto/test_core_crypto.odin | 1 + .../core/crypto/test_core_crypto_modern.odin | 40 +++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 core/crypto/rand_generic.odin create mode 100644 core/crypto/rand_linux.odin diff --git a/core/crypto/crypto.odin b/core/crypto/crypto.odin index ddcc5d367..35e88c5ed 100644 --- a/core/crypto/crypto.odin +++ b/core/crypto/crypto.odin @@ -39,3 +39,14 @@ compare_byte_ptrs_constant_time :: proc "contextless" (a, b: ^byte, n: int) -> i // iff v == 0, setting the sign-bit, which gets returned. return int((u32(v)-1) >> 31) } + +// rand_bytes fills the dst buffer with cryptographic entropy taken from +// the system entropy source. This routine will block if the system entropy +// source is not ready yet. All system entropy source failures are treated +// as catastrophic, resulting in a panic. +rand_bytes :: proc (dst: []byte) { + // zero-fill the buffer first + mem.zero_explicit(raw_data(dst), len(dst)) + + _rand_bytes(dst) +} diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin new file mode 100644 index 000000000..98890b5b1 --- /dev/null +++ b/core/crypto/rand_generic.odin @@ -0,0 +1,7 @@ +package crypto + +when ODIN_OS != "linux" { + _rand_bytes :: proc (dst: []byte) { + unimplemented("crypto: rand_bytes not supported on this OS") + } +} diff --git a/core/crypto/rand_linux.odin b/core/crypto/rand_linux.odin new file mode 100644 index 000000000..4d1183757 --- /dev/null +++ b/core/crypto/rand_linux.odin @@ -0,0 +1,37 @@ +package crypto + +import "core:fmt" +import "core:os" +import "core:sys/unix" + +_MAX_PER_CALL_BYTES :: 33554431 // 2^25 - 1 + +_rand_bytes :: proc (dst: []byte) { + dst := dst + l := len(dst) + + for l > 0 { + to_read := min(l, _MAX_PER_CALL_BYTES) + ret := unix.sys_getrandom(raw_data(dst), to_read, 0) + if ret < 0 { + switch os.Errno(-ret) { + case os.EINTR: + // Call interupted by a signal handler, just retry the + // request. + continue + case os.ENOSYS: + // The kernel is apparently prehistoric (< 3.17 circa 2014) + // and does not support getrandom. + panic("crypto: getrandom not available in kernel") + case: + // All other failures are things that should NEVER happen + // unless the kernel interface changes (ie: the Linux + // developers break userland). + panic(fmt.tprintf("crypto: getrandom failed: %d", ret)) + } + } + + l -= ret + dst = dst[ret:] + } +} diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 731833096..2ad00be66 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -120,6 +120,7 @@ main :: proc() { test_poly1305(&t) test_chacha20poly1305(&t) test_x25519(&t) + test_rand_bytes(&t) bench_modern(&t) diff --git a/tests/core/crypto/test_core_crypto_modern.odin b/tests/core/crypto/test_core_crypto_modern.odin index b3d9e47fd..71adad137 100644 --- a/tests/core/crypto/test_core_crypto_modern.odin +++ b/tests/core/crypto/test_core_crypto_modern.odin @@ -4,6 +4,7 @@ import "core:testing" import "core:fmt" import "core:mem" import "core:time" +import "core:crypto" import "core:crypto/chacha20" import "core:crypto/chacha20poly1305" @@ -303,6 +304,45 @@ test_x25519 :: proc(t: ^testing.T) { // how to work with JSON. } +@(test) +test_rand_bytes :: proc(t: ^testing.T) { + log(t, "Testing rand_bytes") + + if ODIN_OS != "linux" { + log(t, "rand_bytes not supported - skipping") + return + } + + allocator := context.allocator + + buf := make([]byte, 1 << 25, allocator) + defer delete(buf) + + // Testing a CSPRNG for correctness is incredibly involved and + // beyond the scope of an implementation that offloads + // responsibility for correctness to the OS. + // + // Just attempt to randomize a sufficiently large buffer, where + // sufficiently large is: + // * Larger than the maximum getentropy request size (256 bytes). + // * Larger than the maximum getrandom request size (2^25 - 1 bytes). + // + // While theoretically non-deterministic, if this fails, chances + // are the CSPRNG is busted. + seems_ok := false + for i := 0; i < 256; i = i + 1 { + mem.zero_explicit(raw_data(buf), len(buf)) + crypto.rand_bytes(buf) + + if buf[0] != 0 && buf[len(buf)-1] != 0 { + seems_ok = true + break + } + } + + expect(t, seems_ok, "Expected to randomize the head and tail of the buffer within a handful of attempts") +} + @(test) bench_modern :: proc(t: ^testing.T) { fmt.println("Starting benchmarks:") From ae59f214ee6a47d3eb3832674928e7d66f9ac2e5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 17 Nov 2021 21:32:33 +0000 Subject: [PATCH 0032/1258] `@(tag=)` - dummy attribute for tooling --- src/checker.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index fa74c23ed..c0a15905b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2603,11 +2603,18 @@ ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) { return ev; } +#define ATTRIBUTE_USER_TAG_NAME "tag" + DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); - if (name == "default_calling_convention") { + if (name == ATTRIBUTE_USER_TAG_NAME) { + if (ev.kind != ExactValue_String) { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "default_calling_convention") { if (ev.kind == ExactValue_String) { auto cc = string_to_calling_convention(ev.value_string); if (cc == ProcCC_Invalid) { @@ -2655,7 +2662,13 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { } DECL_ATTRIBUTE_PROC(proc_decl_attribute) { - if (name == "test") { + if (name == ATTRIBUTE_USER_TAG_NAME) { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind != ExactValue_String) { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "test") { if (value != nullptr) { error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); } @@ -2896,7 +2909,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { DECL_ATTRIBUTE_PROC(var_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); - if (name == "static") { + if (name == ATTRIBUTE_USER_TAG_NAME) { + if (ev.kind != ExactValue_String) { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "static") { if (value != nullptr) { error(elem, "'static' does not have any parameters"); } @@ -3011,7 +3029,13 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) { } DECL_ATTRIBUTE_PROC(const_decl_attribute) { - if (name == "private") { + if (name == ATTRIBUTE_USER_TAG_NAME) { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind != ExactValue_String) { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "private") { // NOTE(bill): Handled elsewhere `check_collect_value_decl` return true; } @@ -3019,7 +3043,13 @@ DECL_ATTRIBUTE_PROC(const_decl_attribute) { } DECL_ATTRIBUTE_PROC(type_decl_attribute) { - if (name == "private") { + if (name == ATTRIBUTE_USER_TAG_NAME) { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind != ExactValue_String) { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "private") { // NOTE(bill): Handled elsewhere `check_collect_value_decl` return true; } @@ -4020,7 +4050,13 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { } DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { - if (name == "force" || name == "require") { + if (name == ATTRIBUTE_USER_TAG_NAME) { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind != ExactValue_String) { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; + } else if (name == "force" || name == "require") { if (value != nullptr) { error(elem, "Expected no parameter for '%.*s'", LIT(name)); } else if (name == "force") { From 61bc963e92964af4d92a0e8a8d1ff5e2520836c3 Mon Sep 17 00:00:00 2001 From: Patric Dexheimer Date: Wed, 17 Nov 2021 19:03:01 -0300 Subject: [PATCH 0033/1258] GetMouseDelta --- vendor/raylib/raylib.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 0c4dc6365..fb4d7dd92 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -1077,6 +1077,7 @@ foreign lib { GetMouseX :: proc() -> c.int --- // Returns mouse position X GetMouseY :: proc() -> c.int --- // Returns mouse position Y GetMousePosition :: proc() -> Vector2 --- // Returns mouse position XY + GetMouseDelta :: proc() -> Vector2 --- // Returns mouse delta XY SetMousePosition :: proc(x, y: c.int) --- // Set mouse position XY SetMouseOffset :: proc(offsetX, offsetY: c.int) --- // Set mouse offset SetMouseScale :: proc(scaleX, scaleY: f32) --- // Set mouse scaling @@ -1568,4 +1569,4 @@ MemAllocatorProc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, return nil, .Mode_Not_Implemented } return nil, .Mode_Not_Implemented -} \ No newline at end of file +} From 12c1291805ce2aecc2f730c3db335e99181c7290 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 18 Nov 2021 16:14:33 +0000 Subject: [PATCH 0034/1258] Add optional seed parameters to all hashes --- core/hash/hash.odin | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/core/hash/hash.odin b/core/hash/hash.odin index 64c7ad5c4..f0d01bd25 100644 --- a/core/hash/hash.odin +++ b/core/hash/hash.odin @@ -47,8 +47,8 @@ adler32 :: proc(data: []byte, seed := u32(1)) -> u32 #no_bounds_check { } @(optimization_mode="speed") -djb2 :: proc(data: []byte) -> u32 { - hash: u32 = 5381 +djb2 :: proc(data: []byte, seed := u32(5381)) -> u32 { + hash: u32 = seed for b in data { hash = (hash << 5) + hash + u32(b) // hash * 33 + u32(b) } @@ -56,8 +56,8 @@ djb2 :: proc(data: []byte) -> u32 { } @(optimization_mode="speed") -fnv32 :: proc(data: []byte) -> u32 { - h: u32 = 0x811c9dc5 +fnv32 :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 { + h: u32 = seed for b in data { h = (h * 0x01000193) ~ u32(b) } @@ -65,8 +65,8 @@ fnv32 :: proc(data: []byte) -> u32 { } @(optimization_mode="speed") -fnv64 :: proc(data: []byte) -> u64 { - h: u64 = 0xcbf29ce484222325 +fnv64 :: proc(data: []byte, seed := u64(0xcbf29ce484222325)) -> u64 { + h: u64 = seed for b in data { h = (h * 0x100000001b3) ~ u64(b) } @@ -74,8 +74,8 @@ fnv64 :: proc(data: []byte) -> u64 { } @(optimization_mode="speed") -fnv32a :: proc(data: []byte) -> u32 { - h: u32 = 0x811c9dc5 +fnv32a :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 { + h: u32 = seed for b in data { h = (h ~ u32(b)) * 0x01000193 } @@ -83,8 +83,8 @@ fnv32a :: proc(data: []byte) -> u32 { } @(optimization_mode="speed") -fnv64a :: proc(data: []byte) -> u64 { - h: u64 = 0xcbf29ce484222325 +fnv64a :: proc(data: []byte, seed := u64(0xcbf29ce484222325)) -> u64 { + h: u64 = seed for b in data { h = (h ~ u64(b)) * 0x100000001b3 } @@ -92,8 +92,8 @@ fnv64a :: proc(data: []byte) -> u64 { } @(optimization_mode="speed") -jenkins :: proc(data: []byte) -> u32 { - hash: u32 = 0 +jenkins :: proc(data: []byte, seed := u32(0)) -> u32 { + hash: u32 = seed for b in data { hash += u32(b) hash += hash << 10 @@ -106,11 +106,11 @@ jenkins :: proc(data: []byte) -> u32 { } @(optimization_mode="speed") -murmur32 :: proc(data: []byte) -> u32 { +murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 { c1_32: u32 : 0xcc9e2d51 c2_32: u32 : 0x1b873593 - h1: u32 = 0 + h1: u32 = seed nblocks := len(data)/4 p := raw_data(data) p1 := mem.ptr_offset(p, 4*nblocks) @@ -156,14 +156,12 @@ murmur32 :: proc(data: []byte) -> u32 { } @(optimization_mode="speed") -murmur64 :: proc(data: []byte) -> u64 { - SEED :: 0x9747b28c - +murmur64 :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 { when size_of(int) == 8 { m :: 0xc6a4a7935bd1e995 r :: 47 - h: u64 = SEED ~ (u64(len(data)) * m) + h: u64 = seed ~ (u64(len(data)) * m) data64 := mem.slice_ptr(cast(^u64)raw_data(data), len(data)/size_of(u64)) for _, i in data64 { @@ -198,8 +196,8 @@ murmur64 :: proc(data: []byte) -> u64 { m :: 0x5bd1e995 r :: 24 - h1 := u32(SEED) ~ u32(len(data)) - h2 := u32(SEED) >> 32 + h1 := u32(seed) ~ u32(len(data)) + h2 := u32(seed) >> 32 data32 := mem.slice_ptr(cast(^u32)raw_data(data), len(data)/size_of(u32)) len := len(data) i := 0 @@ -262,8 +260,8 @@ murmur64 :: proc(data: []byte) -> u64 { } @(optimization_mode="speed") -sdbm :: proc(data: []byte) -> u32 { - hash: u32 = 0 +sdbm :: proc(data: []byte, seed := u32(0)) -> u32 { + hash: u32 = seed for b in data { hash = u32(b) + (hash<<6) + (hash<<16) - hash } From 4439d59105daa74ab04433572e24891630ac0216 Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Fri, 19 Nov 2021 00:24:56 +0100 Subject: [PATCH 0035/1258] add builtin. --- core/slice/slice.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 1dd777ccc..487dd46c2 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -20,7 +20,7 @@ swap :: proc(array: $T/[]$E, a, b: int) { } swap_between :: proc(a, b: $T/[]$E) { - n := min(len(a), len(b)) + n := builtin.min(len(a), len(b)) if n >= 0 { ptr_swap_overlapping(&a[0], &b[0], size_of(E)*n) } From 3e04b451062d4e46bd26baad82d7c75ce5e9e1d9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 19 Nov 2021 12:26:10 +0000 Subject: [PATCH 0036/1258] Allow cast from float to complex --- src/check_expr.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 96ca2d308..3c884d117 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2453,6 +2453,9 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { return true; } + if (is_type_float(src) && is_type_complex(dst)) { + return true; + } if (is_type_float(src) && is_type_quaternion(dst)) { return true; } From daebaa8b5027731680037a12ad3e63936dc5aef2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 19 Nov 2021 15:43:13 +0000 Subject: [PATCH 0037/1258] Fix #1319 --- src/llvm_backend_expr.cpp | 2 -- src/llvm_backend_general.cpp | 11 ++++++++--- src/llvm_backend_stmt.cpp | 9 ++++++++- src/types.cpp | 8 +++++++- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index a23d60894..5187279fa 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1841,7 +1841,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return res; } - #if 1 if (is_type_union(dst)) { for_array(i, dst->Union.variants) { Type *vt = dst->Union.variants[i]; @@ -1852,7 +1851,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } } } - #endif // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's // subtype polymorphism casting diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b671f0c8f..17eeb0bea 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1142,7 +1142,7 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value)); unsigned element_count = LLVMCountStructElementTypes(uvt); - GB_ASSERT_MSG(element_count == 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); + GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); lbValue tag_ptr = {}; tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 1, ""); @@ -1795,7 +1795,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { unsigned block_size = cast(unsigned)type->Union.variant_block_size; - auto fields = array_make(temporary_allocator(), 0, 2); + auto fields = array_make(temporary_allocator(), 0, 3); if (is_type_union_maybe_pointer(type)) { LLVMTypeRef variant = lb_type(m, type->Union.variants[0]); array_add(&fields, variant); @@ -1804,7 +1804,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { LLVMTypeRef tag_type = lb_type(m, union_tag_type(type)); array_add(&fields, block_type); array_add(&fields, tag_type); - + i64 used_size = lb_sizeof(block_type) + lb_sizeof(tag_type); + i64 padding = size - used_size; + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align); + array_add(&fields, padding_type); + } } return LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, false); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index c2ff0dfe1..016e464b8 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1485,7 +1485,14 @@ void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) { if (return_by_pointer) { if (res.value != nullptr) { - LLVMBuildStore(p->builder, res.value, p->return_ptr.addr.value); + LLVMValueRef res_val = res.value; + i64 sz = type_size_of(res.type); + if (LLVMIsALoadInst(res_val) && sz > build_context.word_size) { + lbValue ptr = lb_address_from_load_or_generate_local(p, res); + lb_mem_copy_non_overlapping(p, p->return_ptr.addr, ptr, lb_const_int(p->module, t_int, sz)); + } else { + LLVMBuildStore(p->builder, res_val, p->return_ptr.addr.value); + } } else { LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value); } diff --git a/src/types.cpp b/src/types.cpp index e609815c6..c8bdbd72a 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4019,7 +4019,13 @@ gbString write_type_to_string(gbString str, Type *type) { case Type_BitSet: str = gb_string_appendc(str, "bit_set["); - str = write_type_to_string(str, type->BitSet.elem); + if (is_type_enum(type->BitSet.elem)) { + str = write_type_to_string(str, type->BitSet.elem); + } else { + str = gb_string_append_fmt(str, "%lld", type->BitSet.lower); + str = gb_string_append_fmt(str, "..="); + str = gb_string_append_fmt(str, "%lld", type->BitSet.upper); + } if (type->BitSet.underlying != nullptr) { str = gb_string_appendc(str, "; "); str = write_type_to_string(str, type->BitSet.underlying); From 2c7bf87998ff41191697f7fce2509c5a76b721f6 Mon Sep 17 00:00:00 2001 From: Gus <43172308+Gaunsessa@users.noreply.github.com> Date: Sat, 20 Nov 2021 20:02:21 +1100 Subject: [PATCH 0038/1258] Added darwin support --- vendor/glfw/bindings/bindings.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index 06b5f5b32..84905f603 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -4,6 +4,7 @@ import "core:c" import vk "vendor:vulkan" when ODIN_OS == "linux" { foreign import glfw "system:glfw" } // TODO: Add the billion-or-so static libs to link to in linux +when ODIN_OS == "darwin" { foreign import glfw "system:glfw" } when ODIN_OS == "windows" { foreign import glfw { "../lib/glfw3_mt.lib", From 56d2bbc5b9509ecb10c8e700afc5cb14a5e23d8b Mon Sep 17 00:00:00 2001 From: Gus <43172308+Gaunsessa@users.noreply.github.com> Date: Sat, 20 Nov 2021 20:03:54 +1100 Subject: [PATCH 0039/1258] Added back ln for js --- core/math/math_basic_js.odin | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/math/math_basic_js.odin b/core/math/math_basic_js.odin index 06c8b636d..ec572f898 100644 --- a/core/math/math_basic_js.odin +++ b/core/math/math_basic_js.odin @@ -39,4 +39,16 @@ cos_f32 :: proc "c" (θ: f32) -> f32 { return f32(cos_f64(f64(θ pow_f32 :: proc "c" (x, power: f32) -> f32 { return f32(pow_f64(f64(x), f64(power))) } fmuladd_f32 :: proc "c" (a, b, c: f32) -> f32 { return f32(fmuladd_f64(f64(a), f64(a), f64(c))) } ln_f32 :: proc "c" (x: f32) -> f32 { return f32(ln_f64(f64(x))) } -exp_f32 :: proc "c" (x: f32) -> f32 { return f32(exp_f64(f64(x))) } \ No newline at end of file +exp_f32 :: proc "c" (x: f32) -> f32 { return f32(exp_f64(f64(x))) } + +ln_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(ln_f64(f64(x))) } +ln_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(ln_f64(f64(x))) } +ln_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(ln_f64(f64(x))) } +ln_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(ln_f64(f64(x))) } +ln_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(ln_f64(f64(x))) } +ln_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(ln_f64(f64(x))) } +ln :: proc{ + ln_f16, ln_f16le, ln_f16be, + ln_f32, ln_f32le, ln_f32be, + ln_f64, ln_f64le, ln_f64be, +} From 446f1f6183498516028bee7e78903e1f659f3036 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 20 Nov 2021 19:27:34 +0000 Subject: [PATCH 0040/1258] Correct foreign imports for portmidi on Windows --- vendor/portmidi/portmidi.odin | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/vendor/portmidi/portmidi.odin b/vendor/portmidi/portmidi.odin index 05b33aeff..0bf3b4a42 100644 --- a/vendor/portmidi/portmidi.odin +++ b/vendor/portmidi/portmidi.odin @@ -3,7 +3,13 @@ package portmidi import "core:c" import "core:strings" -when ODIN_OS == "windows" { foreign import lib "portmidi.lib" } +when ODIN_OS == "windows" { + foreign import lib { + "portmidi_s.lib", + "system:Winmm.lib", + "system:Advapi32.lib", + } +} #assert(size_of(b32) == size_of(c.int)) @@ -140,7 +146,7 @@ foreign lib { not be manipulated or freed. The pointer is guaranteed to be valid between calls to Initialize() and Terminate(). */ - GetDeviceInfo :: proc(id: DeviceID) -> DeviceInfo --- + GetDeviceInfo :: proc(id: DeviceID) -> ^DeviceInfo --- /** OpenInput() and OpenOutput() open devices. From ca6951d05e845f6e141a3436307d362a490c7a01 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 20 Nov 2021 20:20:12 +0000 Subject: [PATCH 0041/1258] Add `MessageDecompose`; Update the static library --- vendor/portmidi/portmidi.odin | 296 +++++++++++++++++---------------- vendor/portmidi/portmidi_s.lib | Bin 177524 -> 76430 bytes 2 files changed, 152 insertions(+), 144 deletions(-) diff --git a/vendor/portmidi/portmidi.odin b/vendor/portmidi/portmidi.odin index 0bf3b4a42..08f78150c 100644 --- a/vendor/portmidi/portmidi.odin +++ b/vendor/portmidi/portmidi.odin @@ -21,17 +21,17 @@ Error :: enum c.int { GotData = 1, /**< A "no error" return that also indicates data available */ HostError = -10000, InvalidDeviceId, /** out of range or - * output device when input is requested or - * input device when output is requested or - * device is already opened - */ + * output device when input is requested or + * input device when output is requested or + * device is already opened + */ InsufficientMemory, BufferTooSmall, BufferOverflow, BadPtr, /* Stream parameter is nil or - * stream is not opened or - * stream is output when input is required or - * stream is input when output is required */ + * stream is not opened or + * stream is output when input is required or + * stream is input when output is required */ BadData, /** illegal midi data, e.g. missing EOX */ InternalError, BufferMaxSize, /** buffer is already as large as it can be */ @@ -44,30 +44,30 @@ Stream :: distinct rawptr @(default_calling_convention="c", link_prefix="Pm_") foreign lib { /** - Initialize() is the library initialisation function - call this before - using the library. + Initialize() is the library initialisation function - call this before + using the library. */ Initialize :: proc() -> Error --- /** - Terminate() is the library termination function - call this after - using the library. + Terminate() is the library termination function - call this after + using the library. */ Terminate :: proc() -> Error --- /** - Test whether stream has a pending host error. Normally, the client finds - out about errors through returned error codes, but some errors can occur - asynchronously where the client does not - explicitly call a function, and therefore cannot receive an error code. - The client can test for a pending error using HasHostError(). If true, - the error can be accessed and cleared by calling GetErrorText(). - Errors are also cleared by calling other functions that can return - errors, e.g. OpenInput(), OpenOutput(), Read(), Write(). The - client does not need to call HasHostError(). Any pending error will be - reported the next time the client performs an explicit function call on - the stream, e.g. an input or output operation. Until the error is cleared, - no new error codes will be obtained, even for a different stream. + Test whether stream has a pending host error. Normally, the client finds + out about errors through returned error codes, but some errors can occur + asynchronously where the client does not + explicitly call a function, and therefore cannot receive an error code. + The client can test for a pending error using HasHostError(). If true, + the error can be accessed and cleared by calling GetErrorText(). + Errors are also cleared by calling other functions that can return + errors, e.g. OpenInput(), OpenOutput(), Read(), Write(). The + client does not need to call HasHostError(). Any pending error will be + reported the next time the client performs an explicit function call on + the stream, e.g. an input or output operation. Until the error is cleared, + no new error codes will be obtained, even for a different stream. */ HasHostError :: proc(stream: Stream) -> b32 --- } @@ -109,8 +109,8 @@ DeviceInfo :: struct { structVersion: c.int, /**< this internal structure version */ interf: cstring, /**< underlying MIDI API, e.g. MMSystem or DirectX */ name: cstring, /**< device name, e.g. USB MidiSport 1x1 */ - input: c.int, /**< true iff input is available */ - output: c.int, /**< true iff output is available */ + input: b32, /**< true iff input is available */ + output: b32, /**< true iff output is available */ opened: b32, /**< used by generic PortMidi code to do error checking on arguments */ } @@ -138,79 +138,78 @@ Before :: #force_inline proc "c" (t1, t2: Timestamp) -> b32 { @(default_calling_convention="c", link_prefix="Pm_") foreign lib { /** - GetDeviceInfo() returns a pointer to a DeviceInfo structure - referring to the device specified by id. - If id is out of range the function returns nil. + GetDeviceInfo() returns a pointer to a DeviceInfo structure + referring to the device specified by id. + If id is out of range the function returns nil. - The returned structure is owned by the PortMidi implementation and must - not be manipulated or freed. The pointer is guaranteed to be valid - between calls to Initialize() and Terminate(). + The returned structure is owned by the PortMidi implementation and must + not be manipulated or freed. The pointer is guaranteed to be valid + between calls to Initialize() and Terminate(). */ GetDeviceInfo :: proc(id: DeviceID) -> ^DeviceInfo --- /** - OpenInput() and OpenOutput() open devices. + OpenInput() and OpenOutput() open devices. - stream is the address of a Stream pointer which will receive - a pointer to the newly opened stream. + stream is the address of a Stream pointer which will receive + a pointer to the newly opened stream. - inputDevice is the id of the device used for input (see DeviceID above). + inputDevice is the id of the device used for input (see DeviceID above). - inputDriverInfo is a pointer to an optional driver specific data structure - containing additional information for device setup or handle processing. - inputDriverInfo is never required for correct operation. If not used - inputDriverInfo should be nil. + inputDriverInfo is a pointer to an optional driver specific data structure + containing additional information for device setup or handle processing. + inputDriverInfo is never required for correct operation. If not used + inputDriverInfo should be nil. - outputDevice is the id of the device used for output (see DeviceID above.) + outputDevice is the id of the device used for output (see DeviceID above.) - outputDriverInfo is a pointer to an optional driver specific data structure - containing additional information for device setup or handle processing. - outputDriverInfo is never required for correct operation. If not used - outputDriverInfo should be nil. + outputDriverInfo is a pointer to an optional driver specific data structure + containing additional information for device setup or handle processing. + outputDriverInfo is never required for correct operation. If not used + outputDriverInfo should be nil. - For input, the buffersize specifies the number of input events to be - buffered waiting to be read using Read(). For output, buffersize - specifies the number of output events to be buffered waiting for output. - (In some cases -- see below -- PortMidi does not buffer output at all - and merely passes data to a lower-level API, in which case buffersize - is ignored.) - - latency is the delay in milliseconds applied to timestamps to determine - when the output should actually occur. (If latency is < 0, 0 is assumed.) - If latency is zero, timestamps are ignored and all output is delivered - immediately. If latency is greater than zero, output is delayed until the - message timestamp plus the latency. (NOTE: the time is measured relative - to the time source indicated by time_proc. Timestamps are absolute, - not relative delays or offsets.) In some cases, PortMidi can obtain - better timing than your application by passing timestamps along to the - device driver or hardware. Latency may also help you to synchronize midi - data to audio data by matching midi latency to the audio buffer latency. + For input, the buffersize specifies the number of input events to be + buffered waiting to be read using Read(). For output, buffersize + specifies the number of output events to be buffered waiting for output. + (In some cases -- see below -- PortMidi does not buffer output at all + and merely passes data to a lower-level API, in which case buffersize + is ignored.) - time_proc is a pointer to a procedure that returns time in milliseconds. It - may be nil, in which case a default millisecond timebase (PortTime) is - used. If the application wants to use PortTime, it should start the timer - (call Pt_Start) before calling OpenInput or OpenOutput. If the - application tries to start the timer *after* OpenInput or OpenOutput, - it may get a ptAlreadyStarted error from Pt_Start, and the application's - preferred time resolution and callback function will be ignored. - time_proc result values are appended to incoming MIDI data, and time_proc - times are used to schedule outgoing MIDI data (when latency is non-zero). + latency is the delay in milliseconds applied to timestamps to determine + when the output should actually occur. (If latency is < 0, 0 is assumed.) + If latency is zero, timestamps are ignored and all output is delivered + immediately. If latency is greater than zero, output is delayed until the + message timestamp plus the latency. (NOTE: the time is measured relative + to the time source indicated by time_proc. Timestamps are absolute, + not relative delays or offsets.) In some cases, PortMidi can obtain + better timing than your application by passing timestamps along to the + device driver or hardware. Latency may also help you to synchronize midi + data to audio data by matching midi latency to the audio buffer latency. - time_info is a pointer passed to time_proc. + time_proc is a pointer to a procedure that returns time in milliseconds. It + may be nil, in which case a default millisecond timebase (PortTime) is + used. If the application wants to use PortTime, it should start the timer + (call Pt_Start) before calling OpenInput or OpenOutput. If the + application tries to start the timer *after* OpenInput or OpenOutput, + it may get a ptAlreadyStarted error from Pt_Start, and the application's + preferred time resolution and callback function will be ignored. + time_proc result values are appended to incoming MIDI data, and time_proc + times are used to schedule outgoing MIDI data (when latency is non-zero). - Example: If I provide a timestamp of 5000, latency is 1, and time_proc - returns 4990, then the desired output time will be when time_proc returns - timestamp+latency = 5001. This will be 5001-4990 = 11ms from now. + time_info is a pointer passed to time_proc. - return value: - Upon success Open() returns NoError and places a pointer to a - valid Stream in the stream argument. - If a call to Open() fails a nonzero error code is returned (see - PMError above) and the value of port is invalid. + Example: If I provide a timestamp of 5000, latency is 1, and time_proc + returns 4990, then the desired output time will be when time_proc returns + timestamp+latency = 5001. This will be 5001-4990 = 11ms from now. - Any stream that is successfully opened should eventually be closed - by calling Close(). + return value: + Upon success Open() returns NoError and places a pointer to a + valid Stream in the stream argument. + If a call to Open() fails a nonzero error code is returned (see + PMError above) and the value of port is invalid. + Any stream that is successfully opened should eventually be closed + by calling Close(). */ OpenInput :: proc(stream: ^Stream, inputDevice: DeviceID, @@ -379,71 +378,80 @@ MessageData2 :: #force_inline proc "c" (msg: Message) -> c.int { return c.int((msg >> 16) & 0xFF) } +MessageCompose :: MessageMake +MessageDecompose :: #force_inline proc "c" (msg: Message) -> (status, data1, data2: c.int) { + status = c.int(msg & 0xFF) + data1 = c.int((msg >> 8) & 0xFF) + data2 = c.int((msg >> 16) & 0xFF) + return +} + + Message :: distinct i32 /** - All midi data comes in the form of Event structures. A sysex - message is encoded as a sequence of Event structures, with each - structure carrying 4 bytes of the message, i.e. only the first - Event carries the status byte. + All midi data comes in the form of Event structures. A sysex + message is encoded as a sequence of Event structures, with each + structure carrying 4 bytes of the message, i.e. only the first + Event carries the status byte. - Note that MIDI allows nested messages: the so-called "real-time" MIDI - messages can be inserted into the MIDI byte stream at any location, - including within a sysex message. MIDI real-time messages are one-byte - messages used mainly for timing (see the MIDI spec). PortMidi retains - the order of non-real-time MIDI messages on both input and output, but - it does not specify exactly how real-time messages are processed. This - is particulary problematic for MIDI input, because the input parser - must either prepare to buffer an unlimited number of sysex message - bytes or to buffer an unlimited number of real-time messages that - arrive embedded in a long sysex message. To simplify things, the input - parser is allowed to pass real-time MIDI messages embedded within a - sysex message, and it is up to the client to detect, process, and - remove these messages as they arrive. + Note that MIDI allows nested messages: the so-called "real-time" MIDI + messages can be inserted into the MIDI byte stream at any location, + including within a sysex message. MIDI real-time messages are one-byte + messages used mainly for timing (see the MIDI spec). PortMidi retains + the order of non-real-time MIDI messages on both input and output, but + it does not specify exactly how real-time messages are processed. This + is particulary problematic for MIDI input, because the input parser + must either prepare to buffer an unlimited number of sysex message + bytes or to buffer an unlimited number of real-time messages that + arrive embedded in a long sysex message. To simplify things, the input + parser is allowed to pass real-time MIDI messages embedded within a + sysex message, and it is up to the client to detect, process, and + remove these messages as they arrive. - When receiving sysex messages, the sysex message is terminated - by either an EOX status byte (anywhere in the 4 byte messages) or - by a non-real-time status byte in the low order byte of the message. - If you get a non-real-time status byte but there was no EOX byte, it - means the sysex message was somehow truncated. This is not - considered an error; e.g., a missing EOX can result from the user - disconnecting a MIDI cable during sysex transmission. + When receiving sysex messages, the sysex message is terminated + by either an EOX status byte (anywhere in the 4 byte messages) or + by a non-real-time status byte in the low order byte of the message. + If you get a non-real-time status byte but there was no EOX byte, it + means the sysex message was somehow truncated. This is not + considered an error; e.g., a missing EOX can result from the user + disconnecting a MIDI cable during sysex transmission. - A real-time message can occur within a sysex message. A real-time - message will always occupy a full Event with the status byte in - the low-order byte of the Event message field. (This implies that - the byte-order of sysex bytes and real-time message bytes may not - be preserved -- for example, if a real-time message arrives after - 3 bytes of a sysex message, the real-time message will be delivered - first. The first word of the sysex message will be delivered only - after the 4th byte arrives, filling the 4-byte Event message field. - - The timestamp field is observed when the output port is opened with - a non-zero latency. A timestamp of zero means "use the current time", - which in turn means to deliver the message with a delay of - latency (the latency parameter used when opening the output port.) - Do not expect PortMidi to sort data according to timestamps -- - messages should be sent in the correct order, and timestamps MUST - be non-decreasing. See also "Example" for OpenOutput() above. + A real-time message can occur within a sysex message. A real-time + message will always occupy a full Event with the status byte in + the low-order byte of the Event message field. (This implies that + the byte-order of sysex bytes and real-time message bytes may not + be preserved -- for example, if a real-time message arrives after + 3 bytes of a sysex message, the real-time message will be delivered + first. The first word of the sysex message will be delivered only + after the 4th byte arrives, filling the 4-byte Event message field. - A sysex message will generally fill many Event structures. On - output to a Stream with non-zero latency, the first timestamp - on sysex message data will determine the time to begin sending the - message. PortMidi implementations may ignore timestamps for the - remainder of the sysex message. - - On input, the timestamp ideally denotes the arrival time of the - status byte of the message. The first timestamp on sysex message - data will be valid. Subsequent timestamps may denote - when message bytes were actually received, or they may be simply - copies of the first timestamp. + The timestamp field is observed when the output port is opened with + a non-zero latency. A timestamp of zero means "use the current time", + which in turn means to deliver the message with a delay of + latency (the latency parameter used when opening the output port.) + Do not expect PortMidi to sort data according to timestamps -- + messages should be sent in the correct order, and timestamps MUST + be non-decreasing. See also "Example" for OpenOutput() above. - Timestamps for nested messages: If a real-time message arrives in - the middle of some other message, it is enqueued immediately with - the timestamp corresponding to its arrival time. The interrupted - non-real-time message or 4-byte packet of sysex data will be enqueued - later. The timestamp of interrupted data will be equal to that of - the interrupting real-time message to insure that timestamps are - non-decreasing. + A sysex message will generally fill many Event structures. On + output to a Stream with non-zero latency, the first timestamp + on sysex message data will determine the time to begin sending the + message. PortMidi implementations may ignore timestamps for the + remainder of the sysex message. + + On input, the timestamp ideally denotes the arrival time of the + status byte of the message. The first timestamp on sysex message + data will be valid. Subsequent timestamps may denote + when message bytes were actually received, or they may be simply + copies of the first timestamp. + + Timestamps for nested messages: If a real-time message arrives in + the middle of some other message, it is enqueued immediately with + the timestamp corresponding to its arrival time. The interrupted + non-real-time message or 4-byte packet of sysex data will be enqueued + later. The timestamp of interrupted data will be equal to that of + the interrupting real-time message to insure that timestamps are + non-decreasing. */ Event :: struct { message: Message, @@ -486,18 +494,18 @@ foreign lib { /** Write() writes midi data from a buffer. This may contain: - - short messages + - short messages or - - sysex messages that are converted into a sequence of Event - structures, e.g. sending data from a file or forwarding them - from midi input. + - sysex messages that are converted into a sequence of Event + structures, e.g. sending data from a file or forwarding them + from midi input. Use WriteSysEx() to write a sysex message stored as a contiguous array of bytes. Sysex data may contain embedded real-time messages. */ - Write :: proc(stream: Stream, buffer: [^]Event, length: i32) -> Error --- + Write :: proc(stream: Stream, buffer: [^]Event, length: i32) -> Error --- /** WriteShort() writes a timestamped non-system-exclusive midi message. diff --git a/vendor/portmidi/portmidi_s.lib b/vendor/portmidi/portmidi_s.lib index 7dd7de4a9566b81710c76a2c6c3c1e6911b6b2af..4f8b4f0e9e709db4fd07c479dc84a766170d239f 100644 GIT binary patch literal 76430 zcmeFa2V4|a_cuNZDwTfLW(Vo_j~TWGqW=+LZ09AfBx_Le%`AyoH_S<&bjy8 zI(KL8^dFyBk-zZLkdan>7&Rt(Y)o`~%$OKGKT2GV9vwf5ler<1B+Zbd3l9FDeR%Jc zr1Kq*MMzRh$L1-L^fwPv_XniEaU>?@IBYplQI3qPj3m3uVY5ksH99RhCBvPO?zSaH zCB~}kB$q8K!=9Oym6>eIDy#6M7ZnsGMkmH5Mx@wXWtE=9*usj6vWmnwO(N9>JrmQ? zoEgm|lJW`?W6R5mN1XD{F=M@(rnFWQ5i}DK-V^f_zk`B8q zC2eAIhBGP4k7Om%T9jW@SPHk46qb}#Eb|pbBApq@lk8c|GnrakT(}^wSaD`-X;sO* z!V1-;4*1@kmg=xOoqnvsm!%}D7Ef%lk7$Z5DP^K7Gi9Q~kEqCMda5&(Qe0V?x1dn7 zI?3k9%5o=7N}1G5G)a_7eqL#58FD)hjw;D3ut`}ZIre#|Cqy`k%PI>QQC3yzaWa2a z(sfFqxJoUZUnUsIRE?$-E@hGcQ03C`TzQo$k7QCyi#$ars;iiZ%<{t0)Y9@QCQcWb zRUUDbRaRU~0+$u$70}=8LXTr1(p^}bo>#d@a3&TN!;kD@S!w>lin3CncuHYKNl|H@ zhgq3kQRG8pFBBPN?CfQg$xEez!pi)LqH<4JMWs|)R$7=->7$M@mXMB|dCQ>4=em;V zDlf^&D=5g}RZqf|rY@(bw4iXQfmf2pIP>$0igV_dQY0fiMJP*8UP-yage+9e&#Nl- z_$Xfp7qiw&g6c(%hYA6lBGthKbjcE1P?YZ}Dl5&aSVpW0c$DR&QoU01QCXFrj|xR8 z$STQk7G7CZSjBvpT&j|jiRXY8?o@W^M9M45mXQ#HH;%M%0)?Dd3j-l4-Y*8K&a6IL)T@jiVFrVeBgBDs{@6_^9e)xGE~?_ ztjzfpN&7>gwv;HoiA|lDl;p~qgl?sxaDJtl)wrZdnaODm2eO>EI4`?wzDJ8nOHQ*- z%9xaDBleQK3azhkqKBK9n&GlfwA&I#WhIVE&q*A0S>mYV#8HmKQJJ`A|8bd-ILgWR zP9RbfN2%JKDK@uzl4GLXo%(lFK)0&GZA(kZNO5Oj7(yb@xM38f!+JH=XR#KK9cxArS4ilz>7f8~*UP+30 zOp>N-mZS%|n`jaxneeY2{+Zc9SH^!7OYxi^AO)~%BZ~O^pMuj6fs*#m1WnpM1=G&Q zDyQ`vMIunCRBfM^{5#dJ<<=b6a?MQoTMhmHO_%=Pbm{L*m&D}zfAj87r1E^DSXNu+ zeg0EE9kX|qplX7c~( zH03`qV^#-TE%6w0|I<@vWi(f3%`~K|7rH65GU)SrmH**X8dliE0e_W=o8Ot5GRtVg ze2zo(^WTt>hJ~Eg)^SF~$B7l4+>mlioM;|99Je5zqWlpBMHRCzD=aR|t1O(Y#EmGM zcZH-}_yv|!d5Vf#hk01?TgR3B4II-pQdy!B`D)1nqoSh5j2UCKMn^@*@};cYkb?Es zNyn$(nHT7iq|Z#4jvxu) zu3YiI*08Kxf4ISIzy(6Z@HXJcZd4m_W7>!t-v*o+c9YtGqkK$k18x~`sle?JSd#PS zzbC;z3e2@VK_Ilp;SU!F{y|_udJ&43k3Zbyh?@w^MuBTd-$THC1I#tONt+~574xTW z2Ke*)NYZOKD9~MpKip;DHv*G%5uqg98~De?fS(J@Edtk)zB;s<-N0n`BW;otio>7X zhk)A$Oj&;hYZ12%(Z_&!Z~(`(WcOo4zX!}S1J94^g6Pi$h9mu_?-E4*3|t?q`%*x1 z{pKSY{ELB^*$OTbxO`xq7r5XS^gS9NNdbc->G8n;AeeFZ^B=k605HD@TubTe3I%@x z6E=*rNm2(K{`9Sef-8VIF`U69s$TwZe}aEzge3h+9U($z9R6^Zf?pkl`iFx;OX=H; z{O$o}6*&^2rSh#u+_S)xQ$<98m|we8f7b~N;V7{5E!B6Zr5 z;O-Jw($8>y^lfdUzU{!h-HN_$uyYcaCL_*I`Ywu+mBIF#{agIJ_~TY1-2#sk-qpg z>azov-ikgd-$iZIw;DLP4f-Aj=2aukPx&4J=9m#@C|^onyRnkg69)y=FMjlm1;$~- z8T3*8%LC?0BhHV$>w&q;i1VXwD=>SFI6wN10rQIyXV6E(eHRSYLukN8IA4BKfXO!E z4EiX)R|2!fi1U-a`+#}Ei1VXwufVVb;?z=o{s_3QThT}58yGK1J#bJsUw&hOu^VxQ z^o2u54lqlMI6wKl6`1>tIDdTM71dgYa`S`_8e)|J6+=w&e zm;9Fo%q%0$kG^HV)EaRHebhc46c|b$g_ivH3UCdr=%e&~-9~+d>qi;Ge`9_>UAJykI0>c#I)Kd9+fxER8eOAbC0_Kpw(fqk3eV+hxq7{8q|Jo-? zQa>CN&X?Z_z@!>+hWt`_EC6PS5$DH$w*qs&5ogdx>3bcR4~#fJ`c463vOxer&4)oB zrLUh2eIO1BD$b9-bQ|g_4hkyHppVkG#6}1$v{W9~+c1B@L7^pm)L(725kd3iEI zNgv^$(2_n%-x-@ES?q-J!THJWaA4w%I75EPf75|kV8r>+R}0LIMw~$(wU1{6hSEo& zrTo4G+|E|?QGP#fqrP*%wM$|qTl62LZ=k?%WXtIr3fx$uz6$+)qX|l;Hq#eo8)3jv zc}{DF!+od$*8{kj&2YA6xW2%Zw*hAb?z%SME&}f9HsGi{_O$^=%O7910oMn(_70qU zf-S6helJG+z&7B90GHYZTz}vy{NeH!E~*?8qo$@D>nb-Ja1x${#Io~9XYxe*RQD7- zWioC6PLA{`1N6*Hw==_@o}4|vO3OPx;n;%XD#=8vQ_}Qtvoi~dN@p)FEG;OjP}kl$ zQCLuvH$1nt3`Zv8OzoM)X4}Mr9FB@XbEXOYnMOPJ-F0eYvO3I6h@$l7uGjxS9 zlSGZRAEQ_|&nT*Z7c$C}sVtS60gB{JQZCL| zkps2m)Q3$?JNY@fUJ$;_-2u{0MA))jHQ!lX@<*=Py;U66bIChh+m8mh0$CDysYciHzuXd~fMyRoRn*_}R8h~$Q*{X_ zj-|@ZQ{@81{ZzYmb)~0h&Gs;?3fG(qUNYa6zg<)@`P#LBNv^;*n?85du@vn5PyeOD zX*JMjcLa6YEK&ZvI07Zg)$5Em8q^L((arK3jG`fB52Gf5+Q%sRZQ~tAT@LC1qtM4m zhZ%JRs1F!LUD#GeQLXuyQPrTX!4W8}!&zq32Ar>D6rJlBMcJVvP`U-@>lk$h&NnjZ zZk(@Y)JB|dVwB4}J0f^Gbr4D&kw21u^Ne<)De#tl95|^irKwqk-E9s>qn*uLd(KWq z?nd{8z9nZT-Jw&RXvcgO0?I56#CZ;*hT+U>3@!XoY&+2(XsM_gPVFtlb+rp{A_dEpQaGJqvxFRzrCjtcWAZ%vuId&EIN`Oy$4R5?$Wnh;WzJ6JfPa zu}`xzPbWuz<;wro=^ca=Ny+k0Zg2l|>bribJ!si58Tm*UPBE6cWY9|Ag}&J3lK*sV zKNjSSFNhEKw5LB-Pso;^&^Mp>5dvG6;zR{%V`b*@2D#)9UGQ15H!`{Q^n9l`*ZeB) zww)2Vc1z|DF0Uh4e%mEGBNo0K%!D0bLe_!qvA(K1dRVvjV#eF@GZ|U~n0HZls{Dc5 zn;(fIs=*N_*|0|77~j-{pQF9`&IX5@m4@iUWOw^Gmls0^>B`T=u@I zwzpC`PQJr@bn+1OYP=fI`YZ2>oS=ADv;@>L9A;?~&X{z7YQULy-pHE3^@UC@F;1mi zpm=wm1&T{7Rby>arx{BBXHoig`2;V0H!uAH$RxzV6iR;vXrI!b;gbJSO23a%`aQ@A zGg$Vt{Lh`UQ>_YF%yX$qRj3N#rT76Xc%$SOBC0{SQAcy_ufm*!Iv(%RD?!%#C&KkV`@OX_YEwbkpOS~3hrj87GD zdKbBs3h+1TMSLTM8P!WI^LUk-s#5bn@w#!f%3~ccbr4~!Z-_qa zlFxZr4WQ{-k5_1thf$dIv#92Alqqz!`5hGRZT~zd-eaI zgtHR()NO!U&NNQl-leIV&xE775jj(7cur`>c9VbARA@dMkKA)l(G-Yxuxmh( zM}wt}I8)zbX1!A|^@(AWWps=y&@oP<;U~H&S#I=_$5H9OMQ2Fa?;x^&a#ol$o9-$=yEiKiNcx?dn;?O{?tGJ|4XK!|*=ttdPQnvR zf31=t*vawxh9LrTPq_~nsR?YzrfCx>Ei32Vv@miKrauK4Bd zsu0=Xtf?1dz*74Z&heGQEVVRK6zUor!*C(l+I$PN4e$d+e!JE-PH(| z+G{8}@J+kCd;9U=4R#X<=Y~<+kB8Z}{}8^x9^l+?WgybEutqYUcoNv;b*GozIN=N^ z&owk!V^l`^JtH7D=q$M7&su8##NSDE-M+>jDK+ptdsCK`riH8qi+syh3~MapN_G_hM(bO*Rw)OQE)vrl*6 zM!R0fW)p6V9aguDYJzsJ)+%r1u-8vhOMgH5ph6?>VJCM}1?K%6^d+&ZMVy3 z>s^1I>|KfW^8GXd^H9ZN_nM{VwhDHANn2hetMH<&{x zu8BA>F#e3ET*X#=#M3p=yW*{=iC)iJF_z6eT z+xt+&Qsl~6S7ma0pNyy`+TuKgKH9PlOBtA1^3kF8NYxzC=ubQgJ{7G}QJmi8!<6NU zA#GW%II#*EYMU(UmLm~z!-+CdnBP%xHU?KGh8e5pI{MScbG2P=a#HUR1WT@ymx%5| z?L5+)HQNgk_N>Ih3R|7vod>Y))coDa@-Y|6#Y#E4jvh@*mw$BEt%!)3e?!Y%$0NWA zW#}_R@1b@bvqWsOt|JK%YS&SSi~paxj*-4y$2X{mm>BXpSJ!Qa)_2^Dm=l>O0(~^^ zJeHlzAP=L0! z`aS}jklH4X8Gi$!>)kT1=x&);a+iE9YtF9dw~oUNDDAr=HlXsm*6gBoPxmxAn9|c^ z>t85HGn;<$ZlVXS`J{secRtm~6TD!l1{Cj(ZbPHyvHt|cyQ8z9Xf@${lQMoEl`8+_ zl)F>X>~x#@E$&t92|HHg+v}37uKYbNG!l_;y4zH4F+yP7#lI`wuLry1edyxF(h@B);VdWFNSI zPl9NQ#3w;?SIX}<=78dbSfs{QfvUw}W|J%)y9U>MdUdtHwPOoFT=T8qaooKsMH2}g z`>M)&Tjd>Ac~m?c_oK@DOXamwD;eGz6u3SrkLEgDHd^I5RNf?&H&^9}`yu5HfscT= zKcK;_ZaBd?>zV^Bb6qlfuP7=YARsmkbHP;Ns z3F-hSE+JNqm&KqJf8-e=+c8Z@wbF!x_1`qXVEK;T%Wjye0=;R&u*xIW{v)7=7F2le zVpsu-!Yn#H|E$yNj=*mUeA4o3GThZZy8c87jleY3rkleV&iK4xRndrBH6m61g9KtrW-Yyi&gv4Pt^5AL{!F-!_+9?K}C)_P_;pIH9_Qz&aIxq{y`aVMCu zur;h^x7k(GU_Nm6G8B`P{;%P4+`a?Q1@#X}5jNIr>x8F1dC`Re`)?P$RC!H+q7cwT|(gY|5S|X5GPM zQ3`Op?1-rgeFG@z&=(!Dqnhfyj+mOW=BmN+l!yprx_7c?i&;obXtG>;6Gp`oFW^L( zIsXnkYxIiss{CEG9*DhiBoG; zinkZ1WpjXAKIoKZ#@Xe1lrb8QTFg5wYj1!iySyh^-h*;}846KA#!|M|9;#XdX{DIk z)nX*eT#hj=WGdZ>cIaU<(P`i8?Z11D~W!4FpVbwKNKIr4h_TsjR zVRqgP4A19dpm^@ET3|Bcwd^EPAW1R&4?C~NIS@{fBu)i`dYJKiCDMtNlO2~?4U$emVlFm#a zL4W+|eF^+P$rKbI1&t1fA{70!ql670crG~=jBDxuAQ57gLSllXkkLWqgq}es5orF) zr8q@WI~mW{n{fh7e{Ny1lp9Ww1T|58$}R^-2{Z@bHaJBR?=qgLTd>rvprh1nN{G~L zbXa5OqoMVP(0TYah9rBOBI)-SkCmQ>1|dy?VmXdVk5g27T*3v4*2a|JPxlc-qV!nJ z2xci!BwEtVB?v`#MN06e`*TF{n&F!gecrUxbG@W9w-vp|RJ~-KbW>9QSRv17E$`1jtr+rP%Ot$zBxrTi%SrSR_B%APdCk2 zp_{cvOqdM%^;)?+d6VlW-S;WV@zbHlUb>lm7(YBhk$PV+LS z!olM8Wl;SLbI=5mU>KaxxN zj1DOZ9DnarB{)SAG#gdwI{bv7NKh=tQLW?@`HM>s>V6zb@TWV0>lP42FZo8ZuUX)F zN#~P_QWdF}u`|7%~Hx&ouovJczbk?<^H%I7&4WwT}`Xx#`@<2hcbN=*`4SKCp3I5Vg>xHQKJ~O`o3LJm$ z!NEPtDa!F8Ced?H2dQgJ7gJYLuqm`L`e|A3@1~n{(#y9>@aGRN(|f))y&4E5&}hX= zj8jx%*K-YQHrYw)785FUyG)x+#weoryAcPM<`hZa%JW6zGRBE^qE;(XR0bSN<;^K7 zZ!Sfs`+aIPkEaZCiuB*b^@F0I=+$F3A|{Z%{>}B0PI@U=2^&Ee(|teBwNH;naxWTIR36x zB{)SAo0x<&%qr2IWV9pMIBPC#I%j3u$PM;oi|s3|d<#Kqs?!jwZBc3EJ5=i8`L>Q$ zY?^6hduHk*^9rnD?@k>*m3H&Q4wP0Ubyl`-qYfh!mx*oqba6_OX%|W)ifuw^bz;{F z9ZG268%|p16~WTCY@NK>%FEuBKJ%CD`2(a z^7vm?*YzB=>D9PJ-QPOA_0tgLZ(2jdFVF3N^H=5C_;=Fye?6P?RYZn@o3Qe}*Y7(s z?}mAEqo)qPXz3lnw_Nob?As~m!$>V{MFpa&kwjf^qV`9|G9m^x*4N;-FDBz6L#1(pZMg=%dvmGx;D(+ z{o~@EMH9by-f6w{k+Q<%Yu~#(@|I^3_xFsv%Rc1xxIVWOe?8bUB+XGe;nyejT;Zvk zZoT7+gzO!+1%7Br?~>Ueea!1uEiJv}mu|yO&wu2*zG2%wT>0ppes?E6o$WncHRke* zdn)-DzF|RQo$zvdgX75 zzC*Kiy?*x#e{E9m7u4@5ZnDL{IjgMV*MLJkt8X}R;M!a2pMRrcrT3QUpv5l*tBc!`&TAB{o|C94odtdx8F8*_}U|V&aU`%;g~l+{LsvX zo#P%|obpQJ{%;<8>!+Yy^XhwsEKj*{Y2wPEj#DG{y){`Wue$>4KY8f3bCzKtqrbfH z%V3lJpnc0dul$u5TxVV^CEc}fo8`sz1NuK1==#03cFyC-{} zD2=|i(d7tuZjgDX5`WFH_X=LQ;>%G=`uDDV^{EZ-94~yl^sAXAcX#fo)W1z-ridG# zN&e#P_d9?2-qAzXAB%S`m~!276?0cCe6=#R{gsNpUY8rIZw(#!F6za(@JAH-rcn6syilBtv+?D%{%4!i|>1S34?S^v zRBihGwa>nLL*o9%s|G$@`JDO4IHg~);l+va5k&kKmtuPx;78WB!V!ci@)8Va5=|HY)TA5 z05&7iHV-0PplKn_%6c4Oco;4I5{BzZ2E`;)&U8>TnrYVaaYZu%&hgz?s2y=l{EkYJ z-mhKpvYIHiyoqS3on)mH`fOW7_?DzLkO)FhGpY9A2AU`h6zclDjGxMc10=dPq|m;Z z6w65qDSVs@A-Bd9(n?!PDSSalb!a9<_XsUX?G;iXkP6g!gYJw1O-kv$cKY4Rw0s>B zQXQK~(Oj)1ZyXa+q0OYIMg*Fc(HX~Q8@oEWE#K0iUq=H?PvT4-AAakzSne}{^2Jyf zCJtvR%U3#BXEn#L8e_T~@ucTIdp=s1QBN1d1ezYg`9d5Mz9{yCxqxA2;7qmcJ7@al z=6bp^3>?Su(nm!hocjkS2yg3HufgvwZ=y{|cZY7Or?uD2@(?6FmyjeslVyrQ>U6^`ZEm8F>^KUkP6~%_IS)=}RqA0O)my=^ zy*J5LxWZvO#1p57!r>degL4t%P}~b9I!kydM)4TEIz*u#<0$)#bDo0PFEHHmz_5+S z^_U|%48?uhjPqMF4i>3JP;77o&NRX4uX5;-0SW`a;q`lk;AnMKTU#URxNX&{Gt(2{&Y&TK z1?r81ByiAs@<9C$xRG-;+lBN6A2 zW(qX!a48zYD9~umISPh)K`zA{gsX6cGfI)_p>W2q%;SoBbta`i*b8M`a}>D)fqHDl zQS)V0IAawS^`cx#u}*y^x_gwO>dvjLsGY10P!ly0^Pallodn zF^tX@jmUh4Pwk~w=O2F4q|ON`hSAv?sIJiE*qdp z4H8leqq8+!XDhSI!QGlvf{VX*;1%}btqJC4eHRGeDziCp#gcQT*Y*A03)%h3q-t>(oWfM{i zqq9YQgJw(0x^_)Qu^MvpLS+wQbD2gDKvz4r~Rk>sA z*P7H^A;mB{TN9a7H#*~pzHn2xCRHh<7)EC+MQ5v`WK*&xb&Zf>7@aK_lTym-y5Ebh z)THhgQVgTBm8!EfX6u1VHK{E^ieYrNCNU``UpII7I9HQ;S4c68&Q_Yv)}{v!{-Q~J zBcvEcXUol`l)CY8_WG+esXv7j!{}_K>umMzf8!EOs#_2u5g0~iD+64uecczCJ6n?) zDx?@jXNzWpTKgI~_VS~eRFaTl7@e&wCdKZoLFLDP*Q80!6jBVMvo%>~YeDoqMVeH( zkYX5}t;?8{;zNDDt`<@ZqqCK*v$dvwuf3YBdxaFk=xj|nLYo^Xt$<{stG^q~l5sAPsI$M{6tJTBs{+54eQoV%~!{}_y zVp2-q`$EWbeKo1!LW*H@wq`Ra>NhA%edz#pI~UDLN)%EIqq8*!Sj~rrulVG4O)67J zF^taETqZ^Jkiw&DGQaPk+L|k*7)ED{?xr+b$9K+Lqe+ztDTdM6%4JfDt68BOY5A;mB{Tlq{%DX%NHzW<~q z^{kL$7@e&GCZ)9Hj2<^Wq)F`%QVgTBRj9L7-20h7G^xWvieYrN<})cPopBVbpM8TS z^^K5X7@e&JOiIaDWn|YIHL0^gieYrN7BVTNEz`YTU$wkK1e;-Wwu*GNh8AYOqDfhW z6vOCjUBRTRIGb?H*|N>uPqh^*q!>nLYY~%D^7VMvuddXj(u5Sl=xh};DP>%4cj}hw zHK|-7#V|TsB|2NFwpSB0sU<>+VRW`inUqpDlFx10qe)#Sq!>nLt4wFhz5DibP3mDG z#V|Ts<+^;G=(HBQ{44#&HX+3@I$KxjY!y}gajzzINJue^&Q`^F^7XBdVi=vRN}a7u zk^lzNyxzWWSKs#HiZjLz0Foh{q% z)4$QAYK0WT=xklZq?CHN=%xKzG^x9V6vOCjE!Ww4{rdRvn$#vC#V|TsE0~n11QOjZ zN2or0Q%Et4&elqut+6SOT%}1J6;ceNv$cvzDRm?Buba~QtF}%FDTdM6TCKBnm#MTs zlj;_NNCbw_*{TLtzYZ`!wKZBuF^taE8YZRG!%Tb14VqM{kYX6gcT>r=Op5wKEd&TM zM@SI{zt#F|MOg!m_B-RncO80&5Ij@}DZ=Qb)-kCb0+$mp8J&b8zR~QNTn~k|5{Dzl#n8fUg~Nlb&-&YeB_evHL0kMoJ|F2Nk!mHp=ZhG=$;j+yM+{C^itP=6Nnu(cvw+?(56X!AfyPR zmy*E=G+oSvq`qq>qoY-9b*3tVKp4FgTn4Ej6p1i?zV|gvDpg1kMlV$dPN1nji6Cs4 zIvw4ZVyjk25r*^X1&6Sl^OlY?!e_(H>wpO~(UzO~@F^tl>xkitx9a!2{D0ib&j)dR zzBxvp=G89Q2XeJb@kO#`-~aVtXdejn{em$4gmb=+{W1k*`1~>dw(x>N5Bn-v4*$$A zi(Qyk>C4M9eo0yPRXO8Fm+{d(_Hf_%KGf`J?Q75H`BpQ&&Fu3f=H?%2)_(wxe|Oo> zSD2OG;^>>d;yc1Ee`eVKR|$PSJ`AV(e9ahF`foJj`^7DO1$lmv-!CuEFRrRwh)+XT z;)~8XIVst$ywU>ffa+LSh>s8F2GxpFL;CRY7v>d}MnsXk50~pSayfRCU#yXqnoh} z+0&!d{3&ch1{F5ft>#c+bMzR+9SWPHo3S~1tbcSfHb=+#M>k_@&bH6PgW*1Y7S|ep zKNq1@U2)Cru`M*_>Lt?Vo=we8bU>c#zDwCJ`6aq7W&&Cte$BDjdUTK&oec2q% z+P5#8qnoigTJwc4$Y3S`;GMx_8H85gnYQ-`^jzpx_OezmX%@8%*x74wkdB_ zBt|F3CPt*#X>?4CWfQu@IQ7%@Ntw3vjHGmXTFS&`65<7m#901PNMh`N>Kolj8MdTJ zsY#R4vyz$_UDv+niYwGm=wN(wd1X$yDA<@wJ#@OG=sO%1oK)XeOq*lwMj% zj1_OKs1_ZQY>uofchaPP<6Gbk_|ln?JjtHbJhkH87Nz)O`P(fvOc_&4@)i^(;S;;M z=_8*whK!6EW%UiMeam+2*w`43r*GK~Vc)WyZ~=b-kZzoOA6%#FkvLWa5#6ieD74O%+La|zi&f+34WupdP9N;{%{|Ge+Ww~Pm0@isP>CX z0sm)U;>B%nOLpnjbh^NRWWk?ZJ7Si$0Y{7HTY>8>>5L9)=2zB=f-vlV?5{gS{4buE6wg|;Jqw-tSq z-|vAjb>iC8e6TS>vA`d`?gz|JBhHXt(w7R%93#$;zU9DNZNwS$(ZbHdz`Sb2`O$X- zm}5qqAARjQ;{iJy6wa651YlB(ID0%^bpjMAd7@-HcDb8uZQA3` zug6x~*uOF0IJq~v$-6wVE(M!U>!oP>HtdQx#924hjNh&?vLQ}YkF>OwDZ*O@oiYvQo!@r{6_)?gQ{nr}_ZzT=QL)AP4e z5?poNHXt=DCD;%-++7#?6s1abghe+c$)O?GhqX7`trp)Dk=^V6@UB?@2O<;ptoVW9 z^XpUVLc5TvXud5LcJpI9@&>-0kQQu7KIcuKeZsKsoj!Zf^(T)Nz>pP(S^7bxVo(G7 zGak134aP2Dd_!++h)G*iW0$R9I6YLtCmU$XaCVJ-!uU?;(Wjl*-?a9~Dr`xaYEG4H z;gr4j(Nzw6({@+Q4s&wCz7>s(kHUq__=wc}rDo)L3rlipU8>oc@ZqXNmSMYmLG8h+ z{&ug)E$=qO@ZK0ZZZx>h1c5_pGDh${YY+)% zF7_K$l&4{1LH?nNE}|Onjf_!312r`)D!SfViS!0~9id)FH++qmetES$Zny`PxkE#M2FI@Q?naU*X)Dd{F z!8*XaAh9vNJhNMaoyG^gm8&-g{Rr4KXH8X|yeaT>ij|}J7Jls;Qo5n3NIbteJ4b=0 z(OI`8KDCspVA+n^>9zAJyVK+dmK+7xDP~GAc8tNUF=EFUnwl$tijVJ>z^Pzd({D%E z&%|ek2AZTRVIT-D!6}j$$#{InwqV+^Ef)-?hyGHaU(C1^r${Q6@%VmdbbFvlP%OvM zER<6;R&fbR-y|GL@TWTgk+kavex36C9o?k2T2YL@{&d^HhwgS}?7D$FD}#Q0in%-$ zHcxvsDB71s3I6nxx5bVqq?>FYD8J~PUq9)lTRA28)1Qt=v0n|`Lt!}o!_I?n<|V}` zDhvM9AS2NNaS75p8;277>7I#5fpgUdocm(7Oo_v*UII| zn_P-?Ur#U*{OQj@9C?$cSxJo<*Bq_S0oO}9AH$&pe|ifMNqVUUfF!>l?GzMmk{`Gv zrI=IHaJg?t|CczF;LpY)M5-;ZoRE|cC0q=GmlUTcC-{k&QboI|VUH*ZiUh@S9Ql+} zltLi^DhY=YcszNDQzXrwQBm|MfAtv60@q7A$x}-3rX@sZc*N@3_4evLv;XmQX{V&0 zf3SCKJhuPMi<7!Md?I`07pHD_JP>`g>H7~JzjJ)UOYsYj+&1y~ealDmJ15NyNUT|~ z!TQpA9&&EQ;(i`{rc*8OK-`KyLI20pT~3^Jo}=wo8q4x;k^8&ZyvS{dwg?` zqt7mVKIx98c0Y9(GO*@-#l!#AT@ZX0k*Hq?G*RC})WL>^M{Kyt8s> za}3t7fT22!tVzGFxZ_{VF}QC6hGrQQt|-3(a6(g{JX7F%ClJ+@P6&Ko1fmAg2_aCj zisvata0a9mPQ2jo9S-PXqTukI66j)z;PCwn=ps*WXs-hHHfpQyr#64r6P(II>f=}- zJ$P%Ay<15PDlhh4;20Lou9PZqrfmaTb;nwKfM*C+Pa6y@OLz^--FK$ zH?5&)w&=-pP3lD<#V|Tsv=YIk2r_EhR{?>lt+#{}!{}^LU#;0%xhx(pmyz!&e8&HX zojrWtlI(&Q?Jcgb@vc#t)K5Z+VRW{z?(AdBo%qHCO{$%Vi!qEYUsSI(Tic57s?wx- z3Mq!s*`l#g%U9aRWnN8cxR7EPovrRnibhkaTcht>iB}^PZ`g$t!{}^XsIzrx?dD0E z)KnqGFgjcG>>Gc=lx!`zXjiHxRV1VsMrVtqO?|6%^5%*qnv}999#6k-dG%zrs9&Pc z<%OKpm}T+{=|*9TVRW{70ipTu>Lr!)G%4EMf&#;*Eu$2v{wO(DfFI$QK~p60`zrezy6sZWIz!{}_$t)rH&->a|Kq)GiOq!>nL zi~3>hZH&tIZ4)#p+|;nZFgjaSCZ*)-vC!WaX;Qs}6vOCj^=DE%znIxyd*y?g)CeKP zFgjZUbhZkPK3u6uB?&2p(b=L=LhGZVPqbUxL9H9gTmB5AvlXGUwP)VHVl}Bn!WP5m zYz<;kyxrj=;;+tpQIlFNq!>nLi_PxTI^X`XVaGM8TZI�s7W?4DdeX6|q6SR+D-{ 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 Pf1?7rD>A&gH~;?t_}U@? From 42b9ce636f72bcad6cb04817d42bb39ba952c1a7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 21 Nov 2021 13:59:28 +0000 Subject: [PATCH 0042/1258] Remove `#force_inline` from all wrappers --- vendor/OpenGL/wrappers.odin | 2802 +++++++++++++++++------------------ 1 file changed, 1401 insertions(+), 1401 deletions(-) diff --git a/vendor/OpenGL/wrappers.odin b/vendor/OpenGL/wrappers.odin index 2d805d952..f3bd9166b 100644 --- a/vendor/OpenGL/wrappers.odin +++ b/vendor/OpenGL/wrappers.odin @@ -4,748 +4,748 @@ package odin_gl when !ODIN_DEBUG { // VERSION_1_0 - CullFace :: #force_inline proc "c" (mode: u32) { impl_CullFace(mode) } - FrontFace :: #force_inline proc "c" (mode: u32) { impl_FrontFace(mode) } - Hint :: #force_inline proc "c" (target, mode: u32) { impl_Hint(target, mode) } - LineWidth :: #force_inline proc "c" (width: f32) { impl_LineWidth(width) } - PointSize :: #force_inline proc "c" (size: f32) { impl_PointSize(size) } - PolygonMode :: #force_inline proc "c" (face, mode: u32) { impl_PolygonMode(face, mode) } - Scissor :: #force_inline proc "c" (x, y, width, height: i32) { impl_Scissor(x, y, width, height) } - TexParameterf :: #force_inline proc "c" (target, pname: u32, param: f32) { impl_TexParameterf(target, pname, param) } - TexParameterfv :: #force_inline proc "c" (target, pname: u32, params: [^]f32) { impl_TexParameterfv(target, pname, params) } - TexParameteri :: #force_inline proc "c" (target, pname: u32, param: i32) { impl_TexParameteri(target, pname, param) } - TexParameteriv :: #force_inline proc "c" (target, pname: u32, params: [^]i32) { impl_TexParameteriv(target, pname, params) } - TexImage1D :: #force_inline proc "c" (target: u32, level, internalformat, width, border: i32, format, type: u32, pixels: rawptr) { impl_TexImage1D(target, level, internalformat, width, border, format, type, pixels) } - TexImage2D :: #force_inline proc "c" (target: u32, level, internalformat, width, height, border: i32, format, type: u32, pixels: rawptr) { impl_TexImage2D(target, level, internalformat, width, height, border, format, type, pixels) } - DrawBuffer :: #force_inline proc "c" (buf: u32) { impl_DrawBuffer(buf) } - Clear :: #force_inline proc "c" (mask: u32) { impl_Clear(mask) } - ClearColor :: #force_inline proc "c" (red, green, blue, alpha: f32) { impl_ClearColor(red, green, blue, alpha) } - ClearStencil :: #force_inline proc "c" (s: i32) { impl_ClearStencil(s) } - ClearDepth :: #force_inline proc "c" (depth: f64) { impl_ClearDepth(depth) } - StencilMask :: #force_inline proc "c" (mask: u32) { impl_StencilMask(mask) } - ColorMask :: #force_inline proc "c" (red, green, blue, alpha: bool) { impl_ColorMask(red, green, blue, alpha) } - DepthMask :: #force_inline proc "c" (flag: bool) { impl_DepthMask(flag) } - Disable :: #force_inline proc "c" (cap: u32) { impl_Disable(cap) } - Enable :: #force_inline proc "c" (cap: u32) { impl_Enable(cap) } - Finish :: #force_inline proc "c" () { impl_Finish() } - Flush :: #force_inline proc "c" () { impl_Flush() } - BlendFunc :: #force_inline proc "c" (sfactor, dfactor: u32) { impl_BlendFunc(sfactor, dfactor) } - LogicOp :: #force_inline proc "c" (opcode: u32) { impl_LogicOp(opcode) } - StencilFunc :: #force_inline proc "c" (func: u32, ref: i32, mask: u32) { impl_StencilFunc(func, ref, mask) } - StencilOp :: #force_inline proc "c" (fail, zfail, zpass: u32) { impl_StencilOp(fail, zfail, zpass) } - DepthFunc :: #force_inline proc "c" (func: u32) { impl_DepthFunc(func) } - PixelStoref :: #force_inline proc "c" (pname: u32, param: f32) { impl_PixelStoref(pname, param) } - PixelStorei :: #force_inline proc "c" (pname: u32, param: i32) { impl_PixelStorei(pname, param) } - ReadBuffer :: #force_inline proc "c" (src: u32) { impl_ReadBuffer(src) } - ReadPixels :: #force_inline proc "c" (x, y, width, height: i32, format, type: u32, pixels: rawptr) { impl_ReadPixels(x, y, width, height, format, type, pixels) } - GetBooleanv :: #force_inline proc "c" (pname: u32, data: ^bool) { impl_GetBooleanv(pname, data) } - GetDoublev :: #force_inline proc "c" (pname: u32, data: ^f64) { impl_GetDoublev(pname, data) } - GetError :: #force_inline proc "c" () -> u32 { return impl_GetError() } - GetFloatv :: #force_inline proc "c" (pname: u32, data: ^f32) { impl_GetFloatv(pname, data) } - GetIntegerv :: #force_inline proc "c" (pname: u32, data: ^i32) { impl_GetIntegerv(pname, data) } - GetString :: #force_inline proc "c" (name: u32) -> cstring { return impl_GetString(name) } - GetTexImage :: #force_inline proc "c" (target: u32, level: i32, format, type: u32, pixels: rawptr) { impl_GetTexImage(target, level, format, type, pixels) } - GetTexParameterfv :: #force_inline proc "c" (target, pname: u32, params: [^]f32) { impl_GetTexParameterfv(target, pname, params) } - GetTexParameteriv :: #force_inline proc "c" (target, pname: u32, params: [^]i32) { impl_GetTexParameteriv(target, pname, params) } - GetTexLevelParameterfv :: #force_inline proc "c" (target: u32, level: i32, pname: u32, params: [^]f32) { impl_GetTexLevelParameterfv(target, level, pname, params) } - GetTexLevelParameteriv :: #force_inline proc "c" (target: u32, level: i32, pname: u32, params: [^]i32) { impl_GetTexLevelParameteriv(target, level, pname, params) } - IsEnabled :: #force_inline proc "c" (cap: u32) -> bool { return impl_IsEnabled(cap) } - DepthRange :: #force_inline proc "c" (near, far: f64) { impl_DepthRange(near, far) } - Viewport :: #force_inline proc "c" (x, y, width, height: i32) { impl_Viewport(x, y, width, height) } + CullFace :: proc "c" (mode: u32) { impl_CullFace(mode) } + FrontFace :: proc "c" (mode: u32) { impl_FrontFace(mode) } + Hint :: proc "c" (target, mode: u32) { impl_Hint(target, mode) } + LineWidth :: proc "c" (width: f32) { impl_LineWidth(width) } + PointSize :: proc "c" (size: f32) { impl_PointSize(size) } + PolygonMode :: proc "c" (face, mode: u32) { impl_PolygonMode(face, mode) } + Scissor :: proc "c" (x, y, width, height: i32) { impl_Scissor(x, y, width, height) } + TexParameterf :: proc "c" (target, pname: u32, param: f32) { impl_TexParameterf(target, pname, param) } + TexParameterfv :: proc "c" (target, pname: u32, params: [^]f32) { impl_TexParameterfv(target, pname, params) } + TexParameteri :: proc "c" (target, pname: u32, param: i32) { impl_TexParameteri(target, pname, param) } + TexParameteriv :: proc "c" (target, pname: u32, params: [^]i32) { impl_TexParameteriv(target, pname, params) } + TexImage1D :: proc "c" (target: u32, level, internalformat, width, border: i32, format, type: u32, pixels: rawptr) { impl_TexImage1D(target, level, internalformat, width, border, format, type, pixels) } + TexImage2D :: proc "c" (target: u32, level, internalformat, width, height, border: i32, format, type: u32, pixels: rawptr) { impl_TexImage2D(target, level, internalformat, width, height, border, format, type, pixels) } + DrawBuffer :: proc "c" (buf: u32) { impl_DrawBuffer(buf) } + Clear :: proc "c" (mask: u32) { impl_Clear(mask) } + ClearColor :: proc "c" (red, green, blue, alpha: f32) { impl_ClearColor(red, green, blue, alpha) } + ClearStencil :: proc "c" (s: i32) { impl_ClearStencil(s) } + ClearDepth :: proc "c" (depth: f64) { impl_ClearDepth(depth) } + StencilMask :: proc "c" (mask: u32) { impl_StencilMask(mask) } + ColorMask :: proc "c" (red, green, blue, alpha: bool) { impl_ColorMask(red, green, blue, alpha) } + DepthMask :: proc "c" (flag: bool) { impl_DepthMask(flag) } + Disable :: proc "c" (cap: u32) { impl_Disable(cap) } + Enable :: proc "c" (cap: u32) { impl_Enable(cap) } + Finish :: proc "c" () { impl_Finish() } + Flush :: proc "c" () { impl_Flush() } + BlendFunc :: proc "c" (sfactor, dfactor: u32) { impl_BlendFunc(sfactor, dfactor) } + LogicOp :: proc "c" (opcode: u32) { impl_LogicOp(opcode) } + StencilFunc :: proc "c" (func: u32, ref: i32, mask: u32) { impl_StencilFunc(func, ref, mask) } + StencilOp :: proc "c" (fail, zfail, zpass: u32) { impl_StencilOp(fail, zfail, zpass) } + DepthFunc :: proc "c" (func: u32) { impl_DepthFunc(func) } + PixelStoref :: proc "c" (pname: u32, param: f32) { impl_PixelStoref(pname, param) } + PixelStorei :: proc "c" (pname: u32, param: i32) { impl_PixelStorei(pname, param) } + ReadBuffer :: proc "c" (src: u32) { impl_ReadBuffer(src) } + ReadPixels :: proc "c" (x, y, width, height: i32, format, type: u32, pixels: rawptr) { impl_ReadPixels(x, y, width, height, format, type, pixels) } + GetBooleanv :: proc "c" (pname: u32, data: ^bool) { impl_GetBooleanv(pname, data) } + GetDoublev :: proc "c" (pname: u32, data: ^f64) { impl_GetDoublev(pname, data) } + GetError :: proc "c" () -> u32 { return impl_GetError() } + GetFloatv :: proc "c" (pname: u32, data: ^f32) { impl_GetFloatv(pname, data) } + GetIntegerv :: proc "c" (pname: u32, data: ^i32) { impl_GetIntegerv(pname, data) } + GetString :: proc "c" (name: u32) -> cstring { return impl_GetString(name) } + GetTexImage :: proc "c" (target: u32, level: i32, format, type: u32, pixels: rawptr) { impl_GetTexImage(target, level, format, type, pixels) } + GetTexParameterfv :: proc "c" (target, pname: u32, params: [^]f32) { impl_GetTexParameterfv(target, pname, params) } + GetTexParameteriv :: proc "c" (target, pname: u32, params: [^]i32) { impl_GetTexParameteriv(target, pname, params) } + GetTexLevelParameterfv :: proc "c" (target: u32, level: i32, pname: u32, params: [^]f32) { impl_GetTexLevelParameterfv(target, level, pname, params) } + GetTexLevelParameteriv :: proc "c" (target: u32, level: i32, pname: u32, params: [^]i32) { impl_GetTexLevelParameteriv(target, level, pname, params) } + IsEnabled :: proc "c" (cap: u32) -> bool { return impl_IsEnabled(cap) } + DepthRange :: proc "c" (near, far: f64) { impl_DepthRange(near, far) } + Viewport :: proc "c" (x, y, width, height: i32) { impl_Viewport(x, y, width, height) } // VERSION_1_1 - DrawArrays :: #force_inline proc "c" (mode: u32, first: i32, count: i32) { impl_DrawArrays(mode, first, count) } - DrawElements :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr) { impl_DrawElements(mode, count, type, indices) } - PolygonOffset :: #force_inline proc "c" (factor: f32, units: f32) { impl_PolygonOffset(factor, units) } - CopyTexImage1D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, border: i32) { impl_CopyTexImage1D(target, level, internalformat, x, y, width, border) } - CopyTexImage2D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, height: i32, border: i32) { impl_CopyTexImage2D(target, level, internalformat, x, y, width, height, border) } - CopyTexSubImage1D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32) { impl_CopyTexSubImage1D(target, level, xoffset, x, y, width) } - CopyTexSubImage2D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32) { impl_CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) } - TexSubImage1D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: rawptr) { impl_TexSubImage1D(target, level, xoffset, width, format, type, pixels) } - TexSubImage2D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: rawptr) { impl_TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels) } - BindTexture :: #force_inline proc "c" (target: u32, texture: u32) { impl_BindTexture(target, texture) } - DeleteTextures :: #force_inline proc "c" (n: i32, textures: [^]u32) { impl_DeleteTextures(n, textures) } - GenTextures :: #force_inline proc "c" (n: i32, textures: [^]u32) { impl_GenTextures(n, textures) } - IsTexture :: #force_inline proc "c" (texture: u32) -> bool { return impl_IsTexture(texture) } + DrawArrays :: proc "c" (mode: u32, first: i32, count: i32) { impl_DrawArrays(mode, first, count) } + DrawElements :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr) { impl_DrawElements(mode, count, type, indices) } + PolygonOffset :: proc "c" (factor: f32, units: f32) { impl_PolygonOffset(factor, units) } + CopyTexImage1D :: proc "c" (target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, border: i32) { impl_CopyTexImage1D(target, level, internalformat, x, y, width, border) } + CopyTexImage2D :: proc "c" (target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, height: i32, border: i32) { impl_CopyTexImage2D(target, level, internalformat, x, y, width, height, border) } + CopyTexSubImage1D :: proc "c" (target: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32) { impl_CopyTexSubImage1D(target, level, xoffset, x, y, width) } + CopyTexSubImage2D :: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32) { impl_CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) } + TexSubImage1D :: proc "c" (target: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: rawptr) { impl_TexSubImage1D(target, level, xoffset, width, format, type, pixels) } + TexSubImage2D :: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: rawptr) { impl_TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels) } + BindTexture :: proc "c" (target: u32, texture: u32) { impl_BindTexture(target, texture) } + DeleteTextures :: proc "c" (n: i32, textures: [^]u32) { impl_DeleteTextures(n, textures) } + GenTextures :: proc "c" (n: i32, textures: [^]u32) { impl_GenTextures(n, textures) } + IsTexture :: proc "c" (texture: u32) -> bool { return impl_IsTexture(texture) } // VERSION_1_2 - DrawRangeElements :: #force_inline proc "c" (mode, start, end: u32, count: i32, type: u32, indices: rawptr) { impl_DrawRangeElements(mode, start, end, count, type, indices) } - TexImage3D :: #force_inline proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, pixels: rawptr) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels) } - TexSubImage3D :: #force_inline proc "c" (target: u32, level, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: u32, pixels: rawptr) { impl_TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } - CopyTexSubImage3D :: #force_inline proc "c" (target: u32, level, xoffset, yoffset, zoffset, x, y, width, height: i32) { impl_CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height) } + DrawRangeElements :: proc "c" (mode, start, end: u32, count: i32, type: u32, indices: rawptr) { impl_DrawRangeElements(mode, start, end, count, type, indices) } + TexImage3D :: proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, pixels: rawptr) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels) } + TexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: u32, pixels: rawptr) { impl_TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } + CopyTexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, x, y, width, height: i32) { impl_CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height) } // VERSION_1_3 - ActiveTexture :: #force_inline proc "c" (texture: u32) { impl_ActiveTexture(texture) } - SampleCoverage :: #force_inline proc "c" (value: f32, invert: bool) { impl_SampleCoverage(value, invert) } - CompressedTexImage3D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, width: i32, height: i32, depth: i32, border: i32, imageSize: i32, data: rawptr) { impl_CompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data) } - CompressedTexImage2D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, width: i32, height: i32, border: i32, imageSize: i32, data: rawptr) { impl_CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data) } - CompressedTexImage1D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, width: i32, border: i32, imageSize: i32, data: rawptr) { impl_CompressedTexImage1D(target, level, internalformat, width, border, imageSize, data) } - CompressedTexSubImage3D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) } - CompressedTexSubImage2D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data) } - CompressedTexSubImage1D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data) } - GetCompressedTexImage :: #force_inline proc "c" (target: u32, level: i32, img: rawptr) { impl_GetCompressedTexImage(target, level, img) } + ActiveTexture :: proc "c" (texture: u32) { impl_ActiveTexture(texture) } + SampleCoverage :: proc "c" (value: f32, invert: bool) { impl_SampleCoverage(value, invert) } + CompressedTexImage3D :: proc "c" (target: u32, level: i32, internalformat: u32, width: i32, height: i32, depth: i32, border: i32, imageSize: i32, data: rawptr) { impl_CompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data) } + CompressedTexImage2D :: proc "c" (target: u32, level: i32, internalformat: u32, width: i32, height: i32, border: i32, imageSize: i32, data: rawptr) { impl_CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data) } + CompressedTexImage1D :: proc "c" (target: u32, level: i32, internalformat: u32, width: i32, border: i32, imageSize: i32, data: rawptr) { impl_CompressedTexImage1D(target, level, internalformat, width, border, imageSize, data) } + CompressedTexSubImage3D :: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) } + CompressedTexSubImage2D :: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data) } + CompressedTexSubImage1D :: proc "c" (target: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data) } + GetCompressedTexImage :: proc "c" (target: u32, level: i32, img: rawptr) { impl_GetCompressedTexImage(target, level, img) } // VERSION_1_4 - BlendFuncSeparate :: #force_inline proc "c" (sfactorRGB: u32, dfactorRGB: u32, sfactorAlpha: u32, dfactorAlpha: u32) { impl_BlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha) } - MultiDrawArrays :: #force_inline proc "c" (mode: u32, first: [^]i32, count: [^]i32, drawcount: i32) { impl_MultiDrawArrays(mode, first, count, drawcount) } - MultiDrawElements :: #force_inline proc "c" (mode: u32, count: [^]i32, type: u32, indices: [^]rawptr, drawcount: i32) { impl_MultiDrawElements(mode, count, type, indices, drawcount) } - PointParameterf :: #force_inline proc "c" (pname: u32, param: f32) { impl_PointParameterf(pname, param) } - PointParameterfv :: #force_inline proc "c" (pname: u32, params: [^]f32) { impl_PointParameterfv(pname, params) } - PointParameteri :: #force_inline proc "c" (pname: u32, param: i32) { impl_PointParameteri(pname, param) } - PointParameteriv :: #force_inline proc "c" (pname: u32, params: [^]i32) { impl_PointParameteriv(pname, params) } - BlendColor :: #force_inline proc "c" (red: f32, green: f32, blue: f32, alpha: f32) { impl_BlendColor(red, green, blue, alpha) } - BlendEquation :: #force_inline proc "c" (mode: u32) { impl_BlendEquation(mode) } + BlendFuncSeparate :: proc "c" (sfactorRGB: u32, dfactorRGB: u32, sfactorAlpha: u32, dfactorAlpha: u32) { impl_BlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha) } + MultiDrawArrays :: proc "c" (mode: u32, first: [^]i32, count: [^]i32, drawcount: i32) { impl_MultiDrawArrays(mode, first, count, drawcount) } + MultiDrawElements :: proc "c" (mode: u32, count: [^]i32, type: u32, indices: [^]rawptr, drawcount: i32) { impl_MultiDrawElements(mode, count, type, indices, drawcount) } + PointParameterf :: proc "c" (pname: u32, param: f32) { impl_PointParameterf(pname, param) } + PointParameterfv :: proc "c" (pname: u32, params: [^]f32) { impl_PointParameterfv(pname, params) } + PointParameteri :: proc "c" (pname: u32, param: i32) { impl_PointParameteri(pname, param) } + PointParameteriv :: proc "c" (pname: u32, params: [^]i32) { impl_PointParameteriv(pname, params) } + BlendColor :: proc "c" (red: f32, green: f32, blue: f32, alpha: f32) { impl_BlendColor(red, green, blue, alpha) } + BlendEquation :: proc "c" (mode: u32) { impl_BlendEquation(mode) } // VERSION_1_5 - GenQueries :: #force_inline proc "c" (n: i32, ids: [^]u32) { impl_GenQueries(n, ids) } - DeleteQueries :: #force_inline proc "c" (n: i32, ids: [^]u32) { impl_DeleteQueries(n, ids) } - IsQuery :: #force_inline proc "c" (id: u32) -> bool { ret := impl_IsQuery(id); return ret } - BeginQuery :: #force_inline proc "c" (target: u32, id: u32) { impl_BeginQuery(target, id) } - EndQuery :: #force_inline proc "c" (target: u32) { impl_EndQuery(target) } - GetQueryiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetQueryiv(target, pname, params) } - GetQueryObjectiv :: #force_inline proc "c" (id: u32, pname: u32, params: [^]i32) { impl_GetQueryObjectiv(id, pname, params) } - GetQueryObjectuiv :: #force_inline proc "c" (id: u32, pname: u32, params: [^]u32) { impl_GetQueryObjectuiv(id, pname, params) } - BindBuffer :: #force_inline proc "c" (target: u32, buffer: u32) { impl_BindBuffer(target, buffer) } - DeleteBuffers :: #force_inline proc "c" (n: i32, buffers: [^]u32) { impl_DeleteBuffers(n, buffers) } - GenBuffers :: #force_inline proc "c" (n: i32, buffers: [^]u32) { impl_GenBuffers(n, buffers) } - IsBuffer :: #force_inline proc "c" (buffer: u32) -> bool { ret := impl_IsBuffer(buffer); return ret } - BufferData :: #force_inline proc "c" (target: u32, size: int, data: rawptr, usage: u32) { impl_BufferData(target, size, data, usage) } - BufferSubData :: #force_inline proc "c" (target: u32, offset: int, size: int, data: rawptr) { impl_BufferSubData(target, offset, size, data) } - GetBufferSubData :: #force_inline proc "c" (target: u32, offset: int, size: int, data: rawptr) { impl_GetBufferSubData(target, offset, size, data) } - MapBuffer :: #force_inline proc "c" (target: u32, access: u32) -> rawptr { ret := impl_MapBuffer(target, access); return ret } - UnmapBuffer :: #force_inline proc "c" (target: u32) -> bool { ret := impl_UnmapBuffer(target); return ret } - GetBufferParameteriv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetBufferParameteriv(target, pname, params) } - GetBufferPointerv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]rawptr) { impl_GetBufferPointerv(target, pname, params) } + GenQueries :: proc "c" (n: i32, ids: [^]u32) { impl_GenQueries(n, ids) } + DeleteQueries :: proc "c" (n: i32, ids: [^]u32) { impl_DeleteQueries(n, ids) } + IsQuery :: proc "c" (id: u32) -> bool { ret := impl_IsQuery(id); return ret } + BeginQuery :: proc "c" (target: u32, id: u32) { impl_BeginQuery(target, id) } + EndQuery :: proc "c" (target: u32) { impl_EndQuery(target) } + GetQueryiv :: proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetQueryiv(target, pname, params) } + GetQueryObjectiv :: proc "c" (id: u32, pname: u32, params: [^]i32) { impl_GetQueryObjectiv(id, pname, params) } + GetQueryObjectuiv :: proc "c" (id: u32, pname: u32, params: [^]u32) { impl_GetQueryObjectuiv(id, pname, params) } + BindBuffer :: proc "c" (target: u32, buffer: u32) { impl_BindBuffer(target, buffer) } + DeleteBuffers :: proc "c" (n: i32, buffers: [^]u32) { impl_DeleteBuffers(n, buffers) } + GenBuffers :: proc "c" (n: i32, buffers: [^]u32) { impl_GenBuffers(n, buffers) } + IsBuffer :: proc "c" (buffer: u32) -> bool { ret := impl_IsBuffer(buffer); return ret } + BufferData :: proc "c" (target: u32, size: int, data: rawptr, usage: u32) { impl_BufferData(target, size, data, usage) } + BufferSubData :: proc "c" (target: u32, offset: int, size: int, data: rawptr) { impl_BufferSubData(target, offset, size, data) } + GetBufferSubData :: proc "c" (target: u32, offset: int, size: int, data: rawptr) { impl_GetBufferSubData(target, offset, size, data) } + MapBuffer :: proc "c" (target: u32, access: u32) -> rawptr { ret := impl_MapBuffer(target, access); return ret } + UnmapBuffer :: proc "c" (target: u32) -> bool { ret := impl_UnmapBuffer(target); return ret } + GetBufferParameteriv :: proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetBufferParameteriv(target, pname, params) } + GetBufferPointerv :: proc "c" (target: u32, pname: u32, params: [^]rawptr) { impl_GetBufferPointerv(target, pname, params) } // VERSION_2_0 - BlendEquationSeparate :: #force_inline proc "c" (modeRGB: u32, modeAlpha: u32) { impl_BlendEquationSeparate(modeRGB, modeAlpha) } - DrawBuffers :: #force_inline proc "c" (n: i32, bufs: [^]u32) { impl_DrawBuffers(n, bufs) } - StencilOpSeparate :: #force_inline proc "c" (face: u32, sfail: u32, dpfail: u32, dppass: u32) { impl_StencilOpSeparate(face, sfail, dpfail, dppass) } - StencilFuncSeparate :: #force_inline proc "c" (face: u32, func: u32, ref: i32, mask: u32) { impl_StencilFuncSeparate(face, func, ref, mask) } - StencilMaskSeparate :: #force_inline proc "c" (face: u32, mask: u32) { impl_StencilMaskSeparate(face, mask) } - AttachShader :: #force_inline proc "c" (program: u32, shader: u32) { impl_AttachShader(program, shader) } - BindAttribLocation :: #force_inline proc "c" (program: u32, index: u32, name: cstring) { impl_BindAttribLocation(program, index, name) } - CompileShader :: #force_inline proc "c" (shader: u32) { impl_CompileShader(shader) } - CreateProgram :: #force_inline proc "c" () -> u32 { ret := impl_CreateProgram(); return ret } - CreateShader :: #force_inline proc "c" (type: u32) -> u32 { ret := impl_CreateShader(type); return ret } - DeleteProgram :: #force_inline proc "c" (program: u32) { impl_DeleteProgram(program) } - DeleteShader :: #force_inline proc "c" (shader: u32) { impl_DeleteShader(shader) } - DetachShader :: #force_inline proc "c" (program: u32, shader: u32) { impl_DetachShader(program, shader) } - DisableVertexAttribArray :: #force_inline proc "c" (index: u32) { impl_DisableVertexAttribArray(index) } - EnableVertexAttribArray :: #force_inline proc "c" (index: u32) { impl_EnableVertexAttribArray(index) } - GetActiveAttrib :: #force_inline proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8) { impl_GetActiveAttrib(program, index, bufSize, length, size, type, name) } - GetActiveUniform :: #force_inline proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8) { impl_GetActiveUniform(program, index, bufSize, length, size, type, name) } - GetAttachedShaders :: #force_inline proc "c" (program: u32, maxCount: i32, count: [^]i32, shaders: [^]u32) { impl_GetAttachedShaders(program, maxCount, count, shaders) } - GetAttribLocation :: #force_inline proc "c" (program: u32, name: cstring) -> i32 { ret := impl_GetAttribLocation(program, name); return ret } - GetProgramiv :: #force_inline proc "c" (program: u32, pname: u32, params: [^]i32) { impl_GetProgramiv(program, pname, params) } - GetProgramInfoLog :: #force_inline proc "c" (program: u32, bufSize: i32, length: ^i32, infoLog: [^]u8) { impl_GetProgramInfoLog(program, bufSize, length, infoLog) } - GetShaderiv :: #force_inline proc "c" (shader: u32, pname: u32, params: [^]i32) { impl_GetShaderiv(shader, pname, params) } - GetShaderInfoLog :: #force_inline proc "c" (shader: u32, bufSize: i32, length: ^i32, infoLog: [^]u8) { impl_GetShaderInfoLog(shader, bufSize, length, infoLog) } - GetShaderSource :: #force_inline proc "c" (shader: u32, bufSize: i32, length: ^i32, source: [^]u8) { impl_GetShaderSource(shader, bufSize, length, source) } - GetUniformLocation :: #force_inline proc "c" (program: u32, name: cstring) -> i32 { ret := impl_GetUniformLocation(program, name); return ret } - GetUniformfv :: #force_inline proc "c" (program: u32, location: i32, params: [^]f32) { impl_GetUniformfv(program, location, params) } - GetUniformiv :: #force_inline proc "c" (program: u32, location: i32, params: [^]i32) { impl_GetUniformiv(program, location, params) } - GetVertexAttribdv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]f64) { impl_GetVertexAttribdv(index, pname, params) } - GetVertexAttribfv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]f32) { impl_GetVertexAttribfv(index, pname, params) } - GetVertexAttribiv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]i32) { impl_GetVertexAttribiv(index, pname, params) } - GetVertexAttribPointerv :: #force_inline proc "c" (index: u32, pname: u32, pointer: ^uintptr) { impl_GetVertexAttribPointerv(index, pname, pointer) } - IsProgram :: #force_inline proc "c" (program: u32) -> bool { ret := impl_IsProgram(program); return ret } - IsShader :: #force_inline proc "c" (shader: u32) -> bool { ret := impl_IsShader(shader); return ret } - LinkProgram :: #force_inline proc "c" (program: u32) { impl_LinkProgram(program) } - ShaderSource :: #force_inline proc "c" (shader: u32, count: i32, string: [^]cstring, length: [^]i32) { impl_ShaderSource(shader, count, string, length) } - UseProgram :: #force_inline proc "c" (program: u32) { impl_UseProgram(program) } - Uniform1f :: #force_inline proc "c" (location: i32, v0: f32) { impl_Uniform1f(location, v0) } - Uniform2f :: #force_inline proc "c" (location: i32, v0: f32, v1: f32) { impl_Uniform2f(location, v0, v1) } - Uniform3f :: #force_inline proc "c" (location: i32, v0: f32, v1: f32, v2: f32) { impl_Uniform3f(location, v0, v1, v2) } - Uniform4f :: #force_inline proc "c" (location: i32, v0: f32, v1: f32, v2: f32, v3: f32) { impl_Uniform4f(location, v0, v1, v2, v3) } - Uniform1i :: #force_inline proc "c" (location: i32, v0: i32) { impl_Uniform1i(location, v0) } - Uniform2i :: #force_inline proc "c" (location: i32, v0: i32, v1: i32) { impl_Uniform2i(location, v0, v1) } - Uniform3i :: #force_inline proc "c" (location: i32, v0: i32, v1: i32, v2: i32) { impl_Uniform3i(location, v0, v1, v2) } - Uniform4i :: #force_inline proc "c" (location: i32, v0: i32, v1: i32, v2: i32, v3: i32) { impl_Uniform4i(location, v0, v1, v2, v3) } - Uniform1fv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f32) { impl_Uniform1fv(location, count, value) } - Uniform2fv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f32) { impl_Uniform2fv(location, count, value) } - Uniform3fv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f32) { impl_Uniform3fv(location, count, value) } - Uniform4fv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f32) { impl_Uniform4fv(location, count, value) } - Uniform1iv :: #force_inline proc "c" (location: i32, count: i32, value: [^]i32) { impl_Uniform1iv(location, count, value) } - Uniform2iv :: #force_inline proc "c" (location: i32, count: i32, value: [^]i32) { impl_Uniform2iv(location, count, value) } - Uniform3iv :: #force_inline proc "c" (location: i32, count: i32, value: [^]i32) { impl_Uniform3iv(location, count, value) } - Uniform4iv :: #force_inline proc "c" (location: i32, count: i32, value: [^]i32) { impl_Uniform4iv(location, count, value) } - UniformMatrix2fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix2fv(location, count, transpose, value) } - UniformMatrix3fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix3fv(location, count, transpose, value) } - UniformMatrix4fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix4fv(location, count, transpose, value) } - ValidateProgram :: #force_inline proc "c" (program: u32) { impl_ValidateProgram(program) } - VertexAttrib1d :: #force_inline proc "c" (index: u32, x: f64) { impl_VertexAttrib1d(index, x) } - VertexAttrib1dv :: #force_inline proc "c" (index: u32, v: ^f64) { impl_VertexAttrib1dv(index, v) } - VertexAttrib1f :: #force_inline proc "c" (index: u32, x: f32) { impl_VertexAttrib1f(index, x) } - VertexAttrib1fv :: #force_inline proc "c" (index: u32, v: ^f32) { impl_VertexAttrib1fv(index, v) } - VertexAttrib1s :: #force_inline proc "c" (index: u32, x: i16) { impl_VertexAttrib1s(index, x) } - VertexAttrib1sv :: #force_inline proc "c" (index: u32, v: ^i16) { impl_VertexAttrib1sv(index, v) } - VertexAttrib2d :: #force_inline proc "c" (index: u32, x: f64, y: f64) { impl_VertexAttrib2d(index, x, y) } - VertexAttrib2dv :: #force_inline proc "c" (index: u32, v: ^[2]f64) { impl_VertexAttrib2dv(index, v) } - VertexAttrib2f :: #force_inline proc "c" (index: u32, x: f32, y: f32) { impl_VertexAttrib2f(index, x, y) } - VertexAttrib2fv :: #force_inline proc "c" (index: u32, v: ^[2]f32) { impl_VertexAttrib2fv(index, v) } - VertexAttrib2s :: #force_inline proc "c" (index: u32, x: i16, y: i16) { impl_VertexAttrib2s(index, x, y) } - VertexAttrib2sv :: #force_inline proc "c" (index: u32, v: ^[2]i16) { impl_VertexAttrib2sv(index, v) } - VertexAttrib3d :: #force_inline proc "c" (index: u32, x: f64, y: f64, z: f64) { impl_VertexAttrib3d(index, x, y, z) } - VertexAttrib3dv :: #force_inline proc "c" (index: u32, v: ^[3]f64) { impl_VertexAttrib3dv(index, v) } - VertexAttrib3f :: #force_inline proc "c" (index: u32, x: f32, y: f32, z: f32) { impl_VertexAttrib3f(index, x, y, z) } - VertexAttrib3fv :: #force_inline proc "c" (index: u32, v: ^[3]f32) { impl_VertexAttrib3fv(index, v) } - VertexAttrib3s :: #force_inline proc "c" (index: u32, x: i16, y: i16, z: i16) { impl_VertexAttrib3s(index, x, y, z) } - VertexAttrib3sv :: #force_inline proc "c" (index: u32, v: ^[3]i16) { impl_VertexAttrib3sv(index, v) } - VertexAttrib4Nbv :: #force_inline proc "c" (index: u32, v: ^[4]i8) { impl_VertexAttrib4Nbv(index, v) } - VertexAttrib4Niv :: #force_inline proc "c" (index: u32, v: ^[4]i32) { impl_VertexAttrib4Niv(index, v) } - VertexAttrib4Nsv :: #force_inline proc "c" (index: u32, v: ^[4]i16) { impl_VertexAttrib4Nsv(index, v) } - VertexAttrib4Nub :: #force_inline proc "c" (index: u32, x: u8, y: u8, z: u8, w: u8) { impl_VertexAttrib4Nub(index, x, y, z, w) } - VertexAttrib4Nubv :: #force_inline proc "c" (index: u32, v: ^[4]u8) { impl_VertexAttrib4Nubv(index, v) } - VertexAttrib4Nuiv :: #force_inline proc "c" (index: u32, v: ^[4]u32) { impl_VertexAttrib4Nuiv(index, v) } - VertexAttrib4Nusv :: #force_inline proc "c" (index: u32, v: ^[4]u16) { impl_VertexAttrib4Nusv(index, v) } - VertexAttrib4bv :: #force_inline proc "c" (index: u32, v: ^[4]i8) { impl_VertexAttrib4bv(index, v) } - VertexAttrib4d :: #force_inline proc "c" (index: u32, x: f64, y: f64, z: f64, w: f64) { impl_VertexAttrib4d(index, x, y, z, w) } - VertexAttrib4dv :: #force_inline proc "c" (index: u32, v: ^[4]f64) { impl_VertexAttrib4dv(index, v) } - VertexAttrib4f :: #force_inline proc "c" (index: u32, x: f32, y: f32, z: f32, w: f32) { impl_VertexAttrib4f(index, x, y, z, w) } - VertexAttrib4fv :: #force_inline proc "c" (index: u32, v: ^[4]f32) { impl_VertexAttrib4fv(index, v) } - VertexAttrib4iv :: #force_inline proc "c" (index: u32, v: ^[4]i32) { impl_VertexAttrib4iv(index, v) } - VertexAttrib4s :: #force_inline proc "c" (index: u32, x: i16, y: i16, z: i16, w: i16) { impl_VertexAttrib4s(index, x, y, z, w) } - VertexAttrib4sv :: #force_inline proc "c" (index: u32, v: ^[4]i16) { impl_VertexAttrib4sv(index, v) } - VertexAttrib4ubv :: #force_inline proc "c" (index: u32, v: ^[4]u8) { impl_VertexAttrib4ubv(index, v) } - VertexAttrib4uiv :: #force_inline proc "c" (index: u32, v: ^[4]u32) { impl_VertexAttrib4uiv(index, v) } - VertexAttrib4usv :: #force_inline proc "c" (index: u32, v: ^[4]u16) { impl_VertexAttrib4usv(index, v) } - VertexAttribPointer :: #force_inline proc "c" (index: u32, size: i32, type: u32, normalized: bool, stride: i32, pointer: uintptr) { impl_VertexAttribPointer(index, size, type, normalized, stride, pointer) } + BlendEquationSeparate :: proc "c" (modeRGB: u32, modeAlpha: u32) { impl_BlendEquationSeparate(modeRGB, modeAlpha) } + DrawBuffers :: proc "c" (n: i32, bufs: [^]u32) { impl_DrawBuffers(n, bufs) } + StencilOpSeparate :: proc "c" (face: u32, sfail: u32, dpfail: u32, dppass: u32) { impl_StencilOpSeparate(face, sfail, dpfail, dppass) } + StencilFuncSeparate :: proc "c" (face: u32, func: u32, ref: i32, mask: u32) { impl_StencilFuncSeparate(face, func, ref, mask) } + StencilMaskSeparate :: proc "c" (face: u32, mask: u32) { impl_StencilMaskSeparate(face, mask) } + AttachShader :: proc "c" (program: u32, shader: u32) { impl_AttachShader(program, shader) } + BindAttribLocation :: proc "c" (program: u32, index: u32, name: cstring) { impl_BindAttribLocation(program, index, name) } + CompileShader :: proc "c" (shader: u32) { impl_CompileShader(shader) } + CreateProgram :: proc "c" () -> u32 { ret := impl_CreateProgram(); return ret } + CreateShader :: proc "c" (type: u32) -> u32 { ret := impl_CreateShader(type); return ret } + DeleteProgram :: proc "c" (program: u32) { impl_DeleteProgram(program) } + DeleteShader :: proc "c" (shader: u32) { impl_DeleteShader(shader) } + DetachShader :: proc "c" (program: u32, shader: u32) { impl_DetachShader(program, shader) } + DisableVertexAttribArray :: proc "c" (index: u32) { impl_DisableVertexAttribArray(index) } + EnableVertexAttribArray :: proc "c" (index: u32) { impl_EnableVertexAttribArray(index) } + GetActiveAttrib :: proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8) { impl_GetActiveAttrib(program, index, bufSize, length, size, type, name) } + GetActiveUniform :: proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8) { impl_GetActiveUniform(program, index, bufSize, length, size, type, name) } + GetAttachedShaders :: proc "c" (program: u32, maxCount: i32, count: [^]i32, shaders: [^]u32) { impl_GetAttachedShaders(program, maxCount, count, shaders) } + GetAttribLocation :: proc "c" (program: u32, name: cstring) -> i32 { ret := impl_GetAttribLocation(program, name); return ret } + GetProgramiv :: proc "c" (program: u32, pname: u32, params: [^]i32) { impl_GetProgramiv(program, pname, params) } + GetProgramInfoLog :: proc "c" (program: u32, bufSize: i32, length: ^i32, infoLog: [^]u8) { impl_GetProgramInfoLog(program, bufSize, length, infoLog) } + GetShaderiv :: proc "c" (shader: u32, pname: u32, params: [^]i32) { impl_GetShaderiv(shader, pname, params) } + GetShaderInfoLog :: proc "c" (shader: u32, bufSize: i32, length: ^i32, infoLog: [^]u8) { impl_GetShaderInfoLog(shader, bufSize, length, infoLog) } + GetShaderSource :: proc "c" (shader: u32, bufSize: i32, length: ^i32, source: [^]u8) { impl_GetShaderSource(shader, bufSize, length, source) } + GetUniformLocation :: proc "c" (program: u32, name: cstring) -> i32 { ret := impl_GetUniformLocation(program, name); return ret } + GetUniformfv :: proc "c" (program: u32, location: i32, params: [^]f32) { impl_GetUniformfv(program, location, params) } + GetUniformiv :: proc "c" (program: u32, location: i32, params: [^]i32) { impl_GetUniformiv(program, location, params) } + GetVertexAttribdv :: proc "c" (index: u32, pname: u32, params: [^]f64) { impl_GetVertexAttribdv(index, pname, params) } + GetVertexAttribfv :: proc "c" (index: u32, pname: u32, params: [^]f32) { impl_GetVertexAttribfv(index, pname, params) } + GetVertexAttribiv :: proc "c" (index: u32, pname: u32, params: [^]i32) { impl_GetVertexAttribiv(index, pname, params) } + GetVertexAttribPointerv :: proc "c" (index: u32, pname: u32, pointer: ^uintptr) { impl_GetVertexAttribPointerv(index, pname, pointer) } + IsProgram :: proc "c" (program: u32) -> bool { ret := impl_IsProgram(program); return ret } + IsShader :: proc "c" (shader: u32) -> bool { ret := impl_IsShader(shader); return ret } + LinkProgram :: proc "c" (program: u32) { impl_LinkProgram(program) } + ShaderSource :: proc "c" (shader: u32, count: i32, string: [^]cstring, length: [^]i32) { impl_ShaderSource(shader, count, string, length) } + UseProgram :: proc "c" (program: u32) { impl_UseProgram(program) } + Uniform1f :: proc "c" (location: i32, v0: f32) { impl_Uniform1f(location, v0) } + Uniform2f :: proc "c" (location: i32, v0: f32, v1: f32) { impl_Uniform2f(location, v0, v1) } + Uniform3f :: proc "c" (location: i32, v0: f32, v1: f32, v2: f32) { impl_Uniform3f(location, v0, v1, v2) } + Uniform4f :: proc "c" (location: i32, v0: f32, v1: f32, v2: f32, v3: f32) { impl_Uniform4f(location, v0, v1, v2, v3) } + Uniform1i :: proc "c" (location: i32, v0: i32) { impl_Uniform1i(location, v0) } + Uniform2i :: proc "c" (location: i32, v0: i32, v1: i32) { impl_Uniform2i(location, v0, v1) } + Uniform3i :: proc "c" (location: i32, v0: i32, v1: i32, v2: i32) { impl_Uniform3i(location, v0, v1, v2) } + Uniform4i :: proc "c" (location: i32, v0: i32, v1: i32, v2: i32, v3: i32) { impl_Uniform4i(location, v0, v1, v2, v3) } + Uniform1fv :: proc "c" (location: i32, count: i32, value: [^]f32) { impl_Uniform1fv(location, count, value) } + Uniform2fv :: proc "c" (location: i32, count: i32, value: [^]f32) { impl_Uniform2fv(location, count, value) } + Uniform3fv :: proc "c" (location: i32, count: i32, value: [^]f32) { impl_Uniform3fv(location, count, value) } + Uniform4fv :: proc "c" (location: i32, count: i32, value: [^]f32) { impl_Uniform4fv(location, count, value) } + Uniform1iv :: proc "c" (location: i32, count: i32, value: [^]i32) { impl_Uniform1iv(location, count, value) } + Uniform2iv :: proc "c" (location: i32, count: i32, value: [^]i32) { impl_Uniform2iv(location, count, value) } + Uniform3iv :: proc "c" (location: i32, count: i32, value: [^]i32) { impl_Uniform3iv(location, count, value) } + Uniform4iv :: proc "c" (location: i32, count: i32, value: [^]i32) { impl_Uniform4iv(location, count, value) } + UniformMatrix2fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix2fv(location, count, transpose, value) } + UniformMatrix3fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix3fv(location, count, transpose, value) } + UniformMatrix4fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix4fv(location, count, transpose, value) } + ValidateProgram :: proc "c" (program: u32) { impl_ValidateProgram(program) } + VertexAttrib1d :: proc "c" (index: u32, x: f64) { impl_VertexAttrib1d(index, x) } + VertexAttrib1dv :: proc "c" (index: u32, v: ^f64) { impl_VertexAttrib1dv(index, v) } + VertexAttrib1f :: proc "c" (index: u32, x: f32) { impl_VertexAttrib1f(index, x) } + VertexAttrib1fv :: proc "c" (index: u32, v: ^f32) { impl_VertexAttrib1fv(index, v) } + VertexAttrib1s :: proc "c" (index: u32, x: i16) { impl_VertexAttrib1s(index, x) } + VertexAttrib1sv :: proc "c" (index: u32, v: ^i16) { impl_VertexAttrib1sv(index, v) } + VertexAttrib2d :: proc "c" (index: u32, x: f64, y: f64) { impl_VertexAttrib2d(index, x, y) } + VertexAttrib2dv :: proc "c" (index: u32, v: ^[2]f64) { impl_VertexAttrib2dv(index, v) } + VertexAttrib2f :: proc "c" (index: u32, x: f32, y: f32) { impl_VertexAttrib2f(index, x, y) } + VertexAttrib2fv :: proc "c" (index: u32, v: ^[2]f32) { impl_VertexAttrib2fv(index, v) } + VertexAttrib2s :: proc "c" (index: u32, x: i16, y: i16) { impl_VertexAttrib2s(index, x, y) } + VertexAttrib2sv :: proc "c" (index: u32, v: ^[2]i16) { impl_VertexAttrib2sv(index, v) } + VertexAttrib3d :: proc "c" (index: u32, x: f64, y: f64, z: f64) { impl_VertexAttrib3d(index, x, y, z) } + VertexAttrib3dv :: proc "c" (index: u32, v: ^[3]f64) { impl_VertexAttrib3dv(index, v) } + VertexAttrib3f :: proc "c" (index: u32, x: f32, y: f32, z: f32) { impl_VertexAttrib3f(index, x, y, z) } + VertexAttrib3fv :: proc "c" (index: u32, v: ^[3]f32) { impl_VertexAttrib3fv(index, v) } + VertexAttrib3s :: proc "c" (index: u32, x: i16, y: i16, z: i16) { impl_VertexAttrib3s(index, x, y, z) } + VertexAttrib3sv :: proc "c" (index: u32, v: ^[3]i16) { impl_VertexAttrib3sv(index, v) } + VertexAttrib4Nbv :: proc "c" (index: u32, v: ^[4]i8) { impl_VertexAttrib4Nbv(index, v) } + VertexAttrib4Niv :: proc "c" (index: u32, v: ^[4]i32) { impl_VertexAttrib4Niv(index, v) } + VertexAttrib4Nsv :: proc "c" (index: u32, v: ^[4]i16) { impl_VertexAttrib4Nsv(index, v) } + VertexAttrib4Nub :: proc "c" (index: u32, x: u8, y: u8, z: u8, w: u8) { impl_VertexAttrib4Nub(index, x, y, z, w) } + VertexAttrib4Nubv :: proc "c" (index: u32, v: ^[4]u8) { impl_VertexAttrib4Nubv(index, v) } + VertexAttrib4Nuiv :: proc "c" (index: u32, v: ^[4]u32) { impl_VertexAttrib4Nuiv(index, v) } + VertexAttrib4Nusv :: proc "c" (index: u32, v: ^[4]u16) { impl_VertexAttrib4Nusv(index, v) } + VertexAttrib4bv :: proc "c" (index: u32, v: ^[4]i8) { impl_VertexAttrib4bv(index, v) } + VertexAttrib4d :: proc "c" (index: u32, x: f64, y: f64, z: f64, w: f64) { impl_VertexAttrib4d(index, x, y, z, w) } + VertexAttrib4dv :: proc "c" (index: u32, v: ^[4]f64) { impl_VertexAttrib4dv(index, v) } + VertexAttrib4f :: proc "c" (index: u32, x: f32, y: f32, z: f32, w: f32) { impl_VertexAttrib4f(index, x, y, z, w) } + VertexAttrib4fv :: proc "c" (index: u32, v: ^[4]f32) { impl_VertexAttrib4fv(index, v) } + VertexAttrib4iv :: proc "c" (index: u32, v: ^[4]i32) { impl_VertexAttrib4iv(index, v) } + VertexAttrib4s :: proc "c" (index: u32, x: i16, y: i16, z: i16, w: i16) { impl_VertexAttrib4s(index, x, y, z, w) } + VertexAttrib4sv :: proc "c" (index: u32, v: ^[4]i16) { impl_VertexAttrib4sv(index, v) } + VertexAttrib4ubv :: proc "c" (index: u32, v: ^[4]u8) { impl_VertexAttrib4ubv(index, v) } + VertexAttrib4uiv :: proc "c" (index: u32, v: ^[4]u32) { impl_VertexAttrib4uiv(index, v) } + VertexAttrib4usv :: proc "c" (index: u32, v: ^[4]u16) { impl_VertexAttrib4usv(index, v) } + VertexAttribPointer :: proc "c" (index: u32, size: i32, type: u32, normalized: bool, stride: i32, pointer: uintptr) { impl_VertexAttribPointer(index, size, type, normalized, stride, pointer) } // VERSION_2_1 - UniformMatrix2x3fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix2x3fv(location, count, transpose, value) } - UniformMatrix3x2fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix3x2fv(location, count, transpose, value) } - UniformMatrix2x4fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix2x4fv(location, count, transpose, value) } - UniformMatrix4x2fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix4x2fv(location, count, transpose, value) } - UniformMatrix3x4fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix3x4fv(location, count, transpose, value) } - UniformMatrix4x3fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix4x3fv(location, count, transpose, value) } + UniformMatrix2x3fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix2x3fv(location, count, transpose, value) } + UniformMatrix3x2fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix3x2fv(location, count, transpose, value) } + UniformMatrix2x4fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix2x4fv(location, count, transpose, value) } + UniformMatrix4x2fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix4x2fv(location, count, transpose, value) } + UniformMatrix3x4fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix3x4fv(location, count, transpose, value) } + UniformMatrix4x3fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32) { impl_UniformMatrix4x3fv(location, count, transpose, value) } // VERSION_3_0 - ColorMaski :: #force_inline proc "c" (index: u32, r: bool, g: bool, b: bool, a: bool) { impl_ColorMaski(index, r, g, b, a) } - GetBooleani_v :: #force_inline proc "c" (target: u32, index: u32, data: ^bool) { impl_GetBooleani_v(target, index, data) } - GetIntegeri_v :: #force_inline proc "c" (target: u32, index: u32, data: ^i32) { impl_GetIntegeri_v(target, index, data) } - Enablei :: #force_inline proc "c" (target: u32, index: u32) { impl_Enablei(target, index) } - Disablei :: #force_inline proc "c" (target: u32, index: u32) { impl_Disablei(target, index) } - IsEnabledi :: #force_inline proc "c" (target: u32, index: u32) -> bool { ret := impl_IsEnabledi(target, index); return ret } - BeginTransformFeedback :: #force_inline proc "c" (primitiveMode: u32) { impl_BeginTransformFeedback(primitiveMode) } - EndTransformFeedback :: #force_inline proc "c" () { impl_EndTransformFeedback() } - BindBufferRange :: #force_inline proc "c" (target: u32, index: u32, buffer: u32, offset: int, size: int) { impl_BindBufferRange(target, index, buffer, offset, size) } - BindBufferBase :: #force_inline proc "c" (target: u32, index: u32, buffer: u32) { impl_BindBufferBase(target, index, buffer) } - TransformFeedbackVaryings :: #force_inline proc "c" (program: u32, count: i32, varyings: [^]cstring, bufferMode: u32) { impl_TransformFeedbackVaryings(program, count, varyings, bufferMode) } - GetTransformFeedbackVarying :: #force_inline proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8) { impl_GetTransformFeedbackVarying(program, index, bufSize, length, size, type, name) } - ClampColor :: #force_inline proc "c" (target: u32, clamp: u32) { impl_ClampColor(target, clamp) } - BeginConditionalRender :: #force_inline proc "c" (id: u32, mode: u32) { impl_BeginConditionalRender(id, mode) } - EndConditionalRender :: #force_inline proc "c" () { impl_EndConditionalRender() } - VertexAttribIPointer :: #force_inline proc "c" (index: u32, size: i32, type: u32, stride: i32, pointer: uintptr) { impl_VertexAttribIPointer(index, size, type, stride, pointer) } - GetVertexAttribIiv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]i32) { impl_GetVertexAttribIiv(index, pname, params) } - GetVertexAttribIuiv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]u32) { impl_GetVertexAttribIuiv(index, pname, params) } - VertexAttribI1i :: #force_inline proc "c" (index: u32, x: i32) { impl_VertexAttribI1i(index, x) } - VertexAttribI2i :: #force_inline proc "c" (index: u32, x: i32, y: i32) { impl_VertexAttribI2i(index, x, y) } - VertexAttribI3i :: #force_inline proc "c" (index: u32, x: i32, y: i32, z: i32) { impl_VertexAttribI3i(index, x, y, z) } - VertexAttribI4i :: #force_inline proc "c" (index: u32, x: i32, y: i32, z: i32, w: i32) { impl_VertexAttribI4i(index, x, y, z, w) } - VertexAttribI1ui :: #force_inline proc "c" (index: u32, x: u32) { impl_VertexAttribI1ui(index, x) } - VertexAttribI2ui :: #force_inline proc "c" (index: u32, x: u32, y: u32) { impl_VertexAttribI2ui(index, x, y) } - VertexAttribI3ui :: #force_inline proc "c" (index: u32, x: u32, y: u32, z: u32) { impl_VertexAttribI3ui(index, x, y, z) } - VertexAttribI4ui :: #force_inline proc "c" (index: u32, x: u32, y: u32, z: u32, w: u32) { impl_VertexAttribI4ui(index, x, y, z, w) } - VertexAttribI1iv :: #force_inline proc "c" (index: u32, v: [^]i32) { impl_VertexAttribI1iv(index, v) } - VertexAttribI2iv :: #force_inline proc "c" (index: u32, v: [^]i32) { impl_VertexAttribI2iv(index, v) } - VertexAttribI3iv :: #force_inline proc "c" (index: u32, v: [^]i32) { impl_VertexAttribI3iv(index, v) } - VertexAttribI4iv :: #force_inline proc "c" (index: u32, v: [^]i32) { impl_VertexAttribI4iv(index, v) } - VertexAttribI1uiv :: #force_inline proc "c" (index: u32, v: [^]u32) { impl_VertexAttribI1uiv(index, v) } - VertexAttribI2uiv :: #force_inline proc "c" (index: u32, v: [^]u32) { impl_VertexAttribI2uiv(index, v) } - VertexAttribI3uiv :: #force_inline proc "c" (index: u32, v: [^]u32) { impl_VertexAttribI3uiv(index, v) } - VertexAttribI4uiv :: #force_inline proc "c" (index: u32, v: [^]u32) { impl_VertexAttribI4uiv(index, v) } - VertexAttribI4bv :: #force_inline proc "c" (index: u32, v: [^]i8) { impl_VertexAttribI4bv(index, v) } - VertexAttribI4sv :: #force_inline proc "c" (index: u32, v: [^]i16) { impl_VertexAttribI4sv(index, v) } - VertexAttribI4ubv :: #force_inline proc "c" (index: u32, v: [^]u8) { impl_VertexAttribI4ubv(index, v) } - VertexAttribI4usv :: #force_inline proc "c" (index: u32, v: [^]u16) { impl_VertexAttribI4usv(index, v) } - GetUniformuiv :: #force_inline proc "c" (program: u32, location: i32, params: [^]u32) { impl_GetUniformuiv(program, location, params) } - BindFragDataLocation :: #force_inline proc "c" (program: u32, color: u32, name: cstring) { impl_BindFragDataLocation(program, color, name) } - GetFragDataLocation :: #force_inline proc "c" (program: u32, name: cstring) -> i32 { ret := impl_GetFragDataLocation(program, name); return ret } - Uniform1ui :: #force_inline proc "c" (location: i32, v0: u32) { impl_Uniform1ui(location, v0) } - Uniform2ui :: #force_inline proc "c" (location: i32, v0: u32, v1: u32) { impl_Uniform2ui(location, v0, v1) } - Uniform3ui :: #force_inline proc "c" (location: i32, v0: u32, v1: u32, v2: u32) { impl_Uniform3ui(location, v0, v1, v2) } - Uniform4ui :: #force_inline proc "c" (location: i32, v0: u32, v1: u32, v2: u32, v3: u32) { impl_Uniform4ui(location, v0, v1, v2, v3) } - Uniform1uiv :: #force_inline proc "c" (location: i32, count: i32, value: [^]u32) { impl_Uniform1uiv(location, count, value) } - Uniform2uiv :: #force_inline proc "c" (location: i32, count: i32, value: [^]u32) { impl_Uniform2uiv(location, count, value) } - Uniform3uiv :: #force_inline proc "c" (location: i32, count: i32, value: [^]u32) { impl_Uniform3uiv(location, count, value) } - Uniform4uiv :: #force_inline proc "c" (location: i32, count: i32, value: [^]u32) { impl_Uniform4uiv(location, count, value) } - TexParameterIiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32) { impl_TexParameterIiv(target, pname, params) } - TexParameterIuiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]u32) { impl_TexParameterIuiv(target, pname, params) } - GetTexParameterIiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetTexParameterIiv(target, pname, params) } - GetTexParameterIuiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]u32) { impl_GetTexParameterIuiv(target, pname, params) } - ClearBufferiv :: #force_inline proc "c" (buffer: u32, drawbuffer: i32, value: ^i32) { impl_ClearBufferiv(buffer, drawbuffer, value) } - ClearBufferuiv :: #force_inline proc "c" (buffer: u32, drawbuffer: i32, value: ^u32) { impl_ClearBufferuiv(buffer, drawbuffer, value) } - ClearBufferfv :: #force_inline proc "c" (buffer: u32, drawbuffer: i32, value: ^f32) { impl_ClearBufferfv(buffer, drawbuffer, value) } - ClearBufferfi :: #force_inline proc "c" (buffer: u32, drawbuffer: i32, depth: f32, stencil: i32) -> rawptr { ret := impl_ClearBufferfi(buffer, drawbuffer, depth, stencil); return ret } - GetStringi :: #force_inline proc "c" (name: u32, index: u32) -> cstring { ret := impl_GetStringi(name, index); return ret } - IsRenderbuffer :: #force_inline proc "c" (renderbuffer: u32) -> bool { ret := impl_IsRenderbuffer(renderbuffer); return ret } - BindRenderbuffer :: #force_inline proc "c" (target: u32, renderbuffer: u32) { impl_BindRenderbuffer(target, renderbuffer) } - DeleteRenderbuffers :: #force_inline proc "c" (n: i32, renderbuffers: [^]u32) { impl_DeleteRenderbuffers(n, renderbuffers) } - GenRenderbuffers :: #force_inline proc "c" (n: i32, renderbuffers: [^]u32) { impl_GenRenderbuffers(n, renderbuffers) } - RenderbufferStorage :: #force_inline proc "c" (target: u32, internalformat: u32, width: i32, height: i32) { impl_RenderbufferStorage(target, internalformat, width, height) } - GetRenderbufferParameteriv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetRenderbufferParameteriv(target, pname, params) } - IsFramebuffer :: #force_inline proc "c" (framebuffer: u32) -> bool { ret := impl_IsFramebuffer(framebuffer); return ret } - BindFramebuffer :: #force_inline proc "c" (target: u32, framebuffer: u32) { impl_BindFramebuffer(target, framebuffer) } - DeleteFramebuffers :: #force_inline proc "c" (n: i32, framebuffers: [^]u32) { impl_DeleteFramebuffers(n, framebuffers) } - GenFramebuffers :: #force_inline proc "c" (n: i32, framebuffers: [^]u32) { impl_GenFramebuffers(n, framebuffers) } - CheckFramebufferStatus :: #force_inline proc "c" (target: u32) -> u32 { ret := impl_CheckFramebufferStatus(target); return ret } - FramebufferTexture1D :: #force_inline proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32) { impl_FramebufferTexture1D(target, attachment, textarget, texture, level) } - FramebufferTexture2D :: #force_inline proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32) { impl_FramebufferTexture2D(target, attachment, textarget, texture, level) } - FramebufferTexture3D :: #force_inline proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32, zoffset: i32) { impl_FramebufferTexture3D(target, attachment, textarget, texture, level, zoffset) } - FramebufferRenderbuffer :: #force_inline proc "c" (target: u32, attachment: u32, renderbuffertarget: u32, renderbuffer: u32) { impl_FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer) } - GetFramebufferAttachmentParameteriv :: #force_inline proc "c" (target: u32, attachment: u32, pname: u32, params: [^]i32) { impl_GetFramebufferAttachmentParameteriv(target, attachment, pname, params) } - GenerateMipmap :: #force_inline proc "c" (target: u32) { impl_GenerateMipmap(target) } - BlitFramebuffer :: #force_inline proc "c" (srcX0: i32, srcY0: i32, srcX1: i32, srcY1: i32, dstX0: i32, dstY0: i32, dstX1: i32, dstY1: i32, mask: u32, filter: u32) { impl_BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) } - RenderbufferStorageMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32) { impl_RenderbufferStorageMultisample(target, samples, internalformat, width, height) } - FramebufferTextureLayer :: #force_inline proc "c" (target: u32, attachment: u32, texture: u32, level: i32, layer: i32) { impl_FramebufferTextureLayer(target, attachment, texture, level, layer) } - MapBufferRange :: #force_inline proc "c" (target: u32, offset: int, length: int, access: u32) -> rawptr { ret := impl_MapBufferRange(target, offset, length, access); return ret } - FlushMappedBufferRange :: #force_inline proc "c" (target: u32, offset: int, length: int) { impl_FlushMappedBufferRange(target, offset, length) } - BindVertexArray :: #force_inline proc "c" (array: u32) { impl_BindVertexArray(array) } - DeleteVertexArrays :: #force_inline proc "c" (n: i32, arrays: [^]u32) { impl_DeleteVertexArrays(n, arrays) } - GenVertexArrays :: #force_inline proc "c" (n: i32, arrays: [^]u32) { impl_GenVertexArrays(n, arrays) } - IsVertexArray :: #force_inline proc "c" (array: u32) -> bool { ret := impl_IsVertexArray(array); return ret } + ColorMaski :: proc "c" (index: u32, r: bool, g: bool, b: bool, a: bool) { impl_ColorMaski(index, r, g, b, a) } + GetBooleani_v :: proc "c" (target: u32, index: u32, data: ^bool) { impl_GetBooleani_v(target, index, data) } + GetIntegeri_v :: proc "c" (target: u32, index: u32, data: ^i32) { impl_GetIntegeri_v(target, index, data) } + Enablei :: proc "c" (target: u32, index: u32) { impl_Enablei(target, index) } + Disablei :: proc "c" (target: u32, index: u32) { impl_Disablei(target, index) } + IsEnabledi :: proc "c" (target: u32, index: u32) -> bool { ret := impl_IsEnabledi(target, index); return ret } + BeginTransformFeedback :: proc "c" (primitiveMode: u32) { impl_BeginTransformFeedback(primitiveMode) } + EndTransformFeedback :: proc "c" () { impl_EndTransformFeedback() } + BindBufferRange :: proc "c" (target: u32, index: u32, buffer: u32, offset: int, size: int) { impl_BindBufferRange(target, index, buffer, offset, size) } + BindBufferBase :: proc "c" (target: u32, index: u32, buffer: u32) { impl_BindBufferBase(target, index, buffer) } + TransformFeedbackVaryings :: proc "c" (program: u32, count: i32, varyings: [^]cstring, bufferMode: u32) { impl_TransformFeedbackVaryings(program, count, varyings, bufferMode) } + GetTransformFeedbackVarying :: proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8) { impl_GetTransformFeedbackVarying(program, index, bufSize, length, size, type, name) } + ClampColor :: proc "c" (target: u32, clamp: u32) { impl_ClampColor(target, clamp) } + BeginConditionalRender :: proc "c" (id: u32, mode: u32) { impl_BeginConditionalRender(id, mode) } + EndConditionalRender :: proc "c" () { impl_EndConditionalRender() } + VertexAttribIPointer :: proc "c" (index: u32, size: i32, type: u32, stride: i32, pointer: uintptr) { impl_VertexAttribIPointer(index, size, type, stride, pointer) } + GetVertexAttribIiv :: proc "c" (index: u32, pname: u32, params: [^]i32) { impl_GetVertexAttribIiv(index, pname, params) } + GetVertexAttribIuiv :: proc "c" (index: u32, pname: u32, params: [^]u32) { impl_GetVertexAttribIuiv(index, pname, params) } + VertexAttribI1i :: proc "c" (index: u32, x: i32) { impl_VertexAttribI1i(index, x) } + VertexAttribI2i :: proc "c" (index: u32, x: i32, y: i32) { impl_VertexAttribI2i(index, x, y) } + VertexAttribI3i :: proc "c" (index: u32, x: i32, y: i32, z: i32) { impl_VertexAttribI3i(index, x, y, z) } + VertexAttribI4i :: proc "c" (index: u32, x: i32, y: i32, z: i32, w: i32) { impl_VertexAttribI4i(index, x, y, z, w) } + VertexAttribI1ui :: proc "c" (index: u32, x: u32) { impl_VertexAttribI1ui(index, x) } + VertexAttribI2ui :: proc "c" (index: u32, x: u32, y: u32) { impl_VertexAttribI2ui(index, x, y) } + VertexAttribI3ui :: proc "c" (index: u32, x: u32, y: u32, z: u32) { impl_VertexAttribI3ui(index, x, y, z) } + VertexAttribI4ui :: proc "c" (index: u32, x: u32, y: u32, z: u32, w: u32) { impl_VertexAttribI4ui(index, x, y, z, w) } + VertexAttribI1iv :: proc "c" (index: u32, v: [^]i32) { impl_VertexAttribI1iv(index, v) } + VertexAttribI2iv :: proc "c" (index: u32, v: [^]i32) { impl_VertexAttribI2iv(index, v) } + VertexAttribI3iv :: proc "c" (index: u32, v: [^]i32) { impl_VertexAttribI3iv(index, v) } + VertexAttribI4iv :: proc "c" (index: u32, v: [^]i32) { impl_VertexAttribI4iv(index, v) } + VertexAttribI1uiv :: proc "c" (index: u32, v: [^]u32) { impl_VertexAttribI1uiv(index, v) } + VertexAttribI2uiv :: proc "c" (index: u32, v: [^]u32) { impl_VertexAttribI2uiv(index, v) } + VertexAttribI3uiv :: proc "c" (index: u32, v: [^]u32) { impl_VertexAttribI3uiv(index, v) } + VertexAttribI4uiv :: proc "c" (index: u32, v: [^]u32) { impl_VertexAttribI4uiv(index, v) } + VertexAttribI4bv :: proc "c" (index: u32, v: [^]i8) { impl_VertexAttribI4bv(index, v) } + VertexAttribI4sv :: proc "c" (index: u32, v: [^]i16) { impl_VertexAttribI4sv(index, v) } + VertexAttribI4ubv :: proc "c" (index: u32, v: [^]u8) { impl_VertexAttribI4ubv(index, v) } + VertexAttribI4usv :: proc "c" (index: u32, v: [^]u16) { impl_VertexAttribI4usv(index, v) } + GetUniformuiv :: proc "c" (program: u32, location: i32, params: [^]u32) { impl_GetUniformuiv(program, location, params) } + BindFragDataLocation :: proc "c" (program: u32, color: u32, name: cstring) { impl_BindFragDataLocation(program, color, name) } + GetFragDataLocation :: proc "c" (program: u32, name: cstring) -> i32 { ret := impl_GetFragDataLocation(program, name); return ret } + Uniform1ui :: proc "c" (location: i32, v0: u32) { impl_Uniform1ui(location, v0) } + Uniform2ui :: proc "c" (location: i32, v0: u32, v1: u32) { impl_Uniform2ui(location, v0, v1) } + Uniform3ui :: proc "c" (location: i32, v0: u32, v1: u32, v2: u32) { impl_Uniform3ui(location, v0, v1, v2) } + Uniform4ui :: proc "c" (location: i32, v0: u32, v1: u32, v2: u32, v3: u32) { impl_Uniform4ui(location, v0, v1, v2, v3) } + Uniform1uiv :: proc "c" (location: i32, count: i32, value: [^]u32) { impl_Uniform1uiv(location, count, value) } + Uniform2uiv :: proc "c" (location: i32, count: i32, value: [^]u32) { impl_Uniform2uiv(location, count, value) } + Uniform3uiv :: proc "c" (location: i32, count: i32, value: [^]u32) { impl_Uniform3uiv(location, count, value) } + Uniform4uiv :: proc "c" (location: i32, count: i32, value: [^]u32) { impl_Uniform4uiv(location, count, value) } + TexParameterIiv :: proc "c" (target: u32, pname: u32, params: [^]i32) { impl_TexParameterIiv(target, pname, params) } + TexParameterIuiv :: proc "c" (target: u32, pname: u32, params: [^]u32) { impl_TexParameterIuiv(target, pname, params) } + GetTexParameterIiv :: proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetTexParameterIiv(target, pname, params) } + GetTexParameterIuiv :: proc "c" (target: u32, pname: u32, params: [^]u32) { impl_GetTexParameterIuiv(target, pname, params) } + ClearBufferiv :: proc "c" (buffer: u32, drawbuffer: i32, value: ^i32) { impl_ClearBufferiv(buffer, drawbuffer, value) } + ClearBufferuiv :: proc "c" (buffer: u32, drawbuffer: i32, value: ^u32) { impl_ClearBufferuiv(buffer, drawbuffer, value) } + ClearBufferfv :: proc "c" (buffer: u32, drawbuffer: i32, value: ^f32) { impl_ClearBufferfv(buffer, drawbuffer, value) } + ClearBufferfi :: proc "c" (buffer: u32, drawbuffer: i32, depth: f32, stencil: i32) -> rawptr { ret := impl_ClearBufferfi(buffer, drawbuffer, depth, stencil); return ret } + GetStringi :: proc "c" (name: u32, index: u32) -> cstring { ret := impl_GetStringi(name, index); return ret } + IsRenderbuffer :: proc "c" (renderbuffer: u32) -> bool { ret := impl_IsRenderbuffer(renderbuffer); return ret } + BindRenderbuffer :: proc "c" (target: u32, renderbuffer: u32) { impl_BindRenderbuffer(target, renderbuffer) } + DeleteRenderbuffers :: proc "c" (n: i32, renderbuffers: [^]u32) { impl_DeleteRenderbuffers(n, renderbuffers) } + GenRenderbuffers :: proc "c" (n: i32, renderbuffers: [^]u32) { impl_GenRenderbuffers(n, renderbuffers) } + RenderbufferStorage :: proc "c" (target: u32, internalformat: u32, width: i32, height: i32) { impl_RenderbufferStorage(target, internalformat, width, height) } + GetRenderbufferParameteriv :: proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetRenderbufferParameteriv(target, pname, params) } + IsFramebuffer :: proc "c" (framebuffer: u32) -> bool { ret := impl_IsFramebuffer(framebuffer); return ret } + BindFramebuffer :: proc "c" (target: u32, framebuffer: u32) { impl_BindFramebuffer(target, framebuffer) } + DeleteFramebuffers :: proc "c" (n: i32, framebuffers: [^]u32) { impl_DeleteFramebuffers(n, framebuffers) } + GenFramebuffers :: proc "c" (n: i32, framebuffers: [^]u32) { impl_GenFramebuffers(n, framebuffers) } + CheckFramebufferStatus :: proc "c" (target: u32) -> u32 { ret := impl_CheckFramebufferStatus(target); return ret } + FramebufferTexture1D :: proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32) { impl_FramebufferTexture1D(target, attachment, textarget, texture, level) } + FramebufferTexture2D :: proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32) { impl_FramebufferTexture2D(target, attachment, textarget, texture, level) } + FramebufferTexture3D :: proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32, zoffset: i32) { impl_FramebufferTexture3D(target, attachment, textarget, texture, level, zoffset) } + FramebufferRenderbuffer :: proc "c" (target: u32, attachment: u32, renderbuffertarget: u32, renderbuffer: u32) { impl_FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer) } + GetFramebufferAttachmentParameteriv :: proc "c" (target: u32, attachment: u32, pname: u32, params: [^]i32) { impl_GetFramebufferAttachmentParameteriv(target, attachment, pname, params) } + GenerateMipmap :: proc "c" (target: u32) { impl_GenerateMipmap(target) } + BlitFramebuffer :: proc "c" (srcX0: i32, srcY0: i32, srcX1: i32, srcY1: i32, dstX0: i32, dstY0: i32, dstX1: i32, dstY1: i32, mask: u32, filter: u32) { impl_BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) } + RenderbufferStorageMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32) { impl_RenderbufferStorageMultisample(target, samples, internalformat, width, height) } + FramebufferTextureLayer :: proc "c" (target: u32, attachment: u32, texture: u32, level: i32, layer: i32) { impl_FramebufferTextureLayer(target, attachment, texture, level, layer) } + MapBufferRange :: proc "c" (target: u32, offset: int, length: int, access: u32) -> rawptr { ret := impl_MapBufferRange(target, offset, length, access); return ret } + FlushMappedBufferRange :: proc "c" (target: u32, offset: int, length: int) { impl_FlushMappedBufferRange(target, offset, length) } + BindVertexArray :: proc "c" (array: u32) { impl_BindVertexArray(array) } + DeleteVertexArrays :: proc "c" (n: i32, arrays: [^]u32) { impl_DeleteVertexArrays(n, arrays) } + GenVertexArrays :: proc "c" (n: i32, arrays: [^]u32) { impl_GenVertexArrays(n, arrays) } + IsVertexArray :: proc "c" (array: u32) -> bool { ret := impl_IsVertexArray(array); return ret } // VERSION_3_1 - DrawArraysInstanced :: #force_inline proc "c" (mode: u32, first: i32, count: i32, instancecount: i32) { impl_DrawArraysInstanced(mode, first, count, instancecount) } - DrawElementsInstanced :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32) { impl_DrawElementsInstanced(mode, count, type, indices, instancecount) } - TexBuffer :: #force_inline proc "c" (target: u32, internalformat: u32, buffer: u32) { impl_TexBuffer(target, internalformat, buffer) } - PrimitiveRestartIndex :: #force_inline proc "c" (index: u32) { impl_PrimitiveRestartIndex(index) } - CopyBufferSubData :: #force_inline proc "c" (readTarget: u32, writeTarget: u32, readOffset: int, writeOffset: int, size: int) { impl_CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) } - GetUniformIndices :: #force_inline proc "c" (program: u32, uniformCount: i32, uniformNames: [^]cstring, uniformIndices: [^]u32) { impl_GetUniformIndices(program, uniformCount, uniformNames, uniformIndices) } - GetActiveUniformsiv :: #force_inline proc "c" (program: u32, uniformCount: i32, uniformIndices: [^]u32, pname: u32, params: [^]i32) { impl_GetActiveUniformsiv(program, uniformCount, uniformIndices, pname, params) } - GetActiveUniformName :: #force_inline proc "c" (program: u32, uniformIndex: u32, bufSize: i32, length: ^i32, uniformName: [^]u8) { impl_GetActiveUniformName(program, uniformIndex, bufSize, length, uniformName) } - GetUniformBlockIndex :: #force_inline proc "c" (program: u32, uniformBlockName: cstring) -> u32 { ret := impl_GetUniformBlockIndex(program, uniformBlockName); return ret } - GetActiveUniformBlockiv :: #force_inline proc "c" (program: u32, uniformBlockIndex: u32, pname: u32, params: [^]i32) { impl_GetActiveUniformBlockiv(program, uniformBlockIndex, pname, params) } - GetActiveUniformBlockName :: #force_inline proc "c" (program: u32, uniformBlockIndex: u32, bufSize: i32, length: ^i32, uniformBlockName: [^]u8) { impl_GetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, uniformBlockName) } - UniformBlockBinding :: #force_inline proc "c" (program: u32, uniformBlockIndex: u32, uniformBlockBinding: u32) { impl_UniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding) } + DrawArraysInstanced :: proc "c" (mode: u32, first: i32, count: i32, instancecount: i32) { impl_DrawArraysInstanced(mode, first, count, instancecount) } + DrawElementsInstanced :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32) { impl_DrawElementsInstanced(mode, count, type, indices, instancecount) } + TexBuffer :: proc "c" (target: u32, internalformat: u32, buffer: u32) { impl_TexBuffer(target, internalformat, buffer) } + PrimitiveRestartIndex :: proc "c" (index: u32) { impl_PrimitiveRestartIndex(index) } + CopyBufferSubData :: proc "c" (readTarget: u32, writeTarget: u32, readOffset: int, writeOffset: int, size: int) { impl_CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) } + GetUniformIndices :: proc "c" (program: u32, uniformCount: i32, uniformNames: [^]cstring, uniformIndices: [^]u32) { impl_GetUniformIndices(program, uniformCount, uniformNames, uniformIndices) } + GetActiveUniformsiv :: proc "c" (program: u32, uniformCount: i32, uniformIndices: [^]u32, pname: u32, params: [^]i32) { impl_GetActiveUniformsiv(program, uniformCount, uniformIndices, pname, params) } + GetActiveUniformName :: proc "c" (program: u32, uniformIndex: u32, bufSize: i32, length: ^i32, uniformName: [^]u8) { impl_GetActiveUniformName(program, uniformIndex, bufSize, length, uniformName) } + GetUniformBlockIndex :: proc "c" (program: u32, uniformBlockName: cstring) -> u32 { ret := impl_GetUniformBlockIndex(program, uniformBlockName); return ret } + GetActiveUniformBlockiv :: proc "c" (program: u32, uniformBlockIndex: u32, pname: u32, params: [^]i32) { impl_GetActiveUniformBlockiv(program, uniformBlockIndex, pname, params) } + GetActiveUniformBlockName :: proc "c" (program: u32, uniformBlockIndex: u32, bufSize: i32, length: ^i32, uniformBlockName: [^]u8) { impl_GetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, uniformBlockName) } + UniformBlockBinding :: proc "c" (program: u32, uniformBlockIndex: u32, uniformBlockBinding: u32) { impl_UniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding) } // VERSION_3_2 - DrawElementsBaseVertex :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, basevertex: i32) { impl_DrawElementsBaseVertex(mode, count, type, indices, basevertex) } - DrawRangeElementsBaseVertex :: #force_inline proc "c" (mode: u32, start: u32, end: u32, count: i32, type: u32, indices: rawptr, basevertex: i32) { impl_DrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex) } - DrawElementsInstancedBaseVertex :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, basevertex: i32) { impl_DrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount, basevertex) } - MultiDrawElementsBaseVertex :: #force_inline proc "c" (mode: u32, count: [^]i32, type: u32, indices: [^]rawptr, drawcount: i32, basevertex: [^]i32) { impl_MultiDrawElementsBaseVertex(mode, count, type, indices, drawcount, basevertex) } - ProvokingVertex :: #force_inline proc "c" (mode: u32) { impl_ProvokingVertex(mode) } - FenceSync :: #force_inline proc "c" (condition: u32, flags: u32) -> sync_t { ret := impl_FenceSync(condition, flags); return ret } - IsSync :: #force_inline proc "c" (sync: sync_t) -> bool { ret := impl_IsSync(sync); return ret } - DeleteSync :: #force_inline proc "c" (sync: sync_t) { impl_DeleteSync(sync) } - ClientWaitSync :: #force_inline proc "c" (sync: sync_t, flags: u32, timeout: u64) -> u32 { ret := impl_ClientWaitSync(sync, flags, timeout); return ret } - WaitSync :: #force_inline proc "c" (sync: sync_t, flags: u32, timeout: u64) { impl_WaitSync(sync, flags, timeout) } - GetInteger64v :: #force_inline proc "c" (pname: u32, data: ^i64) { impl_GetInteger64v(pname, data) } - GetSynciv :: #force_inline proc "c" (sync: sync_t, pname: u32, bufSize: i32, length: ^i32, values: [^]i32) { impl_GetSynciv(sync, pname, bufSize, length, values) } - GetInteger64i_v :: #force_inline proc "c" (target: u32, index: u32, data: ^i64) { impl_GetInteger64i_v(target, index, data) } - GetBufferParameteri64v :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i64) { impl_GetBufferParameteri64v(target, pname, params) } - FramebufferTexture :: #force_inline proc "c" (target: u32, attachment: u32, texture: u32, level: i32) { impl_FramebufferTexture(target, attachment, texture, level) } - TexImage2DMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool) { impl_TexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations) } - TexImage3DMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool) { impl_TexImage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations) } - GetMultisamplefv :: #force_inline proc "c" (pname: u32, index: u32, val: ^f32) { impl_GetMultisamplefv(pname, index, val) } - SampleMaski :: #force_inline proc "c" (maskNumber: u32, mask: u32) { impl_SampleMaski(maskNumber, mask) } + DrawElementsBaseVertex :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, basevertex: i32) { impl_DrawElementsBaseVertex(mode, count, type, indices, basevertex) } + DrawRangeElementsBaseVertex :: proc "c" (mode: u32, start: u32, end: u32, count: i32, type: u32, indices: rawptr, basevertex: i32) { impl_DrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex) } + DrawElementsInstancedBaseVertex :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, basevertex: i32) { impl_DrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount, basevertex) } + MultiDrawElementsBaseVertex :: proc "c" (mode: u32, count: [^]i32, type: u32, indices: [^]rawptr, drawcount: i32, basevertex: [^]i32) { impl_MultiDrawElementsBaseVertex(mode, count, type, indices, drawcount, basevertex) } + ProvokingVertex :: proc "c" (mode: u32) { impl_ProvokingVertex(mode) } + FenceSync :: proc "c" (condition: u32, flags: u32) -> sync_t { ret := impl_FenceSync(condition, flags); return ret } + IsSync :: proc "c" (sync: sync_t) -> bool { ret := impl_IsSync(sync); return ret } + DeleteSync :: proc "c" (sync: sync_t) { impl_DeleteSync(sync) } + ClientWaitSync :: proc "c" (sync: sync_t, flags: u32, timeout: u64) -> u32 { ret := impl_ClientWaitSync(sync, flags, timeout); return ret } + WaitSync :: proc "c" (sync: sync_t, flags: u32, timeout: u64) { impl_WaitSync(sync, flags, timeout) } + GetInteger64v :: proc "c" (pname: u32, data: ^i64) { impl_GetInteger64v(pname, data) } + GetSynciv :: proc "c" (sync: sync_t, pname: u32, bufSize: i32, length: ^i32, values: [^]i32) { impl_GetSynciv(sync, pname, bufSize, length, values) } + GetInteger64i_v :: proc "c" (target: u32, index: u32, data: ^i64) { impl_GetInteger64i_v(target, index, data) } + GetBufferParameteri64v :: proc "c" (target: u32, pname: u32, params: [^]i64) { impl_GetBufferParameteri64v(target, pname, params) } + FramebufferTexture :: proc "c" (target: u32, attachment: u32, texture: u32, level: i32) { impl_FramebufferTexture(target, attachment, texture, level) } + TexImage2DMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool) { impl_TexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations) } + TexImage3DMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool) { impl_TexImage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations) } + GetMultisamplefv :: proc "c" (pname: u32, index: u32, val: ^f32) { impl_GetMultisamplefv(pname, index, val) } + SampleMaski :: proc "c" (maskNumber: u32, mask: u32) { impl_SampleMaski(maskNumber, mask) } // VERSION_3_3 - BindFragDataLocationIndexed :: #force_inline proc "c" (program: u32, colorNumber: u32, index: u32, name: cstring) { impl_BindFragDataLocationIndexed(program, colorNumber, index, name) } - GetFragDataIndex :: #force_inline proc "c" (program: u32, name: cstring) -> i32 { ret := impl_GetFragDataIndex(program, name); return ret } - GenSamplers :: #force_inline proc "c" (count: i32, samplers: [^]u32) { impl_GenSamplers(count, samplers) } - DeleteSamplers :: #force_inline proc "c" (count: i32, samplers: [^]u32) { impl_DeleteSamplers(count, samplers) } - IsSampler :: #force_inline proc "c" (sampler: u32) -> bool { ret := impl_IsSampler(sampler); return ret } - BindSampler :: #force_inline proc "c" (unit: u32, sampler: u32) { impl_BindSampler(unit, sampler) } - SamplerParameteri :: #force_inline proc "c" (sampler: u32, pname: u32, param: i32) { impl_SamplerParameteri(sampler, pname, param) } - SamplerParameteriv :: #force_inline proc "c" (sampler: u32, pname: u32, param: ^i32) { impl_SamplerParameteriv(sampler, pname, param) } - SamplerParameterf :: #force_inline proc "c" (sampler: u32, pname: u32, param: f32) { impl_SamplerParameterf(sampler, pname, param) } - SamplerParameterfv :: #force_inline proc "c" (sampler: u32, pname: u32, param: ^f32) { impl_SamplerParameterfv(sampler, pname, param) } - SamplerParameterIiv :: #force_inline proc "c" (sampler: u32, pname: u32, param: ^i32) { impl_SamplerParameterIiv(sampler, pname, param) } - SamplerParameterIuiv :: #force_inline proc "c" (sampler: u32, pname: u32, param: ^u32) { impl_SamplerParameterIuiv(sampler, pname, param) } - GetSamplerParameteriv :: #force_inline proc "c" (sampler: u32, pname: u32, params: [^]i32) { impl_GetSamplerParameteriv(sampler, pname, params) } - GetSamplerParameterIiv :: #force_inline proc "c" (sampler: u32, pname: u32, params: [^]i32) { impl_GetSamplerParameterIiv(sampler, pname, params) } - GetSamplerParameterfv :: #force_inline proc "c" (sampler: u32, pname: u32, params: [^]f32) { impl_GetSamplerParameterfv(sampler, pname, params) } - GetSamplerParameterIuiv :: #force_inline proc "c" (sampler: u32, pname: u32, params: [^]u32) { impl_GetSamplerParameterIuiv(sampler, pname, params) } - QueryCounter :: #force_inline proc "c" (id: u32, target: u32) { impl_QueryCounter(id, target) } - GetQueryObjecti64v :: #force_inline proc "c" (id: u32, pname: u32, params: [^]i64) { impl_GetQueryObjecti64v(id, pname, params) } - GetQueryObjectui64v :: #force_inline proc "c" (id: u32, pname: u32, params: [^]u64) { impl_GetQueryObjectui64v(id, pname, params) } - VertexAttribDivisor :: #force_inline proc "c" (index: u32, divisor: u32) { impl_VertexAttribDivisor(index, divisor) } - VertexAttribP1ui :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: u32) { impl_VertexAttribP1ui(index, type, normalized, value) } - VertexAttribP1uiv :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: ^u32) { impl_VertexAttribP1uiv(index, type, normalized, value) } - VertexAttribP2ui :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: u32) { impl_VertexAttribP2ui(index, type, normalized, value) } - VertexAttribP2uiv :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: ^u32) { impl_VertexAttribP2uiv(index, type, normalized, value) } - VertexAttribP3ui :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: u32) { impl_VertexAttribP3ui(index, type, normalized, value) } - VertexAttribP3uiv :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: ^u32) { impl_VertexAttribP3uiv(index, type, normalized, value) } - VertexAttribP4ui :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: u32) { impl_VertexAttribP4ui(index, type, normalized, value) } - VertexAttribP4uiv :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: ^u32) { impl_VertexAttribP4uiv(index, type, normalized, value) } - VertexP2ui :: #force_inline proc "c" (type: u32, value: u32) { impl_VertexP2ui(type, value) } - VertexP2uiv :: #force_inline proc "c" (type: u32, value: ^u32) { impl_VertexP2uiv(type, value) } - VertexP3ui :: #force_inline proc "c" (type: u32, value: u32) { impl_VertexP3ui(type, value) } - VertexP3uiv :: #force_inline proc "c" (type: u32, value: ^u32) { impl_VertexP3uiv(type, value) } - VertexP4ui :: #force_inline proc "c" (type: u32, value: u32) { impl_VertexP4ui(type, value) } - VertexP4uiv :: #force_inline proc "c" (type: u32, value: ^u32) { impl_VertexP4uiv(type, value) } - TexCoordP1ui :: #force_inline proc "c" (type: u32, coords: u32) { impl_TexCoordP1ui(type, coords) } - TexCoordP1uiv :: #force_inline proc "c" (type: u32, coords: [^]u32) { impl_TexCoordP1uiv(type, coords) } - TexCoordP2ui :: #force_inline proc "c" (type: u32, coords: u32) { impl_TexCoordP2ui(type, coords) } - TexCoordP2uiv :: #force_inline proc "c" (type: u32, coords: [^]u32) { impl_TexCoordP2uiv(type, coords) } - TexCoordP3ui :: #force_inline proc "c" (type: u32, coords: u32) { impl_TexCoordP3ui(type, coords) } - TexCoordP3uiv :: #force_inline proc "c" (type: u32, coords: [^]u32) { impl_TexCoordP3uiv(type, coords) } - TexCoordP4ui :: #force_inline proc "c" (type: u32, coords: u32) { impl_TexCoordP4ui(type, coords) } - TexCoordP4uiv :: #force_inline proc "c" (type: u32, coords: [^]u32) { impl_TexCoordP4uiv(type, coords) } - MultiTexCoordP1ui :: #force_inline proc "c" (texture: u32, type: u32, coords: u32) { impl_MultiTexCoordP1ui(texture, type, coords) } - MultiTexCoordP1uiv :: #force_inline proc "c" (texture: u32, type: u32, coords: [^]u32) { impl_MultiTexCoordP1uiv(texture, type, coords) } - MultiTexCoordP2ui :: #force_inline proc "c" (texture: u32, type: u32, coords: u32) { impl_MultiTexCoordP2ui(texture, type, coords) } - MultiTexCoordP2uiv :: #force_inline proc "c" (texture: u32, type: u32, coords: [^]u32) { impl_MultiTexCoordP2uiv(texture, type, coords) } - MultiTexCoordP3ui :: #force_inline proc "c" (texture: u32, type: u32, coords: u32) { impl_MultiTexCoordP3ui(texture, type, coords) } - MultiTexCoordP3uiv :: #force_inline proc "c" (texture: u32, type: u32, coords: [^]u32) { impl_MultiTexCoordP3uiv(texture, type, coords) } - MultiTexCoordP4ui :: #force_inline proc "c" (texture: u32, type: u32, coords: u32) { impl_MultiTexCoordP4ui(texture, type, coords) } - MultiTexCoordP4uiv :: #force_inline proc "c" (texture: u32, type: u32, coords: [^]u32) { impl_MultiTexCoordP4uiv(texture, type, coords) } - NormalP3ui :: #force_inline proc "c" (type: u32, coords: u32) { impl_NormalP3ui(type, coords) } - NormalP3uiv :: #force_inline proc "c" (type: u32, coords: [^]u32) { impl_NormalP3uiv(type, coords) } - ColorP3ui :: #force_inline proc "c" (type: u32, color: u32) { impl_ColorP3ui(type, color) } - ColorP3uiv :: #force_inline proc "c" (type: u32, color: ^u32) { impl_ColorP3uiv(type, color) } - ColorP4ui :: #force_inline proc "c" (type: u32, color: u32) { impl_ColorP4ui(type, color) } - ColorP4uiv :: #force_inline proc "c" (type: u32, color: ^u32) { impl_ColorP4uiv(type, color) } - SecondaryColorP3ui :: #force_inline proc "c" (type: u32, color: u32) { impl_SecondaryColorP3ui(type, color) } - SecondaryColorP3uiv :: #force_inline proc "c" (type: u32, color: ^u32) { impl_SecondaryColorP3uiv(type, color) } + BindFragDataLocationIndexed :: proc "c" (program: u32, colorNumber: u32, index: u32, name: cstring) { impl_BindFragDataLocationIndexed(program, colorNumber, index, name) } + GetFragDataIndex :: proc "c" (program: u32, name: cstring) -> i32 { ret := impl_GetFragDataIndex(program, name); return ret } + GenSamplers :: proc "c" (count: i32, samplers: [^]u32) { impl_GenSamplers(count, samplers) } + DeleteSamplers :: proc "c" (count: i32, samplers: [^]u32) { impl_DeleteSamplers(count, samplers) } + IsSampler :: proc "c" (sampler: u32) -> bool { ret := impl_IsSampler(sampler); return ret } + BindSampler :: proc "c" (unit: u32, sampler: u32) { impl_BindSampler(unit, sampler) } + SamplerParameteri :: proc "c" (sampler: u32, pname: u32, param: i32) { impl_SamplerParameteri(sampler, pname, param) } + SamplerParameteriv :: proc "c" (sampler: u32, pname: u32, param: ^i32) { impl_SamplerParameteriv(sampler, pname, param) } + SamplerParameterf :: proc "c" (sampler: u32, pname: u32, param: f32) { impl_SamplerParameterf(sampler, pname, param) } + SamplerParameterfv :: proc "c" (sampler: u32, pname: u32, param: ^f32) { impl_SamplerParameterfv(sampler, pname, param) } + SamplerParameterIiv :: proc "c" (sampler: u32, pname: u32, param: ^i32) { impl_SamplerParameterIiv(sampler, pname, param) } + SamplerParameterIuiv :: proc "c" (sampler: u32, pname: u32, param: ^u32) { impl_SamplerParameterIuiv(sampler, pname, param) } + GetSamplerParameteriv :: proc "c" (sampler: u32, pname: u32, params: [^]i32) { impl_GetSamplerParameteriv(sampler, pname, params) } + GetSamplerParameterIiv :: proc "c" (sampler: u32, pname: u32, params: [^]i32) { impl_GetSamplerParameterIiv(sampler, pname, params) } + GetSamplerParameterfv :: proc "c" (sampler: u32, pname: u32, params: [^]f32) { impl_GetSamplerParameterfv(sampler, pname, params) } + GetSamplerParameterIuiv :: proc "c" (sampler: u32, pname: u32, params: [^]u32) { impl_GetSamplerParameterIuiv(sampler, pname, params) } + QueryCounter :: proc "c" (id: u32, target: u32) { impl_QueryCounter(id, target) } + GetQueryObjecti64v :: proc "c" (id: u32, pname: u32, params: [^]i64) { impl_GetQueryObjecti64v(id, pname, params) } + GetQueryObjectui64v :: proc "c" (id: u32, pname: u32, params: [^]u64) { impl_GetQueryObjectui64v(id, pname, params) } + VertexAttribDivisor :: proc "c" (index: u32, divisor: u32) { impl_VertexAttribDivisor(index, divisor) } + VertexAttribP1ui :: proc "c" (index: u32, type: u32, normalized: bool, value: u32) { impl_VertexAttribP1ui(index, type, normalized, value) } + VertexAttribP1uiv :: proc "c" (index: u32, type: u32, normalized: bool, value: ^u32) { impl_VertexAttribP1uiv(index, type, normalized, value) } + VertexAttribP2ui :: proc "c" (index: u32, type: u32, normalized: bool, value: u32) { impl_VertexAttribP2ui(index, type, normalized, value) } + VertexAttribP2uiv :: proc "c" (index: u32, type: u32, normalized: bool, value: ^u32) { impl_VertexAttribP2uiv(index, type, normalized, value) } + VertexAttribP3ui :: proc "c" (index: u32, type: u32, normalized: bool, value: u32) { impl_VertexAttribP3ui(index, type, normalized, value) } + VertexAttribP3uiv :: proc "c" (index: u32, type: u32, normalized: bool, value: ^u32) { impl_VertexAttribP3uiv(index, type, normalized, value) } + VertexAttribP4ui :: proc "c" (index: u32, type: u32, normalized: bool, value: u32) { impl_VertexAttribP4ui(index, type, normalized, value) } + VertexAttribP4uiv :: proc "c" (index: u32, type: u32, normalized: bool, value: ^u32) { impl_VertexAttribP4uiv(index, type, normalized, value) } + VertexP2ui :: proc "c" (type: u32, value: u32) { impl_VertexP2ui(type, value) } + VertexP2uiv :: proc "c" (type: u32, value: ^u32) { impl_VertexP2uiv(type, value) } + VertexP3ui :: proc "c" (type: u32, value: u32) { impl_VertexP3ui(type, value) } + VertexP3uiv :: proc "c" (type: u32, value: ^u32) { impl_VertexP3uiv(type, value) } + VertexP4ui :: proc "c" (type: u32, value: u32) { impl_VertexP4ui(type, value) } + VertexP4uiv :: proc "c" (type: u32, value: ^u32) { impl_VertexP4uiv(type, value) } + TexCoordP1ui :: proc "c" (type: u32, coords: u32) { impl_TexCoordP1ui(type, coords) } + TexCoordP1uiv :: proc "c" (type: u32, coords: [^]u32) { impl_TexCoordP1uiv(type, coords) } + TexCoordP2ui :: proc "c" (type: u32, coords: u32) { impl_TexCoordP2ui(type, coords) } + TexCoordP2uiv :: proc "c" (type: u32, coords: [^]u32) { impl_TexCoordP2uiv(type, coords) } + TexCoordP3ui :: proc "c" (type: u32, coords: u32) { impl_TexCoordP3ui(type, coords) } + TexCoordP3uiv :: proc "c" (type: u32, coords: [^]u32) { impl_TexCoordP3uiv(type, coords) } + TexCoordP4ui :: proc "c" (type: u32, coords: u32) { impl_TexCoordP4ui(type, coords) } + TexCoordP4uiv :: proc "c" (type: u32, coords: [^]u32) { impl_TexCoordP4uiv(type, coords) } + MultiTexCoordP1ui :: proc "c" (texture: u32, type: u32, coords: u32) { impl_MultiTexCoordP1ui(texture, type, coords) } + MultiTexCoordP1uiv :: proc "c" (texture: u32, type: u32, coords: [^]u32) { impl_MultiTexCoordP1uiv(texture, type, coords) } + MultiTexCoordP2ui :: proc "c" (texture: u32, type: u32, coords: u32) { impl_MultiTexCoordP2ui(texture, type, coords) } + MultiTexCoordP2uiv :: proc "c" (texture: u32, type: u32, coords: [^]u32) { impl_MultiTexCoordP2uiv(texture, type, coords) } + MultiTexCoordP3ui :: proc "c" (texture: u32, type: u32, coords: u32) { impl_MultiTexCoordP3ui(texture, type, coords) } + MultiTexCoordP3uiv :: proc "c" (texture: u32, type: u32, coords: [^]u32) { impl_MultiTexCoordP3uiv(texture, type, coords) } + MultiTexCoordP4ui :: proc "c" (texture: u32, type: u32, coords: u32) { impl_MultiTexCoordP4ui(texture, type, coords) } + MultiTexCoordP4uiv :: proc "c" (texture: u32, type: u32, coords: [^]u32) { impl_MultiTexCoordP4uiv(texture, type, coords) } + NormalP3ui :: proc "c" (type: u32, coords: u32) { impl_NormalP3ui(type, coords) } + NormalP3uiv :: proc "c" (type: u32, coords: [^]u32) { impl_NormalP3uiv(type, coords) } + ColorP3ui :: proc "c" (type: u32, color: u32) { impl_ColorP3ui(type, color) } + ColorP3uiv :: proc "c" (type: u32, color: ^u32) { impl_ColorP3uiv(type, color) } + ColorP4ui :: proc "c" (type: u32, color: u32) { impl_ColorP4ui(type, color) } + ColorP4uiv :: proc "c" (type: u32, color: ^u32) { impl_ColorP4uiv(type, color) } + SecondaryColorP3ui :: proc "c" (type: u32, color: u32) { impl_SecondaryColorP3ui(type, color) } + SecondaryColorP3uiv :: proc "c" (type: u32, color: ^u32) { impl_SecondaryColorP3uiv(type, color) } // VERSION_4_0 - MinSampleShading :: #force_inline proc "c" (value: f32) { impl_MinSampleShading(value) } - BlendEquationi :: #force_inline proc "c" (buf: u32, mode: u32) { impl_BlendEquationi(buf, mode) } - BlendEquationSeparatei :: #force_inline proc "c" (buf: u32, modeRGB: u32, modeAlpha: u32) { impl_BlendEquationSeparatei(buf, modeRGB, modeAlpha) } - BlendFunci :: #force_inline proc "c" (buf: u32, src: u32, dst: u32) { impl_BlendFunci(buf, src, dst) } - BlendFuncSeparatei :: #force_inline proc "c" (buf: u32, srcRGB: u32, dstRGB: u32, srcAlpha: u32, dstAlpha: u32) { impl_BlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha) } - DrawArraysIndirect :: #force_inline proc "c" (mode: u32, indirect: ^DrawArraysIndirectCommand) { impl_DrawArraysIndirect(mode, indirect) } - DrawElementsIndirect :: #force_inline proc "c" (mode: u32, type: u32, indirect: ^DrawElementsIndirectCommand) { impl_DrawElementsIndirect(mode, type, indirect) } - Uniform1d :: #force_inline proc "c" (location: i32, x: f64) { impl_Uniform1d(location, x) } - Uniform2d :: #force_inline proc "c" (location: i32, x: f64, y: f64) { impl_Uniform2d(location, x, y) } - Uniform3d :: #force_inline proc "c" (location: i32, x: f64, y: f64, z: f64) { impl_Uniform3d(location, x, y, z) } - Uniform4d :: #force_inline proc "c" (location: i32, x: f64, y: f64, z: f64, w: f64) { impl_Uniform4d(location, x, y, z, w) } - Uniform1dv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f64) { impl_Uniform1dv(location, count, value) } - Uniform2dv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f64) { impl_Uniform2dv(location, count, value) } - Uniform3dv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f64) { impl_Uniform3dv(location, count, value) } - Uniform4dv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f64) { impl_Uniform4dv(location, count, value) } - UniformMatrix2dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix2dv(location, count, transpose, value) } - UniformMatrix3dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix3dv(location, count, transpose, value) } - UniformMatrix4dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix4dv(location, count, transpose, value) } - UniformMatrix2x3dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix2x3dv(location, count, transpose, value) } - UniformMatrix2x4dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix2x4dv(location, count, transpose, value) } - UniformMatrix3x2dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix3x2dv(location, count, transpose, value) } - UniformMatrix3x4dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix3x4dv(location, count, transpose, value) } - UniformMatrix4x2dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix4x2dv(location, count, transpose, value) } - UniformMatrix4x3dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix4x3dv(location, count, transpose, value) } - GetUniformdv :: #force_inline proc "c" (program: u32, location: i32, params: [^]f64) { impl_GetUniformdv(program, location, params) } - GetSubroutineUniformLocation :: #force_inline proc "c" (program: u32, shadertype: u32, name: cstring) -> i32 { ret := impl_GetSubroutineUniformLocation(program, shadertype, name); return ret } - GetSubroutineIndex :: #force_inline proc "c" (program: u32, shadertype: u32, name: cstring) -> u32 { ret := impl_GetSubroutineIndex(program, shadertype, name); return ret } - GetActiveSubroutineUniformiv :: #force_inline proc "c" (program: u32, shadertype: u32, index: u32, pname: u32, values: [^]i32) { impl_GetActiveSubroutineUniformiv(program, shadertype, index, pname, values) } - GetActiveSubroutineUniformName :: #force_inline proc "c" (program: u32, shadertype: u32, index: u32, bufsize: i32, length: ^i32, name: [^]u8) { impl_GetActiveSubroutineUniformName(program, shadertype, index, bufsize, length, name) } - GetActiveSubroutineName :: #force_inline proc "c" (program: u32, shadertype: u32, index: u32, bufsize: i32, length: ^i32, name: [^]u8) { impl_GetActiveSubroutineName(program, shadertype, index, bufsize, length, name) } - UniformSubroutinesuiv :: #force_inline proc "c" (shadertype: u32, count: i32, indices: [^]u32) { impl_UniformSubroutinesuiv(shadertype, count, indices) } - GetUniformSubroutineuiv :: #force_inline proc "c" (shadertype: u32, location: i32, params: [^]u32) { impl_GetUniformSubroutineuiv(shadertype, location, params) } - GetProgramStageiv :: #force_inline proc "c" (program: u32, shadertype: u32, pname: u32, values: [^]i32) { impl_GetProgramStageiv(program, shadertype, pname, values) } - PatchParameteri :: #force_inline proc "c" (pname: u32, value: i32) { impl_PatchParameteri(pname, value) } - PatchParameterfv :: #force_inline proc "c" (pname: u32, values: [^]f32) { impl_PatchParameterfv(pname, values) } - BindTransformFeedback :: #force_inline proc "c" (target: u32, id: u32) { impl_BindTransformFeedback(target, id) } - DeleteTransformFeedbacks :: #force_inline proc "c" (n: i32, ids: [^]u32) { impl_DeleteTransformFeedbacks(n, ids) } - GenTransformFeedbacks :: #force_inline proc "c" (n: i32, ids: [^]u32) { impl_GenTransformFeedbacks(n, ids) } - IsTransformFeedback :: #force_inline proc "c" (id: u32) -> bool { ret := impl_IsTransformFeedback(id); return ret } - PauseTransformFeedback :: #force_inline proc "c" () { impl_PauseTransformFeedback() } - ResumeTransformFeedback :: #force_inline proc "c" () { impl_ResumeTransformFeedback() } - DrawTransformFeedback :: #force_inline proc "c" (mode: u32, id: u32) { impl_DrawTransformFeedback(mode, id) } - DrawTransformFeedbackStream :: #force_inline proc "c" (mode: u32, id: u32, stream: u32) { impl_DrawTransformFeedbackStream(mode, id, stream) } - BeginQueryIndexed :: #force_inline proc "c" (target: u32, index: u32, id: u32) { impl_BeginQueryIndexed(target, index, id) } - EndQueryIndexed :: #force_inline proc "c" (target: u32, index: u32) { impl_EndQueryIndexed(target, index) } - GetQueryIndexediv :: #force_inline proc "c" (target: u32, index: u32, pname: u32, params: [^]i32) { impl_GetQueryIndexediv(target, index, pname, params) } + MinSampleShading :: proc "c" (value: f32) { impl_MinSampleShading(value) } + BlendEquationi :: proc "c" (buf: u32, mode: u32) { impl_BlendEquationi(buf, mode) } + BlendEquationSeparatei :: proc "c" (buf: u32, modeRGB: u32, modeAlpha: u32) { impl_BlendEquationSeparatei(buf, modeRGB, modeAlpha) } + BlendFunci :: proc "c" (buf: u32, src: u32, dst: u32) { impl_BlendFunci(buf, src, dst) } + BlendFuncSeparatei :: proc "c" (buf: u32, srcRGB: u32, dstRGB: u32, srcAlpha: u32, dstAlpha: u32) { impl_BlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha) } + DrawArraysIndirect :: proc "c" (mode: u32, indirect: ^DrawArraysIndirectCommand) { impl_DrawArraysIndirect(mode, indirect) } + DrawElementsIndirect :: proc "c" (mode: u32, type: u32, indirect: ^DrawElementsIndirectCommand) { impl_DrawElementsIndirect(mode, type, indirect) } + Uniform1d :: proc "c" (location: i32, x: f64) { impl_Uniform1d(location, x) } + Uniform2d :: proc "c" (location: i32, x: f64, y: f64) { impl_Uniform2d(location, x, y) } + Uniform3d :: proc "c" (location: i32, x: f64, y: f64, z: f64) { impl_Uniform3d(location, x, y, z) } + Uniform4d :: proc "c" (location: i32, x: f64, y: f64, z: f64, w: f64) { impl_Uniform4d(location, x, y, z, w) } + Uniform1dv :: proc "c" (location: i32, count: i32, value: [^]f64) { impl_Uniform1dv(location, count, value) } + Uniform2dv :: proc "c" (location: i32, count: i32, value: [^]f64) { impl_Uniform2dv(location, count, value) } + Uniform3dv :: proc "c" (location: i32, count: i32, value: [^]f64) { impl_Uniform3dv(location, count, value) } + Uniform4dv :: proc "c" (location: i32, count: i32, value: [^]f64) { impl_Uniform4dv(location, count, value) } + UniformMatrix2dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix2dv(location, count, transpose, value) } + UniformMatrix3dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix3dv(location, count, transpose, value) } + UniformMatrix4dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix4dv(location, count, transpose, value) } + UniformMatrix2x3dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix2x3dv(location, count, transpose, value) } + UniformMatrix2x4dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix2x4dv(location, count, transpose, value) } + UniformMatrix3x2dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix3x2dv(location, count, transpose, value) } + UniformMatrix3x4dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix3x4dv(location, count, transpose, value) } + UniformMatrix4x2dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix4x2dv(location, count, transpose, value) } + UniformMatrix4x3dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64) { impl_UniformMatrix4x3dv(location, count, transpose, value) } + GetUniformdv :: proc "c" (program: u32, location: i32, params: [^]f64) { impl_GetUniformdv(program, location, params) } + GetSubroutineUniformLocation :: proc "c" (program: u32, shadertype: u32, name: cstring) -> i32 { ret := impl_GetSubroutineUniformLocation(program, shadertype, name); return ret } + GetSubroutineIndex :: proc "c" (program: u32, shadertype: u32, name: cstring) -> u32 { ret := impl_GetSubroutineIndex(program, shadertype, name); return ret } + GetActiveSubroutineUniformiv :: proc "c" (program: u32, shadertype: u32, index: u32, pname: u32, values: [^]i32) { impl_GetActiveSubroutineUniformiv(program, shadertype, index, pname, values) } + GetActiveSubroutineUniformName :: proc "c" (program: u32, shadertype: u32, index: u32, bufsize: i32, length: ^i32, name: [^]u8) { impl_GetActiveSubroutineUniformName(program, shadertype, index, bufsize, length, name) } + GetActiveSubroutineName :: proc "c" (program: u32, shadertype: u32, index: u32, bufsize: i32, length: ^i32, name: [^]u8) { impl_GetActiveSubroutineName(program, shadertype, index, bufsize, length, name) } + UniformSubroutinesuiv :: proc "c" (shadertype: u32, count: i32, indices: [^]u32) { impl_UniformSubroutinesuiv(shadertype, count, indices) } + GetUniformSubroutineuiv :: proc "c" (shadertype: u32, location: i32, params: [^]u32) { impl_GetUniformSubroutineuiv(shadertype, location, params) } + GetProgramStageiv :: proc "c" (program: u32, shadertype: u32, pname: u32, values: [^]i32) { impl_GetProgramStageiv(program, shadertype, pname, values) } + PatchParameteri :: proc "c" (pname: u32, value: i32) { impl_PatchParameteri(pname, value) } + PatchParameterfv :: proc "c" (pname: u32, values: [^]f32) { impl_PatchParameterfv(pname, values) } + BindTransformFeedback :: proc "c" (target: u32, id: u32) { impl_BindTransformFeedback(target, id) } + DeleteTransformFeedbacks :: proc "c" (n: i32, ids: [^]u32) { impl_DeleteTransformFeedbacks(n, ids) } + GenTransformFeedbacks :: proc "c" (n: i32, ids: [^]u32) { impl_GenTransformFeedbacks(n, ids) } + IsTransformFeedback :: proc "c" (id: u32) -> bool { ret := impl_IsTransformFeedback(id); return ret } + PauseTransformFeedback :: proc "c" () { impl_PauseTransformFeedback() } + ResumeTransformFeedback :: proc "c" () { impl_ResumeTransformFeedback() } + DrawTransformFeedback :: proc "c" (mode: u32, id: u32) { impl_DrawTransformFeedback(mode, id) } + DrawTransformFeedbackStream :: proc "c" (mode: u32, id: u32, stream: u32) { impl_DrawTransformFeedbackStream(mode, id, stream) } + BeginQueryIndexed :: proc "c" (target: u32, index: u32, id: u32) { impl_BeginQueryIndexed(target, index, id) } + EndQueryIndexed :: proc "c" (target: u32, index: u32) { impl_EndQueryIndexed(target, index) } + GetQueryIndexediv :: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32) { impl_GetQueryIndexediv(target, index, pname, params) } // VERSION_4_1 - ReleaseShaderCompiler :: #force_inline proc "c" () { impl_ReleaseShaderCompiler() } - ShaderBinary :: #force_inline proc "c" (count: i32, shaders: ^u32, binaryformat: u32, binary: rawptr, length: i32) { impl_ShaderBinary(count, shaders, binaryformat, binary, length) } - GetShaderPrecisionFormat :: #force_inline proc "c" (shadertype: u32, precisiontype: u32, range: ^i32, precision: ^i32) { impl_GetShaderPrecisionFormat(shadertype, precisiontype, range, precision) } - DepthRangef :: #force_inline proc "c" (n: f32, f: f32) { impl_DepthRangef(n, f) } - ClearDepthf :: #force_inline proc "c" (d: f32) { impl_ClearDepthf(d) } - GetProgramBinary :: #force_inline proc "c" (program: u32, bufSize: i32, length: ^i32, binaryFormat: ^u32, binary: rawptr) { impl_GetProgramBinary(program, bufSize, length, binaryFormat, binary) } - ProgramBinary :: #force_inline proc "c" (program: u32, binaryFormat: u32, binary: rawptr, length: i32) { impl_ProgramBinary(program, binaryFormat, binary, length) } - ProgramParameteri :: #force_inline proc "c" (program: u32, pname: u32, value: i32) { impl_ProgramParameteri(program, pname, value) } - UseProgramStages :: #force_inline proc "c" (pipeline: u32, stages: u32, program: u32) { impl_UseProgramStages(pipeline, stages, program) } - ActiveShaderProgram :: #force_inline proc "c" (pipeline: u32, program: u32) { impl_ActiveShaderProgram(pipeline, program) } - CreateShaderProgramv :: #force_inline proc "c" (type: u32, count: i32, strings: [^]cstring) -> u32 { ret := impl_CreateShaderProgramv(type, count, strings); return ret } - BindProgramPipeline :: #force_inline proc "c" (pipeline: u32) { impl_BindProgramPipeline(pipeline) } - DeleteProgramPipelines :: #force_inline proc "c" (n: i32, pipelines: [^]u32) { impl_DeleteProgramPipelines(n, pipelines) } - GenProgramPipelines :: #force_inline proc "c" (n: i32, pipelines: [^]u32) { impl_GenProgramPipelines(n, pipelines) } - IsProgramPipeline :: #force_inline proc "c" (pipeline: u32) -> bool { ret := impl_IsProgramPipeline(pipeline); return ret } - GetProgramPipelineiv :: #force_inline proc "c" (pipeline: u32, pname: u32, params: [^]i32) { impl_GetProgramPipelineiv(pipeline, pname, params) } - ProgramUniform1i :: #force_inline proc "c" (program: u32, location: i32, v0: i32) { impl_ProgramUniform1i(program, location, v0) } - ProgramUniform1iv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]i32) { impl_ProgramUniform1iv(program, location, count, value) } - ProgramUniform1f :: #force_inline proc "c" (program: u32, location: i32, v0: f32) { impl_ProgramUniform1f(program, location, v0) } - ProgramUniform1fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f32) { impl_ProgramUniform1fv(program, location, count, value) } - ProgramUniform1d :: #force_inline proc "c" (program: u32, location: i32, v0: f64) { impl_ProgramUniform1d(program, location, v0) } - ProgramUniform1dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f64) { impl_ProgramUniform1dv(program, location, count, value) } - ProgramUniform1ui :: #force_inline proc "c" (program: u32, location: i32, v0: u32) { impl_ProgramUniform1ui(program, location, v0) } - ProgramUniform1uiv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]u32) { impl_ProgramUniform1uiv(program, location, count, value) } - ProgramUniform2i :: #force_inline proc "c" (program: u32, location: i32, v0: i32, v1: i32) { impl_ProgramUniform2i(program, location, v0, v1) } - ProgramUniform2iv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]i32) { impl_ProgramUniform2iv(program, location, count, value) } - ProgramUniform2f :: #force_inline proc "c" (program: u32, location: i32, v0: f32, v1: f32) { impl_ProgramUniform2f(program, location, v0, v1) } - ProgramUniform2fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f32) { impl_ProgramUniform2fv(program, location, count, value) } - ProgramUniform2d :: #force_inline proc "c" (program: u32, location: i32, v0: f64, v1: f64) { impl_ProgramUniform2d(program, location, v0, v1) } - ProgramUniform2dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f64) { impl_ProgramUniform2dv(program, location, count, value) } - ProgramUniform2ui :: #force_inline proc "c" (program: u32, location: i32, v0: u32, v1: u32) { impl_ProgramUniform2ui(program, location, v0, v1) } - ProgramUniform2uiv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]u32) { impl_ProgramUniform2uiv(program, location, count, value) } - ProgramUniform3i :: #force_inline proc "c" (program: u32, location: i32, v0: i32, v1: i32, v2: i32) { impl_ProgramUniform3i(program, location, v0, v1, v2) } - ProgramUniform3iv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]i32) { impl_ProgramUniform3iv(program, location, count, value) } - ProgramUniform3f :: #force_inline proc "c" (program: u32, location: i32, v0: f32, v1: f32, v2: f32) { impl_ProgramUniform3f(program, location, v0, v1, v2) } - ProgramUniform3fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f32) { impl_ProgramUniform3fv(program, location, count, value) } - ProgramUniform3d :: #force_inline proc "c" (program: u32, location: i32, v0: f64, v1: f64, v2: f64) { impl_ProgramUniform3d(program, location, v0, v1, v2) } - ProgramUniform3dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f64) { impl_ProgramUniform3dv(program, location, count, value) } - ProgramUniform3ui :: #force_inline proc "c" (program: u32, location: i32, v0: u32, v1: u32, v2: u32) { impl_ProgramUniform3ui(program, location, v0, v1, v2) } - ProgramUniform3uiv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]u32) { impl_ProgramUniform3uiv(program, location, count, value) } - ProgramUniform4i :: #force_inline proc "c" (program: u32, location: i32, v0: i32, v1: i32, v2: i32, v3: i32) { impl_ProgramUniform4i(program, location, v0, v1, v2, v3) } - ProgramUniform4iv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]i32) { impl_ProgramUniform4iv(program, location, count, value) } - ProgramUniform4f :: #force_inline proc "c" (program: u32, location: i32, v0: f32, v1: f32, v2: f32, v3: f32) { impl_ProgramUniform4f(program, location, v0, v1, v2, v3) } - ProgramUniform4fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f32) { impl_ProgramUniform4fv(program, location, count, value) } - ProgramUniform4d :: #force_inline proc "c" (program: u32, location: i32, v0: f64, v1: f64, v2: f64, v3: f64) { impl_ProgramUniform4d(program, location, v0, v1, v2, v3) } - ProgramUniform4dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f64) { impl_ProgramUniform4dv(program, location, count, value) } - ProgramUniform4ui :: #force_inline proc "c" (program: u32, location: i32, v0: u32, v1: u32, v2: u32, v3: u32) { impl_ProgramUniform4ui(program, location, v0, v1, v2, v3) } - ProgramUniform4uiv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]u32) { impl_ProgramUniform4uiv(program, location, count, value) } - ProgramUniformMatrix2fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix2fv(program, location, count, transpose, value) } - ProgramUniformMatrix3fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix3fv(program, location, count, transpose, value) } - ProgramUniformMatrix4fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix4fv(program, location, count, transpose, value) } - ProgramUniformMatrix2dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix2dv(program, location, count, transpose, value) } - ProgramUniformMatrix3dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix3dv(program, location, count, transpose, value) } - ProgramUniformMatrix4dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix4dv(program, location, count, transpose, value) } - ProgramUniformMatrix2x3fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix2x3fv(program, location, count, transpose, value) } - ProgramUniformMatrix3x2fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix3x2fv(program, location, count, transpose, value) } - ProgramUniformMatrix2x4fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix2x4fv(program, location, count, transpose, value) } - ProgramUniformMatrix4x2fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix4x2fv(program, location, count, transpose, value) } - ProgramUniformMatrix3x4fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix3x4fv(program, location, count, transpose, value) } - ProgramUniformMatrix4x3fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix4x3fv(program, location, count, transpose, value) } - ProgramUniformMatrix2x3dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix2x3dv(program, location, count, transpose, value) } - ProgramUniformMatrix3x2dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix3x2dv(program, location, count, transpose, value) } - ProgramUniformMatrix2x4dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix2x4dv(program, location, count, transpose, value) } - ProgramUniformMatrix4x2dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix4x2dv(program, location, count, transpose, value) } - ProgramUniformMatrix3x4dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix3x4dv(program, location, count, transpose, value) } - ProgramUniformMatrix4x3dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix4x3dv(program, location, count, transpose, value) } - ValidateProgramPipeline :: #force_inline proc "c" (pipeline: u32) { impl_ValidateProgramPipeline(pipeline) } - GetProgramPipelineInfoLog :: #force_inline proc "c" (pipeline: u32, bufSize: i32, length: ^i32, infoLog: [^]u8) { impl_GetProgramPipelineInfoLog(pipeline, bufSize, length, infoLog) } - VertexAttribL1d :: #force_inline proc "c" (index: u32, x: f64) { impl_VertexAttribL1d(index, x) } - VertexAttribL2d :: #force_inline proc "c" (index: u32, x: f64, y: f64) { impl_VertexAttribL2d(index, x, y) } - VertexAttribL3d :: #force_inline proc "c" (index: u32, x: f64, y: f64, z: f64) { impl_VertexAttribL3d(index, x, y, z) } - VertexAttribL4d :: #force_inline proc "c" (index: u32, x: f64, y: f64, z: f64, w: f64) { impl_VertexAttribL4d(index, x, y, z, w) } - VertexAttribL1dv :: #force_inline proc "c" (index: u32, v: ^f64) { impl_VertexAttribL1dv(index, v) } - VertexAttribL2dv :: #force_inline proc "c" (index: u32, v: ^[2]f64) { impl_VertexAttribL2dv(index, v) } - VertexAttribL3dv :: #force_inline proc "c" (index: u32, v: ^[3]f64) { impl_VertexAttribL3dv(index, v) } - VertexAttribL4dv :: #force_inline proc "c" (index: u32, v: ^[4]f64) { impl_VertexAttribL4dv(index, v) } - VertexAttribLPointer :: #force_inline proc "c" (index: u32, size: i32, type: u32, stride: i32, pointer: uintptr) { impl_VertexAttribLPointer(index, size, type, stride, pointer) } - GetVertexAttribLdv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]f64) { impl_GetVertexAttribLdv(index, pname, params) } - ViewportArrayv :: #force_inline proc "c" (first: u32, count: i32, v: [^]f32) { impl_ViewportArrayv(first, count, v) } - ViewportIndexedf :: #force_inline proc "c" (index: u32, x: f32, y: f32, w: f32, h: f32) { impl_ViewportIndexedf(index, x, y, w, h) } - ViewportIndexedfv :: #force_inline proc "c" (index: u32, v: ^[4]f32) { impl_ViewportIndexedfv(index, v) } - ScissorArrayv :: #force_inline proc "c" (first: u32, count: i32, v: [^]i32) { impl_ScissorArrayv(first, count, v) } - ScissorIndexed :: #force_inline proc "c" (index: u32, left: i32, bottom: i32, width: i32, height: i32) { impl_ScissorIndexed(index, left, bottom, width, height) } - ScissorIndexedv :: #force_inline proc "c" (index: u32, v: ^[4]i32) { impl_ScissorIndexedv(index, v) } - DepthRangeArrayv :: #force_inline proc "c" (first: u32, count: i32, v: [^]f64) { impl_DepthRangeArrayv(first, count, v) } - DepthRangeIndexed :: #force_inline proc "c" (index: u32, n: f64, f: f64) { impl_DepthRangeIndexed(index, n, f) } - GetFloati_v :: #force_inline proc "c" (target: u32, index: u32, data: ^f32) { impl_GetFloati_v(target, index, data) } - GetDoublei_v :: #force_inline proc "c" (target: u32, index: u32, data: ^f64) { impl_GetDoublei_v(target, index, data) } + ReleaseShaderCompiler :: proc "c" () { impl_ReleaseShaderCompiler() } + ShaderBinary :: proc "c" (count: i32, shaders: ^u32, binaryformat: u32, binary: rawptr, length: i32) { impl_ShaderBinary(count, shaders, binaryformat, binary, length) } + GetShaderPrecisionFormat :: proc "c" (shadertype: u32, precisiontype: u32, range: ^i32, precision: ^i32) { impl_GetShaderPrecisionFormat(shadertype, precisiontype, range, precision) } + DepthRangef :: proc "c" (n: f32, f: f32) { impl_DepthRangef(n, f) } + ClearDepthf :: proc "c" (d: f32) { impl_ClearDepthf(d) } + GetProgramBinary :: proc "c" (program: u32, bufSize: i32, length: ^i32, binaryFormat: ^u32, binary: rawptr) { impl_GetProgramBinary(program, bufSize, length, binaryFormat, binary) } + ProgramBinary :: proc "c" (program: u32, binaryFormat: u32, binary: rawptr, length: i32) { impl_ProgramBinary(program, binaryFormat, binary, length) } + ProgramParameteri :: proc "c" (program: u32, pname: u32, value: i32) { impl_ProgramParameteri(program, pname, value) } + UseProgramStages :: proc "c" (pipeline: u32, stages: u32, program: u32) { impl_UseProgramStages(pipeline, stages, program) } + ActiveShaderProgram :: proc "c" (pipeline: u32, program: u32) { impl_ActiveShaderProgram(pipeline, program) } + CreateShaderProgramv :: proc "c" (type: u32, count: i32, strings: [^]cstring) -> u32 { ret := impl_CreateShaderProgramv(type, count, strings); return ret } + BindProgramPipeline :: proc "c" (pipeline: u32) { impl_BindProgramPipeline(pipeline) } + DeleteProgramPipelines :: proc "c" (n: i32, pipelines: [^]u32) { impl_DeleteProgramPipelines(n, pipelines) } + GenProgramPipelines :: proc "c" (n: i32, pipelines: [^]u32) { impl_GenProgramPipelines(n, pipelines) } + IsProgramPipeline :: proc "c" (pipeline: u32) -> bool { ret := impl_IsProgramPipeline(pipeline); return ret } + GetProgramPipelineiv :: proc "c" (pipeline: u32, pname: u32, params: [^]i32) { impl_GetProgramPipelineiv(pipeline, pname, params) } + ProgramUniform1i :: proc "c" (program: u32, location: i32, v0: i32) { impl_ProgramUniform1i(program, location, v0) } + ProgramUniform1iv :: proc "c" (program: u32, location: i32, count: i32, value: [^]i32) { impl_ProgramUniform1iv(program, location, count, value) } + ProgramUniform1f :: proc "c" (program: u32, location: i32, v0: f32) { impl_ProgramUniform1f(program, location, v0) } + ProgramUniform1fv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f32) { impl_ProgramUniform1fv(program, location, count, value) } + ProgramUniform1d :: proc "c" (program: u32, location: i32, v0: f64) { impl_ProgramUniform1d(program, location, v0) } + ProgramUniform1dv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f64) { impl_ProgramUniform1dv(program, location, count, value) } + ProgramUniform1ui :: proc "c" (program: u32, location: i32, v0: u32) { impl_ProgramUniform1ui(program, location, v0) } + ProgramUniform1uiv :: proc "c" (program: u32, location: i32, count: i32, value: [^]u32) { impl_ProgramUniform1uiv(program, location, count, value) } + ProgramUniform2i :: proc "c" (program: u32, location: i32, v0: i32, v1: i32) { impl_ProgramUniform2i(program, location, v0, v1) } + ProgramUniform2iv :: proc "c" (program: u32, location: i32, count: i32, value: [^]i32) { impl_ProgramUniform2iv(program, location, count, value) } + ProgramUniform2f :: proc "c" (program: u32, location: i32, v0: f32, v1: f32) { impl_ProgramUniform2f(program, location, v0, v1) } + ProgramUniform2fv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f32) { impl_ProgramUniform2fv(program, location, count, value) } + ProgramUniform2d :: proc "c" (program: u32, location: i32, v0: f64, v1: f64) { impl_ProgramUniform2d(program, location, v0, v1) } + ProgramUniform2dv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f64) { impl_ProgramUniform2dv(program, location, count, value) } + ProgramUniform2ui :: proc "c" (program: u32, location: i32, v0: u32, v1: u32) { impl_ProgramUniform2ui(program, location, v0, v1) } + ProgramUniform2uiv :: proc "c" (program: u32, location: i32, count: i32, value: [^]u32) { impl_ProgramUniform2uiv(program, location, count, value) } + ProgramUniform3i :: proc "c" (program: u32, location: i32, v0: i32, v1: i32, v2: i32) { impl_ProgramUniform3i(program, location, v0, v1, v2) } + ProgramUniform3iv :: proc "c" (program: u32, location: i32, count: i32, value: [^]i32) { impl_ProgramUniform3iv(program, location, count, value) } + ProgramUniform3f :: proc "c" (program: u32, location: i32, v0: f32, v1: f32, v2: f32) { impl_ProgramUniform3f(program, location, v0, v1, v2) } + ProgramUniform3fv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f32) { impl_ProgramUniform3fv(program, location, count, value) } + ProgramUniform3d :: proc "c" (program: u32, location: i32, v0: f64, v1: f64, v2: f64) { impl_ProgramUniform3d(program, location, v0, v1, v2) } + ProgramUniform3dv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f64) { impl_ProgramUniform3dv(program, location, count, value) } + ProgramUniform3ui :: proc "c" (program: u32, location: i32, v0: u32, v1: u32, v2: u32) { impl_ProgramUniform3ui(program, location, v0, v1, v2) } + ProgramUniform3uiv :: proc "c" (program: u32, location: i32, count: i32, value: [^]u32) { impl_ProgramUniform3uiv(program, location, count, value) } + ProgramUniform4i :: proc "c" (program: u32, location: i32, v0: i32, v1: i32, v2: i32, v3: i32) { impl_ProgramUniform4i(program, location, v0, v1, v2, v3) } + ProgramUniform4iv :: proc "c" (program: u32, location: i32, count: i32, value: [^]i32) { impl_ProgramUniform4iv(program, location, count, value) } + ProgramUniform4f :: proc "c" (program: u32, location: i32, v0: f32, v1: f32, v2: f32, v3: f32) { impl_ProgramUniform4f(program, location, v0, v1, v2, v3) } + ProgramUniform4fv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f32) { impl_ProgramUniform4fv(program, location, count, value) } + ProgramUniform4d :: proc "c" (program: u32, location: i32, v0: f64, v1: f64, v2: f64, v3: f64) { impl_ProgramUniform4d(program, location, v0, v1, v2, v3) } + ProgramUniform4dv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f64) { impl_ProgramUniform4dv(program, location, count, value) } + ProgramUniform4ui :: proc "c" (program: u32, location: i32, v0: u32, v1: u32, v2: u32, v3: u32) { impl_ProgramUniform4ui(program, location, v0, v1, v2, v3) } + ProgramUniform4uiv :: proc "c" (program: u32, location: i32, count: i32, value: [^]u32) { impl_ProgramUniform4uiv(program, location, count, value) } + ProgramUniformMatrix2fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix2fv(program, location, count, transpose, value) } + ProgramUniformMatrix3fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix3fv(program, location, count, transpose, value) } + ProgramUniformMatrix4fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix4fv(program, location, count, transpose, value) } + ProgramUniformMatrix2dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix2dv(program, location, count, transpose, value) } + ProgramUniformMatrix3dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix3dv(program, location, count, transpose, value) } + ProgramUniformMatrix4dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix4dv(program, location, count, transpose, value) } + ProgramUniformMatrix2x3fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix2x3fv(program, location, count, transpose, value) } + ProgramUniformMatrix3x2fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix3x2fv(program, location, count, transpose, value) } + ProgramUniformMatrix2x4fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix2x4fv(program, location, count, transpose, value) } + ProgramUniformMatrix4x2fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix4x2fv(program, location, count, transpose, value) } + ProgramUniformMatrix3x4fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix3x4fv(program, location, count, transpose, value) } + ProgramUniformMatrix4x3fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32) { impl_ProgramUniformMatrix4x3fv(program, location, count, transpose, value) } + ProgramUniformMatrix2x3dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix2x3dv(program, location, count, transpose, value) } + ProgramUniformMatrix3x2dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix3x2dv(program, location, count, transpose, value) } + ProgramUniformMatrix2x4dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix2x4dv(program, location, count, transpose, value) } + ProgramUniformMatrix4x2dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix4x2dv(program, location, count, transpose, value) } + ProgramUniformMatrix3x4dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix3x4dv(program, location, count, transpose, value) } + ProgramUniformMatrix4x3dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64) { impl_ProgramUniformMatrix4x3dv(program, location, count, transpose, value) } + ValidateProgramPipeline :: proc "c" (pipeline: u32) { impl_ValidateProgramPipeline(pipeline) } + GetProgramPipelineInfoLog :: proc "c" (pipeline: u32, bufSize: i32, length: ^i32, infoLog: [^]u8) { impl_GetProgramPipelineInfoLog(pipeline, bufSize, length, infoLog) } + VertexAttribL1d :: proc "c" (index: u32, x: f64) { impl_VertexAttribL1d(index, x) } + VertexAttribL2d :: proc "c" (index: u32, x: f64, y: f64) { impl_VertexAttribL2d(index, x, y) } + VertexAttribL3d :: proc "c" (index: u32, x: f64, y: f64, z: f64) { impl_VertexAttribL3d(index, x, y, z) } + VertexAttribL4d :: proc "c" (index: u32, x: f64, y: f64, z: f64, w: f64) { impl_VertexAttribL4d(index, x, y, z, w) } + VertexAttribL1dv :: proc "c" (index: u32, v: ^f64) { impl_VertexAttribL1dv(index, v) } + VertexAttribL2dv :: proc "c" (index: u32, v: ^[2]f64) { impl_VertexAttribL2dv(index, v) } + VertexAttribL3dv :: proc "c" (index: u32, v: ^[3]f64) { impl_VertexAttribL3dv(index, v) } + VertexAttribL4dv :: proc "c" (index: u32, v: ^[4]f64) { impl_VertexAttribL4dv(index, v) } + VertexAttribLPointer :: proc "c" (index: u32, size: i32, type: u32, stride: i32, pointer: uintptr) { impl_VertexAttribLPointer(index, size, type, stride, pointer) } + GetVertexAttribLdv :: proc "c" (index: u32, pname: u32, params: [^]f64) { impl_GetVertexAttribLdv(index, pname, params) } + ViewportArrayv :: proc "c" (first: u32, count: i32, v: [^]f32) { impl_ViewportArrayv(first, count, v) } + ViewportIndexedf :: proc "c" (index: u32, x: f32, y: f32, w: f32, h: f32) { impl_ViewportIndexedf(index, x, y, w, h) } + ViewportIndexedfv :: proc "c" (index: u32, v: ^[4]f32) { impl_ViewportIndexedfv(index, v) } + ScissorArrayv :: proc "c" (first: u32, count: i32, v: [^]i32) { impl_ScissorArrayv(first, count, v) } + ScissorIndexed :: proc "c" (index: u32, left: i32, bottom: i32, width: i32, height: i32) { impl_ScissorIndexed(index, left, bottom, width, height) } + ScissorIndexedv :: proc "c" (index: u32, v: ^[4]i32) { impl_ScissorIndexedv(index, v) } + DepthRangeArrayv :: proc "c" (first: u32, count: i32, v: [^]f64) { impl_DepthRangeArrayv(first, count, v) } + DepthRangeIndexed :: proc "c" (index: u32, n: f64, f: f64) { impl_DepthRangeIndexed(index, n, f) } + GetFloati_v :: proc "c" (target: u32, index: u32, data: ^f32) { impl_GetFloati_v(target, index, data) } + GetDoublei_v :: proc "c" (target: u32, index: u32, data: ^f64) { impl_GetDoublei_v(target, index, data) } // VERSION_4_2 - DrawArraysInstancedBaseInstance :: #force_inline proc "c" (mode: u32, first: i32, count: i32, instancecount: i32, baseinstance: u32) { impl_DrawArraysInstancedBaseInstance(mode, first, count, instancecount, baseinstance) } - DrawElementsInstancedBaseInstance :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, baseinstance: u32) { impl_DrawElementsInstancedBaseInstance(mode, count, type, indices, instancecount, baseinstance) } - DrawElementsInstancedBaseVertexBaseInstance :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, basevertex: i32, baseinstance: u32) { impl_DrawElementsInstancedBaseVertexBaseInstance(mode, count, type, indices, instancecount, basevertex, baseinstance) } - GetInternalformativ :: #force_inline proc "c" (target: u32, internalformat: u32, pname: u32, bufSize: i32, params: [^]i32) { impl_GetInternalformativ(target, internalformat, pname, bufSize, params) } - GetActiveAtomicCounterBufferiv :: #force_inline proc "c" (program: u32, bufferIndex: u32, pname: u32, params: [^]i32) { impl_GetActiveAtomicCounterBufferiv(program, bufferIndex, pname, params) } - BindImageTexture :: #force_inline proc "c" (unit: u32, texture: u32, level: i32, layered: bool, layer: i32, access: u32, format: u32) { impl_BindImageTexture(unit, texture, level, layered, layer, access, format) } - MemoryBarrier :: #force_inline proc "c" (barriers: u32) { impl_MemoryBarrier(barriers) } - TexStorage1D :: #force_inline proc "c" (target: u32, levels: i32, internalformat: u32, width: i32) { impl_TexStorage1D(target, levels, internalformat, width) } - TexStorage2D :: #force_inline proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, height: i32) { impl_TexStorage2D(target, levels, internalformat, width, height) } - TexStorage3D :: #force_inline proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, height: i32, depth: i32) { impl_TexStorage3D(target, levels, internalformat, width, height, depth) } - DrawTransformFeedbackInstanced :: #force_inline proc "c" (mode: u32, id: u32, instancecount: i32) { impl_DrawTransformFeedbackInstanced(mode, id, instancecount) } - DrawTransformFeedbackStreamInstanced :: #force_inline proc "c" (mode: u32, id: u32, stream: u32, instancecount: i32) { impl_DrawTransformFeedbackStreamInstanced(mode, id, stream, instancecount) } + DrawArraysInstancedBaseInstance :: proc "c" (mode: u32, first: i32, count: i32, instancecount: i32, baseinstance: u32) { impl_DrawArraysInstancedBaseInstance(mode, first, count, instancecount, baseinstance) } + DrawElementsInstancedBaseInstance :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, baseinstance: u32) { impl_DrawElementsInstancedBaseInstance(mode, count, type, indices, instancecount, baseinstance) } + DrawElementsInstancedBaseVertexBaseInstance :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, basevertex: i32, baseinstance: u32) { impl_DrawElementsInstancedBaseVertexBaseInstance(mode, count, type, indices, instancecount, basevertex, baseinstance) } + GetInternalformativ :: proc "c" (target: u32, internalformat: u32, pname: u32, bufSize: i32, params: [^]i32) { impl_GetInternalformativ(target, internalformat, pname, bufSize, params) } + GetActiveAtomicCounterBufferiv :: proc "c" (program: u32, bufferIndex: u32, pname: u32, params: [^]i32) { impl_GetActiveAtomicCounterBufferiv(program, bufferIndex, pname, params) } + BindImageTexture :: proc "c" (unit: u32, texture: u32, level: i32, layered: bool, layer: i32, access: u32, format: u32) { impl_BindImageTexture(unit, texture, level, layered, layer, access, format) } + MemoryBarrier :: proc "c" (barriers: u32) { impl_MemoryBarrier(barriers) } + TexStorage1D :: proc "c" (target: u32, levels: i32, internalformat: u32, width: i32) { impl_TexStorage1D(target, levels, internalformat, width) } + TexStorage2D :: proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, height: i32) { impl_TexStorage2D(target, levels, internalformat, width, height) } + TexStorage3D :: proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, height: i32, depth: i32) { impl_TexStorage3D(target, levels, internalformat, width, height, depth) } + DrawTransformFeedbackInstanced :: proc "c" (mode: u32, id: u32, instancecount: i32) { impl_DrawTransformFeedbackInstanced(mode, id, instancecount) } + DrawTransformFeedbackStreamInstanced :: proc "c" (mode: u32, id: u32, stream: u32, instancecount: i32) { impl_DrawTransformFeedbackStreamInstanced(mode, id, stream, instancecount) } // VERSION_4_3 - ClearBufferData :: #force_inline proc "c" (target: u32, internalformat: u32, format: u32, type: u32, data: rawptr) { impl_ClearBufferData(target, internalformat, format, type, data) } - ClearBufferSubData :: #force_inline proc "c" (target: u32, internalformat: u32, offset: int, size: int, format: u32, type: u32, data: rawptr) { impl_ClearBufferSubData(target, internalformat, offset, size, format, type, data) } - DispatchCompute :: #force_inline proc "c" (num_groups_x: u32, num_groups_y: u32, num_groups_z: u32) { impl_DispatchCompute(num_groups_x, num_groups_y, num_groups_z) } - DispatchComputeIndirect :: #force_inline proc "c" (indirect: ^DispatchIndirectCommand) { impl_DispatchComputeIndirect(indirect) } - CopyImageSubData :: #force_inline proc "c" (srcName: u32, srcTarget: u32, srcLevel: i32, srcX: i32, srcY: i32, srcZ: i32, dstName: u32, dstTarget: u32, dstLevel: i32, dstX: i32, dstY: i32, dstZ: i32, srcWidth: i32, srcHeight: i32, srcDepth: i32) { impl_CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth) } - FramebufferParameteri :: #force_inline proc "c" (target: u32, pname: u32, param: i32) { impl_FramebufferParameteri(target, pname, param) } - GetFramebufferParameteriv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetFramebufferParameteriv(target, pname, params) } - GetInternalformati64v :: #force_inline proc "c" (target: u32, internalformat: u32, pname: u32, bufSize: i32, params: [^]i64) { impl_GetInternalformati64v(target, internalformat, pname, bufSize, params) } - InvalidateTexSubImage :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32) { impl_InvalidateTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth) } - InvalidateTexImage :: #force_inline proc "c" (texture: u32, level: i32) { impl_InvalidateTexImage(texture, level) } - InvalidateBufferSubData :: #force_inline proc "c" (buffer: u32, offset: int, length: int) { impl_InvalidateBufferSubData(buffer, offset, length) } - InvalidateBufferData :: #force_inline proc "c" (buffer: u32) { impl_InvalidateBufferData(buffer) } - InvalidateFramebuffer :: #force_inline proc "c" (target: u32, numAttachments: i32, attachments: [^]u32) { impl_InvalidateFramebuffer(target, numAttachments, attachments) } - InvalidateSubFramebuffer :: #force_inline proc "c" (target: u32, numAttachments: i32, attachments: [^]u32, x: i32, y: i32, width: i32, height: i32) { impl_InvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height) } - MultiDrawArraysIndirect :: #force_inline proc "c" (mode: u32, indirect: [^]DrawArraysIndirectCommand, drawcount: i32, stride: i32) { impl_MultiDrawArraysIndirect(mode, indirect, drawcount, stride) } - MultiDrawElementsIndirect :: #force_inline proc "c" (mode: u32, type: u32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, stride: i32) { impl_MultiDrawElementsIndirect(mode, type, indirect, drawcount, stride) } - GetProgramInterfaceiv :: #force_inline proc "c" (program: u32, programInterface: u32, pname: u32, params: [^]i32) { impl_GetProgramInterfaceiv(program, programInterface, pname, params) } - GetProgramResourceIndex :: #force_inline proc "c" (program: u32, programInterface: u32, name: cstring) -> u32 { ret := impl_GetProgramResourceIndex(program, programInterface, name) ; return ret } - GetProgramResourceName :: #force_inline proc "c" (program: u32, programInterface: u32, index: u32, bufSize: i32, length: ^i32, name: [^]u8) { impl_GetProgramResourceName(program, programInterface, index, bufSize, length, name) } - GetProgramResourceiv :: #force_inline proc "c" (program: u32, programInterface: u32, index: u32, propCount: i32, props: [^]u32, bufSize: i32, length: ^i32, params: [^]i32) { impl_GetProgramResourceiv(program, programInterface, index, propCount, props, bufSize, length, params) } - GetProgramResourceLocation :: #force_inline proc "c" (program: u32, programInterface: u32, name: cstring) -> i32 { ret := impl_GetProgramResourceLocation(program, programInterface, name); return ret } - GetProgramResourceLocationIndex :: #force_inline proc "c" (program: u32, programInterface: u32, name: cstring) -> i32 { ret := impl_GetProgramResourceLocationIndex(program, programInterface, name); return ret } - ShaderStorageBlockBinding :: #force_inline proc "c" (program: u32, storageBlockIndex: u32, storageBlockBinding: u32) { impl_ShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding) } - TexBufferRange :: #force_inline proc "c" (target: u32, internalformat: u32, buffer: u32, offset: int, size: int) { impl_TexBufferRange(target, internalformat, buffer, offset, size) } - TexStorage2DMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool) { impl_TexStorage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations) } - TexStorage3DMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool) { impl_TexStorage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations) } - TextureView :: #force_inline proc "c" (texture: u32, target: u32, origtexture: u32, internalformat: u32, minlevel: u32, numlevels: u32, minlayer: u32, numlayers: u32) { impl_TextureView(texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers) } - BindVertexBuffer :: #force_inline proc "c" (bindingindex: u32, buffer: u32, offset: int, stride: i32) { impl_BindVertexBuffer(bindingindex, buffer, offset, stride) } - VertexAttribFormat :: #force_inline proc "c" (attribindex: u32, size: i32, type: u32, normalized: bool, relativeoffset: u32) { impl_VertexAttribFormat(attribindex, size, type, normalized, relativeoffset) } - VertexAttribIFormat :: #force_inline proc "c" (attribindex: u32, size: i32, type: u32, relativeoffset: u32) { impl_VertexAttribIFormat(attribindex, size, type, relativeoffset) } - VertexAttribLFormat :: #force_inline proc "c" (attribindex: u32, size: i32, type: u32, relativeoffset: u32) { impl_VertexAttribLFormat(attribindex, size, type, relativeoffset) } - VertexAttribBinding :: #force_inline proc "c" (attribindex: u32, bindingindex: u32) { impl_VertexAttribBinding(attribindex, bindingindex) } - VertexBindingDivisor :: #force_inline proc "c" (bindingindex: u32, divisor: u32) { impl_VertexBindingDivisor(bindingindex, divisor) } - DebugMessageControl :: #force_inline proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool) { impl_DebugMessageControl(source, type, severity, count, ids, enabled) } - DebugMessageInsert :: #force_inline proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: ^u8) { impl_DebugMessageInsert(source, type, id, severity, length, buf) } - DebugMessageCallback :: #force_inline proc "c" (callback: debug_proc_t, userParam: rawptr) { impl_DebugMessageCallback(callback, userParam) } - GetDebugMessageLog :: #force_inline proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8) -> u32 { ret := impl_GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog); return ret } - PushDebugGroup :: #force_inline proc "c" (source: u32, id: u32, length: i32, message: cstring) { impl_PushDebugGroup(source, id, length, message) } - PopDebugGroup :: #force_inline proc "c" () { impl_PopDebugGroup() } - ObjectLabel :: #force_inline proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8) { impl_ObjectLabel(identifier, name, length, label) } - GetObjectLabel :: #force_inline proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8) { impl_GetObjectLabel(identifier, name, bufSize, length, label) } - ObjectPtrLabel :: #force_inline proc "c" (ptr: rawptr, length: i32, label: [^]u8) { impl_ObjectPtrLabel(ptr, length, label) } - GetObjectPtrLabel :: #force_inline proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8) { impl_GetObjectPtrLabel(ptr, bufSize, length, label) } + ClearBufferData :: proc "c" (target: u32, internalformat: u32, format: u32, type: u32, data: rawptr) { impl_ClearBufferData(target, internalformat, format, type, data) } + ClearBufferSubData :: proc "c" (target: u32, internalformat: u32, offset: int, size: int, format: u32, type: u32, data: rawptr) { impl_ClearBufferSubData(target, internalformat, offset, size, format, type, data) } + DispatchCompute :: proc "c" (num_groups_x: u32, num_groups_y: u32, num_groups_z: u32) { impl_DispatchCompute(num_groups_x, num_groups_y, num_groups_z) } + DispatchComputeIndirect :: proc "c" (indirect: ^DispatchIndirectCommand) { impl_DispatchComputeIndirect(indirect) } + CopyImageSubData :: proc "c" (srcName: u32, srcTarget: u32, srcLevel: i32, srcX: i32, srcY: i32, srcZ: i32, dstName: u32, dstTarget: u32, dstLevel: i32, dstX: i32, dstY: i32, dstZ: i32, srcWidth: i32, srcHeight: i32, srcDepth: i32) { impl_CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth) } + FramebufferParameteri :: proc "c" (target: u32, pname: u32, param: i32) { impl_FramebufferParameteri(target, pname, param) } + GetFramebufferParameteriv :: proc "c" (target: u32, pname: u32, params: [^]i32) { impl_GetFramebufferParameteriv(target, pname, params) } + GetInternalformati64v :: proc "c" (target: u32, internalformat: u32, pname: u32, bufSize: i32, params: [^]i64) { impl_GetInternalformati64v(target, internalformat, pname, bufSize, params) } + InvalidateTexSubImage :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32) { impl_InvalidateTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth) } + InvalidateTexImage :: proc "c" (texture: u32, level: i32) { impl_InvalidateTexImage(texture, level) } + InvalidateBufferSubData :: proc "c" (buffer: u32, offset: int, length: int) { impl_InvalidateBufferSubData(buffer, offset, length) } + InvalidateBufferData :: proc "c" (buffer: u32) { impl_InvalidateBufferData(buffer) } + InvalidateFramebuffer :: proc "c" (target: u32, numAttachments: i32, attachments: [^]u32) { impl_InvalidateFramebuffer(target, numAttachments, attachments) } + InvalidateSubFramebuffer :: proc "c" (target: u32, numAttachments: i32, attachments: [^]u32, x: i32, y: i32, width: i32, height: i32) { impl_InvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height) } + MultiDrawArraysIndirect :: proc "c" (mode: u32, indirect: [^]DrawArraysIndirectCommand, drawcount: i32, stride: i32) { impl_MultiDrawArraysIndirect(mode, indirect, drawcount, stride) } + MultiDrawElementsIndirect :: proc "c" (mode: u32, type: u32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, stride: i32) { impl_MultiDrawElementsIndirect(mode, type, indirect, drawcount, stride) } + GetProgramInterfaceiv :: proc "c" (program: u32, programInterface: u32, pname: u32, params: [^]i32) { impl_GetProgramInterfaceiv(program, programInterface, pname, params) } + GetProgramResourceIndex :: proc "c" (program: u32, programInterface: u32, name: cstring) -> u32 { ret := impl_GetProgramResourceIndex(program, programInterface, name) ; return ret } + GetProgramResourceName :: proc "c" (program: u32, programInterface: u32, index: u32, bufSize: i32, length: ^i32, name: [^]u8) { impl_GetProgramResourceName(program, programInterface, index, bufSize, length, name) } + GetProgramResourceiv :: proc "c" (program: u32, programInterface: u32, index: u32, propCount: i32, props: [^]u32, bufSize: i32, length: ^i32, params: [^]i32) { impl_GetProgramResourceiv(program, programInterface, index, propCount, props, bufSize, length, params) } + GetProgramResourceLocation :: proc "c" (program: u32, programInterface: u32, name: cstring) -> i32 { ret := impl_GetProgramResourceLocation(program, programInterface, name); return ret } + GetProgramResourceLocationIndex :: proc "c" (program: u32, programInterface: u32, name: cstring) -> i32 { ret := impl_GetProgramResourceLocationIndex(program, programInterface, name); return ret } + ShaderStorageBlockBinding :: proc "c" (program: u32, storageBlockIndex: u32, storageBlockBinding: u32) { impl_ShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding) } + TexBufferRange :: proc "c" (target: u32, internalformat: u32, buffer: u32, offset: int, size: int) { impl_TexBufferRange(target, internalformat, buffer, offset, size) } + TexStorage2DMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool) { impl_TexStorage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations) } + TexStorage3DMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool) { impl_TexStorage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations) } + TextureView :: proc "c" (texture: u32, target: u32, origtexture: u32, internalformat: u32, minlevel: u32, numlevels: u32, minlayer: u32, numlayers: u32) { impl_TextureView(texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers) } + BindVertexBuffer :: proc "c" (bindingindex: u32, buffer: u32, offset: int, stride: i32) { impl_BindVertexBuffer(bindingindex, buffer, offset, stride) } + VertexAttribFormat :: proc "c" (attribindex: u32, size: i32, type: u32, normalized: bool, relativeoffset: u32) { impl_VertexAttribFormat(attribindex, size, type, normalized, relativeoffset) } + VertexAttribIFormat :: proc "c" (attribindex: u32, size: i32, type: u32, relativeoffset: u32) { impl_VertexAttribIFormat(attribindex, size, type, relativeoffset) } + VertexAttribLFormat :: proc "c" (attribindex: u32, size: i32, type: u32, relativeoffset: u32) { impl_VertexAttribLFormat(attribindex, size, type, relativeoffset) } + VertexAttribBinding :: proc "c" (attribindex: u32, bindingindex: u32) { impl_VertexAttribBinding(attribindex, bindingindex) } + VertexBindingDivisor :: proc "c" (bindingindex: u32, divisor: u32) { impl_VertexBindingDivisor(bindingindex, divisor) } + DebugMessageControl :: proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool) { impl_DebugMessageControl(source, type, severity, count, ids, enabled) } + DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: ^u8) { impl_DebugMessageInsert(source, type, id, severity, length, buf) } + DebugMessageCallback :: proc "c" (callback: debug_proc_t, userParam: rawptr) { impl_DebugMessageCallback(callback, userParam) } + GetDebugMessageLog :: proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8) -> u32 { ret := impl_GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog); return ret } + PushDebugGroup :: proc "c" (source: u32, id: u32, length: i32, message: cstring) { impl_PushDebugGroup(source, id, length, message) } + PopDebugGroup :: proc "c" () { impl_PopDebugGroup() } + ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8) { impl_ObjectLabel(identifier, name, length, label) } + GetObjectLabel :: proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8) { impl_GetObjectLabel(identifier, name, bufSize, length, label) } + ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: [^]u8) { impl_ObjectPtrLabel(ptr, length, label) } + GetObjectPtrLabel :: proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8) { impl_GetObjectPtrLabel(ptr, bufSize, length, label) } // VERSION_4_4 - BufferStorage :: #force_inline proc "c" (target: u32, size: int, data: rawptr, flags: u32) { impl_BufferStorage(target, size, data, flags) } - ClearTexImage :: #force_inline proc "c" (texture: u32, level: i32, format: u32, type: u32, data: rawptr) { impl_ClearTexImage(texture, level, format, type, data) } - ClearTexSubImage :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, data: rawptr) { impl_ClearTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data) } - BindBuffersBase :: #force_inline proc "c" (target: u32, first: u32, count: i32, buffers: [^]u32) { impl_BindBuffersBase(target, first, count, buffers) } - BindBuffersRange :: #force_inline proc "c" (target: u32, first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, sizes: [^]int) { impl_BindBuffersRange(target, first, count, buffers, offsets, sizes) } - BindTextures :: #force_inline proc "c" (first: u32, count: i32, textures: [^]u32) { impl_BindTextures(first, count, textures) } - BindSamplers :: #force_inline proc "c" (first: u32, count: i32, samplers: [^]u32) { impl_BindSamplers(first, count, samplers) } - BindImageTextures :: #force_inline proc "c" (first: u32, count: i32, textures: [^]u32) { impl_BindImageTextures(first, count, textures) } - BindVertexBuffers :: #force_inline proc "c" (first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, strides: [^]i32) { impl_BindVertexBuffers(first, count, buffers, offsets, strides) } + BufferStorage :: proc "c" (target: u32, size: int, data: rawptr, flags: u32) { impl_BufferStorage(target, size, data, flags) } + ClearTexImage :: proc "c" (texture: u32, level: i32, format: u32, type: u32, data: rawptr) { impl_ClearTexImage(texture, level, format, type, data) } + ClearTexSubImage :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, data: rawptr) { impl_ClearTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data) } + BindBuffersBase :: proc "c" (target: u32, first: u32, count: i32, buffers: [^]u32) { impl_BindBuffersBase(target, first, count, buffers) } + BindBuffersRange :: proc "c" (target: u32, first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, sizes: [^]int) { impl_BindBuffersRange(target, first, count, buffers, offsets, sizes) } + BindTextures :: proc "c" (first: u32, count: i32, textures: [^]u32) { impl_BindTextures(first, count, textures) } + BindSamplers :: proc "c" (first: u32, count: i32, samplers: [^]u32) { impl_BindSamplers(first, count, samplers) } + BindImageTextures :: proc "c" (first: u32, count: i32, textures: [^]u32) { impl_BindImageTextures(first, count, textures) } + BindVertexBuffers :: proc "c" (first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, strides: [^]i32) { impl_BindVertexBuffers(first, count, buffers, offsets, strides) } // VERSION_4_5 - ClipControl :: #force_inline proc "c" (origin: u32, depth: u32) { impl_ClipControl(origin, depth) } - CreateTransformFeedbacks :: #force_inline proc "c" (n: i32, ids: [^]u32) { impl_CreateTransformFeedbacks(n, ids) } - TransformFeedbackBufferBase :: #force_inline proc "c" (xfb: u32, index: u32, buffer: u32) { impl_TransformFeedbackBufferBase(xfb, index, buffer) } - TransformFeedbackBufferRange :: #force_inline proc "c" (xfb: u32, index: u32, buffer: u32, offset: int, size: int) { impl_TransformFeedbackBufferRange(xfb, index, buffer, offset, size) } - GetTransformFeedbackiv :: #force_inline proc "c" (xfb: u32, pname: u32, param: ^i32) { impl_GetTransformFeedbackiv(xfb, pname, param) } - GetTransformFeedbacki_v :: #force_inline proc "c" (xfb: u32, pname: u32, index: u32, param: ^i32) { impl_GetTransformFeedbacki_v(xfb, pname, index, param) } - GetTransformFeedbacki64_v :: #force_inline proc "c" (xfb: u32, pname: u32, index: u32, param: ^i64) { impl_GetTransformFeedbacki64_v(xfb, pname, index, param) } - CreateBuffers :: #force_inline proc "c" (n: i32, buffers: [^]u32) { impl_CreateBuffers(n, buffers) } - NamedBufferStorage :: #force_inline proc "c" (buffer: u32, size: int, data: rawptr, flags: u32) { impl_NamedBufferStorage(buffer, size, data, flags) } - NamedBufferData :: #force_inline proc "c" (buffer: u32, size: int, data: rawptr, usage: u32) { impl_NamedBufferData(buffer, size, data, usage) } - NamedBufferSubData :: #force_inline proc "c" (buffer: u32, offset: int, size: int, data: rawptr) { impl_NamedBufferSubData(buffer, offset, size, data) } - CopyNamedBufferSubData :: #force_inline proc "c" (readBuffer: u32, writeBuffer: u32, readOffset: int, writeOffset: int, size: int) { impl_CopyNamedBufferSubData(readBuffer, writeBuffer, readOffset, writeOffset, size) } - ClearNamedBufferData :: #force_inline proc "c" (buffer: u32, internalformat: u32, format: u32, type: u32, data: rawptr) { impl_ClearNamedBufferData(buffer, internalformat, format, type, data) } - ClearNamedBufferSubData :: #force_inline proc "c" (buffer: u32, internalformat: u32, offset: int, size: int, format: u32, type: u32, data: rawptr) { impl_ClearNamedBufferSubData(buffer, internalformat, offset, size, format, type, data) } - MapNamedBuffer :: #force_inline proc "c" (buffer: u32, access: u32) -> rawptr { ret := impl_MapNamedBuffer(buffer, access); return ret } - MapNamedBufferRange :: #force_inline proc "c" (buffer: u32, offset: int, length: int, access: u32) -> rawptr { ret := impl_MapNamedBufferRange(buffer, offset, length, access); return ret } - UnmapNamedBuffer :: #force_inline proc "c" (buffer: u32) -> bool { ret := impl_UnmapNamedBuffer(buffer); return ret } - FlushMappedNamedBufferRange :: #force_inline proc "c" (buffer: u32, offset: int, length: int) { impl_FlushMappedNamedBufferRange(buffer, offset, length) } - GetNamedBufferParameteriv :: #force_inline proc "c" (buffer: u32, pname: u32, params: [^]i32) { impl_GetNamedBufferParameteriv(buffer, pname, params) } - GetNamedBufferParameteri64v :: #force_inline proc "c" (buffer: u32, pname: u32, params: [^]i64) { impl_GetNamedBufferParameteri64v(buffer, pname, params) } - GetNamedBufferPointerv :: #force_inline proc "c" (buffer: u32, pname: u32, params: [^]rawptr) { impl_GetNamedBufferPointerv(buffer, pname, params) } - GetNamedBufferSubData :: #force_inline proc "c" (buffer: u32, offset: int, size: int, data: rawptr) { impl_GetNamedBufferSubData(buffer, offset, size, data) } - CreateFramebuffers :: #force_inline proc "c" (n: i32, framebuffers: [^]u32) { impl_CreateFramebuffers(n, framebuffers) } - NamedFramebufferRenderbuffer :: #force_inline proc "c" (framebuffer: u32, attachment: u32, renderbuffertarget: u32, renderbuffer: u32) { impl_NamedFramebufferRenderbuffer(framebuffer, attachment, renderbuffertarget, renderbuffer) } - NamedFramebufferParameteri :: #force_inline proc "c" (framebuffer: u32, pname: u32, param: i32) { impl_NamedFramebufferParameteri(framebuffer, pname, param) } - NamedFramebufferTexture :: #force_inline proc "c" (framebuffer: u32, attachment: u32, texture: u32, level: i32) { impl_NamedFramebufferTexture(framebuffer, attachment, texture, level) } - NamedFramebufferTextureLayer :: #force_inline proc "c" (framebuffer: u32, attachment: u32, texture: u32, level: i32, layer: i32) { impl_NamedFramebufferTextureLayer(framebuffer, attachment, texture, level, layer) } - NamedFramebufferDrawBuffer :: #force_inline proc "c" (framebuffer: u32, buf: u32) { impl_NamedFramebufferDrawBuffer(framebuffer, buf) } - NamedFramebufferDrawBuffers :: #force_inline proc "c" (framebuffer: u32, n: i32, bufs: [^]u32) { impl_NamedFramebufferDrawBuffers(framebuffer, n, bufs) } - NamedFramebufferReadBuffer :: #force_inline proc "c" (framebuffer: u32, src: u32) { impl_NamedFramebufferReadBuffer(framebuffer, src) } - InvalidateNamedFramebufferData :: #force_inline proc "c" (framebuffer: u32, numAttachments: i32, attachments: [^]u32) { impl_InvalidateNamedFramebufferData(framebuffer, numAttachments, attachments) } - InvalidateNamedFramebufferSubData :: #force_inline proc "c" (framebuffer: u32, numAttachments: i32, attachments: [^]u32, x: i32, y: i32, width: i32, height: i32) { impl_InvalidateNamedFramebufferSubData(framebuffer, numAttachments, attachments, x, y, width, height) } - ClearNamedFramebufferiv :: #force_inline proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^i32) { impl_ClearNamedFramebufferiv(framebuffer, buffer, drawbuffer, value) } - ClearNamedFramebufferuiv :: #force_inline proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^u32) { impl_ClearNamedFramebufferuiv(framebuffer, buffer, drawbuffer, value) } - ClearNamedFramebufferfv :: #force_inline proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^f32) { impl_ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value) } - ClearNamedFramebufferfi :: #force_inline proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, depth: f32, stencil: i32) { impl_ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil) } - BlitNamedFramebuffer :: #force_inline proc "c" (readFramebuffer: u32, drawFramebuffer: u32, srcX0: i32, srcY0: i32, srcX1: i32, srcY1: i32, dstX0: i32, dstY0: i32, dstX1: i32, dstY1: i32, mask: u32, filter: u32) { impl_BlitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) } - CheckNamedFramebufferStatus :: #force_inline proc "c" (framebuffer: u32, target: u32) -> u32 { ret := impl_CheckNamedFramebufferStatus(framebuffer, target); return ret } - GetNamedFramebufferParameteriv :: #force_inline proc "c" (framebuffer: u32, pname: u32, param: ^i32) { impl_GetNamedFramebufferParameteriv(framebuffer, pname, param) } - GetNamedFramebufferAttachmentParameteriv :: #force_inline proc "c" (framebuffer: u32, attachment: u32, pname: u32, params: [^]i32) { impl_GetNamedFramebufferAttachmentParameteriv(framebuffer, attachment, pname, params) } - CreateRenderbuffers :: #force_inline proc "c" (n: i32, renderbuffers: [^]u32) { impl_CreateRenderbuffers(n, renderbuffers) } - NamedRenderbufferStorage :: #force_inline proc "c" (renderbuffer: u32, internalformat: u32, width: i32, height: i32) { impl_NamedRenderbufferStorage(renderbuffer, internalformat, width, height) } - NamedRenderbufferStorageMultisample :: #force_inline proc "c" (renderbuffer: u32, samples: i32, internalformat: u32, width: i32, height: i32) { impl_NamedRenderbufferStorageMultisample(renderbuffer, samples, internalformat, width, height) } - GetNamedRenderbufferParameteriv :: #force_inline proc "c" (renderbuffer: u32, pname: u32, params: [^]i32) { impl_GetNamedRenderbufferParameteriv(renderbuffer, pname, params) } - CreateTextures :: #force_inline proc "c" (target: u32, n: i32, textures: [^]u32) { impl_CreateTextures(target, n, textures) } - TextureBuffer :: #force_inline proc "c" (texture: u32, internalformat: u32, buffer: u32) { impl_TextureBuffer(texture, internalformat, buffer) } - TextureBufferRange :: #force_inline proc "c" (texture: u32, internalformat: u32, buffer: u32, offset: int, size: int) { impl_TextureBufferRange(texture, internalformat, buffer, offset, size) } - TextureStorage1D :: #force_inline proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32) { impl_TextureStorage1D(texture, levels, internalformat, width) } - TextureStorage2D :: #force_inline proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, height: i32) { impl_TextureStorage2D(texture, levels, internalformat, width, height) } - TextureStorage3D :: #force_inline proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, height: i32, depth: i32) { impl_TextureStorage3D(texture, levels, internalformat, width, height, depth) } - TextureStorage2DMultisample :: #force_inline proc "c" (texture: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool) { impl_TextureStorage2DMultisample(texture, samples, internalformat, width, height, fixedsamplelocations) } - TextureStorage3DMultisample :: #force_inline proc "c" (texture: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool) { impl_TextureStorage3DMultisample(texture, samples, internalformat, width, height, depth, fixedsamplelocations) } - TextureSubImage1D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: rawptr) { impl_TextureSubImage1D(texture, level, xoffset, width, format, type, pixels) } - TextureSubImage2D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: rawptr) { impl_TextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, type, pixels) } - TextureSubImage3D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, pixels: rawptr) { impl_TextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } - CompressedTextureSubImage1D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTextureSubImage1D(texture, level, xoffset, width, format, imageSize, data) } - CompressedTextureSubImage2D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, imageSize, data) } - CompressedTextureSubImage3D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) } - CopyTextureSubImage1D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32) { impl_CopyTextureSubImage1D(texture, level, xoffset, x, y, width) } - CopyTextureSubImage2D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32) { impl_CopyTextureSubImage2D(texture, level, xoffset, yoffset, x, y, width, height) } - CopyTextureSubImage3D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, x: i32, y: i32, width: i32, height: i32) { impl_CopyTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, x, y, width, height) } - TextureParameterf :: #force_inline proc "c" (texture: u32, pname: u32, param: f32) { impl_TextureParameterf(texture, pname, param) } - TextureParameterfv :: #force_inline proc "c" (texture: u32, pname: u32, param: ^f32) { impl_TextureParameterfv(texture, pname, param) } - TextureParameteri :: #force_inline proc "c" (texture: u32, pname: u32, param: i32) { impl_TextureParameteri(texture, pname, param) } - TextureParameterIiv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]i32) { impl_TextureParameterIiv(texture, pname, params) } - TextureParameterIuiv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]u32) { impl_TextureParameterIuiv(texture, pname, params) } - TextureParameteriv :: #force_inline proc "c" (texture: u32, pname: u32, param: ^i32) { impl_TextureParameteriv(texture, pname, param) } - GenerateTextureMipmap :: #force_inline proc "c" (texture: u32) { impl_GenerateTextureMipmap(texture) } - BindTextureUnit :: #force_inline proc "c" (unit: u32, texture: u32) { impl_BindTextureUnit(unit, texture) } - GetTextureImage :: #force_inline proc "c" (texture: u32, level: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr) { impl_GetTextureImage(texture, level, format, type, bufSize, pixels) } - GetCompressedTextureImage :: #force_inline proc "c" (texture: u32, level: i32, bufSize: i32, pixels: rawptr) { impl_GetCompressedTextureImage(texture, level, bufSize, pixels) } - GetTextureLevelParameterfv :: #force_inline proc "c" (texture: u32, level: i32, pname: u32, params: [^]f32) { impl_GetTextureLevelParameterfv(texture, level, pname, params) } - GetTextureLevelParameteriv :: #force_inline proc "c" (texture: u32, level: i32, pname: u32, params: [^]i32) { impl_GetTextureLevelParameteriv(texture, level, pname, params) } - GetTextureParameterfv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]f32) { impl_GetTextureParameterfv(texture, pname, params) } - GetTextureParameterIiv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]i32) { impl_GetTextureParameterIiv(texture, pname, params) } - GetTextureParameterIuiv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]u32) { impl_GetTextureParameterIuiv(texture, pname, params) } - GetTextureParameteriv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]i32) { impl_GetTextureParameteriv(texture, pname, params) } - CreateVertexArrays :: #force_inline proc "c" (n: i32, arrays: [^]u32) { impl_CreateVertexArrays(n, arrays) } - DisableVertexArrayAttrib :: #force_inline proc "c" (vaobj: u32, index: u32) { impl_DisableVertexArrayAttrib(vaobj, index) } - EnableVertexArrayAttrib :: #force_inline proc "c" (vaobj: u32, index: u32) { impl_EnableVertexArrayAttrib(vaobj, index) } - VertexArrayElementBuffer :: #force_inline proc "c" (vaobj: u32, buffer: u32) { impl_VertexArrayElementBuffer(vaobj, buffer) } - VertexArrayVertexBuffer :: #force_inline proc "c" (vaobj: u32, bindingindex: u32, buffer: u32, offset: int, stride: i32) { impl_VertexArrayVertexBuffer(vaobj, bindingindex, buffer, offset, stride) } - VertexArrayVertexBuffers :: #force_inline proc "c" (vaobj: u32, first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, strides: [^]i32) { impl_VertexArrayVertexBuffers(vaobj, first, count, buffers, offsets, strides) } - VertexArrayAttribBinding :: #force_inline proc "c" (vaobj: u32, attribindex: u32, bindingindex: u32) { impl_VertexArrayAttribBinding(vaobj, attribindex, bindingindex) } - VertexArrayAttribFormat :: #force_inline proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, normalized: bool, relativeoffset: u32) { impl_VertexArrayAttribFormat(vaobj, attribindex, size, type, normalized, relativeoffset) } - VertexArrayAttribIFormat :: #force_inline proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, relativeoffset: u32) { impl_VertexArrayAttribIFormat(vaobj, attribindex, size, type, relativeoffset) } - VertexArrayAttribLFormat :: #force_inline proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, relativeoffset: u32) { impl_VertexArrayAttribLFormat(vaobj, attribindex, size, type, relativeoffset) } - VertexArrayBindingDivisor :: #force_inline proc "c" (vaobj: u32, bindingindex: u32, divisor: u32) { impl_VertexArrayBindingDivisor(vaobj, bindingindex, divisor) } - GetVertexArrayiv :: #force_inline proc "c" (vaobj: u32, pname: u32, param: ^i32) { impl_GetVertexArrayiv(vaobj, pname, param) } - GetVertexArrayIndexediv :: #force_inline proc "c" (vaobj: u32, index: u32, pname: u32, param: ^i32) { impl_GetVertexArrayIndexediv(vaobj, index, pname, param) } - GetVertexArrayIndexed64iv :: #force_inline proc "c" (vaobj: u32, index: u32, pname: u32, param: ^i64) { impl_GetVertexArrayIndexed64iv(vaobj, index, pname, param) } - CreateSamplers :: #force_inline proc "c" (n: i32, samplers: [^]u32) { impl_CreateSamplers(n, samplers) } - CreateProgramPipelines :: #force_inline proc "c" (n: i32, pipelines: [^]u32) { impl_CreateProgramPipelines(n, pipelines) } - CreateQueries :: #force_inline proc "c" (target: u32, n: i32, ids: [^]u32) { impl_CreateQueries(target, n, ids) } - GetQueryBufferObjecti64v :: #force_inline proc "c" (id: u32, buffer: u32, pname: u32, offset: int) { impl_GetQueryBufferObjecti64v(id, buffer, pname, offset) } - GetQueryBufferObjectiv :: #force_inline proc "c" (id: u32, buffer: u32, pname: u32, offset: int) { impl_GetQueryBufferObjectiv(id, buffer, pname, offset) } - GetQueryBufferObjectui64v :: #force_inline proc "c" (id: u32, buffer: u32, pname: u32, offset: int) { impl_GetQueryBufferObjectui64v(id, buffer, pname, offset) } - GetQueryBufferObjectuiv :: #force_inline proc "c" (id: u32, buffer: u32, pname: u32, offset: int) { impl_GetQueryBufferObjectuiv(id, buffer, pname, offset) } - MemoryBarrierByRegion :: #force_inline proc "c" (barriers: u32) { impl_MemoryBarrierByRegion(barriers) } - GetTextureSubImage :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr) { impl_GetTextureSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels) } - GetCompressedTextureSubImage :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, bufSize: i32, pixels: rawptr) { impl_GetCompressedTextureSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels) } - GetGraphicsResetStatus :: #force_inline proc "c" () -> u32 { ret := impl_GetGraphicsResetStatus(); return ret } - GetnCompressedTexImage :: #force_inline proc "c" (target: u32, lod: i32, bufSize: i32, pixels: rawptr) { impl_GetnCompressedTexImage(target, lod, bufSize, pixels) } - GetnTexImage :: #force_inline proc "c" (target: u32, level: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr) { impl_GetnTexImage(target, level, format, type, bufSize, pixels) } - GetnUniformdv :: #force_inline proc "c" (program: u32, location: i32, bufSize: i32, params: [^]f64) { impl_GetnUniformdv(program, location, bufSize, params) } - GetnUniformfv :: #force_inline proc "c" (program: u32, location: i32, bufSize: i32, params: [^]f32) { impl_GetnUniformfv(program, location, bufSize, params) } - GetnUniformiv :: #force_inline proc "c" (program: u32, location: i32, bufSize: i32, params: [^]i32) { impl_GetnUniformiv(program, location, bufSize, params) } - GetnUniformuiv :: #force_inline proc "c" (program: u32, location: i32, bufSize: i32, params: [^]u32) { impl_GetnUniformuiv(program, location, bufSize, params) } - ReadnPixels :: #force_inline proc "c" (x: i32, y: i32, width: i32, height: i32, format: u32, type: u32, bufSize: i32, data: rawptr) { impl_ReadnPixels(x, y, width, height, format, type, bufSize, data) } - GetnMapdv :: #force_inline proc "c" (target: u32, query: u32, bufSize: i32, v: [^]f64) { impl_GetnMapdv(target, query, bufSize, v) } - GetnMapfv :: #force_inline proc "c" (target: u32, query: u32, bufSize: i32, v: [^]f32) { impl_GetnMapfv(target, query, bufSize, v) } - GetnMapiv :: #force_inline proc "c" (target: u32, query: u32, bufSize: i32, v: [^]i32) { impl_GetnMapiv(target, query, bufSize, v) } - GetnPixelMapusv :: #force_inline proc "c" (map_: u32, bufSize: i32, values: [^]u16) { impl_GetnPixelMapusv(map_, bufSize, values) } - GetnPixelMapfv :: #force_inline proc "c" (map_: u32, bufSize: i32, values: [^]f32) { impl_GetnPixelMapfv(map_, bufSize, values) } - GetnPixelMapuiv :: #force_inline proc "c" (map_: u32, bufSize: i32, values: [^]u32) { impl_GetnPixelMapuiv(map_, bufSize, values) } - GetnPolygonStipple :: #force_inline proc "c" (bufSize: i32, pattern: [^]u8) { impl_GetnPolygonStipple(bufSize, pattern) } - GetnColorTable :: #force_inline proc "c" (target: u32, format: u32, type: u32, bufSize: i32, table: rawptr) { impl_GetnColorTable(target, format, type, bufSize, table) } - GetnConvolutionFilter :: #force_inline proc "c" (target: u32, format: u32, type: u32, bufSize: i32, image: rawptr) { impl_GetnConvolutionFilter(target, format, type, bufSize, image) } - GetnSeparableFilter :: #force_inline proc "c" (target: u32, format: u32, type: u32, rowBufSize: i32, row: rawptr, columnBufSize: i32, column: rawptr, span: rawptr) { impl_GetnSeparableFilter(target, format, type, rowBufSize, row, columnBufSize, column, span) } - GetnHistogram :: #force_inline proc "c" (target: u32, reset: bool, format: u32, type: u32, bufSize: i32, values: rawptr) { impl_GetnHistogram(target, reset, format, type, bufSize, values) } - GetnMinmax :: #force_inline proc "c" (target: u32, reset: bool, format: u32, type: u32, bufSize: i32, values: rawptr) { impl_GetnMinmax(target, reset, format, type, bufSize, values) } - TextureBarrier :: #force_inline proc "c" () { impl_TextureBarrier() } - GetUnsignedBytevEXT :: #force_inline proc "c" (pname: u32, data: ^byte) { impl_GetUnsignedBytevEXT(pname, data) } - TexPageCommitmentARB :: #force_inline proc "c"(target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, commit: bool) { impl_TexPageCommitmentARB(target, level, xoffset, yoffset, zoffset, width, height, depth, commit) } + ClipControl :: proc "c" (origin: u32, depth: u32) { impl_ClipControl(origin, depth) } + CreateTransformFeedbacks :: proc "c" (n: i32, ids: [^]u32) { impl_CreateTransformFeedbacks(n, ids) } + TransformFeedbackBufferBase :: proc "c" (xfb: u32, index: u32, buffer: u32) { impl_TransformFeedbackBufferBase(xfb, index, buffer) } + TransformFeedbackBufferRange :: proc "c" (xfb: u32, index: u32, buffer: u32, offset: int, size: int) { impl_TransformFeedbackBufferRange(xfb, index, buffer, offset, size) } + GetTransformFeedbackiv :: proc "c" (xfb: u32, pname: u32, param: ^i32) { impl_GetTransformFeedbackiv(xfb, pname, param) } + GetTransformFeedbacki_v :: proc "c" (xfb: u32, pname: u32, index: u32, param: ^i32) { impl_GetTransformFeedbacki_v(xfb, pname, index, param) } + GetTransformFeedbacki64_v :: proc "c" (xfb: u32, pname: u32, index: u32, param: ^i64) { impl_GetTransformFeedbacki64_v(xfb, pname, index, param) } + CreateBuffers :: proc "c" (n: i32, buffers: [^]u32) { impl_CreateBuffers(n, buffers) } + NamedBufferStorage :: proc "c" (buffer: u32, size: int, data: rawptr, flags: u32) { impl_NamedBufferStorage(buffer, size, data, flags) } + NamedBufferData :: proc "c" (buffer: u32, size: int, data: rawptr, usage: u32) { impl_NamedBufferData(buffer, size, data, usage) } + NamedBufferSubData :: proc "c" (buffer: u32, offset: int, size: int, data: rawptr) { impl_NamedBufferSubData(buffer, offset, size, data) } + CopyNamedBufferSubData :: proc "c" (readBuffer: u32, writeBuffer: u32, readOffset: int, writeOffset: int, size: int) { impl_CopyNamedBufferSubData(readBuffer, writeBuffer, readOffset, writeOffset, size) } + ClearNamedBufferData :: proc "c" (buffer: u32, internalformat: u32, format: u32, type: u32, data: rawptr) { impl_ClearNamedBufferData(buffer, internalformat, format, type, data) } + ClearNamedBufferSubData :: proc "c" (buffer: u32, internalformat: u32, offset: int, size: int, format: u32, type: u32, data: rawptr) { impl_ClearNamedBufferSubData(buffer, internalformat, offset, size, format, type, data) } + MapNamedBuffer :: proc "c" (buffer: u32, access: u32) -> rawptr { ret := impl_MapNamedBuffer(buffer, access); return ret } + MapNamedBufferRange :: proc "c" (buffer: u32, offset: int, length: int, access: u32) -> rawptr { ret := impl_MapNamedBufferRange(buffer, offset, length, access); return ret } + UnmapNamedBuffer :: proc "c" (buffer: u32) -> bool { ret := impl_UnmapNamedBuffer(buffer); return ret } + FlushMappedNamedBufferRange :: proc "c" (buffer: u32, offset: int, length: int) { impl_FlushMappedNamedBufferRange(buffer, offset, length) } + GetNamedBufferParameteriv :: proc "c" (buffer: u32, pname: u32, params: [^]i32) { impl_GetNamedBufferParameteriv(buffer, pname, params) } + GetNamedBufferParameteri64v :: proc "c" (buffer: u32, pname: u32, params: [^]i64) { impl_GetNamedBufferParameteri64v(buffer, pname, params) } + GetNamedBufferPointerv :: proc "c" (buffer: u32, pname: u32, params: [^]rawptr) { impl_GetNamedBufferPointerv(buffer, pname, params) } + GetNamedBufferSubData :: proc "c" (buffer: u32, offset: int, size: int, data: rawptr) { impl_GetNamedBufferSubData(buffer, offset, size, data) } + CreateFramebuffers :: proc "c" (n: i32, framebuffers: [^]u32) { impl_CreateFramebuffers(n, framebuffers) } + NamedFramebufferRenderbuffer :: proc "c" (framebuffer: u32, attachment: u32, renderbuffertarget: u32, renderbuffer: u32) { impl_NamedFramebufferRenderbuffer(framebuffer, attachment, renderbuffertarget, renderbuffer) } + NamedFramebufferParameteri :: proc "c" (framebuffer: u32, pname: u32, param: i32) { impl_NamedFramebufferParameteri(framebuffer, pname, param) } + NamedFramebufferTexture :: proc "c" (framebuffer: u32, attachment: u32, texture: u32, level: i32) { impl_NamedFramebufferTexture(framebuffer, attachment, texture, level) } + NamedFramebufferTextureLayer :: proc "c" (framebuffer: u32, attachment: u32, texture: u32, level: i32, layer: i32) { impl_NamedFramebufferTextureLayer(framebuffer, attachment, texture, level, layer) } + NamedFramebufferDrawBuffer :: proc "c" (framebuffer: u32, buf: u32) { impl_NamedFramebufferDrawBuffer(framebuffer, buf) } + NamedFramebufferDrawBuffers :: proc "c" (framebuffer: u32, n: i32, bufs: [^]u32) { impl_NamedFramebufferDrawBuffers(framebuffer, n, bufs) } + NamedFramebufferReadBuffer :: proc "c" (framebuffer: u32, src: u32) { impl_NamedFramebufferReadBuffer(framebuffer, src) } + InvalidateNamedFramebufferData :: proc "c" (framebuffer: u32, numAttachments: i32, attachments: [^]u32) { impl_InvalidateNamedFramebufferData(framebuffer, numAttachments, attachments) } + InvalidateNamedFramebufferSubData :: proc "c" (framebuffer: u32, numAttachments: i32, attachments: [^]u32, x: i32, y: i32, width: i32, height: i32) { impl_InvalidateNamedFramebufferSubData(framebuffer, numAttachments, attachments, x, y, width, height) } + ClearNamedFramebufferiv :: proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^i32) { impl_ClearNamedFramebufferiv(framebuffer, buffer, drawbuffer, value) } + ClearNamedFramebufferuiv :: proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^u32) { impl_ClearNamedFramebufferuiv(framebuffer, buffer, drawbuffer, value) } + ClearNamedFramebufferfv :: proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^f32) { impl_ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value) } + ClearNamedFramebufferfi :: proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, depth: f32, stencil: i32) { impl_ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil) } + BlitNamedFramebuffer :: proc "c" (readFramebuffer: u32, drawFramebuffer: u32, srcX0: i32, srcY0: i32, srcX1: i32, srcY1: i32, dstX0: i32, dstY0: i32, dstX1: i32, dstY1: i32, mask: u32, filter: u32) { impl_BlitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) } + CheckNamedFramebufferStatus :: proc "c" (framebuffer: u32, target: u32) -> u32 { ret := impl_CheckNamedFramebufferStatus(framebuffer, target); return ret } + GetNamedFramebufferParameteriv :: proc "c" (framebuffer: u32, pname: u32, param: ^i32) { impl_GetNamedFramebufferParameteriv(framebuffer, pname, param) } + GetNamedFramebufferAttachmentParameteriv :: proc "c" (framebuffer: u32, attachment: u32, pname: u32, params: [^]i32) { impl_GetNamedFramebufferAttachmentParameteriv(framebuffer, attachment, pname, params) } + CreateRenderbuffers :: proc "c" (n: i32, renderbuffers: [^]u32) { impl_CreateRenderbuffers(n, renderbuffers) } + NamedRenderbufferStorage :: proc "c" (renderbuffer: u32, internalformat: u32, width: i32, height: i32) { impl_NamedRenderbufferStorage(renderbuffer, internalformat, width, height) } + NamedRenderbufferStorageMultisample :: proc "c" (renderbuffer: u32, samples: i32, internalformat: u32, width: i32, height: i32) { impl_NamedRenderbufferStorageMultisample(renderbuffer, samples, internalformat, width, height) } + GetNamedRenderbufferParameteriv :: proc "c" (renderbuffer: u32, pname: u32, params: [^]i32) { impl_GetNamedRenderbufferParameteriv(renderbuffer, pname, params) } + CreateTextures :: proc "c" (target: u32, n: i32, textures: [^]u32) { impl_CreateTextures(target, n, textures) } + TextureBuffer :: proc "c" (texture: u32, internalformat: u32, buffer: u32) { impl_TextureBuffer(texture, internalformat, buffer) } + TextureBufferRange :: proc "c" (texture: u32, internalformat: u32, buffer: u32, offset: int, size: int) { impl_TextureBufferRange(texture, internalformat, buffer, offset, size) } + TextureStorage1D :: proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32) { impl_TextureStorage1D(texture, levels, internalformat, width) } + TextureStorage2D :: proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, height: i32) { impl_TextureStorage2D(texture, levels, internalformat, width, height) } + TextureStorage3D :: proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, height: i32, depth: i32) { impl_TextureStorage3D(texture, levels, internalformat, width, height, depth) } + TextureStorage2DMultisample :: proc "c" (texture: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool) { impl_TextureStorage2DMultisample(texture, samples, internalformat, width, height, fixedsamplelocations) } + TextureStorage3DMultisample :: proc "c" (texture: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool) { impl_TextureStorage3DMultisample(texture, samples, internalformat, width, height, depth, fixedsamplelocations) } + TextureSubImage1D :: proc "c" (texture: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: rawptr) { impl_TextureSubImage1D(texture, level, xoffset, width, format, type, pixels) } + TextureSubImage2D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: rawptr) { impl_TextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, type, pixels) } + TextureSubImage3D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, pixels: rawptr) { impl_TextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } + CompressedTextureSubImage1D :: proc "c" (texture: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTextureSubImage1D(texture, level, xoffset, width, format, imageSize, data) } + CompressedTextureSubImage2D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, imageSize, data) } + CompressedTextureSubImage3D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: rawptr) { impl_CompressedTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) } + CopyTextureSubImage1D :: proc "c" (texture: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32) { impl_CopyTextureSubImage1D(texture, level, xoffset, x, y, width) } + CopyTextureSubImage2D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32) { impl_CopyTextureSubImage2D(texture, level, xoffset, yoffset, x, y, width, height) } + CopyTextureSubImage3D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, x: i32, y: i32, width: i32, height: i32) { impl_CopyTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, x, y, width, height) } + TextureParameterf :: proc "c" (texture: u32, pname: u32, param: f32) { impl_TextureParameterf(texture, pname, param) } + TextureParameterfv :: proc "c" (texture: u32, pname: u32, param: ^f32) { impl_TextureParameterfv(texture, pname, param) } + TextureParameteri :: proc "c" (texture: u32, pname: u32, param: i32) { impl_TextureParameteri(texture, pname, param) } + TextureParameterIiv :: proc "c" (texture: u32, pname: u32, params: [^]i32) { impl_TextureParameterIiv(texture, pname, params) } + TextureParameterIuiv :: proc "c" (texture: u32, pname: u32, params: [^]u32) { impl_TextureParameterIuiv(texture, pname, params) } + TextureParameteriv :: proc "c" (texture: u32, pname: u32, param: ^i32) { impl_TextureParameteriv(texture, pname, param) } + GenerateTextureMipmap :: proc "c" (texture: u32) { impl_GenerateTextureMipmap(texture) } + BindTextureUnit :: proc "c" (unit: u32, texture: u32) { impl_BindTextureUnit(unit, texture) } + GetTextureImage :: proc "c" (texture: u32, level: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr) { impl_GetTextureImage(texture, level, format, type, bufSize, pixels) } + GetCompressedTextureImage :: proc "c" (texture: u32, level: i32, bufSize: i32, pixels: rawptr) { impl_GetCompressedTextureImage(texture, level, bufSize, pixels) } + GetTextureLevelParameterfv :: proc "c" (texture: u32, level: i32, pname: u32, params: [^]f32) { impl_GetTextureLevelParameterfv(texture, level, pname, params) } + GetTextureLevelParameteriv :: proc "c" (texture: u32, level: i32, pname: u32, params: [^]i32) { impl_GetTextureLevelParameteriv(texture, level, pname, params) } + GetTextureParameterfv :: proc "c" (texture: u32, pname: u32, params: [^]f32) { impl_GetTextureParameterfv(texture, pname, params) } + GetTextureParameterIiv :: proc "c" (texture: u32, pname: u32, params: [^]i32) { impl_GetTextureParameterIiv(texture, pname, params) } + GetTextureParameterIuiv :: proc "c" (texture: u32, pname: u32, params: [^]u32) { impl_GetTextureParameterIuiv(texture, pname, params) } + GetTextureParameteriv :: proc "c" (texture: u32, pname: u32, params: [^]i32) { impl_GetTextureParameteriv(texture, pname, params) } + CreateVertexArrays :: proc "c" (n: i32, arrays: [^]u32) { impl_CreateVertexArrays(n, arrays) } + DisableVertexArrayAttrib :: proc "c" (vaobj: u32, index: u32) { impl_DisableVertexArrayAttrib(vaobj, index) } + EnableVertexArrayAttrib :: proc "c" (vaobj: u32, index: u32) { impl_EnableVertexArrayAttrib(vaobj, index) } + VertexArrayElementBuffer :: proc "c" (vaobj: u32, buffer: u32) { impl_VertexArrayElementBuffer(vaobj, buffer) } + VertexArrayVertexBuffer :: proc "c" (vaobj: u32, bindingindex: u32, buffer: u32, offset: int, stride: i32) { impl_VertexArrayVertexBuffer(vaobj, bindingindex, buffer, offset, stride) } + VertexArrayVertexBuffers :: proc "c" (vaobj: u32, first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, strides: [^]i32) { impl_VertexArrayVertexBuffers(vaobj, first, count, buffers, offsets, strides) } + VertexArrayAttribBinding :: proc "c" (vaobj: u32, attribindex: u32, bindingindex: u32) { impl_VertexArrayAttribBinding(vaobj, attribindex, bindingindex) } + VertexArrayAttribFormat :: proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, normalized: bool, relativeoffset: u32) { impl_VertexArrayAttribFormat(vaobj, attribindex, size, type, normalized, relativeoffset) } + VertexArrayAttribIFormat :: proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, relativeoffset: u32) { impl_VertexArrayAttribIFormat(vaobj, attribindex, size, type, relativeoffset) } + VertexArrayAttribLFormat :: proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, relativeoffset: u32) { impl_VertexArrayAttribLFormat(vaobj, attribindex, size, type, relativeoffset) } + VertexArrayBindingDivisor :: proc "c" (vaobj: u32, bindingindex: u32, divisor: u32) { impl_VertexArrayBindingDivisor(vaobj, bindingindex, divisor) } + GetVertexArrayiv :: proc "c" (vaobj: u32, pname: u32, param: ^i32) { impl_GetVertexArrayiv(vaobj, pname, param) } + GetVertexArrayIndexediv :: proc "c" (vaobj: u32, index: u32, pname: u32, param: ^i32) { impl_GetVertexArrayIndexediv(vaobj, index, pname, param) } + GetVertexArrayIndexed64iv :: proc "c" (vaobj: u32, index: u32, pname: u32, param: ^i64) { impl_GetVertexArrayIndexed64iv(vaobj, index, pname, param) } + CreateSamplers :: proc "c" (n: i32, samplers: [^]u32) { impl_CreateSamplers(n, samplers) } + CreateProgramPipelines :: proc "c" (n: i32, pipelines: [^]u32) { impl_CreateProgramPipelines(n, pipelines) } + CreateQueries :: proc "c" (target: u32, n: i32, ids: [^]u32) { impl_CreateQueries(target, n, ids) } + GetQueryBufferObjecti64v :: proc "c" (id: u32, buffer: u32, pname: u32, offset: int) { impl_GetQueryBufferObjecti64v(id, buffer, pname, offset) } + GetQueryBufferObjectiv :: proc "c" (id: u32, buffer: u32, pname: u32, offset: int) { impl_GetQueryBufferObjectiv(id, buffer, pname, offset) } + GetQueryBufferObjectui64v :: proc "c" (id: u32, buffer: u32, pname: u32, offset: int) { impl_GetQueryBufferObjectui64v(id, buffer, pname, offset) } + GetQueryBufferObjectuiv :: proc "c" (id: u32, buffer: u32, pname: u32, offset: int) { impl_GetQueryBufferObjectuiv(id, buffer, pname, offset) } + MemoryBarrierByRegion :: proc "c" (barriers: u32) { impl_MemoryBarrierByRegion(barriers) } + GetTextureSubImage :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr) { impl_GetTextureSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels) } + GetCompressedTextureSubImage :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, bufSize: i32, pixels: rawptr) { impl_GetCompressedTextureSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels) } + GetGraphicsResetStatus :: proc "c" () -> u32 { ret := impl_GetGraphicsResetStatus(); return ret } + GetnCompressedTexImage :: proc "c" (target: u32, lod: i32, bufSize: i32, pixels: rawptr) { impl_GetnCompressedTexImage(target, lod, bufSize, pixels) } + GetnTexImage :: proc "c" (target: u32, level: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr) { impl_GetnTexImage(target, level, format, type, bufSize, pixels) } + GetnUniformdv :: proc "c" (program: u32, location: i32, bufSize: i32, params: [^]f64) { impl_GetnUniformdv(program, location, bufSize, params) } + GetnUniformfv :: proc "c" (program: u32, location: i32, bufSize: i32, params: [^]f32) { impl_GetnUniformfv(program, location, bufSize, params) } + GetnUniformiv :: proc "c" (program: u32, location: i32, bufSize: i32, params: [^]i32) { impl_GetnUniformiv(program, location, bufSize, params) } + GetnUniformuiv :: proc "c" (program: u32, location: i32, bufSize: i32, params: [^]u32) { impl_GetnUniformuiv(program, location, bufSize, params) } + ReadnPixels :: proc "c" (x: i32, y: i32, width: i32, height: i32, format: u32, type: u32, bufSize: i32, data: rawptr) { impl_ReadnPixels(x, y, width, height, format, type, bufSize, data) } + GetnMapdv :: proc "c" (target: u32, query: u32, bufSize: i32, v: [^]f64) { impl_GetnMapdv(target, query, bufSize, v) } + GetnMapfv :: proc "c" (target: u32, query: u32, bufSize: i32, v: [^]f32) { impl_GetnMapfv(target, query, bufSize, v) } + GetnMapiv :: proc "c" (target: u32, query: u32, bufSize: i32, v: [^]i32) { impl_GetnMapiv(target, query, bufSize, v) } + GetnPixelMapusv :: proc "c" (map_: u32, bufSize: i32, values: [^]u16) { impl_GetnPixelMapusv(map_, bufSize, values) } + GetnPixelMapfv :: proc "c" (map_: u32, bufSize: i32, values: [^]f32) { impl_GetnPixelMapfv(map_, bufSize, values) } + GetnPixelMapuiv :: proc "c" (map_: u32, bufSize: i32, values: [^]u32) { impl_GetnPixelMapuiv(map_, bufSize, values) } + GetnPolygonStipple :: proc "c" (bufSize: i32, pattern: [^]u8) { impl_GetnPolygonStipple(bufSize, pattern) } + GetnColorTable :: proc "c" (target: u32, format: u32, type: u32, bufSize: i32, table: rawptr) { impl_GetnColorTable(target, format, type, bufSize, table) } + GetnConvolutionFilter :: proc "c" (target: u32, format: u32, type: u32, bufSize: i32, image: rawptr) { impl_GetnConvolutionFilter(target, format, type, bufSize, image) } + GetnSeparableFilter :: proc "c" (target: u32, format: u32, type: u32, rowBufSize: i32, row: rawptr, columnBufSize: i32, column: rawptr, span: rawptr) { impl_GetnSeparableFilter(target, format, type, rowBufSize, row, columnBufSize, column, span) } + GetnHistogram :: proc "c" (target: u32, reset: bool, format: u32, type: u32, bufSize: i32, values: rawptr) { impl_GetnHistogram(target, reset, format, type, bufSize, values) } + GetnMinmax :: proc "c" (target: u32, reset: bool, format: u32, type: u32, bufSize: i32, values: rawptr) { impl_GetnMinmax(target, reset, format, type, bufSize, values) } + TextureBarrier :: proc "c" () { impl_TextureBarrier() } + GetUnsignedBytevEXT :: proc "c" (pname: u32, data: ^byte) { impl_GetUnsignedBytevEXT(pname, data) } + TexPageCommitmentARB :: proc "c"(target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, commit: bool) { impl_TexPageCommitmentARB(target, level, xoffset, yoffset, zoffset, width, height, depth, commit) } // VERSION_4_6 - SpecializeShader :: #force_inline proc "c" (shader: u32, pEntryPoint: cstring, numSpecializationConstants: u32, pConstantIndex: ^u32, pConstantValue: ^u32) { impl_SpecializeShader(shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue) } - MultiDrawArraysIndirectCount :: #force_inline proc "c" (mode: i32, indirect: [^]DrawArraysIndirectCommand, drawcount: i32, maxdrawcount, stride: i32) { impl_MultiDrawArraysIndirectCount(mode, indirect, drawcount, maxdrawcount, stride) } - MultiDrawElementsIndirectCount :: #force_inline proc "c" (mode: i32, type: i32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, maxdrawcount, stride: i32) { impl_MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride) } - PolygonOffsetClamp :: #force_inline proc "c" (factor, units, clamp: f32) { impl_PolygonOffsetClamp(factor, units, clamp) } + SpecializeShader :: proc "c" (shader: u32, pEntryPoint: cstring, numSpecializationConstants: u32, pConstantIndex: ^u32, pConstantValue: ^u32) { impl_SpecializeShader(shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue) } + MultiDrawArraysIndirectCount :: proc "c" (mode: i32, indirect: [^]DrawArraysIndirectCommand, drawcount: i32, maxdrawcount, stride: i32) { impl_MultiDrawArraysIndirectCount(mode, indirect, drawcount, maxdrawcount, stride) } + MultiDrawElementsIndirectCount :: proc "c" (mode: i32, type: i32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, maxdrawcount, stride: i32) { impl_MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride) } + PolygonOffsetClamp :: proc "c" (factor, units, clamp: f32) { impl_PolygonOffsetClamp(factor, units, clamp) } } else { import "core:runtime" import "core:fmt" - debug_helper :: #force_inline proc"c"(from_loc: runtime.Source_Code_Location, num_ret: int, args: ..any, loc := #caller_location) { + debug_helper :: proc"c"(from_loc: runtime.Source_Code_Location, num_ret: int, args: ..any, loc := #caller_location) { context = runtime.default_context() Error_Enum :: enum { @@ -805,740 +805,740 @@ when !ODIN_DEBUG { } } - CullFace :: #force_inline proc "c" (mode: u32, loc := #caller_location) { impl_CullFace(mode); debug_helper(loc, 0, mode) } - FrontFace :: #force_inline proc "c" (mode: u32, loc := #caller_location) { impl_FrontFace(mode); debug_helper(loc, 0, mode) } - Hint :: #force_inline proc "c" (target, mode: u32, loc := #caller_location) { impl_Hint(target, mode); debug_helper(loc, 0, target, mode) } - LineWidth :: #force_inline proc "c" (width: f32, loc := #caller_location) { impl_LineWidth(width); debug_helper(loc, 0, width) } - PointSize :: #force_inline proc "c" (size: f32, loc := #caller_location) { impl_PointSize(size); debug_helper(loc, 0, size) } - PolygonMode :: #force_inline proc "c" (face, mode: u32, loc := #caller_location) { impl_PolygonMode(face, mode); debug_helper(loc, 0, face, mode) } - Scissor :: #force_inline proc "c" (x, y, width, height: i32, loc := #caller_location) { impl_Scissor(x, y, width, height); debug_helper(loc, 0, x, y, width, height) } - TexParameterf :: #force_inline proc "c" (target, pname: u32, param: f32, loc := #caller_location) { impl_TexParameterf(target, pname, param); debug_helper(loc, 0, target, pname, param) } - TexParameterfv :: #force_inline proc "c" (target, pname: u32, params: [^]f32, loc := #caller_location) { impl_TexParameterfv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - TexParameteri :: #force_inline proc "c" (target, pname: u32, param: i32, loc := #caller_location) { impl_TexParameteri(target, pname, param); debug_helper(loc, 0, target, pname, param) } - TexParameteriv :: #force_inline proc "c" (target, pname: u32, params: [^]i32, loc := #caller_location) { impl_TexParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - TexImage1D :: #force_inline proc "c" (target: u32, level, internalformat, width, border: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexImage1D(target, level, internalformat, width, border, format, type, pixels); debug_helper(loc, 0, target, level, internalformat, width, border, format, type, pixels) } - TexImage2D :: #force_inline proc "c" (target: u32, level, internalformat, width, height, border: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexImage2D(target, level, internalformat, width, height, border, format, type, pixels); debug_helper(loc, 0, target, level, internalformat, width, height, border, format, type, pixels) } - DrawBuffer :: #force_inline proc "c" (buf: u32, loc := #caller_location) { impl_DrawBuffer(buf); debug_helper(loc, 0, buf) } - Clear :: #force_inline proc "c" (mask: u32, loc := #caller_location) { impl_Clear(mask); debug_helper(loc, 0, mask) } - ClearColor :: #force_inline proc "c" (red, green, blue, alpha: f32, loc := #caller_location) { impl_ClearColor(red, green, blue, alpha); debug_helper(loc, 0, red, green, blue, alpha) } - ClearStencil :: #force_inline proc "c" (s: i32, loc := #caller_location) { impl_ClearStencil(s); debug_helper(loc, 0, s) } - ClearDepth :: #force_inline proc "c" (depth: f64, loc := #caller_location) { impl_ClearDepth(depth); debug_helper(loc, 0, depth) } - StencilMask :: #force_inline proc "c" (mask: u32, loc := #caller_location) { impl_StencilMask(mask); debug_helper(loc, 0, mask) } - ColorMask :: #force_inline proc "c" (red, green, blue, alpha: bool, loc := #caller_location) { impl_ColorMask(red, green, blue, alpha); debug_helper(loc, 0, red, green, blue, alpha) } - DepthMask :: #force_inline proc "c" (flag: bool, loc := #caller_location) { impl_DepthMask(flag); debug_helper(loc, 0, flag) } - Disable :: #force_inline proc "c" (cap: u32, loc := #caller_location) { impl_Disable(cap); debug_helper(loc, 0, cap) } - Enable :: #force_inline proc "c" (cap: u32, loc := #caller_location) { impl_Enable(cap); debug_helper(loc, 0, cap) } - Finish :: #force_inline proc "c" (loc := #caller_location) { impl_Finish(); debug_helper(loc, 0) } - Flush :: #force_inline proc "c" (loc := #caller_location) { impl_Flush(); debug_helper(loc, 0) } - BlendFunc :: #force_inline proc "c" (sfactor, dfactor: u32, loc := #caller_location) { impl_BlendFunc(sfactor, dfactor); debug_helper(loc, 0, sfactor, dfactor) } - LogicOp :: #force_inline proc "c" (opcode: u32, loc := #caller_location) { impl_LogicOp(opcode); debug_helper(loc, 0, opcode) } - StencilFunc :: #force_inline proc "c" (func: u32, ref: i32, mask: u32, loc := #caller_location) { impl_StencilFunc(func, ref, mask); debug_helper(loc, 0, func, ref, mask) } - StencilOp :: #force_inline proc "c" (fail, zfail, zpass: u32, loc := #caller_location) { impl_StencilOp(fail, zfail, zpass); debug_helper(loc, 0, fail, zfail, zpass) } - DepthFunc :: #force_inline proc "c" (func: u32, loc := #caller_location) { impl_DepthFunc(func); debug_helper(loc, 0, func) } - PixelStoref :: #force_inline proc "c" (pname: u32, param: f32, loc := #caller_location) { impl_PixelStoref(pname, param); debug_helper(loc, 0, pname, param) } - PixelStorei :: #force_inline proc "c" (pname: u32, param: i32, loc := #caller_location) { impl_PixelStorei(pname, param); debug_helper(loc, 0, pname, param) } - ReadBuffer :: #force_inline proc "c" (src: u32, loc := #caller_location) { impl_ReadBuffer(src); debug_helper(loc, 0, src) } - ReadPixels :: #force_inline proc "c" (x, y, width, height: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_ReadPixels(x, y, width, height, format, type, pixels); debug_helper(loc, 0, x, y, width, height, format, type, pixels) } - GetBooleanv :: #force_inline proc "c" (pname: u32, data: ^bool, loc := #caller_location) { impl_GetBooleanv(pname, data); debug_helper(loc, 0, pname, data) } - GetDoublev :: #force_inline proc "c" (pname: u32, data: ^f64, loc := #caller_location) { impl_GetDoublev(pname, data); debug_helper(loc, 0, pname, data) } - GetError :: #force_inline proc "c" (loc := #caller_location) -> u32 { ret := impl_GetError(); debug_helper(loc, 1, ret); return ret } - GetFloatv :: #force_inline proc "c" (pname: u32, data: ^f32, loc := #caller_location) { impl_GetFloatv(pname, data); debug_helper(loc, 0, pname, data) } - GetIntegerv :: #force_inline proc "c" (pname: u32, data: ^i32, loc := #caller_location) { impl_GetIntegerv(pname, data); debug_helper(loc, 0, pname, data) } - GetString :: #force_inline proc "c" (name: u32, loc := #caller_location) -> cstring { ret := impl_GetString(name); debug_helper(loc, 1, ret, name); return ret } - GetTexImage :: #force_inline proc "c" (target: u32, level: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_GetTexImage(target, level, format, type, pixels); debug_helper(loc, 0, target, level, format, type, pixels) } - GetTexParameterfv :: #force_inline proc "c" (target, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetTexParameterfv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - GetTexParameteriv :: #force_inline proc "c" (target, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTexParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - GetTexLevelParameterfv :: #force_inline proc "c" (target: u32, level: i32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetTexLevelParameterfv(target, level, pname, params); debug_helper(loc, 0, target, level, pname, params) } - GetTexLevelParameteriv :: #force_inline proc "c" (target: u32, level: i32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTexLevelParameteriv(target, level, pname, params); debug_helper(loc, 0, target, level, pname, params) } - IsEnabled :: #force_inline proc "c" (cap: u32, loc := #caller_location) -> bool { ret := impl_IsEnabled(cap); debug_helper(loc, 1, ret, cap); return ret } - DepthRange :: #force_inline proc "c" (near, far: f64, loc := #caller_location) { impl_DepthRange(near, far); debug_helper(loc, 0, near, far) } - Viewport :: #force_inline proc "c" (x, y, width, height: i32, loc := #caller_location) { impl_Viewport(x, y, width, height); debug_helper(loc, 0, x, y, width, height) } + CullFace :: proc "c" (mode: u32, loc := #caller_location) { impl_CullFace(mode); debug_helper(loc, 0, mode) } + FrontFace :: proc "c" (mode: u32, loc := #caller_location) { impl_FrontFace(mode); debug_helper(loc, 0, mode) } + Hint :: proc "c" (target, mode: u32, loc := #caller_location) { impl_Hint(target, mode); debug_helper(loc, 0, target, mode) } + LineWidth :: proc "c" (width: f32, loc := #caller_location) { impl_LineWidth(width); debug_helper(loc, 0, width) } + PointSize :: proc "c" (size: f32, loc := #caller_location) { impl_PointSize(size); debug_helper(loc, 0, size) } + PolygonMode :: proc "c" (face, mode: u32, loc := #caller_location) { impl_PolygonMode(face, mode); debug_helper(loc, 0, face, mode) } + Scissor :: proc "c" (x, y, width, height: i32, loc := #caller_location) { impl_Scissor(x, y, width, height); debug_helper(loc, 0, x, y, width, height) } + TexParameterf :: proc "c" (target, pname: u32, param: f32, loc := #caller_location) { impl_TexParameterf(target, pname, param); debug_helper(loc, 0, target, pname, param) } + TexParameterfv :: proc "c" (target, pname: u32, params: [^]f32, loc := #caller_location) { impl_TexParameterfv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + TexParameteri :: proc "c" (target, pname: u32, param: i32, loc := #caller_location) { impl_TexParameteri(target, pname, param); debug_helper(loc, 0, target, pname, param) } + TexParameteriv :: proc "c" (target, pname: u32, params: [^]i32, loc := #caller_location) { impl_TexParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + TexImage1D :: proc "c" (target: u32, level, internalformat, width, border: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexImage1D(target, level, internalformat, width, border, format, type, pixels); debug_helper(loc, 0, target, level, internalformat, width, border, format, type, pixels) } + TexImage2D :: proc "c" (target: u32, level, internalformat, width, height, border: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexImage2D(target, level, internalformat, width, height, border, format, type, pixels); debug_helper(loc, 0, target, level, internalformat, width, height, border, format, type, pixels) } + DrawBuffer :: proc "c" (buf: u32, loc := #caller_location) { impl_DrawBuffer(buf); debug_helper(loc, 0, buf) } + Clear :: proc "c" (mask: u32, loc := #caller_location) { impl_Clear(mask); debug_helper(loc, 0, mask) } + ClearColor :: proc "c" (red, green, blue, alpha: f32, loc := #caller_location) { impl_ClearColor(red, green, blue, alpha); debug_helper(loc, 0, red, green, blue, alpha) } + ClearStencil :: proc "c" (s: i32, loc := #caller_location) { impl_ClearStencil(s); debug_helper(loc, 0, s) } + ClearDepth :: proc "c" (depth: f64, loc := #caller_location) { impl_ClearDepth(depth); debug_helper(loc, 0, depth) } + StencilMask :: proc "c" (mask: u32, loc := #caller_location) { impl_StencilMask(mask); debug_helper(loc, 0, mask) } + ColorMask :: proc "c" (red, green, blue, alpha: bool, loc := #caller_location) { impl_ColorMask(red, green, blue, alpha); debug_helper(loc, 0, red, green, blue, alpha) } + DepthMask :: proc "c" (flag: bool, loc := #caller_location) { impl_DepthMask(flag); debug_helper(loc, 0, flag) } + Disable :: proc "c" (cap: u32, loc := #caller_location) { impl_Disable(cap); debug_helper(loc, 0, cap) } + Enable :: proc "c" (cap: u32, loc := #caller_location) { impl_Enable(cap); debug_helper(loc, 0, cap) } + Finish :: proc "c" (loc := #caller_location) { impl_Finish(); debug_helper(loc, 0) } + Flush :: proc "c" (loc := #caller_location) { impl_Flush(); debug_helper(loc, 0) } + BlendFunc :: proc "c" (sfactor, dfactor: u32, loc := #caller_location) { impl_BlendFunc(sfactor, dfactor); debug_helper(loc, 0, sfactor, dfactor) } + LogicOp :: proc "c" (opcode: u32, loc := #caller_location) { impl_LogicOp(opcode); debug_helper(loc, 0, opcode) } + StencilFunc :: proc "c" (func: u32, ref: i32, mask: u32, loc := #caller_location) { impl_StencilFunc(func, ref, mask); debug_helper(loc, 0, func, ref, mask) } + StencilOp :: proc "c" (fail, zfail, zpass: u32, loc := #caller_location) { impl_StencilOp(fail, zfail, zpass); debug_helper(loc, 0, fail, zfail, zpass) } + DepthFunc :: proc "c" (func: u32, loc := #caller_location) { impl_DepthFunc(func); debug_helper(loc, 0, func) } + PixelStoref :: proc "c" (pname: u32, param: f32, loc := #caller_location) { impl_PixelStoref(pname, param); debug_helper(loc, 0, pname, param) } + PixelStorei :: proc "c" (pname: u32, param: i32, loc := #caller_location) { impl_PixelStorei(pname, param); debug_helper(loc, 0, pname, param) } + ReadBuffer :: proc "c" (src: u32, loc := #caller_location) { impl_ReadBuffer(src); debug_helper(loc, 0, src) } + ReadPixels :: proc "c" (x, y, width, height: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_ReadPixels(x, y, width, height, format, type, pixels); debug_helper(loc, 0, x, y, width, height, format, type, pixels) } + GetBooleanv :: proc "c" (pname: u32, data: ^bool, loc := #caller_location) { impl_GetBooleanv(pname, data); debug_helper(loc, 0, pname, data) } + GetDoublev :: proc "c" (pname: u32, data: ^f64, loc := #caller_location) { impl_GetDoublev(pname, data); debug_helper(loc, 0, pname, data) } + GetError :: proc "c" (loc := #caller_location) -> u32 { ret := impl_GetError(); debug_helper(loc, 1, ret); return ret } + GetFloatv :: proc "c" (pname: u32, data: ^f32, loc := #caller_location) { impl_GetFloatv(pname, data); debug_helper(loc, 0, pname, data) } + GetIntegerv :: proc "c" (pname: u32, data: ^i32, loc := #caller_location) { impl_GetIntegerv(pname, data); debug_helper(loc, 0, pname, data) } + GetString :: proc "c" (name: u32, loc := #caller_location) -> cstring { ret := impl_GetString(name); debug_helper(loc, 1, ret, name); return ret } + GetTexImage :: proc "c" (target: u32, level: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_GetTexImage(target, level, format, type, pixels); debug_helper(loc, 0, target, level, format, type, pixels) } + GetTexParameterfv :: proc "c" (target, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetTexParameterfv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + GetTexParameteriv :: proc "c" (target, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTexParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + GetTexLevelParameterfv :: proc "c" (target: u32, level: i32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetTexLevelParameterfv(target, level, pname, params); debug_helper(loc, 0, target, level, pname, params) } + GetTexLevelParameteriv :: proc "c" (target: u32, level: i32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTexLevelParameteriv(target, level, pname, params); debug_helper(loc, 0, target, level, pname, params) } + IsEnabled :: proc "c" (cap: u32, loc := #caller_location) -> bool { ret := impl_IsEnabled(cap); debug_helper(loc, 1, ret, cap); return ret } + DepthRange :: proc "c" (near, far: f64, loc := #caller_location) { impl_DepthRange(near, far); debug_helper(loc, 0, near, far) } + Viewport :: proc "c" (x, y, width, height: i32, loc := #caller_location) { impl_Viewport(x, y, width, height); debug_helper(loc, 0, x, y, width, height) } // VERSION_1_1 - DrawArrays :: #force_inline proc "c" (mode: u32, first: i32, count: i32, loc := #caller_location) { impl_DrawArrays(mode, first, count); debug_helper(loc, 0, mode, first, count) } - DrawElements :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, loc := #caller_location) { impl_DrawElements(mode, count, type, indices); debug_helper(loc, 0, mode, count, type, indices) } - PolygonOffset :: #force_inline proc "c" (factor: f32, units: f32, loc := #caller_location) { impl_PolygonOffset(factor, units); debug_helper(loc, 0, factor, units) } - CopyTexImage1D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, border: i32, loc := #caller_location) { impl_CopyTexImage1D(target, level, internalformat, x, y, width, border); debug_helper(loc, 0, target, level, internalformat, x, y, width, border) } - CopyTexImage2D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, height: i32, border: i32, loc := #caller_location) { impl_CopyTexImage2D(target, level, internalformat, x, y, width, height, border); debug_helper(loc, 0, target, level, internalformat, x, y, width, height, border) } - CopyTexSubImage1D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32, loc := #caller_location) { impl_CopyTexSubImage1D(target, level, xoffset, x, y, width); debug_helper(loc, 0, target, level, xoffset, x, y, width) } - CopyTexSubImage2D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); debug_helper(loc, 0, target, level, xoffset, yoffset, x, y, width, height) } - TexSubImage1D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexSubImage1D(target, level, xoffset, width, format, type, pixels); debug_helper(loc, 0, target, level, xoffset, width, format, type, pixels) } - TexSubImage2D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); debug_helper(loc, 0, target, level, xoffset, yoffset, width, height, format, type, pixels) } - BindTexture :: #force_inline proc "c" (target: u32, texture: u32, loc := #caller_location) { impl_BindTexture(target, texture); debug_helper(loc, 0, target, texture) } - DeleteTextures :: #force_inline proc "c" (n: i32, textures: [^]u32, loc := #caller_location) { impl_DeleteTextures(n, textures); debug_helper(loc, 0, n, textures) } - GenTextures :: #force_inline proc "c" (n: i32, textures: [^]u32, loc := #caller_location) { impl_GenTextures(n, textures); debug_helper(loc, 0, n, textures) } - IsTexture :: #force_inline proc "c" (texture: u32, loc := #caller_location) -> bool { ret := impl_IsTexture(texture); debug_helper(loc, 1, ret, texture); return ret } + DrawArrays :: proc "c" (mode: u32, first: i32, count: i32, loc := #caller_location) { impl_DrawArrays(mode, first, count); debug_helper(loc, 0, mode, first, count) } + DrawElements :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, loc := #caller_location) { impl_DrawElements(mode, count, type, indices); debug_helper(loc, 0, mode, count, type, indices) } + PolygonOffset :: proc "c" (factor: f32, units: f32, loc := #caller_location) { impl_PolygonOffset(factor, units); debug_helper(loc, 0, factor, units) } + CopyTexImage1D :: proc "c" (target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, border: i32, loc := #caller_location) { impl_CopyTexImage1D(target, level, internalformat, x, y, width, border); debug_helper(loc, 0, target, level, internalformat, x, y, width, border) } + CopyTexImage2D :: proc "c" (target: u32, level: i32, internalformat: u32, x: i32, y: i32, width: i32, height: i32, border: i32, loc := #caller_location) { impl_CopyTexImage2D(target, level, internalformat, x, y, width, height, border); debug_helper(loc, 0, target, level, internalformat, x, y, width, height, border) } + CopyTexSubImage1D :: proc "c" (target: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32, loc := #caller_location) { impl_CopyTexSubImage1D(target, level, xoffset, x, y, width); debug_helper(loc, 0, target, level, xoffset, x, y, width) } + CopyTexSubImage2D :: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); debug_helper(loc, 0, target, level, xoffset, yoffset, x, y, width, height) } + TexSubImage1D :: proc "c" (target: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexSubImage1D(target, level, xoffset, width, format, type, pixels); debug_helper(loc, 0, target, level, xoffset, width, format, type, pixels) } + TexSubImage2D :: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); debug_helper(loc, 0, target, level, xoffset, yoffset, width, height, format, type, pixels) } + BindTexture :: proc "c" (target: u32, texture: u32, loc := #caller_location) { impl_BindTexture(target, texture); debug_helper(loc, 0, target, texture) } + DeleteTextures :: proc "c" (n: i32, textures: [^]u32, loc := #caller_location) { impl_DeleteTextures(n, textures); debug_helper(loc, 0, n, textures) } + GenTextures :: proc "c" (n: i32, textures: [^]u32, loc := #caller_location) { impl_GenTextures(n, textures); debug_helper(loc, 0, n, textures) } + IsTexture :: proc "c" (texture: u32, loc := #caller_location) -> bool { ret := impl_IsTexture(texture); debug_helper(loc, 1, ret, texture); return ret } // VERSION_1_2 - DrawRangeElements :: #force_inline proc "c" (mode, start, end: u32, count: i32, type: u32, indices: rawptr, loc := #caller_location) { impl_DrawRangeElements(mode, start, end, count, type, indices); debug_helper(loc, 0, mode, start, end, count, type, indices) } - TexImage3D :: #force_inline proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); debug_helper(loc, 0, target, level, internalformat, width, height, depth, border, format, type, pixels) } - TexSubImage3D :: #force_inline proc "c" (target: u32, level, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } - CopyTexSubImage3D :: #force_inline proc "c" (target: u32, level, xoffset, yoffset, zoffset, x, y, width, height: i32, loc := #caller_location) { impl_CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, x, y, width, height) } + DrawRangeElements :: proc "c" (mode, start, end: u32, count: i32, type: u32, indices: rawptr, loc := #caller_location) { impl_DrawRangeElements(mode, start, end, count, type, indices); debug_helper(loc, 0, mode, start, end, count, type, indices) } + TexImage3D :: proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); debug_helper(loc, 0, target, level, internalformat, width, height, depth, border, format, type, pixels) } + TexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } + CopyTexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, x, y, width, height: i32, loc := #caller_location) { impl_CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, x, y, width, height) } // VERSION_1_3 - ActiveTexture :: #force_inline proc "c" (texture: u32, loc := #caller_location) { impl_ActiveTexture(texture); debug_helper(loc, 0, texture) } - SampleCoverage :: #force_inline proc "c" (value: f32, invert: bool, loc := #caller_location) { impl_SampleCoverage(value, invert); debug_helper(loc, 0, value, invert) } - CompressedTexImage3D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, width: i32, height: i32, depth: i32, border: i32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); debug_helper(loc, 0, target, level, internalformat, width, height, depth, border, imageSize, data) } - CompressedTexImage2D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, width: i32, height: i32, border: i32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); debug_helper(loc, 0, target, level, internalformat, width, height, border, imageSize, data) } - CompressedTexImage1D :: #force_inline proc "c" (target: u32, level: i32, internalformat: u32, width: i32, border: i32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexImage1D(target, level, internalformat, width, border, imageSize, data); debug_helper(loc, 0, target, level, internalformat, width, border, imageSize, data) } - CompressedTexSubImage3D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) } - CompressedTexSubImage2D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); debug_helper(loc, 0, target, level, xoffset, yoffset, width, height, format, imageSize, data) } - CompressedTexSubImage1D :: #force_inline proc "c" (target: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data); debug_helper(loc, 0, target, level, xoffset, width, format, imageSize, data) } - GetCompressedTexImage :: #force_inline proc "c" (target: u32, level: i32, img: rawptr, loc := #caller_location) { impl_GetCompressedTexImage(target, level, img); debug_helper(loc, 0, target, level, img) } + ActiveTexture :: proc "c" (texture: u32, loc := #caller_location) { impl_ActiveTexture(texture); debug_helper(loc, 0, texture) } + SampleCoverage :: proc "c" (value: f32, invert: bool, loc := #caller_location) { impl_SampleCoverage(value, invert); debug_helper(loc, 0, value, invert) } + CompressedTexImage3D :: proc "c" (target: u32, level: i32, internalformat: u32, width: i32, height: i32, depth: i32, border: i32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data); debug_helper(loc, 0, target, level, internalformat, width, height, depth, border, imageSize, data) } + CompressedTexImage2D :: proc "c" (target: u32, level: i32, internalformat: u32, width: i32, height: i32, border: i32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); debug_helper(loc, 0, target, level, internalformat, width, height, border, imageSize, data) } + CompressedTexImage1D :: proc "c" (target: u32, level: i32, internalformat: u32, width: i32, border: i32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexImage1D(target, level, internalformat, width, border, imageSize, data); debug_helper(loc, 0, target, level, internalformat, width, border, imageSize, data) } + CompressedTexSubImage3D :: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) } + CompressedTexSubImage2D :: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); debug_helper(loc, 0, target, level, xoffset, yoffset, width, height, format, imageSize, data) } + CompressedTexSubImage1D :: proc "c" (target: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data); debug_helper(loc, 0, target, level, xoffset, width, format, imageSize, data) } + GetCompressedTexImage :: proc "c" (target: u32, level: i32, img: rawptr, loc := #caller_location) { impl_GetCompressedTexImage(target, level, img); debug_helper(loc, 0, target, level, img) } // VERSION_1_4 - BlendFuncSeparate :: #force_inline proc "c" (sfactorRGB: u32, dfactorRGB: u32, sfactorAlpha: u32, dfactorAlpha: u32, loc := #caller_location) { impl_BlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); debug_helper(loc, 0, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha) } - MultiDrawArrays :: #force_inline proc "c" (mode: u32, first: [^]i32, count: [^]i32, drawcount: i32, loc := #caller_location) { impl_MultiDrawArrays(mode, first, count, drawcount); debug_helper(loc, 0, mode, first, count, drawcount) } - MultiDrawElements :: #force_inline proc "c" (mode: u32, count: [^]i32, type: u32, indices: [^]rawptr, drawcount: i32, loc := #caller_location) { impl_MultiDrawElements(mode, count, type, indices, drawcount); debug_helper(loc, 0, mode, count, type, indices, drawcount) } - PointParameterf :: #force_inline proc "c" (pname: u32, param: f32, loc := #caller_location) { impl_PointParameterf(pname, param); debug_helper(loc, 0, pname, param) } - PointParameterfv :: #force_inline proc "c" (pname: u32, params: [^]f32, loc := #caller_location) { impl_PointParameterfv(pname, params); debug_helper(loc, 0, pname, params) } - PointParameteri :: #force_inline proc "c" (pname: u32, param: i32, loc := #caller_location) { impl_PointParameteri(pname, param); debug_helper(loc, 0, pname, param) } - PointParameteriv :: #force_inline proc "c" (pname: u32, params: [^]i32, loc := #caller_location) { impl_PointParameteriv(pname, params); debug_helper(loc, 0, pname, params) } - BlendColor :: #force_inline proc "c" (red: f32, green: f32, blue: f32, alpha: f32, loc := #caller_location) { impl_BlendColor(red, green, blue, alpha); debug_helper(loc, 0, red, green, blue, alpha) } - BlendEquation :: #force_inline proc "c" (mode: u32, loc := #caller_location) { impl_BlendEquation(mode); debug_helper(loc, 0, mode) } + BlendFuncSeparate :: proc "c" (sfactorRGB: u32, dfactorRGB: u32, sfactorAlpha: u32, dfactorAlpha: u32, loc := #caller_location) { impl_BlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); debug_helper(loc, 0, sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha) } + MultiDrawArrays :: proc "c" (mode: u32, first: [^]i32, count: [^]i32, drawcount: i32, loc := #caller_location) { impl_MultiDrawArrays(mode, first, count, drawcount); debug_helper(loc, 0, mode, first, count, drawcount) } + MultiDrawElements :: proc "c" (mode: u32, count: [^]i32, type: u32, indices: [^]rawptr, drawcount: i32, loc := #caller_location) { impl_MultiDrawElements(mode, count, type, indices, drawcount); debug_helper(loc, 0, mode, count, type, indices, drawcount) } + PointParameterf :: proc "c" (pname: u32, param: f32, loc := #caller_location) { impl_PointParameterf(pname, param); debug_helper(loc, 0, pname, param) } + PointParameterfv :: proc "c" (pname: u32, params: [^]f32, loc := #caller_location) { impl_PointParameterfv(pname, params); debug_helper(loc, 0, pname, params) } + PointParameteri :: proc "c" (pname: u32, param: i32, loc := #caller_location) { impl_PointParameteri(pname, param); debug_helper(loc, 0, pname, param) } + PointParameteriv :: proc "c" (pname: u32, params: [^]i32, loc := #caller_location) { impl_PointParameteriv(pname, params); debug_helper(loc, 0, pname, params) } + BlendColor :: proc "c" (red: f32, green: f32, blue: f32, alpha: f32, loc := #caller_location) { impl_BlendColor(red, green, blue, alpha); debug_helper(loc, 0, red, green, blue, alpha) } + BlendEquation :: proc "c" (mode: u32, loc := #caller_location) { impl_BlendEquation(mode); debug_helper(loc, 0, mode) } // VERSION_1_5 - GenQueries :: #force_inline proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_GenQueries(n, ids); debug_helper(loc, 0, n, ids) } - DeleteQueries :: #force_inline proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_DeleteQueries(n, ids); debug_helper(loc, 0, n, ids) } - IsQuery :: #force_inline proc "c" (id: u32, loc := #caller_location) -> bool { ret := impl_IsQuery(id); debug_helper(loc, 1, ret, id); return ret } - BeginQuery :: #force_inline proc "c" (target: u32, id: u32, loc := #caller_location) { impl_BeginQuery(target, id); debug_helper(loc, 0, target, id) } - EndQuery :: #force_inline proc "c" (target: u32, loc := #caller_location) { impl_EndQuery(target); debug_helper(loc, 0, target) } - GetQueryiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - GetQueryObjectiv :: #force_inline proc "c" (id: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryObjectiv(id, pname, params); debug_helper(loc, 0, id, pname, params) } - GetQueryObjectuiv :: #force_inline proc "c" (id: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetQueryObjectuiv(id, pname, params); debug_helper(loc, 0, id, pname, params) } - BindBuffer :: #force_inline proc "c" (target: u32, buffer: u32, loc := #caller_location) { impl_BindBuffer(target, buffer); debug_helper(loc, 0, target, buffer) } - DeleteBuffers :: #force_inline proc "c" (n: i32, buffers: [^]u32, loc := #caller_location) { impl_DeleteBuffers(n, buffers); debug_helper(loc, 0, n, buffers) } - GenBuffers :: #force_inline proc "c" (n: i32, buffers: [^]u32, loc := #caller_location) { impl_GenBuffers(n, buffers); debug_helper(loc, 0, n, buffers) } - IsBuffer :: #force_inline proc "c" (buffer: u32, loc := #caller_location) -> bool { ret := impl_IsBuffer(buffer); debug_helper(loc, 1, ret, buffer); return ret } - BufferData :: #force_inline proc "c" (target: u32, size: int, data: rawptr, usage: u32, loc := #caller_location) { impl_BufferData(target, size, data, usage); debug_helper(loc, 0, target, size, data, usage) } - BufferSubData :: #force_inline proc "c" (target: u32, offset: int, size: int, data: rawptr, loc := #caller_location) { impl_BufferSubData(target, offset, size, data); debug_helper(loc, 0, target, offset, size, data) } - GetBufferSubData :: #force_inline proc "c" (target: u32, offset: int, size: int, data: rawptr, loc := #caller_location) { impl_GetBufferSubData(target, offset, size, data); debug_helper(loc, 0, target, offset, size, data) } - MapBuffer :: #force_inline proc "c" (target: u32, access: u32, loc := #caller_location) -> rawptr { ret := impl_MapBuffer(target, access); debug_helper(loc, 1, ret, target, access); return ret } - UnmapBuffer :: #force_inline proc "c" (target: u32, loc := #caller_location) -> bool { ret := impl_UnmapBuffer(target); debug_helper(loc, 1, ret, target); return ret } - GetBufferParameteriv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetBufferParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - GetBufferPointerv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]rawptr, loc := #caller_location) { impl_GetBufferPointerv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + GenQueries :: proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_GenQueries(n, ids); debug_helper(loc, 0, n, ids) } + DeleteQueries :: proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_DeleteQueries(n, ids); debug_helper(loc, 0, n, ids) } + IsQuery :: proc "c" (id: u32, loc := #caller_location) -> bool { ret := impl_IsQuery(id); debug_helper(loc, 1, ret, id); return ret } + BeginQuery :: proc "c" (target: u32, id: u32, loc := #caller_location) { impl_BeginQuery(target, id); debug_helper(loc, 0, target, id) } + EndQuery :: proc "c" (target: u32, loc := #caller_location) { impl_EndQuery(target); debug_helper(loc, 0, target) } + GetQueryiv :: proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + GetQueryObjectiv :: proc "c" (id: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryObjectiv(id, pname, params); debug_helper(loc, 0, id, pname, params) } + GetQueryObjectuiv :: proc "c" (id: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetQueryObjectuiv(id, pname, params); debug_helper(loc, 0, id, pname, params) } + BindBuffer :: proc "c" (target: u32, buffer: u32, loc := #caller_location) { impl_BindBuffer(target, buffer); debug_helper(loc, 0, target, buffer) } + DeleteBuffers :: proc "c" (n: i32, buffers: [^]u32, loc := #caller_location) { impl_DeleteBuffers(n, buffers); debug_helper(loc, 0, n, buffers) } + GenBuffers :: proc "c" (n: i32, buffers: [^]u32, loc := #caller_location) { impl_GenBuffers(n, buffers); debug_helper(loc, 0, n, buffers) } + IsBuffer :: proc "c" (buffer: u32, loc := #caller_location) -> bool { ret := impl_IsBuffer(buffer); debug_helper(loc, 1, ret, buffer); return ret } + BufferData :: proc "c" (target: u32, size: int, data: rawptr, usage: u32, loc := #caller_location) { impl_BufferData(target, size, data, usage); debug_helper(loc, 0, target, size, data, usage) } + BufferSubData :: proc "c" (target: u32, offset: int, size: int, data: rawptr, loc := #caller_location) { impl_BufferSubData(target, offset, size, data); debug_helper(loc, 0, target, offset, size, data) } + GetBufferSubData :: proc "c" (target: u32, offset: int, size: int, data: rawptr, loc := #caller_location) { impl_GetBufferSubData(target, offset, size, data); debug_helper(loc, 0, target, offset, size, data) } + MapBuffer :: proc "c" (target: u32, access: u32, loc := #caller_location) -> rawptr { ret := impl_MapBuffer(target, access); debug_helper(loc, 1, ret, target, access); return ret } + UnmapBuffer :: proc "c" (target: u32, loc := #caller_location) -> bool { ret := impl_UnmapBuffer(target); debug_helper(loc, 1, ret, target); return ret } + GetBufferParameteriv :: proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetBufferParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + GetBufferPointerv :: proc "c" (target: u32, pname: u32, params: [^]rawptr, loc := #caller_location) { impl_GetBufferPointerv(target, pname, params); debug_helper(loc, 0, target, pname, params) } // VERSION_2_0 - BlendEquationSeparate :: #force_inline proc "c" (modeRGB: u32, modeAlpha: u32, loc := #caller_location) { impl_BlendEquationSeparate(modeRGB, modeAlpha); debug_helper(loc, 0, modeRGB, modeAlpha) } - DrawBuffers :: #force_inline proc "c" (n: i32, bufs: [^]u32, loc := #caller_location) { impl_DrawBuffers(n, bufs); debug_helper(loc, 0, n, bufs) } - StencilOpSeparate :: #force_inline proc "c" (face: u32, sfail: u32, dpfail: u32, dppass: u32, loc := #caller_location) { impl_StencilOpSeparate(face, sfail, dpfail, dppass); debug_helper(loc, 0, face, sfail, dpfail, dppass) } - StencilFuncSeparate :: #force_inline proc "c" (face: u32, func: u32, ref: i32, mask: u32, loc := #caller_location) { impl_StencilFuncSeparate(face, func, ref, mask); debug_helper(loc, 0, face, func, ref, mask) } - StencilMaskSeparate :: #force_inline proc "c" (face: u32, mask: u32, loc := #caller_location) { impl_StencilMaskSeparate(face, mask); debug_helper(loc, 0, face, mask) } - AttachShader :: #force_inline proc "c" (program: u32, shader: u32, loc := #caller_location) { impl_AttachShader(program, shader); debug_helper(loc, 0, program, shader) } - BindAttribLocation :: #force_inline proc "c" (program: u32, index: u32, name: cstring, loc := #caller_location) { impl_BindAttribLocation(program, index, name); debug_helper(loc, 0, program, index, name) } - CompileShader :: #force_inline proc "c" (shader: u32, loc := #caller_location) { impl_CompileShader(shader); debug_helper(loc, 0, shader) } - CreateProgram :: #force_inline proc "c" (loc := #caller_location) -> u32 { ret := impl_CreateProgram(); debug_helper(loc, 1, ret); return ret } - CreateShader :: #force_inline proc "c" (type: u32, loc := #caller_location) -> u32 { ret := impl_CreateShader(type); debug_helper(loc, 1, ret, type); return ret } - DeleteProgram :: #force_inline proc "c" (program: u32, loc := #caller_location) { impl_DeleteProgram(program); debug_helper(loc, 0, program) } - DeleteShader :: #force_inline proc "c" (shader: u32, loc := #caller_location) { impl_DeleteShader(shader); debug_helper(loc, 0, shader) } - DetachShader :: #force_inline proc "c" (program: u32, shader: u32, loc := #caller_location) { impl_DetachShader(program, shader); debug_helper(loc, 0, program, shader) } - DisableVertexAttribArray :: #force_inline proc "c" (index: u32, loc := #caller_location) { impl_DisableVertexAttribArray(index); debug_helper(loc, 0, index) } - EnableVertexAttribArray :: #force_inline proc "c" (index: u32, loc := #caller_location) { impl_EnableVertexAttribArray(index); debug_helper(loc, 0, index) } - GetActiveAttrib :: #force_inline proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8, loc := #caller_location) { impl_GetActiveAttrib(program, index, bufSize, length, size, type, name); debug_helper(loc, 0, program, index, bufSize, length, size, type, name) } - GetActiveUniform :: #force_inline proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8, loc := #caller_location) { impl_GetActiveUniform(program, index, bufSize, length, size, type, name); debug_helper(loc, 0, program, index, bufSize, length, size, type, name) } - GetAttachedShaders :: #force_inline proc "c" (program: u32, maxCount: i32, count: [^]i32, shaders: [^]u32, loc := #caller_location) { impl_GetAttachedShaders(program, maxCount, count, shaders); debug_helper(loc, 0, program, maxCount, count, shaders) } - GetAttribLocation :: #force_inline proc "c" (program: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetAttribLocation(program, name); debug_helper(loc, 1, ret, program, name); return ret } - GetProgramiv :: #force_inline proc "c" (program: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetProgramiv(program, pname, params); debug_helper(loc, 0, program, pname, params) } - GetProgramInfoLog :: #force_inline proc "c" (program: u32, bufSize: i32, length: ^i32, infoLog: [^]u8, loc := #caller_location) { impl_GetProgramInfoLog(program, bufSize, length, infoLog); debug_helper(loc, 0, program, bufSize, length, infoLog) } - GetShaderiv :: #force_inline proc "c" (shader: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetShaderiv(shader, pname, params); debug_helper(loc, 0, shader, pname, params) } - GetShaderInfoLog :: #force_inline proc "c" (shader: u32, bufSize: i32, length: ^i32, infoLog: [^]u8, loc := #caller_location) { impl_GetShaderInfoLog(shader, bufSize, length, infoLog); debug_helper(loc, 0, shader, bufSize, length, infoLog) } - GetShaderSource :: #force_inline proc "c" (shader: u32, bufSize: i32, length: ^i32, source: [^]u8, loc := #caller_location) { impl_GetShaderSource(shader, bufSize, length, source); debug_helper(loc, 0, shader, bufSize, length, source) } - GetUniformLocation :: #force_inline proc "c" (program: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetUniformLocation(program, name); debug_helper(loc, 1, ret, program, name); return ret } - GetUniformfv :: #force_inline proc "c" (program: u32, location: i32, params: [^]f32, loc := #caller_location) { impl_GetUniformfv(program, location, params); debug_helper(loc, 0, program, location, params) } - GetUniformiv :: #force_inline proc "c" (program: u32, location: i32, params: [^]i32, loc := #caller_location) { impl_GetUniformiv(program, location, params); debug_helper(loc, 0, program, location, params) } - GetVertexAttribdv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]f64, loc := #caller_location) { impl_GetVertexAttribdv(index, pname, params); debug_helper(loc, 0, index, pname, params) } - GetVertexAttribfv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetVertexAttribfv(index, pname, params); debug_helper(loc, 0, index, pname, params) } - GetVertexAttribiv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetVertexAttribiv(index, pname, params); debug_helper(loc, 0, index, pname, params) } - GetVertexAttribPointerv :: #force_inline proc "c" (index: u32, pname: u32, pointer: ^uintptr, loc := #caller_location) { impl_GetVertexAttribPointerv(index, pname, pointer); debug_helper(loc, 0, index, pname, pointer) } - IsProgram :: #force_inline proc "c" (program: u32, loc := #caller_location) -> bool { ret := impl_IsProgram(program); debug_helper(loc, 1, ret, program); return ret } - IsShader :: #force_inline proc "c" (shader: u32, loc := #caller_location) -> bool { ret := impl_IsShader(shader); debug_helper(loc, 1, ret, shader); return ret } - LinkProgram :: #force_inline proc "c" (program: u32, loc := #caller_location) { impl_LinkProgram(program); debug_helper(loc, 0, program) } - ShaderSource :: #force_inline proc "c" (shader: u32, count: i32, string: [^]cstring, length: [^]i32, loc := #caller_location) { impl_ShaderSource(shader, count, string, length); debug_helper(loc, 0, shader, count, string, length) } - UseProgram :: #force_inline proc "c" (program: u32, loc := #caller_location) { impl_UseProgram(program); debug_helper(loc, 0, program) } - Uniform1f :: #force_inline proc "c" (location: i32, v0: f32, loc := #caller_location) { impl_Uniform1f(location, v0); debug_helper(loc, 0, location, v0) } - Uniform2f :: #force_inline proc "c" (location: i32, v0: f32, v1: f32, loc := #caller_location) { impl_Uniform2f(location, v0, v1); debug_helper(loc, 0, location, v0, v1) } - Uniform3f :: #force_inline proc "c" (location: i32, v0: f32, v1: f32, v2: f32, loc := #caller_location) { impl_Uniform3f(location, v0, v1, v2); debug_helper(loc, 0, location, v0, v1, v2) } - Uniform4f :: #force_inline proc "c" (location: i32, v0: f32, v1: f32, v2: f32, v3: f32, loc := #caller_location) { impl_Uniform4f(location, v0, v1, v2, v3); debug_helper(loc, 0, location, v0, v1, v2, v3) } - Uniform1i :: #force_inline proc "c" (location: i32, v0: i32, loc := #caller_location) { impl_Uniform1i(location, v0); debug_helper(loc, 0, location, v0) } - Uniform2i :: #force_inline proc "c" (location: i32, v0: i32, v1: i32, loc := #caller_location) { impl_Uniform2i(location, v0, v1); debug_helper(loc, 0, location, v0, v1) } - Uniform3i :: #force_inline proc "c" (location: i32, v0: i32, v1: i32, v2: i32, loc := #caller_location) { impl_Uniform3i(location, v0, v1, v2); debug_helper(loc, 0, location, v0, v1, v2) } - Uniform4i :: #force_inline proc "c" (location: i32, v0: i32, v1: i32, v2: i32, v3: i32, loc := #caller_location) { impl_Uniform4i(location, v0, v1, v2, v3); debug_helper(loc, 0, location, v0, v1, v2, v3) } - Uniform1fv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_Uniform1fv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform2fv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_Uniform2fv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform3fv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_Uniform3fv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform4fv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_Uniform4fv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform1iv :: #force_inline proc "c" (location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_Uniform1iv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform2iv :: #force_inline proc "c" (location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_Uniform2iv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform3iv :: #force_inline proc "c" (location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_Uniform3iv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform4iv :: #force_inline proc "c" (location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_Uniform4iv(location, count, value); debug_helper(loc, 0, location, count, value) } - UniformMatrix2fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix2fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix3fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix3fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix4fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix4fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - ValidateProgram :: #force_inline proc "c" (program: u32, loc := #caller_location) { impl_ValidateProgram(program); debug_helper(loc, 0, program) } - VertexAttrib1d :: #force_inline proc "c" (index: u32, x: f64, loc := #caller_location) { impl_VertexAttrib1d(index, x); debug_helper(loc, 0, index, x) } - VertexAttrib1dv :: #force_inline proc "c" (index: u32, v: ^f64, loc := #caller_location) { impl_VertexAttrib1dv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib1f :: #force_inline proc "c" (index: u32, x: f32, loc := #caller_location) { impl_VertexAttrib1f(index, x); debug_helper(loc, 0, index, x) } - VertexAttrib1fv :: #force_inline proc "c" (index: u32, v: ^f32, loc := #caller_location) { impl_VertexAttrib1fv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib1s :: #force_inline proc "c" (index: u32, x: i16, loc := #caller_location) { impl_VertexAttrib1s(index, x); debug_helper(loc, 0, index, x) } - VertexAttrib1sv :: #force_inline proc "c" (index: u32, v: ^i16, loc := #caller_location) { impl_VertexAttrib1sv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib2d :: #force_inline proc "c" (index: u32, x: f64, y: f64, loc := #caller_location) { impl_VertexAttrib2d(index, x, y); debug_helper(loc, 0, index, x, y) } - VertexAttrib2dv :: #force_inline proc "c" (index: u32, v: ^[2]f64, loc := #caller_location) { impl_VertexAttrib2dv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib2f :: #force_inline proc "c" (index: u32, x: f32, y: f32, loc := #caller_location) { impl_VertexAttrib2f(index, x, y); debug_helper(loc, 0, index, x, y) } - VertexAttrib2fv :: #force_inline proc "c" (index: u32, v: ^[2]f32, loc := #caller_location) { impl_VertexAttrib2fv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib2s :: #force_inline proc "c" (index: u32, x: i16, y: i16, loc := #caller_location) { impl_VertexAttrib2s(index, x, y); debug_helper(loc, 0, index, x, y) } - VertexAttrib2sv :: #force_inline proc "c" (index: u32, v: ^[2]i16, loc := #caller_location) { impl_VertexAttrib2sv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib3d :: #force_inline proc "c" (index: u32, x: f64, y: f64, z: f64, loc := #caller_location) { impl_VertexAttrib3d(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } - VertexAttrib3dv :: #force_inline proc "c" (index: u32, v: ^[3]f64, loc := #caller_location) { impl_VertexAttrib3dv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib3f :: #force_inline proc "c" (index: u32, x: f32, y: f32, z: f32, loc := #caller_location) { impl_VertexAttrib3f(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } - VertexAttrib3fv :: #force_inline proc "c" (index: u32, v: ^[3]f32, loc := #caller_location) { impl_VertexAttrib3fv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib3s :: #force_inline proc "c" (index: u32, x: i16, y: i16, z: i16, loc := #caller_location) { impl_VertexAttrib3s(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } - VertexAttrib3sv :: #force_inline proc "c" (index: u32, v: ^[3]i16, loc := #caller_location) { impl_VertexAttrib3sv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4Nbv :: #force_inline proc "c" (index: u32, v: ^[4]i8, loc := #caller_location) { impl_VertexAttrib4Nbv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4Niv :: #force_inline proc "c" (index: u32, v: ^[4]i32, loc := #caller_location) { impl_VertexAttrib4Niv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4Nsv :: #force_inline proc "c" (index: u32, v: ^[4]i16, loc := #caller_location) { impl_VertexAttrib4Nsv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4Nub :: #force_inline proc "c" (index: u32, x: u8, y: u8, z: u8, w: u8, loc := #caller_location) { impl_VertexAttrib4Nub(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } - VertexAttrib4Nubv :: #force_inline proc "c" (index: u32, v: ^[4]u8, loc := #caller_location) { impl_VertexAttrib4Nubv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4Nuiv :: #force_inline proc "c" (index: u32, v: ^[4]u32, loc := #caller_location) { impl_VertexAttrib4Nuiv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4Nusv :: #force_inline proc "c" (index: u32, v: ^[4]u16, loc := #caller_location) { impl_VertexAttrib4Nusv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4bv :: #force_inline proc "c" (index: u32, v: ^[4]i8, loc := #caller_location) { impl_VertexAttrib4bv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4d :: #force_inline proc "c" (index: u32, x: f64, y: f64, z: f64, w: f64, loc := #caller_location) { impl_VertexAttrib4d(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } - VertexAttrib4dv :: #force_inline proc "c" (index: u32, v: ^[4]f64, loc := #caller_location) { impl_VertexAttrib4dv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4f :: #force_inline proc "c" (index: u32, x: f32, y: f32, z: f32, w: f32, loc := #caller_location) { impl_VertexAttrib4f(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } - VertexAttrib4fv :: #force_inline proc "c" (index: u32, v: ^[4]f32, loc := #caller_location) { impl_VertexAttrib4fv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4iv :: #force_inline proc "c" (index: u32, v: ^[4]i32, loc := #caller_location) { impl_VertexAttrib4iv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4s :: #force_inline proc "c" (index: u32, x: i16, y: i16, z: i16, w: i16, loc := #caller_location) { impl_VertexAttrib4s(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } - VertexAttrib4sv :: #force_inline proc "c" (index: u32, v: ^[4]i16, loc := #caller_location) { impl_VertexAttrib4sv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4ubv :: #force_inline proc "c" (index: u32, v: ^[4]u8, loc := #caller_location) { impl_VertexAttrib4ubv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4uiv :: #force_inline proc "c" (index: u32, v: ^[4]u32, loc := #caller_location) { impl_VertexAttrib4uiv(index, v); debug_helper(loc, 0, index, v) } - VertexAttrib4usv :: #force_inline proc "c" (index: u32, v: ^[4]u16, loc := #caller_location) { impl_VertexAttrib4usv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribPointer :: #force_inline proc "c" (index: u32, size: i32, type: u32, normalized: bool, stride: i32, pointer: uintptr, loc := #caller_location) { impl_VertexAttribPointer(index, size, type, normalized, stride, pointer); debug_helper(loc, 0, index, size, type, normalized, stride, pointer) } + BlendEquationSeparate :: proc "c" (modeRGB: u32, modeAlpha: u32, loc := #caller_location) { impl_BlendEquationSeparate(modeRGB, modeAlpha); debug_helper(loc, 0, modeRGB, modeAlpha) } + DrawBuffers :: proc "c" (n: i32, bufs: [^]u32, loc := #caller_location) { impl_DrawBuffers(n, bufs); debug_helper(loc, 0, n, bufs) } + StencilOpSeparate :: proc "c" (face: u32, sfail: u32, dpfail: u32, dppass: u32, loc := #caller_location) { impl_StencilOpSeparate(face, sfail, dpfail, dppass); debug_helper(loc, 0, face, sfail, dpfail, dppass) } + StencilFuncSeparate :: proc "c" (face: u32, func: u32, ref: i32, mask: u32, loc := #caller_location) { impl_StencilFuncSeparate(face, func, ref, mask); debug_helper(loc, 0, face, func, ref, mask) } + StencilMaskSeparate :: proc "c" (face: u32, mask: u32, loc := #caller_location) { impl_StencilMaskSeparate(face, mask); debug_helper(loc, 0, face, mask) } + AttachShader :: proc "c" (program: u32, shader: u32, loc := #caller_location) { impl_AttachShader(program, shader); debug_helper(loc, 0, program, shader) } + BindAttribLocation :: proc "c" (program: u32, index: u32, name: cstring, loc := #caller_location) { impl_BindAttribLocation(program, index, name); debug_helper(loc, 0, program, index, name) } + CompileShader :: proc "c" (shader: u32, loc := #caller_location) { impl_CompileShader(shader); debug_helper(loc, 0, shader) } + CreateProgram :: proc "c" (loc := #caller_location) -> u32 { ret := impl_CreateProgram(); debug_helper(loc, 1, ret); return ret } + CreateShader :: proc "c" (type: u32, loc := #caller_location) -> u32 { ret := impl_CreateShader(type); debug_helper(loc, 1, ret, type); return ret } + DeleteProgram :: proc "c" (program: u32, loc := #caller_location) { impl_DeleteProgram(program); debug_helper(loc, 0, program) } + DeleteShader :: proc "c" (shader: u32, loc := #caller_location) { impl_DeleteShader(shader); debug_helper(loc, 0, shader) } + DetachShader :: proc "c" (program: u32, shader: u32, loc := #caller_location) { impl_DetachShader(program, shader); debug_helper(loc, 0, program, shader) } + DisableVertexAttribArray :: proc "c" (index: u32, loc := #caller_location) { impl_DisableVertexAttribArray(index); debug_helper(loc, 0, index) } + EnableVertexAttribArray :: proc "c" (index: u32, loc := #caller_location) { impl_EnableVertexAttribArray(index); debug_helper(loc, 0, index) } + GetActiveAttrib :: proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8, loc := #caller_location) { impl_GetActiveAttrib(program, index, bufSize, length, size, type, name); debug_helper(loc, 0, program, index, bufSize, length, size, type, name) } + GetActiveUniform :: proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8, loc := #caller_location) { impl_GetActiveUniform(program, index, bufSize, length, size, type, name); debug_helper(loc, 0, program, index, bufSize, length, size, type, name) } + GetAttachedShaders :: proc "c" (program: u32, maxCount: i32, count: [^]i32, shaders: [^]u32, loc := #caller_location) { impl_GetAttachedShaders(program, maxCount, count, shaders); debug_helper(loc, 0, program, maxCount, count, shaders) } + GetAttribLocation :: proc "c" (program: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetAttribLocation(program, name); debug_helper(loc, 1, ret, program, name); return ret } + GetProgramiv :: proc "c" (program: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetProgramiv(program, pname, params); debug_helper(loc, 0, program, pname, params) } + GetProgramInfoLog :: proc "c" (program: u32, bufSize: i32, length: ^i32, infoLog: [^]u8, loc := #caller_location) { impl_GetProgramInfoLog(program, bufSize, length, infoLog); debug_helper(loc, 0, program, bufSize, length, infoLog) } + GetShaderiv :: proc "c" (shader: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetShaderiv(shader, pname, params); debug_helper(loc, 0, shader, pname, params) } + GetShaderInfoLog :: proc "c" (shader: u32, bufSize: i32, length: ^i32, infoLog: [^]u8, loc := #caller_location) { impl_GetShaderInfoLog(shader, bufSize, length, infoLog); debug_helper(loc, 0, shader, bufSize, length, infoLog) } + GetShaderSource :: proc "c" (shader: u32, bufSize: i32, length: ^i32, source: [^]u8, loc := #caller_location) { impl_GetShaderSource(shader, bufSize, length, source); debug_helper(loc, 0, shader, bufSize, length, source) } + GetUniformLocation :: proc "c" (program: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetUniformLocation(program, name); debug_helper(loc, 1, ret, program, name); return ret } + GetUniformfv :: proc "c" (program: u32, location: i32, params: [^]f32, loc := #caller_location) { impl_GetUniformfv(program, location, params); debug_helper(loc, 0, program, location, params) } + GetUniformiv :: proc "c" (program: u32, location: i32, params: [^]i32, loc := #caller_location) { impl_GetUniformiv(program, location, params); debug_helper(loc, 0, program, location, params) } + GetVertexAttribdv :: proc "c" (index: u32, pname: u32, params: [^]f64, loc := #caller_location) { impl_GetVertexAttribdv(index, pname, params); debug_helper(loc, 0, index, pname, params) } + GetVertexAttribfv :: proc "c" (index: u32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetVertexAttribfv(index, pname, params); debug_helper(loc, 0, index, pname, params) } + GetVertexAttribiv :: proc "c" (index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetVertexAttribiv(index, pname, params); debug_helper(loc, 0, index, pname, params) } + GetVertexAttribPointerv :: proc "c" (index: u32, pname: u32, pointer: ^uintptr, loc := #caller_location) { impl_GetVertexAttribPointerv(index, pname, pointer); debug_helper(loc, 0, index, pname, pointer) } + IsProgram :: proc "c" (program: u32, loc := #caller_location) -> bool { ret := impl_IsProgram(program); debug_helper(loc, 1, ret, program); return ret } + IsShader :: proc "c" (shader: u32, loc := #caller_location) -> bool { ret := impl_IsShader(shader); debug_helper(loc, 1, ret, shader); return ret } + LinkProgram :: proc "c" (program: u32, loc := #caller_location) { impl_LinkProgram(program); debug_helper(loc, 0, program) } + ShaderSource :: proc "c" (shader: u32, count: i32, string: [^]cstring, length: [^]i32, loc := #caller_location) { impl_ShaderSource(shader, count, string, length); debug_helper(loc, 0, shader, count, string, length) } + UseProgram :: proc "c" (program: u32, loc := #caller_location) { impl_UseProgram(program); debug_helper(loc, 0, program) } + Uniform1f :: proc "c" (location: i32, v0: f32, loc := #caller_location) { impl_Uniform1f(location, v0); debug_helper(loc, 0, location, v0) } + Uniform2f :: proc "c" (location: i32, v0: f32, v1: f32, loc := #caller_location) { impl_Uniform2f(location, v0, v1); debug_helper(loc, 0, location, v0, v1) } + Uniform3f :: proc "c" (location: i32, v0: f32, v1: f32, v2: f32, loc := #caller_location) { impl_Uniform3f(location, v0, v1, v2); debug_helper(loc, 0, location, v0, v1, v2) } + Uniform4f :: proc "c" (location: i32, v0: f32, v1: f32, v2: f32, v3: f32, loc := #caller_location) { impl_Uniform4f(location, v0, v1, v2, v3); debug_helper(loc, 0, location, v0, v1, v2, v3) } + Uniform1i :: proc "c" (location: i32, v0: i32, loc := #caller_location) { impl_Uniform1i(location, v0); debug_helper(loc, 0, location, v0) } + Uniform2i :: proc "c" (location: i32, v0: i32, v1: i32, loc := #caller_location) { impl_Uniform2i(location, v0, v1); debug_helper(loc, 0, location, v0, v1) } + Uniform3i :: proc "c" (location: i32, v0: i32, v1: i32, v2: i32, loc := #caller_location) { impl_Uniform3i(location, v0, v1, v2); debug_helper(loc, 0, location, v0, v1, v2) } + Uniform4i :: proc "c" (location: i32, v0: i32, v1: i32, v2: i32, v3: i32, loc := #caller_location) { impl_Uniform4i(location, v0, v1, v2, v3); debug_helper(loc, 0, location, v0, v1, v2, v3) } + Uniform1fv :: proc "c" (location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_Uniform1fv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform2fv :: proc "c" (location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_Uniform2fv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform3fv :: proc "c" (location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_Uniform3fv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform4fv :: proc "c" (location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_Uniform4fv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform1iv :: proc "c" (location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_Uniform1iv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform2iv :: proc "c" (location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_Uniform2iv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform3iv :: proc "c" (location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_Uniform3iv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform4iv :: proc "c" (location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_Uniform4iv(location, count, value); debug_helper(loc, 0, location, count, value) } + UniformMatrix2fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix2fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix3fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix3fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix4fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix4fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + ValidateProgram :: proc "c" (program: u32, loc := #caller_location) { impl_ValidateProgram(program); debug_helper(loc, 0, program) } + VertexAttrib1d :: proc "c" (index: u32, x: f64, loc := #caller_location) { impl_VertexAttrib1d(index, x); debug_helper(loc, 0, index, x) } + VertexAttrib1dv :: proc "c" (index: u32, v: ^f64, loc := #caller_location) { impl_VertexAttrib1dv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib1f :: proc "c" (index: u32, x: f32, loc := #caller_location) { impl_VertexAttrib1f(index, x); debug_helper(loc, 0, index, x) } + VertexAttrib1fv :: proc "c" (index: u32, v: ^f32, loc := #caller_location) { impl_VertexAttrib1fv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib1s :: proc "c" (index: u32, x: i16, loc := #caller_location) { impl_VertexAttrib1s(index, x); debug_helper(loc, 0, index, x) } + VertexAttrib1sv :: proc "c" (index: u32, v: ^i16, loc := #caller_location) { impl_VertexAttrib1sv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib2d :: proc "c" (index: u32, x: f64, y: f64, loc := #caller_location) { impl_VertexAttrib2d(index, x, y); debug_helper(loc, 0, index, x, y) } + VertexAttrib2dv :: proc "c" (index: u32, v: ^[2]f64, loc := #caller_location) { impl_VertexAttrib2dv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib2f :: proc "c" (index: u32, x: f32, y: f32, loc := #caller_location) { impl_VertexAttrib2f(index, x, y); debug_helper(loc, 0, index, x, y) } + VertexAttrib2fv :: proc "c" (index: u32, v: ^[2]f32, loc := #caller_location) { impl_VertexAttrib2fv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib2s :: proc "c" (index: u32, x: i16, y: i16, loc := #caller_location) { impl_VertexAttrib2s(index, x, y); debug_helper(loc, 0, index, x, y) } + VertexAttrib2sv :: proc "c" (index: u32, v: ^[2]i16, loc := #caller_location) { impl_VertexAttrib2sv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib3d :: proc "c" (index: u32, x: f64, y: f64, z: f64, loc := #caller_location) { impl_VertexAttrib3d(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } + VertexAttrib3dv :: proc "c" (index: u32, v: ^[3]f64, loc := #caller_location) { impl_VertexAttrib3dv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib3f :: proc "c" (index: u32, x: f32, y: f32, z: f32, loc := #caller_location) { impl_VertexAttrib3f(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } + VertexAttrib3fv :: proc "c" (index: u32, v: ^[3]f32, loc := #caller_location) { impl_VertexAttrib3fv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib3s :: proc "c" (index: u32, x: i16, y: i16, z: i16, loc := #caller_location) { impl_VertexAttrib3s(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } + VertexAttrib3sv :: proc "c" (index: u32, v: ^[3]i16, loc := #caller_location) { impl_VertexAttrib3sv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4Nbv :: proc "c" (index: u32, v: ^[4]i8, loc := #caller_location) { impl_VertexAttrib4Nbv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4Niv :: proc "c" (index: u32, v: ^[4]i32, loc := #caller_location) { impl_VertexAttrib4Niv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4Nsv :: proc "c" (index: u32, v: ^[4]i16, loc := #caller_location) { impl_VertexAttrib4Nsv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4Nub :: proc "c" (index: u32, x: u8, y: u8, z: u8, w: u8, loc := #caller_location) { impl_VertexAttrib4Nub(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } + VertexAttrib4Nubv :: proc "c" (index: u32, v: ^[4]u8, loc := #caller_location) { impl_VertexAttrib4Nubv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4Nuiv :: proc "c" (index: u32, v: ^[4]u32, loc := #caller_location) { impl_VertexAttrib4Nuiv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4Nusv :: proc "c" (index: u32, v: ^[4]u16, loc := #caller_location) { impl_VertexAttrib4Nusv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4bv :: proc "c" (index: u32, v: ^[4]i8, loc := #caller_location) { impl_VertexAttrib4bv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4d :: proc "c" (index: u32, x: f64, y: f64, z: f64, w: f64, loc := #caller_location) { impl_VertexAttrib4d(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } + VertexAttrib4dv :: proc "c" (index: u32, v: ^[4]f64, loc := #caller_location) { impl_VertexAttrib4dv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4f :: proc "c" (index: u32, x: f32, y: f32, z: f32, w: f32, loc := #caller_location) { impl_VertexAttrib4f(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } + VertexAttrib4fv :: proc "c" (index: u32, v: ^[4]f32, loc := #caller_location) { impl_VertexAttrib4fv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4iv :: proc "c" (index: u32, v: ^[4]i32, loc := #caller_location) { impl_VertexAttrib4iv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4s :: proc "c" (index: u32, x: i16, y: i16, z: i16, w: i16, loc := #caller_location) { impl_VertexAttrib4s(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } + VertexAttrib4sv :: proc "c" (index: u32, v: ^[4]i16, loc := #caller_location) { impl_VertexAttrib4sv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4ubv :: proc "c" (index: u32, v: ^[4]u8, loc := #caller_location) { impl_VertexAttrib4ubv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4uiv :: proc "c" (index: u32, v: ^[4]u32, loc := #caller_location) { impl_VertexAttrib4uiv(index, v); debug_helper(loc, 0, index, v) } + VertexAttrib4usv :: proc "c" (index: u32, v: ^[4]u16, loc := #caller_location) { impl_VertexAttrib4usv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribPointer :: proc "c" (index: u32, size: i32, type: u32, normalized: bool, stride: i32, pointer: uintptr, loc := #caller_location) { impl_VertexAttribPointer(index, size, type, normalized, stride, pointer); debug_helper(loc, 0, index, size, type, normalized, stride, pointer) } // VERSION_2_1 - UniformMatrix2x3fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix2x3fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix3x2fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix3x2fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix2x4fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix2x4fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix4x2fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix4x2fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix3x4fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix3x4fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix4x3fv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix4x3fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix2x3fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix2x3fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix3x2fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix3x2fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix2x4fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix2x4fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix4x2fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix4x2fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix3x4fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix3x4fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix4x3fv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_UniformMatrix4x3fv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } // VERSION_3_0 - ColorMaski :: #force_inline proc "c" (index: u32, r: bool, g: bool, b: bool, a: bool, loc := #caller_location) { impl_ColorMaski(index, r, g, b, a); debug_helper(loc, 0, index, r, g, b, a) } - GetBooleani_v :: #force_inline proc "c" (target: u32, index: u32, data: ^bool, loc := #caller_location) { impl_GetBooleani_v(target, index, data); debug_helper(loc, 0, target, index, data) } - GetIntegeri_v :: #force_inline proc "c" (target: u32, index: u32, data: ^i32, loc := #caller_location) { impl_GetIntegeri_v(target, index, data); debug_helper(loc, 0, target, index, data) } - Enablei :: #force_inline proc "c" (target: u32, index: u32, loc := #caller_location) { impl_Enablei(target, index); debug_helper(loc, 0, target, index) } - Disablei :: #force_inline proc "c" (target: u32, index: u32, loc := #caller_location) { impl_Disablei(target, index); debug_helper(loc, 0, target, index) } - IsEnabledi :: #force_inline proc "c" (target: u32, index: u32, loc := #caller_location) -> bool { ret := impl_IsEnabledi(target, index); debug_helper(loc, 1, ret, target, index); return ret } - BeginTransformFeedback :: #force_inline proc "c" (primitiveMode: u32, loc := #caller_location) { impl_BeginTransformFeedback(primitiveMode); debug_helper(loc, 0, primitiveMode) } - EndTransformFeedback :: #force_inline proc "c" (loc := #caller_location) { impl_EndTransformFeedback(); debug_helper(loc, 0) } - BindBufferRange :: #force_inline proc "c" (target: u32, index: u32, buffer: u32, offset: int, size: int, loc := #caller_location) { impl_BindBufferRange(target, index, buffer, offset, size); debug_helper(loc, 0, target, index, buffer, offset, size) } - BindBufferBase :: #force_inline proc "c" (target: u32, index: u32, buffer: u32, loc := #caller_location) { impl_BindBufferBase(target, index, buffer); debug_helper(loc, 0, target, index, buffer) } - TransformFeedbackVaryings :: #force_inline proc "c" (program: u32, count: i32, varyings: [^]cstring, bufferMode: u32, loc := #caller_location) { impl_TransformFeedbackVaryings(program, count, varyings, bufferMode); debug_helper(loc, 0, program, count, varyings, bufferMode) } - GetTransformFeedbackVarying :: #force_inline proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8, loc := #caller_location) { impl_GetTransformFeedbackVarying(program, index, bufSize, length, size, type, name); debug_helper(loc, 0, program, index, bufSize, length, size, type, name) } - ClampColor :: #force_inline proc "c" (target: u32, clamp: u32, loc := #caller_location) { impl_ClampColor(target, clamp); debug_helper(loc, 0, target, clamp) } - BeginConditionalRender :: #force_inline proc "c" (id: u32, mode: u32, loc := #caller_location) { impl_BeginConditionalRender(id, mode); debug_helper(loc, 0, id, mode) } - EndConditionalRender :: #force_inline proc "c" (loc := #caller_location) { impl_EndConditionalRender(); debug_helper(loc, 0) } - VertexAttribIPointer :: #force_inline proc "c" (index: u32, size: i32, type: u32, stride: i32, pointer: uintptr, loc := #caller_location) { impl_VertexAttribIPointer(index, size, type, stride, pointer); debug_helper(loc, 0, index, size, type, stride, pointer) } - GetVertexAttribIiv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetVertexAttribIiv(index, pname, params); debug_helper(loc, 0, index, pname, params) } - GetVertexAttribIuiv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetVertexAttribIuiv(index, pname, params); debug_helper(loc, 0, index, pname, params) } - VertexAttribI1i :: #force_inline proc "c" (index: u32, x: i32, loc := #caller_location) { impl_VertexAttribI1i(index, x); debug_helper(loc, 0, index, x) } - VertexAttribI2i :: #force_inline proc "c" (index: u32, x: i32, y: i32, loc := #caller_location) { impl_VertexAttribI2i(index, x, y); debug_helper(loc, 0, index, x, y) } - VertexAttribI3i :: #force_inline proc "c" (index: u32, x: i32, y: i32, z: i32, loc := #caller_location) { impl_VertexAttribI3i(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } - VertexAttribI4i :: #force_inline proc "c" (index: u32, x: i32, y: i32, z: i32, w: i32, loc := #caller_location) { impl_VertexAttribI4i(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } - VertexAttribI1ui :: #force_inline proc "c" (index: u32, x: u32, loc := #caller_location) { impl_VertexAttribI1ui(index, x); debug_helper(loc, 0, index, x) } - VertexAttribI2ui :: #force_inline proc "c" (index: u32, x: u32, y: u32, loc := #caller_location) { impl_VertexAttribI2ui(index, x, y); debug_helper(loc, 0, index, x, y) } - VertexAttribI3ui :: #force_inline proc "c" (index: u32, x: u32, y: u32, z: u32, loc := #caller_location) { impl_VertexAttribI3ui(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } - VertexAttribI4ui :: #force_inline proc "c" (index: u32, x: u32, y: u32, z: u32, w: u32, loc := #caller_location) { impl_VertexAttribI4ui(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } - VertexAttribI1iv :: #force_inline proc "c" (index: u32, v: [^]i32, loc := #caller_location) { impl_VertexAttribI1iv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI2iv :: #force_inline proc "c" (index: u32, v: [^]i32, loc := #caller_location) { impl_VertexAttribI2iv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI3iv :: #force_inline proc "c" (index: u32, v: [^]i32, loc := #caller_location) { impl_VertexAttribI3iv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI4iv :: #force_inline proc "c" (index: u32, v: [^]i32, loc := #caller_location) { impl_VertexAttribI4iv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI1uiv :: #force_inline proc "c" (index: u32, v: [^]u32, loc := #caller_location) { impl_VertexAttribI1uiv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI2uiv :: #force_inline proc "c" (index: u32, v: [^]u32, loc := #caller_location) { impl_VertexAttribI2uiv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI3uiv :: #force_inline proc "c" (index: u32, v: [^]u32, loc := #caller_location) { impl_VertexAttribI3uiv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI4uiv :: #force_inline proc "c" (index: u32, v: [^]u32, loc := #caller_location) { impl_VertexAttribI4uiv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI4bv :: #force_inline proc "c" (index: u32, v: [^]i8, loc := #caller_location) { impl_VertexAttribI4bv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI4sv :: #force_inline proc "c" (index: u32, v: [^]i16, loc := #caller_location) { impl_VertexAttribI4sv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI4ubv :: #force_inline proc "c" (index: u32, v: [^]u8, loc := #caller_location) { impl_VertexAttribI4ubv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribI4usv :: #force_inline proc "c" (index: u32, v: [^]u16, loc := #caller_location) { impl_VertexAttribI4usv(index, v); debug_helper(loc, 0, index, v) } - GetUniformuiv :: #force_inline proc "c" (program: u32, location: i32, params: [^]u32, loc := #caller_location) { impl_GetUniformuiv(program, location, params); debug_helper(loc, 0, program, location, params) } - BindFragDataLocation :: #force_inline proc "c" (program: u32, color: u32, name: cstring, loc := #caller_location) { impl_BindFragDataLocation(program, color, name); debug_helper(loc, 0, program, color, name) } - GetFragDataLocation :: #force_inline proc "c" (program: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetFragDataLocation(program, name); debug_helper(loc, 1, ret, program, name); return ret } - Uniform1ui :: #force_inline proc "c" (location: i32, v0: u32, loc := #caller_location) { impl_Uniform1ui(location, v0); debug_helper(loc, 0, location, v0) } - Uniform2ui :: #force_inline proc "c" (location: i32, v0: u32, v1: u32, loc := #caller_location) { impl_Uniform2ui(location, v0, v1); debug_helper(loc, 0, location, v0, v1) } - Uniform3ui :: #force_inline proc "c" (location: i32, v0: u32, v1: u32, v2: u32, loc := #caller_location) { impl_Uniform3ui(location, v0, v1, v2); debug_helper(loc, 0, location, v0, v1, v2) } - Uniform4ui :: #force_inline proc "c" (location: i32, v0: u32, v1: u32, v2: u32, v3: u32, loc := #caller_location) { impl_Uniform4ui(location, v0, v1, v2, v3); debug_helper(loc, 0, location, v0, v1, v2, v3) } - Uniform1uiv :: #force_inline proc "c" (location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_Uniform1uiv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform2uiv :: #force_inline proc "c" (location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_Uniform2uiv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform3uiv :: #force_inline proc "c" (location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_Uniform3uiv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform4uiv :: #force_inline proc "c" (location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_Uniform4uiv(location, count, value); debug_helper(loc, 0, location, count, value) } - TexParameterIiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_TexParameterIiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - TexParameterIuiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_TexParameterIuiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - GetTexParameterIiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTexParameterIiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - GetTexParameterIuiv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetTexParameterIuiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - ClearBufferiv :: #force_inline proc "c" (buffer: u32, drawbuffer: i32, value: ^i32, loc := #caller_location) { impl_ClearBufferiv(buffer, drawbuffer, value); debug_helper(loc, 0, buffer, drawbuffer, value) } - ClearBufferuiv :: #force_inline proc "c" (buffer: u32, drawbuffer: i32, value: ^u32, loc := #caller_location) { impl_ClearBufferuiv(buffer, drawbuffer, value); debug_helper(loc, 0, buffer, drawbuffer, value) } - ClearBufferfv :: #force_inline proc "c" (buffer: u32, drawbuffer: i32, value: ^f32, loc := #caller_location) { impl_ClearBufferfv(buffer, drawbuffer, value); debug_helper(loc, 0, buffer, drawbuffer, value) } - ClearBufferfi :: #force_inline proc "c" (buffer: u32, drawbuffer: i32, depth: f32, stencil: i32, loc := #caller_location) -> rawptr { ret := impl_ClearBufferfi(buffer, drawbuffer, depth, stencil); debug_helper(loc, 1, ret, buffer, drawbuffer, depth, stencil); return ret } - GetStringi :: #force_inline proc "c" (name: u32, index: u32, loc := #caller_location) -> cstring { ret := impl_GetStringi(name, index); debug_helper(loc, 1, ret, name, index); return ret } - IsRenderbuffer :: #force_inline proc "c" (renderbuffer: u32, loc := #caller_location) -> bool { ret := impl_IsRenderbuffer(renderbuffer); debug_helper(loc, 1, ret, renderbuffer); return ret } - BindRenderbuffer :: #force_inline proc "c" (target: u32, renderbuffer: u32, loc := #caller_location) { impl_BindRenderbuffer(target, renderbuffer); debug_helper(loc, 0, target, renderbuffer) } - DeleteRenderbuffers :: #force_inline proc "c" (n: i32, renderbuffers: [^]u32, loc := #caller_location) { impl_DeleteRenderbuffers(n, renderbuffers); debug_helper(loc, 0, n, renderbuffers) } - GenRenderbuffers :: #force_inline proc "c" (n: i32, renderbuffers: [^]u32, loc := #caller_location) { impl_GenRenderbuffers(n, renderbuffers); debug_helper(loc, 0, n, renderbuffers) } - RenderbufferStorage :: #force_inline proc "c" (target: u32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_RenderbufferStorage(target, internalformat, width, height); debug_helper(loc, 0, target, internalformat, width, height) } - GetRenderbufferParameteriv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetRenderbufferParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - IsFramebuffer :: #force_inline proc "c" (framebuffer: u32, loc := #caller_location) -> bool { ret := impl_IsFramebuffer(framebuffer); debug_helper(loc, 1, ret, framebuffer); return ret } - BindFramebuffer :: #force_inline proc "c" (target: u32, framebuffer: u32, loc := #caller_location) { impl_BindFramebuffer(target, framebuffer); debug_helper(loc, 0, target, framebuffer) } - DeleteFramebuffers :: #force_inline proc "c" (n: i32, framebuffers: [^]u32, loc := #caller_location) { impl_DeleteFramebuffers(n, framebuffers); debug_helper(loc, 0, n, framebuffers) } - GenFramebuffers :: #force_inline proc "c" (n: i32, framebuffers: [^]u32, loc := #caller_location) { impl_GenFramebuffers(n, framebuffers); debug_helper(loc, 0, n, framebuffers) } - CheckFramebufferStatus :: #force_inline proc "c" (target: u32, loc := #caller_location) -> u32 { ret := impl_CheckFramebufferStatus(target); debug_helper(loc, 1, ret, target); return ret } - FramebufferTexture1D :: #force_inline proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32, loc := #caller_location) { impl_FramebufferTexture1D(target, attachment, textarget, texture, level); debug_helper(loc, 0, target, attachment, textarget, texture, level) } - FramebufferTexture2D :: #force_inline proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32, loc := #caller_location) { impl_FramebufferTexture2D(target, attachment, textarget, texture, level); debug_helper(loc, 0, target, attachment, textarget, texture, level) } - FramebufferTexture3D :: #force_inline proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32, zoffset: i32, loc := #caller_location) { impl_FramebufferTexture3D(target, attachment, textarget, texture, level, zoffset); debug_helper(loc, 0, target, attachment, textarget, texture, level, zoffset) } - FramebufferRenderbuffer :: #force_inline proc "c" (target: u32, attachment: u32, renderbuffertarget: u32, renderbuffer: u32, loc := #caller_location) { impl_FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); debug_helper(loc, 0, target, attachment, renderbuffertarget, renderbuffer) } - GetFramebufferAttachmentParameteriv :: #force_inline proc "c" (target: u32, attachment: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetFramebufferAttachmentParameteriv(target, attachment, pname, params); debug_helper(loc, 0, target, attachment, pname, params) } - GenerateMipmap :: #force_inline proc "c" (target: u32, loc := #caller_location) { impl_GenerateMipmap(target); debug_helper(loc, 0, target) } - BlitFramebuffer :: #force_inline proc "c" (srcX0: i32, srcY0: i32, srcX1: i32, srcY1: i32, dstX0: i32, dstY0: i32, dstX1: i32, dstY1: i32, mask: u32, filter: u32, loc := #caller_location) { impl_BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); debug_helper(loc, 0, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) } - RenderbufferStorageMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_RenderbufferStorageMultisample(target, samples, internalformat, width, height); debug_helper(loc, 0, target, samples, internalformat, width, height) } - FramebufferTextureLayer :: #force_inline proc "c" (target: u32, attachment: u32, texture: u32, level: i32, layer: i32, loc := #caller_location) { impl_FramebufferTextureLayer(target, attachment, texture, level, layer); debug_helper(loc, 0, target, attachment, texture, level, layer) } - MapBufferRange :: #force_inline proc "c" (target: u32, offset: int, length: int, access: u32, loc := #caller_location) -> rawptr { ret := impl_MapBufferRange(target, offset, length, access); debug_helper(loc, 1, ret, target, offset, length, access); return ret } - FlushMappedBufferRange :: #force_inline proc "c" (target: u32, offset: int, length: int, loc := #caller_location) { impl_FlushMappedBufferRange(target, offset, length); debug_helper(loc, 0, target, offset, length) } - BindVertexArray :: #force_inline proc "c" (array: u32, loc := #caller_location) { impl_BindVertexArray(array); debug_helper(loc, 0, array) } - DeleteVertexArrays :: #force_inline proc "c" (n: i32, arrays: [^]u32, loc := #caller_location) { impl_DeleteVertexArrays(n, arrays); debug_helper(loc, 0, n, arrays) } - GenVertexArrays :: #force_inline proc "c" (n: i32, arrays: [^]u32, loc := #caller_location) { impl_GenVertexArrays(n, arrays); debug_helper(loc, 0, n, arrays) } - IsVertexArray :: #force_inline proc "c" (array: u32, loc := #caller_location) -> bool { ret := impl_IsVertexArray(array); debug_helper(loc, 1, ret, array); return ret } + ColorMaski :: proc "c" (index: u32, r: bool, g: bool, b: bool, a: bool, loc := #caller_location) { impl_ColorMaski(index, r, g, b, a); debug_helper(loc, 0, index, r, g, b, a) } + GetBooleani_v :: proc "c" (target: u32, index: u32, data: ^bool, loc := #caller_location) { impl_GetBooleani_v(target, index, data); debug_helper(loc, 0, target, index, data) } + GetIntegeri_v :: proc "c" (target: u32, index: u32, data: ^i32, loc := #caller_location) { impl_GetIntegeri_v(target, index, data); debug_helper(loc, 0, target, index, data) } + Enablei :: proc "c" (target: u32, index: u32, loc := #caller_location) { impl_Enablei(target, index); debug_helper(loc, 0, target, index) } + Disablei :: proc "c" (target: u32, index: u32, loc := #caller_location) { impl_Disablei(target, index); debug_helper(loc, 0, target, index) } + IsEnabledi :: proc "c" (target: u32, index: u32, loc := #caller_location) -> bool { ret := impl_IsEnabledi(target, index); debug_helper(loc, 1, ret, target, index); return ret } + BeginTransformFeedback :: proc "c" (primitiveMode: u32, loc := #caller_location) { impl_BeginTransformFeedback(primitiveMode); debug_helper(loc, 0, primitiveMode) } + EndTransformFeedback :: proc "c" (loc := #caller_location) { impl_EndTransformFeedback(); debug_helper(loc, 0) } + BindBufferRange :: proc "c" (target: u32, index: u32, buffer: u32, offset: int, size: int, loc := #caller_location) { impl_BindBufferRange(target, index, buffer, offset, size); debug_helper(loc, 0, target, index, buffer, offset, size) } + BindBufferBase :: proc "c" (target: u32, index: u32, buffer: u32, loc := #caller_location) { impl_BindBufferBase(target, index, buffer); debug_helper(loc, 0, target, index, buffer) } + TransformFeedbackVaryings :: proc "c" (program: u32, count: i32, varyings: [^]cstring, bufferMode: u32, loc := #caller_location) { impl_TransformFeedbackVaryings(program, count, varyings, bufferMode); debug_helper(loc, 0, program, count, varyings, bufferMode) } + GetTransformFeedbackVarying :: proc "c" (program: u32, index: u32, bufSize: i32, length: ^i32, size: ^i32, type: ^u32, name: [^]u8, loc := #caller_location) { impl_GetTransformFeedbackVarying(program, index, bufSize, length, size, type, name); debug_helper(loc, 0, program, index, bufSize, length, size, type, name) } + ClampColor :: proc "c" (target: u32, clamp: u32, loc := #caller_location) { impl_ClampColor(target, clamp); debug_helper(loc, 0, target, clamp) } + BeginConditionalRender :: proc "c" (id: u32, mode: u32, loc := #caller_location) { impl_BeginConditionalRender(id, mode); debug_helper(loc, 0, id, mode) } + EndConditionalRender :: proc "c" (loc := #caller_location) { impl_EndConditionalRender(); debug_helper(loc, 0) } + VertexAttribIPointer :: proc "c" (index: u32, size: i32, type: u32, stride: i32, pointer: uintptr, loc := #caller_location) { impl_VertexAttribIPointer(index, size, type, stride, pointer); debug_helper(loc, 0, index, size, type, stride, pointer) } + GetVertexAttribIiv :: proc "c" (index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetVertexAttribIiv(index, pname, params); debug_helper(loc, 0, index, pname, params) } + GetVertexAttribIuiv :: proc "c" (index: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetVertexAttribIuiv(index, pname, params); debug_helper(loc, 0, index, pname, params) } + VertexAttribI1i :: proc "c" (index: u32, x: i32, loc := #caller_location) { impl_VertexAttribI1i(index, x); debug_helper(loc, 0, index, x) } + VertexAttribI2i :: proc "c" (index: u32, x: i32, y: i32, loc := #caller_location) { impl_VertexAttribI2i(index, x, y); debug_helper(loc, 0, index, x, y) } + VertexAttribI3i :: proc "c" (index: u32, x: i32, y: i32, z: i32, loc := #caller_location) { impl_VertexAttribI3i(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } + VertexAttribI4i :: proc "c" (index: u32, x: i32, y: i32, z: i32, w: i32, loc := #caller_location) { impl_VertexAttribI4i(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } + VertexAttribI1ui :: proc "c" (index: u32, x: u32, loc := #caller_location) { impl_VertexAttribI1ui(index, x); debug_helper(loc, 0, index, x) } + VertexAttribI2ui :: proc "c" (index: u32, x: u32, y: u32, loc := #caller_location) { impl_VertexAttribI2ui(index, x, y); debug_helper(loc, 0, index, x, y) } + VertexAttribI3ui :: proc "c" (index: u32, x: u32, y: u32, z: u32, loc := #caller_location) { impl_VertexAttribI3ui(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } + VertexAttribI4ui :: proc "c" (index: u32, x: u32, y: u32, z: u32, w: u32, loc := #caller_location) { impl_VertexAttribI4ui(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } + VertexAttribI1iv :: proc "c" (index: u32, v: [^]i32, loc := #caller_location) { impl_VertexAttribI1iv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI2iv :: proc "c" (index: u32, v: [^]i32, loc := #caller_location) { impl_VertexAttribI2iv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI3iv :: proc "c" (index: u32, v: [^]i32, loc := #caller_location) { impl_VertexAttribI3iv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI4iv :: proc "c" (index: u32, v: [^]i32, loc := #caller_location) { impl_VertexAttribI4iv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI1uiv :: proc "c" (index: u32, v: [^]u32, loc := #caller_location) { impl_VertexAttribI1uiv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI2uiv :: proc "c" (index: u32, v: [^]u32, loc := #caller_location) { impl_VertexAttribI2uiv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI3uiv :: proc "c" (index: u32, v: [^]u32, loc := #caller_location) { impl_VertexAttribI3uiv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI4uiv :: proc "c" (index: u32, v: [^]u32, loc := #caller_location) { impl_VertexAttribI4uiv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI4bv :: proc "c" (index: u32, v: [^]i8, loc := #caller_location) { impl_VertexAttribI4bv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI4sv :: proc "c" (index: u32, v: [^]i16, loc := #caller_location) { impl_VertexAttribI4sv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI4ubv :: proc "c" (index: u32, v: [^]u8, loc := #caller_location) { impl_VertexAttribI4ubv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribI4usv :: proc "c" (index: u32, v: [^]u16, loc := #caller_location) { impl_VertexAttribI4usv(index, v); debug_helper(loc, 0, index, v) } + GetUniformuiv :: proc "c" (program: u32, location: i32, params: [^]u32, loc := #caller_location) { impl_GetUniformuiv(program, location, params); debug_helper(loc, 0, program, location, params) } + BindFragDataLocation :: proc "c" (program: u32, color: u32, name: cstring, loc := #caller_location) { impl_BindFragDataLocation(program, color, name); debug_helper(loc, 0, program, color, name) } + GetFragDataLocation :: proc "c" (program: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetFragDataLocation(program, name); debug_helper(loc, 1, ret, program, name); return ret } + Uniform1ui :: proc "c" (location: i32, v0: u32, loc := #caller_location) { impl_Uniform1ui(location, v0); debug_helper(loc, 0, location, v0) } + Uniform2ui :: proc "c" (location: i32, v0: u32, v1: u32, loc := #caller_location) { impl_Uniform2ui(location, v0, v1); debug_helper(loc, 0, location, v0, v1) } + Uniform3ui :: proc "c" (location: i32, v0: u32, v1: u32, v2: u32, loc := #caller_location) { impl_Uniform3ui(location, v0, v1, v2); debug_helper(loc, 0, location, v0, v1, v2) } + Uniform4ui :: proc "c" (location: i32, v0: u32, v1: u32, v2: u32, v3: u32, loc := #caller_location) { impl_Uniform4ui(location, v0, v1, v2, v3); debug_helper(loc, 0, location, v0, v1, v2, v3) } + Uniform1uiv :: proc "c" (location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_Uniform1uiv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform2uiv :: proc "c" (location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_Uniform2uiv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform3uiv :: proc "c" (location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_Uniform3uiv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform4uiv :: proc "c" (location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_Uniform4uiv(location, count, value); debug_helper(loc, 0, location, count, value) } + TexParameterIiv :: proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_TexParameterIiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + TexParameterIuiv :: proc "c" (target: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_TexParameterIuiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + GetTexParameterIiv :: proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTexParameterIiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + GetTexParameterIuiv :: proc "c" (target: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetTexParameterIuiv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + ClearBufferiv :: proc "c" (buffer: u32, drawbuffer: i32, value: ^i32, loc := #caller_location) { impl_ClearBufferiv(buffer, drawbuffer, value); debug_helper(loc, 0, buffer, drawbuffer, value) } + ClearBufferuiv :: proc "c" (buffer: u32, drawbuffer: i32, value: ^u32, loc := #caller_location) { impl_ClearBufferuiv(buffer, drawbuffer, value); debug_helper(loc, 0, buffer, drawbuffer, value) } + ClearBufferfv :: proc "c" (buffer: u32, drawbuffer: i32, value: ^f32, loc := #caller_location) { impl_ClearBufferfv(buffer, drawbuffer, value); debug_helper(loc, 0, buffer, drawbuffer, value) } + ClearBufferfi :: proc "c" (buffer: u32, drawbuffer: i32, depth: f32, stencil: i32, loc := #caller_location) -> rawptr { ret := impl_ClearBufferfi(buffer, drawbuffer, depth, stencil); debug_helper(loc, 1, ret, buffer, drawbuffer, depth, stencil); return ret } + GetStringi :: proc "c" (name: u32, index: u32, loc := #caller_location) -> cstring { ret := impl_GetStringi(name, index); debug_helper(loc, 1, ret, name, index); return ret } + IsRenderbuffer :: proc "c" (renderbuffer: u32, loc := #caller_location) -> bool { ret := impl_IsRenderbuffer(renderbuffer); debug_helper(loc, 1, ret, renderbuffer); return ret } + BindRenderbuffer :: proc "c" (target: u32, renderbuffer: u32, loc := #caller_location) { impl_BindRenderbuffer(target, renderbuffer); debug_helper(loc, 0, target, renderbuffer) } + DeleteRenderbuffers :: proc "c" (n: i32, renderbuffers: [^]u32, loc := #caller_location) { impl_DeleteRenderbuffers(n, renderbuffers); debug_helper(loc, 0, n, renderbuffers) } + GenRenderbuffers :: proc "c" (n: i32, renderbuffers: [^]u32, loc := #caller_location) { impl_GenRenderbuffers(n, renderbuffers); debug_helper(loc, 0, n, renderbuffers) } + RenderbufferStorage :: proc "c" (target: u32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_RenderbufferStorage(target, internalformat, width, height); debug_helper(loc, 0, target, internalformat, width, height) } + GetRenderbufferParameteriv :: proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetRenderbufferParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + IsFramebuffer :: proc "c" (framebuffer: u32, loc := #caller_location) -> bool { ret := impl_IsFramebuffer(framebuffer); debug_helper(loc, 1, ret, framebuffer); return ret } + BindFramebuffer :: proc "c" (target: u32, framebuffer: u32, loc := #caller_location) { impl_BindFramebuffer(target, framebuffer); debug_helper(loc, 0, target, framebuffer) } + DeleteFramebuffers :: proc "c" (n: i32, framebuffers: [^]u32, loc := #caller_location) { impl_DeleteFramebuffers(n, framebuffers); debug_helper(loc, 0, n, framebuffers) } + GenFramebuffers :: proc "c" (n: i32, framebuffers: [^]u32, loc := #caller_location) { impl_GenFramebuffers(n, framebuffers); debug_helper(loc, 0, n, framebuffers) } + CheckFramebufferStatus :: proc "c" (target: u32, loc := #caller_location) -> u32 { ret := impl_CheckFramebufferStatus(target); debug_helper(loc, 1, ret, target); return ret } + FramebufferTexture1D :: proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32, loc := #caller_location) { impl_FramebufferTexture1D(target, attachment, textarget, texture, level); debug_helper(loc, 0, target, attachment, textarget, texture, level) } + FramebufferTexture2D :: proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32, loc := #caller_location) { impl_FramebufferTexture2D(target, attachment, textarget, texture, level); debug_helper(loc, 0, target, attachment, textarget, texture, level) } + FramebufferTexture3D :: proc "c" (target: u32, attachment: u32, textarget: u32, texture: u32, level: i32, zoffset: i32, loc := #caller_location) { impl_FramebufferTexture3D(target, attachment, textarget, texture, level, zoffset); debug_helper(loc, 0, target, attachment, textarget, texture, level, zoffset) } + FramebufferRenderbuffer :: proc "c" (target: u32, attachment: u32, renderbuffertarget: u32, renderbuffer: u32, loc := #caller_location) { impl_FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); debug_helper(loc, 0, target, attachment, renderbuffertarget, renderbuffer) } + GetFramebufferAttachmentParameteriv :: proc "c" (target: u32, attachment: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetFramebufferAttachmentParameteriv(target, attachment, pname, params); debug_helper(loc, 0, target, attachment, pname, params) } + GenerateMipmap :: proc "c" (target: u32, loc := #caller_location) { impl_GenerateMipmap(target); debug_helper(loc, 0, target) } + BlitFramebuffer :: proc "c" (srcX0: i32, srcY0: i32, srcX1: i32, srcY1: i32, dstX0: i32, dstY0: i32, dstX1: i32, dstY1: i32, mask: u32, filter: u32, loc := #caller_location) { impl_BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); debug_helper(loc, 0, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) } + RenderbufferStorageMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_RenderbufferStorageMultisample(target, samples, internalformat, width, height); debug_helper(loc, 0, target, samples, internalformat, width, height) } + FramebufferTextureLayer :: proc "c" (target: u32, attachment: u32, texture: u32, level: i32, layer: i32, loc := #caller_location) { impl_FramebufferTextureLayer(target, attachment, texture, level, layer); debug_helper(loc, 0, target, attachment, texture, level, layer) } + MapBufferRange :: proc "c" (target: u32, offset: int, length: int, access: u32, loc := #caller_location) -> rawptr { ret := impl_MapBufferRange(target, offset, length, access); debug_helper(loc, 1, ret, target, offset, length, access); return ret } + FlushMappedBufferRange :: proc "c" (target: u32, offset: int, length: int, loc := #caller_location) { impl_FlushMappedBufferRange(target, offset, length); debug_helper(loc, 0, target, offset, length) } + BindVertexArray :: proc "c" (array: u32, loc := #caller_location) { impl_BindVertexArray(array); debug_helper(loc, 0, array) } + DeleteVertexArrays :: proc "c" (n: i32, arrays: [^]u32, loc := #caller_location) { impl_DeleteVertexArrays(n, arrays); debug_helper(loc, 0, n, arrays) } + GenVertexArrays :: proc "c" (n: i32, arrays: [^]u32, loc := #caller_location) { impl_GenVertexArrays(n, arrays); debug_helper(loc, 0, n, arrays) } + IsVertexArray :: proc "c" (array: u32, loc := #caller_location) -> bool { ret := impl_IsVertexArray(array); debug_helper(loc, 1, ret, array); return ret } // VERSION_3_1 - DrawArraysInstanced :: #force_inline proc "c" (mode: u32, first: i32, count: i32, instancecount: i32, loc := #caller_location) { impl_DrawArraysInstanced(mode, first, count, instancecount); debug_helper(loc, 0, mode, first, count, instancecount) } - DrawElementsInstanced :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, loc := #caller_location) { impl_DrawElementsInstanced(mode, count, type, indices, instancecount); debug_helper(loc, 0, mode, count, type, indices, instancecount) } - TexBuffer :: #force_inline proc "c" (target: u32, internalformat: u32, buffer: u32, loc := #caller_location) { impl_TexBuffer(target, internalformat, buffer); debug_helper(loc, 0, target, internalformat, buffer) } - PrimitiveRestartIndex :: #force_inline proc "c" (index: u32, loc := #caller_location) { impl_PrimitiveRestartIndex(index); debug_helper(loc, 0, index) } - CopyBufferSubData :: #force_inline proc "c" (readTarget: u32, writeTarget: u32, readOffset: int, writeOffset: int, size: int, loc := #caller_location) { impl_CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); debug_helper(loc, 0, readTarget, writeTarget, readOffset, writeOffset, size) } - GetUniformIndices :: #force_inline proc "c" (program: u32, uniformCount: i32, uniformNames: [^]cstring, uniformIndices: [^]u32, loc := #caller_location) { impl_GetUniformIndices(program, uniformCount, uniformNames, uniformIndices); debug_helper(loc, 0, program, uniformCount, uniformNames, uniformIndices) } - GetActiveUniformsiv :: #force_inline proc "c" (program: u32, uniformCount: i32, uniformIndices: [^]u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetActiveUniformsiv(program, uniformCount, uniformIndices, pname, params); debug_helper(loc, 0, program, uniformCount, uniformIndices, pname, params) } - GetActiveUniformName :: #force_inline proc "c" (program: u32, uniformIndex: u32, bufSize: i32, length: ^i32, uniformName: [^]u8, loc := #caller_location) { impl_GetActiveUniformName(program, uniformIndex, bufSize, length, uniformName); debug_helper(loc, 0, program, uniformIndex, bufSize, length, uniformName) } - GetUniformBlockIndex :: #force_inline proc "c" (program: u32, uniformBlockName: cstring, loc := #caller_location) -> u32 { ret := impl_GetUniformBlockIndex(program, uniformBlockName); debug_helper(loc, 1, ret, program, uniformBlockName); return ret } - GetActiveUniformBlockiv :: #force_inline proc "c" (program: u32, uniformBlockIndex: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetActiveUniformBlockiv(program, uniformBlockIndex, pname, params); debug_helper(loc, 0, program, uniformBlockIndex, pname, params) } - GetActiveUniformBlockName :: #force_inline proc "c" (program: u32, uniformBlockIndex: u32, bufSize: i32, length: ^i32, uniformBlockName: [^]u8, loc := #caller_location) { impl_GetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, uniformBlockName); debug_helper(loc, 0, program, uniformBlockIndex, bufSize, length, uniformBlockName) } - UniformBlockBinding :: #force_inline proc "c" (program: u32, uniformBlockIndex: u32, uniformBlockBinding: u32, loc := #caller_location) { impl_UniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); debug_helper(loc, 0, program, uniformBlockIndex, uniformBlockBinding) } + DrawArraysInstanced :: proc "c" (mode: u32, first: i32, count: i32, instancecount: i32, loc := #caller_location) { impl_DrawArraysInstanced(mode, first, count, instancecount); debug_helper(loc, 0, mode, first, count, instancecount) } + DrawElementsInstanced :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, loc := #caller_location) { impl_DrawElementsInstanced(mode, count, type, indices, instancecount); debug_helper(loc, 0, mode, count, type, indices, instancecount) } + TexBuffer :: proc "c" (target: u32, internalformat: u32, buffer: u32, loc := #caller_location) { impl_TexBuffer(target, internalformat, buffer); debug_helper(loc, 0, target, internalformat, buffer) } + PrimitiveRestartIndex :: proc "c" (index: u32, loc := #caller_location) { impl_PrimitiveRestartIndex(index); debug_helper(loc, 0, index) } + CopyBufferSubData :: proc "c" (readTarget: u32, writeTarget: u32, readOffset: int, writeOffset: int, size: int, loc := #caller_location) { impl_CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); debug_helper(loc, 0, readTarget, writeTarget, readOffset, writeOffset, size) } + GetUniformIndices :: proc "c" (program: u32, uniformCount: i32, uniformNames: [^]cstring, uniformIndices: [^]u32, loc := #caller_location) { impl_GetUniformIndices(program, uniformCount, uniformNames, uniformIndices); debug_helper(loc, 0, program, uniformCount, uniformNames, uniformIndices) } + GetActiveUniformsiv :: proc "c" (program: u32, uniformCount: i32, uniformIndices: [^]u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetActiveUniformsiv(program, uniformCount, uniformIndices, pname, params); debug_helper(loc, 0, program, uniformCount, uniformIndices, pname, params) } + GetActiveUniformName :: proc "c" (program: u32, uniformIndex: u32, bufSize: i32, length: ^i32, uniformName: [^]u8, loc := #caller_location) { impl_GetActiveUniformName(program, uniformIndex, bufSize, length, uniformName); debug_helper(loc, 0, program, uniformIndex, bufSize, length, uniformName) } + GetUniformBlockIndex :: proc "c" (program: u32, uniformBlockName: cstring, loc := #caller_location) -> u32 { ret := impl_GetUniformBlockIndex(program, uniformBlockName); debug_helper(loc, 1, ret, program, uniformBlockName); return ret } + GetActiveUniformBlockiv :: proc "c" (program: u32, uniformBlockIndex: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetActiveUniformBlockiv(program, uniformBlockIndex, pname, params); debug_helper(loc, 0, program, uniformBlockIndex, pname, params) } + GetActiveUniformBlockName :: proc "c" (program: u32, uniformBlockIndex: u32, bufSize: i32, length: ^i32, uniformBlockName: [^]u8, loc := #caller_location) { impl_GetActiveUniformBlockName(program, uniformBlockIndex, bufSize, length, uniformBlockName); debug_helper(loc, 0, program, uniformBlockIndex, bufSize, length, uniformBlockName) } + UniformBlockBinding :: proc "c" (program: u32, uniformBlockIndex: u32, uniformBlockBinding: u32, loc := #caller_location) { impl_UniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); debug_helper(loc, 0, program, uniformBlockIndex, uniformBlockBinding) } // VERSION_3_2 - DrawElementsBaseVertex :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, basevertex: i32, loc := #caller_location) { impl_DrawElementsBaseVertex(mode, count, type, indices, basevertex); debug_helper(loc, 0, mode, count, type, indices, basevertex) } - DrawRangeElementsBaseVertex :: #force_inline proc "c" (mode: u32, start: u32, end: u32, count: i32, type: u32, indices: rawptr, basevertex: i32, loc := #caller_location) { impl_DrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex); debug_helper(loc, 0, mode, start, end, count, type, indices, basevertex) } - DrawElementsInstancedBaseVertex :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, basevertex: i32, loc := #caller_location) { impl_DrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount, basevertex); debug_helper(loc, 0, mode, count, type, indices, instancecount, basevertex) } - MultiDrawElementsBaseVertex :: #force_inline proc "c" (mode: u32, count: [^]i32, type: u32, indices: [^]rawptr, drawcount: i32, basevertex: [^]i32, loc := #caller_location) { impl_MultiDrawElementsBaseVertex(mode, count, type, indices, drawcount, basevertex); debug_helper(loc, 0, mode, count, type, indices, drawcount, basevertex) } - ProvokingVertex :: #force_inline proc "c" (mode: u32, loc := #caller_location) { impl_ProvokingVertex(mode); debug_helper(loc, 0, mode) } - FenceSync :: #force_inline proc "c" (condition: u32, flags: u32, loc := #caller_location) -> sync_t { ret := impl_FenceSync(condition, flags); debug_helper(loc, 1, ret, condition, flags); return ret } - IsSync :: #force_inline proc "c" (sync: sync_t, loc := #caller_location) -> bool { ret := impl_IsSync(sync); debug_helper(loc, 1, ret, sync); return ret } - DeleteSync :: #force_inline proc "c" (sync: sync_t, loc := #caller_location) { impl_DeleteSync(sync); debug_helper(loc, 0, sync) } - ClientWaitSync :: #force_inline proc "c" (sync: sync_t, flags: u32, timeout: u64, loc := #caller_location) -> u32 { ret := impl_ClientWaitSync(sync, flags, timeout); debug_helper(loc, 1, ret, sync, flags, timeout); return ret } - WaitSync :: #force_inline proc "c" (sync: sync_t, flags: u32, timeout: u64, loc := #caller_location) { impl_WaitSync(sync, flags, timeout); debug_helper(loc, 0, sync, flags, timeout) } - GetInteger64v :: #force_inline proc "c" (pname: u32, data: ^i64, loc := #caller_location) { impl_GetInteger64v(pname, data); debug_helper(loc, 0, pname, data) } - GetSynciv :: #force_inline proc "c" (sync: sync_t, pname: u32, bufSize: i32, length: ^i32, values: [^]i32, loc := #caller_location) { impl_GetSynciv(sync, pname, bufSize, length, values); debug_helper(loc, 0, sync, pname, bufSize, length, values) } - GetInteger64i_v :: #force_inline proc "c" (target: u32, index: u32, data: ^i64, loc := #caller_location) { impl_GetInteger64i_v(target, index, data); debug_helper(loc, 0, target, index, data) } - GetBufferParameteri64v :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i64, loc := #caller_location) { impl_GetBufferParameteri64v(target, pname, params); debug_helper(loc, 0, target, pname, params) } - FramebufferTexture :: #force_inline proc "c" (target: u32, attachment: u32, texture: u32, level: i32, loc := #caller_location) { impl_FramebufferTexture(target, attachment, texture, level); debug_helper(loc, 0, target, attachment, texture, level) } - TexImage2DMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations); debug_helper(loc, 0, target, samples, internalformat, width, height, fixedsamplelocations) } - TexImage3DMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TexImage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations); debug_helper(loc, 0, target, samples, internalformat, width, height, depth, fixedsamplelocations) } - GetMultisamplefv :: #force_inline proc "c" (pname: u32, index: u32, val: ^f32, loc := #caller_location) { impl_GetMultisamplefv(pname, index, val); debug_helper(loc, 0, pname, index, val) } - SampleMaski :: #force_inline proc "c" (maskNumber: u32, mask: u32, loc := #caller_location) { impl_SampleMaski(maskNumber, mask); debug_helper(loc, 0, maskNumber, mask) } + DrawElementsBaseVertex :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, basevertex: i32, loc := #caller_location) { impl_DrawElementsBaseVertex(mode, count, type, indices, basevertex); debug_helper(loc, 0, mode, count, type, indices, basevertex) } + DrawRangeElementsBaseVertex :: proc "c" (mode: u32, start: u32, end: u32, count: i32, type: u32, indices: rawptr, basevertex: i32, loc := #caller_location) { impl_DrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex); debug_helper(loc, 0, mode, start, end, count, type, indices, basevertex) } + DrawElementsInstancedBaseVertex :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, basevertex: i32, loc := #caller_location) { impl_DrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount, basevertex); debug_helper(loc, 0, mode, count, type, indices, instancecount, basevertex) } + MultiDrawElementsBaseVertex :: proc "c" (mode: u32, count: [^]i32, type: u32, indices: [^]rawptr, drawcount: i32, basevertex: [^]i32, loc := #caller_location) { impl_MultiDrawElementsBaseVertex(mode, count, type, indices, drawcount, basevertex); debug_helper(loc, 0, mode, count, type, indices, drawcount, basevertex) } + ProvokingVertex :: proc "c" (mode: u32, loc := #caller_location) { impl_ProvokingVertex(mode); debug_helper(loc, 0, mode) } + FenceSync :: proc "c" (condition: u32, flags: u32, loc := #caller_location) -> sync_t { ret := impl_FenceSync(condition, flags); debug_helper(loc, 1, ret, condition, flags); return ret } + IsSync :: proc "c" (sync: sync_t, loc := #caller_location) -> bool { ret := impl_IsSync(sync); debug_helper(loc, 1, ret, sync); return ret } + DeleteSync :: proc "c" (sync: sync_t, loc := #caller_location) { impl_DeleteSync(sync); debug_helper(loc, 0, sync) } + ClientWaitSync :: proc "c" (sync: sync_t, flags: u32, timeout: u64, loc := #caller_location) -> u32 { ret := impl_ClientWaitSync(sync, flags, timeout); debug_helper(loc, 1, ret, sync, flags, timeout); return ret } + WaitSync :: proc "c" (sync: sync_t, flags: u32, timeout: u64, loc := #caller_location) { impl_WaitSync(sync, flags, timeout); debug_helper(loc, 0, sync, flags, timeout) } + GetInteger64v :: proc "c" (pname: u32, data: ^i64, loc := #caller_location) { impl_GetInteger64v(pname, data); debug_helper(loc, 0, pname, data) } + GetSynciv :: proc "c" (sync: sync_t, pname: u32, bufSize: i32, length: ^i32, values: [^]i32, loc := #caller_location) { impl_GetSynciv(sync, pname, bufSize, length, values); debug_helper(loc, 0, sync, pname, bufSize, length, values) } + GetInteger64i_v :: proc "c" (target: u32, index: u32, data: ^i64, loc := #caller_location) { impl_GetInteger64i_v(target, index, data); debug_helper(loc, 0, target, index, data) } + GetBufferParameteri64v :: proc "c" (target: u32, pname: u32, params: [^]i64, loc := #caller_location) { impl_GetBufferParameteri64v(target, pname, params); debug_helper(loc, 0, target, pname, params) } + FramebufferTexture :: proc "c" (target: u32, attachment: u32, texture: u32, level: i32, loc := #caller_location) { impl_FramebufferTexture(target, attachment, texture, level); debug_helper(loc, 0, target, attachment, texture, level) } + TexImage2DMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations); debug_helper(loc, 0, target, samples, internalformat, width, height, fixedsamplelocations) } + TexImage3DMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TexImage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations); debug_helper(loc, 0, target, samples, internalformat, width, height, depth, fixedsamplelocations) } + GetMultisamplefv :: proc "c" (pname: u32, index: u32, val: ^f32, loc := #caller_location) { impl_GetMultisamplefv(pname, index, val); debug_helper(loc, 0, pname, index, val) } + SampleMaski :: proc "c" (maskNumber: u32, mask: u32, loc := #caller_location) { impl_SampleMaski(maskNumber, mask); debug_helper(loc, 0, maskNumber, mask) } // VERSION_3_3 - BindFragDataLocationIndexed :: #force_inline proc "c" (program: u32, colorNumber: u32, index: u32, name: cstring, loc := #caller_location) { impl_BindFragDataLocationIndexed(program, colorNumber, index, name); debug_helper(loc, 0, program, colorNumber, index, name) } - GetFragDataIndex :: #force_inline proc "c" (program: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetFragDataIndex(program, name); debug_helper(loc, 1, ret, program, name); return ret } - GenSamplers :: #force_inline proc "c" (count: i32, samplers: [^]u32, loc := #caller_location) { impl_GenSamplers(count, samplers); debug_helper(loc, 0, count, samplers) } - DeleteSamplers :: #force_inline proc "c" (count: i32, samplers: [^]u32, loc := #caller_location) { impl_DeleteSamplers(count, samplers); debug_helper(loc, 0, count, samplers) } - IsSampler :: #force_inline proc "c" (sampler: u32, loc := #caller_location) -> bool { ret := impl_IsSampler(sampler); debug_helper(loc, 1, ret, sampler); return ret } - BindSampler :: #force_inline proc "c" (unit: u32, sampler: u32, loc := #caller_location) { impl_BindSampler(unit, sampler); debug_helper(loc, 0, unit, sampler) } - SamplerParameteri :: #force_inline proc "c" (sampler: u32, pname: u32, param: i32, loc := #caller_location) { impl_SamplerParameteri(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } - SamplerParameteriv :: #force_inline proc "c" (sampler: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_SamplerParameteriv(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } - SamplerParameterf :: #force_inline proc "c" (sampler: u32, pname: u32, param: f32, loc := #caller_location) { impl_SamplerParameterf(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } - SamplerParameterfv :: #force_inline proc "c" (sampler: u32, pname: u32, param: ^f32, loc := #caller_location) { impl_SamplerParameterfv(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } - SamplerParameterIiv :: #force_inline proc "c" (sampler: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_SamplerParameterIiv(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } - SamplerParameterIuiv :: #force_inline proc "c" (sampler: u32, pname: u32, param: ^u32, loc := #caller_location) { impl_SamplerParameterIuiv(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } - GetSamplerParameteriv :: #force_inline proc "c" (sampler: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetSamplerParameteriv(sampler, pname, params); debug_helper(loc, 0, sampler, pname, params) } - GetSamplerParameterIiv :: #force_inline proc "c" (sampler: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetSamplerParameterIiv(sampler, pname, params); debug_helper(loc, 0, sampler, pname, params) } - GetSamplerParameterfv :: #force_inline proc "c" (sampler: u32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetSamplerParameterfv(sampler, pname, params); debug_helper(loc, 0, sampler, pname, params) } - GetSamplerParameterIuiv :: #force_inline proc "c" (sampler: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetSamplerParameterIuiv(sampler, pname, params); debug_helper(loc, 0, sampler, pname, params) } - QueryCounter :: #force_inline proc "c" (id: u32, target: u32, loc := #caller_location) { impl_QueryCounter(id, target); debug_helper(loc, 0, id, target) } - GetQueryObjecti64v :: #force_inline proc "c" (id: u32, pname: u32, params: [^]i64, loc := #caller_location) { impl_GetQueryObjecti64v(id, pname, params); debug_helper(loc, 0, id, pname, params) } - GetQueryObjectui64v :: #force_inline proc "c" (id: u32, pname: u32, params: [^]u64, loc := #caller_location) { impl_GetQueryObjectui64v(id, pname, params); debug_helper(loc, 0, id, pname, params) } - VertexAttribDivisor :: #force_inline proc "c" (index: u32, divisor: u32, loc := #caller_location) { impl_VertexAttribDivisor(index, divisor); debug_helper(loc, 0, index, divisor) } - VertexAttribP1ui :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: u32, loc := #caller_location) { impl_VertexAttribP1ui(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } - VertexAttribP1uiv :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: ^u32, loc := #caller_location) { impl_VertexAttribP1uiv(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } - VertexAttribP2ui :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: u32, loc := #caller_location) { impl_VertexAttribP2ui(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } - VertexAttribP2uiv :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: ^u32, loc := #caller_location) { impl_VertexAttribP2uiv(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } - VertexAttribP3ui :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: u32, loc := #caller_location) { impl_VertexAttribP3ui(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } - VertexAttribP3uiv :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: ^u32, loc := #caller_location) { impl_VertexAttribP3uiv(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } - VertexAttribP4ui :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: u32, loc := #caller_location) { impl_VertexAttribP4ui(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } - VertexAttribP4uiv :: #force_inline proc "c" (index: u32, type: u32, normalized: bool, value: ^u32, loc := #caller_location) { impl_VertexAttribP4uiv(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } - VertexP2ui :: #force_inline proc "c" (type: u32, value: u32, loc := #caller_location) { impl_VertexP2ui(type, value); debug_helper(loc, 0, type, value) } - VertexP2uiv :: #force_inline proc "c" (type: u32, value: ^u32, loc := #caller_location) { impl_VertexP2uiv(type, value); debug_helper(loc, 0, type, value) } - VertexP3ui :: #force_inline proc "c" (type: u32, value: u32, loc := #caller_location) { impl_VertexP3ui(type, value); debug_helper(loc, 0, type, value) } - VertexP3uiv :: #force_inline proc "c" (type: u32, value: ^u32, loc := #caller_location) { impl_VertexP3uiv(type, value); debug_helper(loc, 0, type, value) } - VertexP4ui :: #force_inline proc "c" (type: u32, value: u32, loc := #caller_location) { impl_VertexP4ui(type, value); debug_helper(loc, 0, type, value) } - VertexP4uiv :: #force_inline proc "c" (type: u32, value: ^u32, loc := #caller_location) { impl_VertexP4uiv(type, value); debug_helper(loc, 0, type, value) } - TexCoordP1ui :: #force_inline proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_TexCoordP1ui(type, coords); debug_helper(loc, 0, type, coords) } - TexCoordP1uiv :: #force_inline proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_TexCoordP1uiv(type, coords); debug_helper(loc, 0, type, coords) } - TexCoordP2ui :: #force_inline proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_TexCoordP2ui(type, coords); debug_helper(loc, 0, type, coords) } - TexCoordP2uiv :: #force_inline proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_TexCoordP2uiv(type, coords); debug_helper(loc, 0, type, coords) } - TexCoordP3ui :: #force_inline proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_TexCoordP3ui(type, coords); debug_helper(loc, 0, type, coords) } - TexCoordP3uiv :: #force_inline proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_TexCoordP3uiv(type, coords); debug_helper(loc, 0, type, coords) } - TexCoordP4ui :: #force_inline proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_TexCoordP4ui(type, coords); debug_helper(loc, 0, type, coords) } - TexCoordP4uiv :: #force_inline proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_TexCoordP4uiv(type, coords); debug_helper(loc, 0, type, coords) } - MultiTexCoordP1ui :: #force_inline proc "c" (texture: u32, type: u32, coords: u32, loc := #caller_location) { impl_MultiTexCoordP1ui(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } - MultiTexCoordP1uiv :: #force_inline proc "c" (texture: u32, type: u32, coords: [^]u32, loc := #caller_location) { impl_MultiTexCoordP1uiv(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } - MultiTexCoordP2ui :: #force_inline proc "c" (texture: u32, type: u32, coords: u32, loc := #caller_location) { impl_MultiTexCoordP2ui(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } - MultiTexCoordP2uiv :: #force_inline proc "c" (texture: u32, type: u32, coords: [^]u32, loc := #caller_location) { impl_MultiTexCoordP2uiv(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } - MultiTexCoordP3ui :: #force_inline proc "c" (texture: u32, type: u32, coords: u32, loc := #caller_location) { impl_MultiTexCoordP3ui(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } - MultiTexCoordP3uiv :: #force_inline proc "c" (texture: u32, type: u32, coords: [^]u32, loc := #caller_location) { impl_MultiTexCoordP3uiv(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } - MultiTexCoordP4ui :: #force_inline proc "c" (texture: u32, type: u32, coords: u32, loc := #caller_location) { impl_MultiTexCoordP4ui(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } - MultiTexCoordP4uiv :: #force_inline proc "c" (texture: u32, type: u32, coords: [^]u32, loc := #caller_location) { impl_MultiTexCoordP4uiv(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } - NormalP3ui :: #force_inline proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_NormalP3ui(type, coords); debug_helper(loc, 0, type, coords) } - NormalP3uiv :: #force_inline proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_NormalP3uiv(type, coords); debug_helper(loc, 0, type, coords) } - ColorP3ui :: #force_inline proc "c" (type: u32, color: u32, loc := #caller_location) { impl_ColorP3ui(type, color); debug_helper(loc, 0, type, color) } - ColorP3uiv :: #force_inline proc "c" (type: u32, color: ^u32, loc := #caller_location) { impl_ColorP3uiv(type, color); debug_helper(loc, 0, type, color) } - ColorP4ui :: #force_inline proc "c" (type: u32, color: u32, loc := #caller_location) { impl_ColorP4ui(type, color); debug_helper(loc, 0, type, color) } - ColorP4uiv :: #force_inline proc "c" (type: u32, color: ^u32, loc := #caller_location) { impl_ColorP4uiv(type, color); debug_helper(loc, 0, type, color) } - SecondaryColorP3ui :: #force_inline proc "c" (type: u32, color: u32, loc := #caller_location) { impl_SecondaryColorP3ui(type, color); debug_helper(loc, 0, type, color) } - SecondaryColorP3uiv :: #force_inline proc "c" (type: u32, color: ^u32, loc := #caller_location) { impl_SecondaryColorP3uiv(type, color); debug_helper(loc, 0, type, color) } + BindFragDataLocationIndexed :: proc "c" (program: u32, colorNumber: u32, index: u32, name: cstring, loc := #caller_location) { impl_BindFragDataLocationIndexed(program, colorNumber, index, name); debug_helper(loc, 0, program, colorNumber, index, name) } + GetFragDataIndex :: proc "c" (program: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetFragDataIndex(program, name); debug_helper(loc, 1, ret, program, name); return ret } + GenSamplers :: proc "c" (count: i32, samplers: [^]u32, loc := #caller_location) { impl_GenSamplers(count, samplers); debug_helper(loc, 0, count, samplers) } + DeleteSamplers :: proc "c" (count: i32, samplers: [^]u32, loc := #caller_location) { impl_DeleteSamplers(count, samplers); debug_helper(loc, 0, count, samplers) } + IsSampler :: proc "c" (sampler: u32, loc := #caller_location) -> bool { ret := impl_IsSampler(sampler); debug_helper(loc, 1, ret, sampler); return ret } + BindSampler :: proc "c" (unit: u32, sampler: u32, loc := #caller_location) { impl_BindSampler(unit, sampler); debug_helper(loc, 0, unit, sampler) } + SamplerParameteri :: proc "c" (sampler: u32, pname: u32, param: i32, loc := #caller_location) { impl_SamplerParameteri(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } + SamplerParameteriv :: proc "c" (sampler: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_SamplerParameteriv(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } + SamplerParameterf :: proc "c" (sampler: u32, pname: u32, param: f32, loc := #caller_location) { impl_SamplerParameterf(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } + SamplerParameterfv :: proc "c" (sampler: u32, pname: u32, param: ^f32, loc := #caller_location) { impl_SamplerParameterfv(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } + SamplerParameterIiv :: proc "c" (sampler: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_SamplerParameterIiv(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } + SamplerParameterIuiv :: proc "c" (sampler: u32, pname: u32, param: ^u32, loc := #caller_location) { impl_SamplerParameterIuiv(sampler, pname, param); debug_helper(loc, 0, sampler, pname, param) } + GetSamplerParameteriv :: proc "c" (sampler: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetSamplerParameteriv(sampler, pname, params); debug_helper(loc, 0, sampler, pname, params) } + GetSamplerParameterIiv :: proc "c" (sampler: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetSamplerParameterIiv(sampler, pname, params); debug_helper(loc, 0, sampler, pname, params) } + GetSamplerParameterfv :: proc "c" (sampler: u32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetSamplerParameterfv(sampler, pname, params); debug_helper(loc, 0, sampler, pname, params) } + GetSamplerParameterIuiv :: proc "c" (sampler: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetSamplerParameterIuiv(sampler, pname, params); debug_helper(loc, 0, sampler, pname, params) } + QueryCounter :: proc "c" (id: u32, target: u32, loc := #caller_location) { impl_QueryCounter(id, target); debug_helper(loc, 0, id, target) } + GetQueryObjecti64v :: proc "c" (id: u32, pname: u32, params: [^]i64, loc := #caller_location) { impl_GetQueryObjecti64v(id, pname, params); debug_helper(loc, 0, id, pname, params) } + GetQueryObjectui64v :: proc "c" (id: u32, pname: u32, params: [^]u64, loc := #caller_location) { impl_GetQueryObjectui64v(id, pname, params); debug_helper(loc, 0, id, pname, params) } + VertexAttribDivisor :: proc "c" (index: u32, divisor: u32, loc := #caller_location) { impl_VertexAttribDivisor(index, divisor); debug_helper(loc, 0, index, divisor) } + VertexAttribP1ui :: proc "c" (index: u32, type: u32, normalized: bool, value: u32, loc := #caller_location) { impl_VertexAttribP1ui(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } + VertexAttribP1uiv :: proc "c" (index: u32, type: u32, normalized: bool, value: ^u32, loc := #caller_location) { impl_VertexAttribP1uiv(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } + VertexAttribP2ui :: proc "c" (index: u32, type: u32, normalized: bool, value: u32, loc := #caller_location) { impl_VertexAttribP2ui(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } + VertexAttribP2uiv :: proc "c" (index: u32, type: u32, normalized: bool, value: ^u32, loc := #caller_location) { impl_VertexAttribP2uiv(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } + VertexAttribP3ui :: proc "c" (index: u32, type: u32, normalized: bool, value: u32, loc := #caller_location) { impl_VertexAttribP3ui(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } + VertexAttribP3uiv :: proc "c" (index: u32, type: u32, normalized: bool, value: ^u32, loc := #caller_location) { impl_VertexAttribP3uiv(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } + VertexAttribP4ui :: proc "c" (index: u32, type: u32, normalized: bool, value: u32, loc := #caller_location) { impl_VertexAttribP4ui(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } + VertexAttribP4uiv :: proc "c" (index: u32, type: u32, normalized: bool, value: ^u32, loc := #caller_location) { impl_VertexAttribP4uiv(index, type, normalized, value); debug_helper(loc, 0, index, type, normalized, value) } + VertexP2ui :: proc "c" (type: u32, value: u32, loc := #caller_location) { impl_VertexP2ui(type, value); debug_helper(loc, 0, type, value) } + VertexP2uiv :: proc "c" (type: u32, value: ^u32, loc := #caller_location) { impl_VertexP2uiv(type, value); debug_helper(loc, 0, type, value) } + VertexP3ui :: proc "c" (type: u32, value: u32, loc := #caller_location) { impl_VertexP3ui(type, value); debug_helper(loc, 0, type, value) } + VertexP3uiv :: proc "c" (type: u32, value: ^u32, loc := #caller_location) { impl_VertexP3uiv(type, value); debug_helper(loc, 0, type, value) } + VertexP4ui :: proc "c" (type: u32, value: u32, loc := #caller_location) { impl_VertexP4ui(type, value); debug_helper(loc, 0, type, value) } + VertexP4uiv :: proc "c" (type: u32, value: ^u32, loc := #caller_location) { impl_VertexP4uiv(type, value); debug_helper(loc, 0, type, value) } + TexCoordP1ui :: proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_TexCoordP1ui(type, coords); debug_helper(loc, 0, type, coords) } + TexCoordP1uiv :: proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_TexCoordP1uiv(type, coords); debug_helper(loc, 0, type, coords) } + TexCoordP2ui :: proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_TexCoordP2ui(type, coords); debug_helper(loc, 0, type, coords) } + TexCoordP2uiv :: proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_TexCoordP2uiv(type, coords); debug_helper(loc, 0, type, coords) } + TexCoordP3ui :: proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_TexCoordP3ui(type, coords); debug_helper(loc, 0, type, coords) } + TexCoordP3uiv :: proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_TexCoordP3uiv(type, coords); debug_helper(loc, 0, type, coords) } + TexCoordP4ui :: proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_TexCoordP4ui(type, coords); debug_helper(loc, 0, type, coords) } + TexCoordP4uiv :: proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_TexCoordP4uiv(type, coords); debug_helper(loc, 0, type, coords) } + MultiTexCoordP1ui :: proc "c" (texture: u32, type: u32, coords: u32, loc := #caller_location) { impl_MultiTexCoordP1ui(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } + MultiTexCoordP1uiv :: proc "c" (texture: u32, type: u32, coords: [^]u32, loc := #caller_location) { impl_MultiTexCoordP1uiv(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } + MultiTexCoordP2ui :: proc "c" (texture: u32, type: u32, coords: u32, loc := #caller_location) { impl_MultiTexCoordP2ui(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } + MultiTexCoordP2uiv :: proc "c" (texture: u32, type: u32, coords: [^]u32, loc := #caller_location) { impl_MultiTexCoordP2uiv(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } + MultiTexCoordP3ui :: proc "c" (texture: u32, type: u32, coords: u32, loc := #caller_location) { impl_MultiTexCoordP3ui(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } + MultiTexCoordP3uiv :: proc "c" (texture: u32, type: u32, coords: [^]u32, loc := #caller_location) { impl_MultiTexCoordP3uiv(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } + MultiTexCoordP4ui :: proc "c" (texture: u32, type: u32, coords: u32, loc := #caller_location) { impl_MultiTexCoordP4ui(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } + MultiTexCoordP4uiv :: proc "c" (texture: u32, type: u32, coords: [^]u32, loc := #caller_location) { impl_MultiTexCoordP4uiv(texture, type, coords); debug_helper(loc, 0, texture, type, coords) } + NormalP3ui :: proc "c" (type: u32, coords: u32, loc := #caller_location) { impl_NormalP3ui(type, coords); debug_helper(loc, 0, type, coords) } + NormalP3uiv :: proc "c" (type: u32, coords: [^]u32, loc := #caller_location) { impl_NormalP3uiv(type, coords); debug_helper(loc, 0, type, coords) } + ColorP3ui :: proc "c" (type: u32, color: u32, loc := #caller_location) { impl_ColorP3ui(type, color); debug_helper(loc, 0, type, color) } + ColorP3uiv :: proc "c" (type: u32, color: ^u32, loc := #caller_location) { impl_ColorP3uiv(type, color); debug_helper(loc, 0, type, color) } + ColorP4ui :: proc "c" (type: u32, color: u32, loc := #caller_location) { impl_ColorP4ui(type, color); debug_helper(loc, 0, type, color) } + ColorP4uiv :: proc "c" (type: u32, color: ^u32, loc := #caller_location) { impl_ColorP4uiv(type, color); debug_helper(loc, 0, type, color) } + SecondaryColorP3ui :: proc "c" (type: u32, color: u32, loc := #caller_location) { impl_SecondaryColorP3ui(type, color); debug_helper(loc, 0, type, color) } + SecondaryColorP3uiv :: proc "c" (type: u32, color: ^u32, loc := #caller_location) { impl_SecondaryColorP3uiv(type, color); debug_helper(loc, 0, type, color) } // VERSION_4_0 - MinSampleShading :: #force_inline proc "c" (value: f32, loc := #caller_location) { impl_MinSampleShading(value); debug_helper(loc, 0, value) } - BlendEquationi :: #force_inline proc "c" (buf: u32, mode: u32, loc := #caller_location) { impl_BlendEquationi(buf, mode); debug_helper(loc, 0, buf, mode) } - BlendEquationSeparatei :: #force_inline proc "c" (buf: u32, modeRGB: u32, modeAlpha: u32, loc := #caller_location) { impl_BlendEquationSeparatei(buf, modeRGB, modeAlpha); debug_helper(loc, 0, buf, modeRGB, modeAlpha) } - BlendFunci :: #force_inline proc "c" (buf: u32, src: u32, dst: u32, loc := #caller_location) { impl_BlendFunci(buf, src, dst); debug_helper(loc, 0, buf, src, dst) } - BlendFuncSeparatei :: #force_inline proc "c" (buf: u32, srcRGB: u32, dstRGB: u32, srcAlpha: u32, dstAlpha: u32, loc := #caller_location) { impl_BlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha); debug_helper(loc, 0, buf, srcRGB, dstRGB, srcAlpha, dstAlpha) } - DrawArraysIndirect :: #force_inline proc "c" (mode: u32, indirect: ^DrawArraysIndirectCommand, loc := #caller_location) { impl_DrawArraysIndirect(mode, indirect); debug_helper(loc, 0, mode, indirect) } - DrawElementsIndirect :: #force_inline proc "c" (mode: u32, type: u32, indirect: ^DrawElementsIndirectCommand, loc := #caller_location) { impl_DrawElementsIndirect(mode, type, indirect); debug_helper(loc, 0, mode, type, indirect) } - Uniform1d :: #force_inline proc "c" (location: i32, x: f64, loc := #caller_location) { impl_Uniform1d(location, x); debug_helper(loc, 0, location, x) } - Uniform2d :: #force_inline proc "c" (location: i32, x: f64, y: f64, loc := #caller_location) { impl_Uniform2d(location, x, y); debug_helper(loc, 0, location, x, y) } - Uniform3d :: #force_inline proc "c" (location: i32, x: f64, y: f64, z: f64, loc := #caller_location) { impl_Uniform3d(location, x, y, z); debug_helper(loc, 0, location, x, y, z) } - Uniform4d :: #force_inline proc "c" (location: i32, x: f64, y: f64, z: f64, w: f64, loc := #caller_location) { impl_Uniform4d(location, x, y, z, w); debug_helper(loc, 0, location, x, y, z, w) } - Uniform1dv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_Uniform1dv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform2dv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_Uniform2dv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform3dv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_Uniform3dv(location, count, value); debug_helper(loc, 0, location, count, value) } - Uniform4dv :: #force_inline proc "c" (location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_Uniform4dv(location, count, value); debug_helper(loc, 0, location, count, value) } - UniformMatrix2dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix2dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix3dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix3dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix4dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix4dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix2x3dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix2x3dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix2x4dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix2x4dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix3x2dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix3x2dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix3x4dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix3x4dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix4x2dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix4x2dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - UniformMatrix4x3dv :: #force_inline proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix4x3dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } - GetUniformdv :: #force_inline proc "c" (program: u32, location: i32, params: [^]f64, loc := #caller_location) { impl_GetUniformdv(program, location, params); debug_helper(loc, 0, program, location, params) } - GetSubroutineUniformLocation :: #force_inline proc "c" (program: u32, shadertype: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetSubroutineUniformLocation(program, shadertype, name); debug_helper(loc, 1, ret, program, shadertype, name); return ret } - GetSubroutineIndex :: #force_inline proc "c" (program: u32, shadertype: u32, name: cstring, loc := #caller_location) -> u32 { ret := impl_GetSubroutineIndex(program, shadertype, name); debug_helper(loc, 1, ret, program, shadertype, name); return ret } - GetActiveSubroutineUniformiv :: #force_inline proc "c" (program: u32, shadertype: u32, index: u32, pname: u32, values: [^]i32, loc := #caller_location) { impl_GetActiveSubroutineUniformiv(program, shadertype, index, pname, values); debug_helper(loc, 0, program, shadertype, index, pname, values) } - GetActiveSubroutineUniformName :: #force_inline proc "c" (program: u32, shadertype: u32, index: u32, bufsize: i32, length: ^i32, name: [^]u8, loc := #caller_location) { impl_GetActiveSubroutineUniformName(program, shadertype, index, bufsize, length, name); debug_helper(loc, 0, program, shadertype, index, bufsize, length, name) } - GetActiveSubroutineName :: #force_inline proc "c" (program: u32, shadertype: u32, index: u32, bufsize: i32, length: ^i32, name: [^]u8, loc := #caller_location) { impl_GetActiveSubroutineName(program, shadertype, index, bufsize, length, name); debug_helper(loc, 0, program, shadertype, index, bufsize, length, name) } - UniformSubroutinesuiv :: #force_inline proc "c" (shadertype: u32, count: i32, indices: [^]u32, loc := #caller_location) { impl_UniformSubroutinesuiv(shadertype, count, indices); debug_helper(loc, 0, shadertype, count, indices) } - GetUniformSubroutineuiv :: #force_inline proc "c" (shadertype: u32, location: i32, params: [^]u32, loc := #caller_location) { impl_GetUniformSubroutineuiv(shadertype, location, params); debug_helper(loc, 0, shadertype, location, params) } - GetProgramStageiv :: #force_inline proc "c" (program: u32, shadertype: u32, pname: u32, values: [^]i32, loc := #caller_location) { impl_GetProgramStageiv(program, shadertype, pname, values); debug_helper(loc, 0, program, shadertype, pname, values) } - PatchParameteri :: #force_inline proc "c" (pname: u32, value: i32, loc := #caller_location) { impl_PatchParameteri(pname, value); debug_helper(loc, 0, pname, value) } - PatchParameterfv :: #force_inline proc "c" (pname: u32, values: [^]f32, loc := #caller_location) { impl_PatchParameterfv(pname, values); debug_helper(loc, 0, pname, values) } - BindTransformFeedback :: #force_inline proc "c" (target: u32, id: u32, loc := #caller_location) { impl_BindTransformFeedback(target, id); debug_helper(loc, 0, target, id) } - DeleteTransformFeedbacks :: #force_inline proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_DeleteTransformFeedbacks(n, ids); debug_helper(loc, 0, n, ids) } - GenTransformFeedbacks :: #force_inline proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_GenTransformFeedbacks(n, ids); debug_helper(loc, 0, n, ids) } - IsTransformFeedback :: #force_inline proc "c" (id: u32, loc := #caller_location) -> bool { ret := impl_IsTransformFeedback(id); debug_helper(loc, 1, ret, id); return ret } - PauseTransformFeedback :: #force_inline proc "c" (loc := #caller_location) { impl_PauseTransformFeedback(); debug_helper(loc, 0) } - ResumeTransformFeedback :: #force_inline proc "c" (loc := #caller_location) { impl_ResumeTransformFeedback(); debug_helper(loc, 0) } - DrawTransformFeedback :: #force_inline proc "c" (mode: u32, id: u32, loc := #caller_location) { impl_DrawTransformFeedback(mode, id); debug_helper(loc, 0, mode, id) } - DrawTransformFeedbackStream :: #force_inline proc "c" (mode: u32, id: u32, stream: u32, loc := #caller_location) { impl_DrawTransformFeedbackStream(mode, id, stream); debug_helper(loc, 0, mode, id, stream) } - BeginQueryIndexed :: #force_inline proc "c" (target: u32, index: u32, id: u32, loc := #caller_location) { impl_BeginQueryIndexed(target, index, id); debug_helper(loc, 0, target, index, id) } - EndQueryIndexed :: #force_inline proc "c" (target: u32, index: u32, loc := #caller_location) { impl_EndQueryIndexed(target, index); debug_helper(loc, 0, target, index) } - GetQueryIndexediv :: #force_inline proc "c" (target: u32, index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryIndexediv(target, index, pname, params); debug_helper(loc, 0, target, index, pname, params) } + MinSampleShading :: proc "c" (value: f32, loc := #caller_location) { impl_MinSampleShading(value); debug_helper(loc, 0, value) } + BlendEquationi :: proc "c" (buf: u32, mode: u32, loc := #caller_location) { impl_BlendEquationi(buf, mode); debug_helper(loc, 0, buf, mode) } + BlendEquationSeparatei :: proc "c" (buf: u32, modeRGB: u32, modeAlpha: u32, loc := #caller_location) { impl_BlendEquationSeparatei(buf, modeRGB, modeAlpha); debug_helper(loc, 0, buf, modeRGB, modeAlpha) } + BlendFunci :: proc "c" (buf: u32, src: u32, dst: u32, loc := #caller_location) { impl_BlendFunci(buf, src, dst); debug_helper(loc, 0, buf, src, dst) } + BlendFuncSeparatei :: proc "c" (buf: u32, srcRGB: u32, dstRGB: u32, srcAlpha: u32, dstAlpha: u32, loc := #caller_location) { impl_BlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha); debug_helper(loc, 0, buf, srcRGB, dstRGB, srcAlpha, dstAlpha) } + DrawArraysIndirect :: proc "c" (mode: u32, indirect: ^DrawArraysIndirectCommand, loc := #caller_location) { impl_DrawArraysIndirect(mode, indirect); debug_helper(loc, 0, mode, indirect) } + DrawElementsIndirect :: proc "c" (mode: u32, type: u32, indirect: ^DrawElementsIndirectCommand, loc := #caller_location) { impl_DrawElementsIndirect(mode, type, indirect); debug_helper(loc, 0, mode, type, indirect) } + Uniform1d :: proc "c" (location: i32, x: f64, loc := #caller_location) { impl_Uniform1d(location, x); debug_helper(loc, 0, location, x) } + Uniform2d :: proc "c" (location: i32, x: f64, y: f64, loc := #caller_location) { impl_Uniform2d(location, x, y); debug_helper(loc, 0, location, x, y) } + Uniform3d :: proc "c" (location: i32, x: f64, y: f64, z: f64, loc := #caller_location) { impl_Uniform3d(location, x, y, z); debug_helper(loc, 0, location, x, y, z) } + Uniform4d :: proc "c" (location: i32, x: f64, y: f64, z: f64, w: f64, loc := #caller_location) { impl_Uniform4d(location, x, y, z, w); debug_helper(loc, 0, location, x, y, z, w) } + Uniform1dv :: proc "c" (location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_Uniform1dv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform2dv :: proc "c" (location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_Uniform2dv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform3dv :: proc "c" (location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_Uniform3dv(location, count, value); debug_helper(loc, 0, location, count, value) } + Uniform4dv :: proc "c" (location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_Uniform4dv(location, count, value); debug_helper(loc, 0, location, count, value) } + UniformMatrix2dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix2dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix3dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix3dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix4dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix4dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix2x3dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix2x3dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix2x4dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix2x4dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix3x2dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix3x2dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix3x4dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix3x4dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix4x2dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix4x2dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + UniformMatrix4x3dv :: proc "c" (location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_UniformMatrix4x3dv(location, count, transpose, value); debug_helper(loc, 0, location, count, transpose, value) } + GetUniformdv :: proc "c" (program: u32, location: i32, params: [^]f64, loc := #caller_location) { impl_GetUniformdv(program, location, params); debug_helper(loc, 0, program, location, params) } + GetSubroutineUniformLocation :: proc "c" (program: u32, shadertype: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetSubroutineUniformLocation(program, shadertype, name); debug_helper(loc, 1, ret, program, shadertype, name); return ret } + GetSubroutineIndex :: proc "c" (program: u32, shadertype: u32, name: cstring, loc := #caller_location) -> u32 { ret := impl_GetSubroutineIndex(program, shadertype, name); debug_helper(loc, 1, ret, program, shadertype, name); return ret } + GetActiveSubroutineUniformiv :: proc "c" (program: u32, shadertype: u32, index: u32, pname: u32, values: [^]i32, loc := #caller_location) { impl_GetActiveSubroutineUniformiv(program, shadertype, index, pname, values); debug_helper(loc, 0, program, shadertype, index, pname, values) } + GetActiveSubroutineUniformName :: proc "c" (program: u32, shadertype: u32, index: u32, bufsize: i32, length: ^i32, name: [^]u8, loc := #caller_location) { impl_GetActiveSubroutineUniformName(program, shadertype, index, bufsize, length, name); debug_helper(loc, 0, program, shadertype, index, bufsize, length, name) } + GetActiveSubroutineName :: proc "c" (program: u32, shadertype: u32, index: u32, bufsize: i32, length: ^i32, name: [^]u8, loc := #caller_location) { impl_GetActiveSubroutineName(program, shadertype, index, bufsize, length, name); debug_helper(loc, 0, program, shadertype, index, bufsize, length, name) } + UniformSubroutinesuiv :: proc "c" (shadertype: u32, count: i32, indices: [^]u32, loc := #caller_location) { impl_UniformSubroutinesuiv(shadertype, count, indices); debug_helper(loc, 0, shadertype, count, indices) } + GetUniformSubroutineuiv :: proc "c" (shadertype: u32, location: i32, params: [^]u32, loc := #caller_location) { impl_GetUniformSubroutineuiv(shadertype, location, params); debug_helper(loc, 0, shadertype, location, params) } + GetProgramStageiv :: proc "c" (program: u32, shadertype: u32, pname: u32, values: [^]i32, loc := #caller_location) { impl_GetProgramStageiv(program, shadertype, pname, values); debug_helper(loc, 0, program, shadertype, pname, values) } + PatchParameteri :: proc "c" (pname: u32, value: i32, loc := #caller_location) { impl_PatchParameteri(pname, value); debug_helper(loc, 0, pname, value) } + PatchParameterfv :: proc "c" (pname: u32, values: [^]f32, loc := #caller_location) { impl_PatchParameterfv(pname, values); debug_helper(loc, 0, pname, values) } + BindTransformFeedback :: proc "c" (target: u32, id: u32, loc := #caller_location) { impl_BindTransformFeedback(target, id); debug_helper(loc, 0, target, id) } + DeleteTransformFeedbacks :: proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_DeleteTransformFeedbacks(n, ids); debug_helper(loc, 0, n, ids) } + GenTransformFeedbacks :: proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_GenTransformFeedbacks(n, ids); debug_helper(loc, 0, n, ids) } + IsTransformFeedback :: proc "c" (id: u32, loc := #caller_location) -> bool { ret := impl_IsTransformFeedback(id); debug_helper(loc, 1, ret, id); return ret } + PauseTransformFeedback :: proc "c" (loc := #caller_location) { impl_PauseTransformFeedback(); debug_helper(loc, 0) } + ResumeTransformFeedback :: proc "c" (loc := #caller_location) { impl_ResumeTransformFeedback(); debug_helper(loc, 0) } + DrawTransformFeedback :: proc "c" (mode: u32, id: u32, loc := #caller_location) { impl_DrawTransformFeedback(mode, id); debug_helper(loc, 0, mode, id) } + DrawTransformFeedbackStream :: proc "c" (mode: u32, id: u32, stream: u32, loc := #caller_location) { impl_DrawTransformFeedbackStream(mode, id, stream); debug_helper(loc, 0, mode, id, stream) } + BeginQueryIndexed :: proc "c" (target: u32, index: u32, id: u32, loc := #caller_location) { impl_BeginQueryIndexed(target, index, id); debug_helper(loc, 0, target, index, id) } + EndQueryIndexed :: proc "c" (target: u32, index: u32, loc := #caller_location) { impl_EndQueryIndexed(target, index); debug_helper(loc, 0, target, index) } + GetQueryIndexediv :: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryIndexediv(target, index, pname, params); debug_helper(loc, 0, target, index, pname, params) } // VERSION_4_1 - ReleaseShaderCompiler :: #force_inline proc "c" (loc := #caller_location) { impl_ReleaseShaderCompiler(); debug_helper(loc, 0) } - ShaderBinary :: #force_inline proc "c" (count: i32, shaders: ^u32, binaryformat: u32, binary: rawptr, length: i32, loc := #caller_location) { impl_ShaderBinary(count, shaders, binaryformat, binary, length); debug_helper(loc, 0, count, shaders, binaryformat, binary, length) } - GetShaderPrecisionFormat :: #force_inline proc "c" (shadertype: u32, precisiontype: u32, range: ^i32, precision: ^i32, loc := #caller_location) { impl_GetShaderPrecisionFormat(shadertype, precisiontype, range, precision); debug_helper(loc, 0, shadertype, precisiontype, range, precision) } - DepthRangef :: #force_inline proc "c" (n: f32, f: f32, loc := #caller_location) { impl_DepthRangef(n, f); debug_helper(loc, 0, n, f) } - ClearDepthf :: #force_inline proc "c" (d: f32, loc := #caller_location) { impl_ClearDepthf(d); debug_helper(loc, 0, d) } - GetProgramBinary :: #force_inline proc "c" (program: u32, bufSize: i32, length: ^i32, binaryFormat: ^u32, binary: rawptr, loc := #caller_location) { impl_GetProgramBinary(program, bufSize, length, binaryFormat, binary); debug_helper(loc, 0, program, bufSize, length, binaryFormat, binary) } - ProgramBinary :: #force_inline proc "c" (program: u32, binaryFormat: u32, binary: rawptr, length: i32, loc := #caller_location) { impl_ProgramBinary(program, binaryFormat, binary, length); debug_helper(loc, 0, program, binaryFormat, binary, length) } - ProgramParameteri :: #force_inline proc "c" (program: u32, pname: u32, value: i32, loc := #caller_location) { impl_ProgramParameteri(program, pname, value); debug_helper(loc, 0, program, pname, value) } - UseProgramStages :: #force_inline proc "c" (pipeline: u32, stages: u32, program: u32, loc := #caller_location) { impl_UseProgramStages(pipeline, stages, program); debug_helper(loc, 0, pipeline, stages, program) } - ActiveShaderProgram :: #force_inline proc "c" (pipeline: u32, program: u32, loc := #caller_location) { impl_ActiveShaderProgram(pipeline, program); debug_helper(loc, 0, pipeline, program) } - CreateShaderProgramv :: #force_inline proc "c" (type: u32, count: i32, strings: [^]cstring, loc := #caller_location) -> u32 { ret := impl_CreateShaderProgramv(type, count, strings); debug_helper(loc, 1, ret, type, count, strings); return ret } - BindProgramPipeline :: #force_inline proc "c" (pipeline: u32, loc := #caller_location) { impl_BindProgramPipeline(pipeline); debug_helper(loc, 0, pipeline) } - DeleteProgramPipelines :: #force_inline proc "c" (n: i32, pipelines: [^]u32, loc := #caller_location) { impl_DeleteProgramPipelines(n, pipelines); debug_helper(loc, 0, n, pipelines) } - GenProgramPipelines :: #force_inline proc "c" (n: i32, pipelines: [^]u32, loc := #caller_location) { impl_GenProgramPipelines(n, pipelines); debug_helper(loc, 0, n, pipelines) } - IsProgramPipeline :: #force_inline proc "c" (pipeline: u32, loc := #caller_location) -> bool { ret := impl_IsProgramPipeline(pipeline); debug_helper(loc, 1, ret, pipeline); return ret } - GetProgramPipelineiv :: #force_inline proc "c" (pipeline: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetProgramPipelineiv(pipeline, pname, params); debug_helper(loc, 0, pipeline, pname, params) } - ProgramUniform1i :: #force_inline proc "c" (program: u32, location: i32, v0: i32, loc := #caller_location) { impl_ProgramUniform1i(program, location, v0); debug_helper(loc, 0, program, location, v0) } - ProgramUniform1iv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_ProgramUniform1iv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform1f :: #force_inline proc "c" (program: u32, location: i32, v0: f32, loc := #caller_location) { impl_ProgramUniform1f(program, location, v0); debug_helper(loc, 0, program, location, v0) } - ProgramUniform1fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_ProgramUniform1fv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform1d :: #force_inline proc "c" (program: u32, location: i32, v0: f64, loc := #caller_location) { impl_ProgramUniform1d(program, location, v0); debug_helper(loc, 0, program, location, v0) } - ProgramUniform1dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_ProgramUniform1dv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform1ui :: #force_inline proc "c" (program: u32, location: i32, v0: u32, loc := #caller_location) { impl_ProgramUniform1ui(program, location, v0); debug_helper(loc, 0, program, location, v0) } - ProgramUniform1uiv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_ProgramUniform1uiv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform2i :: #force_inline proc "c" (program: u32, location: i32, v0: i32, v1: i32, loc := #caller_location) { impl_ProgramUniform2i(program, location, v0, v1); debug_helper(loc, 0, program, location, v0, v1) } - ProgramUniform2iv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_ProgramUniform2iv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform2f :: #force_inline proc "c" (program: u32, location: i32, v0: f32, v1: f32, loc := #caller_location) { impl_ProgramUniform2f(program, location, v0, v1); debug_helper(loc, 0, program, location, v0, v1) } - ProgramUniform2fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_ProgramUniform2fv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform2d :: #force_inline proc "c" (program: u32, location: i32, v0: f64, v1: f64, loc := #caller_location) { impl_ProgramUniform2d(program, location, v0, v1); debug_helper(loc, 0, program, location, v0, v1) } - ProgramUniform2dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_ProgramUniform2dv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform2ui :: #force_inline proc "c" (program: u32, location: i32, v0: u32, v1: u32, loc := #caller_location) { impl_ProgramUniform2ui(program, location, v0, v1); debug_helper(loc, 0, program, location, v0, v1) } - ProgramUniform2uiv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_ProgramUniform2uiv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform3i :: #force_inline proc "c" (program: u32, location: i32, v0: i32, v1: i32, v2: i32, loc := #caller_location) { impl_ProgramUniform3i(program, location, v0, v1, v2); debug_helper(loc, 0, program, location, v0, v1, v2) } - ProgramUniform3iv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_ProgramUniform3iv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform3f :: #force_inline proc "c" (program: u32, location: i32, v0: f32, v1: f32, v2: f32, loc := #caller_location) { impl_ProgramUniform3f(program, location, v0, v1, v2); debug_helper(loc, 0, program, location, v0, v1, v2) } - ProgramUniform3fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_ProgramUniform3fv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform3d :: #force_inline proc "c" (program: u32, location: i32, v0: f64, v1: f64, v2: f64, loc := #caller_location) { impl_ProgramUniform3d(program, location, v0, v1, v2); debug_helper(loc, 0, program, location, v0, v1, v2) } - ProgramUniform3dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_ProgramUniform3dv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform3ui :: #force_inline proc "c" (program: u32, location: i32, v0: u32, v1: u32, v2: u32, loc := #caller_location) { impl_ProgramUniform3ui(program, location, v0, v1, v2); debug_helper(loc, 0, program, location, v0, v1, v2) } - ProgramUniform3uiv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_ProgramUniform3uiv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform4i :: #force_inline proc "c" (program: u32, location: i32, v0: i32, v1: i32, v2: i32, v3: i32, loc := #caller_location) { impl_ProgramUniform4i(program, location, v0, v1, v2, v3); debug_helper(loc, 0, program, location, v0, v1, v2, v3) } - ProgramUniform4iv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_ProgramUniform4iv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform4f :: #force_inline proc "c" (program: u32, location: i32, v0: f32, v1: f32, v2: f32, v3: f32, loc := #caller_location) { impl_ProgramUniform4f(program, location, v0, v1, v2, v3); debug_helper(loc, 0, program, location, v0, v1, v2, v3) } - ProgramUniform4fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_ProgramUniform4fv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform4d :: #force_inline proc "c" (program: u32, location: i32, v0: f64, v1: f64, v2: f64, v3: f64, loc := #caller_location) { impl_ProgramUniform4d(program, location, v0, v1, v2, v3); debug_helper(loc, 0, program, location, v0, v1, v2, v3) } - ProgramUniform4dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_ProgramUniform4dv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniform4ui :: #force_inline proc "c" (program: u32, location: i32, v0: u32, v1: u32, v2: u32, v3: u32, loc := #caller_location) { impl_ProgramUniform4ui(program, location, v0, v1, v2, v3); debug_helper(loc, 0, program, location, v0, v1, v2, v3) } - ProgramUniform4uiv :: #force_inline proc "c" (program: u32, location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_ProgramUniform4uiv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } - ProgramUniformMatrix2fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix2fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix3fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix3fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix4fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix4fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix2dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix2dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix3dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix3dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix4dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix4dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix2x3fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix2x3fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix3x2fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix3x2fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix2x4fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix2x4fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix4x2fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix4x2fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix3x4fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix3x4fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix4x3fv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix4x3fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix2x3dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix2x3dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix3x2dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix3x2dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix2x4dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix2x4dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix4x2dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix4x2dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix3x4dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix3x4dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ProgramUniformMatrix4x3dv :: #force_inline proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix4x3dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } - ValidateProgramPipeline :: #force_inline proc "c" (pipeline: u32, loc := #caller_location) { impl_ValidateProgramPipeline(pipeline); debug_helper(loc, 0, pipeline) } - GetProgramPipelineInfoLog :: #force_inline proc "c" (pipeline: u32, bufSize: i32, length: ^i32, infoLog: [^]u8, loc := #caller_location) { impl_GetProgramPipelineInfoLog(pipeline, bufSize, length, infoLog); debug_helper(loc, 0, pipeline, bufSize, length, infoLog) } - VertexAttribL1d :: #force_inline proc "c" (index: u32, x: f64, loc := #caller_location) { impl_VertexAttribL1d(index, x); debug_helper(loc, 0, index, x) } - VertexAttribL2d :: #force_inline proc "c" (index: u32, x: f64, y: f64, loc := #caller_location) { impl_VertexAttribL2d(index, x, y); debug_helper(loc, 0, index, x, y) } - VertexAttribL3d :: #force_inline proc "c" (index: u32, x: f64, y: f64, z: f64, loc := #caller_location) { impl_VertexAttribL3d(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } - VertexAttribL4d :: #force_inline proc "c" (index: u32, x: f64, y: f64, z: f64, w: f64, loc := #caller_location) { impl_VertexAttribL4d(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } - VertexAttribL1dv :: #force_inline proc "c" (index: u32, v: ^f64, loc := #caller_location) { impl_VertexAttribL1dv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribL2dv :: #force_inline proc "c" (index: u32, v: ^[2]f64, loc := #caller_location) { impl_VertexAttribL2dv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribL3dv :: #force_inline proc "c" (index: u32, v: ^[3]f64, loc := #caller_location) { impl_VertexAttribL3dv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribL4dv :: #force_inline proc "c" (index: u32, v: ^[4]f64, loc := #caller_location) { impl_VertexAttribL4dv(index, v); debug_helper(loc, 0, index, v) } - VertexAttribLPointer :: #force_inline proc "c" (index: u32, size: i32, type: u32, stride: i32, pointer: uintptr, loc := #caller_location) { impl_VertexAttribLPointer(index, size, type, stride, pointer); debug_helper(loc, 0, index, size, type, stride, pointer) } - GetVertexAttribLdv :: #force_inline proc "c" (index: u32, pname: u32, params: [^]f64, loc := #caller_location) { impl_GetVertexAttribLdv(index, pname, params); debug_helper(loc, 0, index, pname, params) } - ViewportArrayv :: #force_inline proc "c" (first: u32, count: i32, v: [^]f32, loc := #caller_location) { impl_ViewportArrayv(first, count, v); debug_helper(loc, 0, first, count, v) } - ViewportIndexedf :: #force_inline proc "c" (index: u32, x: f32, y: f32, w: f32, h: f32, loc := #caller_location) { impl_ViewportIndexedf(index, x, y, w, h); debug_helper(loc, 0, index, x, y, w, h) } - ViewportIndexedfv :: #force_inline proc "c" (index: u32, v: ^[4]f32, loc := #caller_location) { impl_ViewportIndexedfv(index, v); debug_helper(loc, 0, index, v) } - ScissorArrayv :: #force_inline proc "c" (first: u32, count: i32, v: [^]i32, loc := #caller_location) { impl_ScissorArrayv(first, count, v); debug_helper(loc, 0, first, count, v) } - ScissorIndexed :: #force_inline proc "c" (index: u32, left: i32, bottom: i32, width: i32, height: i32, loc := #caller_location) { impl_ScissorIndexed(index, left, bottom, width, height); debug_helper(loc, 0, index, left, bottom, width, height) } - ScissorIndexedv :: #force_inline proc "c" (index: u32, v: ^[4]i32, loc := #caller_location) { impl_ScissorIndexedv(index, v); debug_helper(loc, 0, index, v) } - DepthRangeArrayv :: #force_inline proc "c" (first: u32, count: i32, v: [^]f64, loc := #caller_location) { impl_DepthRangeArrayv(first, count, v); debug_helper(loc, 0, first, count, v) } - DepthRangeIndexed :: #force_inline proc "c" (index: u32, n: f64, f: f64, loc := #caller_location) { impl_DepthRangeIndexed(index, n, f); debug_helper(loc, 0, index, n, f) } - GetFloati_v :: #force_inline proc "c" (target: u32, index: u32, data: ^f32, loc := #caller_location) { impl_GetFloati_v(target, index, data); debug_helper(loc, 0, target, index, data) } - GetDoublei_v :: #force_inline proc "c" (target: u32, index: u32, data: ^f64, loc := #caller_location) { impl_GetDoublei_v(target, index, data); debug_helper(loc, 0, target, index, data) } + ReleaseShaderCompiler :: proc "c" (loc := #caller_location) { impl_ReleaseShaderCompiler(); debug_helper(loc, 0) } + ShaderBinary :: proc "c" (count: i32, shaders: ^u32, binaryformat: u32, binary: rawptr, length: i32, loc := #caller_location) { impl_ShaderBinary(count, shaders, binaryformat, binary, length); debug_helper(loc, 0, count, shaders, binaryformat, binary, length) } + GetShaderPrecisionFormat :: proc "c" (shadertype: u32, precisiontype: u32, range: ^i32, precision: ^i32, loc := #caller_location) { impl_GetShaderPrecisionFormat(shadertype, precisiontype, range, precision); debug_helper(loc, 0, shadertype, precisiontype, range, precision) } + DepthRangef :: proc "c" (n: f32, f: f32, loc := #caller_location) { impl_DepthRangef(n, f); debug_helper(loc, 0, n, f) } + ClearDepthf :: proc "c" (d: f32, loc := #caller_location) { impl_ClearDepthf(d); debug_helper(loc, 0, d) } + GetProgramBinary :: proc "c" (program: u32, bufSize: i32, length: ^i32, binaryFormat: ^u32, binary: rawptr, loc := #caller_location) { impl_GetProgramBinary(program, bufSize, length, binaryFormat, binary); debug_helper(loc, 0, program, bufSize, length, binaryFormat, binary) } + ProgramBinary :: proc "c" (program: u32, binaryFormat: u32, binary: rawptr, length: i32, loc := #caller_location) { impl_ProgramBinary(program, binaryFormat, binary, length); debug_helper(loc, 0, program, binaryFormat, binary, length) } + ProgramParameteri :: proc "c" (program: u32, pname: u32, value: i32, loc := #caller_location) { impl_ProgramParameteri(program, pname, value); debug_helper(loc, 0, program, pname, value) } + UseProgramStages :: proc "c" (pipeline: u32, stages: u32, program: u32, loc := #caller_location) { impl_UseProgramStages(pipeline, stages, program); debug_helper(loc, 0, pipeline, stages, program) } + ActiveShaderProgram :: proc "c" (pipeline: u32, program: u32, loc := #caller_location) { impl_ActiveShaderProgram(pipeline, program); debug_helper(loc, 0, pipeline, program) } + CreateShaderProgramv :: proc "c" (type: u32, count: i32, strings: [^]cstring, loc := #caller_location) -> u32 { ret := impl_CreateShaderProgramv(type, count, strings); debug_helper(loc, 1, ret, type, count, strings); return ret } + BindProgramPipeline :: proc "c" (pipeline: u32, loc := #caller_location) { impl_BindProgramPipeline(pipeline); debug_helper(loc, 0, pipeline) } + DeleteProgramPipelines :: proc "c" (n: i32, pipelines: [^]u32, loc := #caller_location) { impl_DeleteProgramPipelines(n, pipelines); debug_helper(loc, 0, n, pipelines) } + GenProgramPipelines :: proc "c" (n: i32, pipelines: [^]u32, loc := #caller_location) { impl_GenProgramPipelines(n, pipelines); debug_helper(loc, 0, n, pipelines) } + IsProgramPipeline :: proc "c" (pipeline: u32, loc := #caller_location) -> bool { ret := impl_IsProgramPipeline(pipeline); debug_helper(loc, 1, ret, pipeline); return ret } + GetProgramPipelineiv :: proc "c" (pipeline: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetProgramPipelineiv(pipeline, pname, params); debug_helper(loc, 0, pipeline, pname, params) } + ProgramUniform1i :: proc "c" (program: u32, location: i32, v0: i32, loc := #caller_location) { impl_ProgramUniform1i(program, location, v0); debug_helper(loc, 0, program, location, v0) } + ProgramUniform1iv :: proc "c" (program: u32, location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_ProgramUniform1iv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform1f :: proc "c" (program: u32, location: i32, v0: f32, loc := #caller_location) { impl_ProgramUniform1f(program, location, v0); debug_helper(loc, 0, program, location, v0) } + ProgramUniform1fv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_ProgramUniform1fv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform1d :: proc "c" (program: u32, location: i32, v0: f64, loc := #caller_location) { impl_ProgramUniform1d(program, location, v0); debug_helper(loc, 0, program, location, v0) } + ProgramUniform1dv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_ProgramUniform1dv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform1ui :: proc "c" (program: u32, location: i32, v0: u32, loc := #caller_location) { impl_ProgramUniform1ui(program, location, v0); debug_helper(loc, 0, program, location, v0) } + ProgramUniform1uiv :: proc "c" (program: u32, location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_ProgramUniform1uiv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform2i :: proc "c" (program: u32, location: i32, v0: i32, v1: i32, loc := #caller_location) { impl_ProgramUniform2i(program, location, v0, v1); debug_helper(loc, 0, program, location, v0, v1) } + ProgramUniform2iv :: proc "c" (program: u32, location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_ProgramUniform2iv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform2f :: proc "c" (program: u32, location: i32, v0: f32, v1: f32, loc := #caller_location) { impl_ProgramUniform2f(program, location, v0, v1); debug_helper(loc, 0, program, location, v0, v1) } + ProgramUniform2fv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_ProgramUniform2fv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform2d :: proc "c" (program: u32, location: i32, v0: f64, v1: f64, loc := #caller_location) { impl_ProgramUniform2d(program, location, v0, v1); debug_helper(loc, 0, program, location, v0, v1) } + ProgramUniform2dv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_ProgramUniform2dv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform2ui :: proc "c" (program: u32, location: i32, v0: u32, v1: u32, loc := #caller_location) { impl_ProgramUniform2ui(program, location, v0, v1); debug_helper(loc, 0, program, location, v0, v1) } + ProgramUniform2uiv :: proc "c" (program: u32, location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_ProgramUniform2uiv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform3i :: proc "c" (program: u32, location: i32, v0: i32, v1: i32, v2: i32, loc := #caller_location) { impl_ProgramUniform3i(program, location, v0, v1, v2); debug_helper(loc, 0, program, location, v0, v1, v2) } + ProgramUniform3iv :: proc "c" (program: u32, location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_ProgramUniform3iv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform3f :: proc "c" (program: u32, location: i32, v0: f32, v1: f32, v2: f32, loc := #caller_location) { impl_ProgramUniform3f(program, location, v0, v1, v2); debug_helper(loc, 0, program, location, v0, v1, v2) } + ProgramUniform3fv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_ProgramUniform3fv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform3d :: proc "c" (program: u32, location: i32, v0: f64, v1: f64, v2: f64, loc := #caller_location) { impl_ProgramUniform3d(program, location, v0, v1, v2); debug_helper(loc, 0, program, location, v0, v1, v2) } + ProgramUniform3dv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_ProgramUniform3dv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform3ui :: proc "c" (program: u32, location: i32, v0: u32, v1: u32, v2: u32, loc := #caller_location) { impl_ProgramUniform3ui(program, location, v0, v1, v2); debug_helper(loc, 0, program, location, v0, v1, v2) } + ProgramUniform3uiv :: proc "c" (program: u32, location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_ProgramUniform3uiv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform4i :: proc "c" (program: u32, location: i32, v0: i32, v1: i32, v2: i32, v3: i32, loc := #caller_location) { impl_ProgramUniform4i(program, location, v0, v1, v2, v3); debug_helper(loc, 0, program, location, v0, v1, v2, v3) } + ProgramUniform4iv :: proc "c" (program: u32, location: i32, count: i32, value: [^]i32, loc := #caller_location) { impl_ProgramUniform4iv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform4f :: proc "c" (program: u32, location: i32, v0: f32, v1: f32, v2: f32, v3: f32, loc := #caller_location) { impl_ProgramUniform4f(program, location, v0, v1, v2, v3); debug_helper(loc, 0, program, location, v0, v1, v2, v3) } + ProgramUniform4fv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f32, loc := #caller_location) { impl_ProgramUniform4fv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform4d :: proc "c" (program: u32, location: i32, v0: f64, v1: f64, v2: f64, v3: f64, loc := #caller_location) { impl_ProgramUniform4d(program, location, v0, v1, v2, v3); debug_helper(loc, 0, program, location, v0, v1, v2, v3) } + ProgramUniform4dv :: proc "c" (program: u32, location: i32, count: i32, value: [^]f64, loc := #caller_location) { impl_ProgramUniform4dv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniform4ui :: proc "c" (program: u32, location: i32, v0: u32, v1: u32, v2: u32, v3: u32, loc := #caller_location) { impl_ProgramUniform4ui(program, location, v0, v1, v2, v3); debug_helper(loc, 0, program, location, v0, v1, v2, v3) } + ProgramUniform4uiv :: proc "c" (program: u32, location: i32, count: i32, value: [^]u32, loc := #caller_location) { impl_ProgramUniform4uiv(program, location, count, value); debug_helper(loc, 0, program, location, count, value) } + ProgramUniformMatrix2fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix2fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix3fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix3fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix4fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix4fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix2dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix2dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix3dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix3dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix4dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix4dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix2x3fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix2x3fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix3x2fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix3x2fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix2x4fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix2x4fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix4x2fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix4x2fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix3x4fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix3x4fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix4x3fv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f32, loc := #caller_location) { impl_ProgramUniformMatrix4x3fv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix2x3dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix2x3dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix3x2dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix3x2dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix2x4dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix2x4dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix4x2dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix4x2dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix3x4dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix3x4dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ProgramUniformMatrix4x3dv :: proc "c" (program: u32, location: i32, count: i32, transpose: bool, value: [^]f64, loc := #caller_location) { impl_ProgramUniformMatrix4x3dv(program, location, count, transpose, value); debug_helper(loc, 0, program, location, count, transpose, value) } + ValidateProgramPipeline :: proc "c" (pipeline: u32, loc := #caller_location) { impl_ValidateProgramPipeline(pipeline); debug_helper(loc, 0, pipeline) } + GetProgramPipelineInfoLog :: proc "c" (pipeline: u32, bufSize: i32, length: ^i32, infoLog: [^]u8, loc := #caller_location) { impl_GetProgramPipelineInfoLog(pipeline, bufSize, length, infoLog); debug_helper(loc, 0, pipeline, bufSize, length, infoLog) } + VertexAttribL1d :: proc "c" (index: u32, x: f64, loc := #caller_location) { impl_VertexAttribL1d(index, x); debug_helper(loc, 0, index, x) } + VertexAttribL2d :: proc "c" (index: u32, x: f64, y: f64, loc := #caller_location) { impl_VertexAttribL2d(index, x, y); debug_helper(loc, 0, index, x, y) } + VertexAttribL3d :: proc "c" (index: u32, x: f64, y: f64, z: f64, loc := #caller_location) { impl_VertexAttribL3d(index, x, y, z); debug_helper(loc, 0, index, x, y, z) } + VertexAttribL4d :: proc "c" (index: u32, x: f64, y: f64, z: f64, w: f64, loc := #caller_location) { impl_VertexAttribL4d(index, x, y, z, w); debug_helper(loc, 0, index, x, y, z, w) } + VertexAttribL1dv :: proc "c" (index: u32, v: ^f64, loc := #caller_location) { impl_VertexAttribL1dv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribL2dv :: proc "c" (index: u32, v: ^[2]f64, loc := #caller_location) { impl_VertexAttribL2dv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribL3dv :: proc "c" (index: u32, v: ^[3]f64, loc := #caller_location) { impl_VertexAttribL3dv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribL4dv :: proc "c" (index: u32, v: ^[4]f64, loc := #caller_location) { impl_VertexAttribL4dv(index, v); debug_helper(loc, 0, index, v) } + VertexAttribLPointer :: proc "c" (index: u32, size: i32, type: u32, stride: i32, pointer: uintptr, loc := #caller_location) { impl_VertexAttribLPointer(index, size, type, stride, pointer); debug_helper(loc, 0, index, size, type, stride, pointer) } + GetVertexAttribLdv :: proc "c" (index: u32, pname: u32, params: [^]f64, loc := #caller_location) { impl_GetVertexAttribLdv(index, pname, params); debug_helper(loc, 0, index, pname, params) } + ViewportArrayv :: proc "c" (first: u32, count: i32, v: [^]f32, loc := #caller_location) { impl_ViewportArrayv(first, count, v); debug_helper(loc, 0, first, count, v) } + ViewportIndexedf :: proc "c" (index: u32, x: f32, y: f32, w: f32, h: f32, loc := #caller_location) { impl_ViewportIndexedf(index, x, y, w, h); debug_helper(loc, 0, index, x, y, w, h) } + ViewportIndexedfv :: proc "c" (index: u32, v: ^[4]f32, loc := #caller_location) { impl_ViewportIndexedfv(index, v); debug_helper(loc, 0, index, v) } + ScissorArrayv :: proc "c" (first: u32, count: i32, v: [^]i32, loc := #caller_location) { impl_ScissorArrayv(first, count, v); debug_helper(loc, 0, first, count, v) } + ScissorIndexed :: proc "c" (index: u32, left: i32, bottom: i32, width: i32, height: i32, loc := #caller_location) { impl_ScissorIndexed(index, left, bottom, width, height); debug_helper(loc, 0, index, left, bottom, width, height) } + ScissorIndexedv :: proc "c" (index: u32, v: ^[4]i32, loc := #caller_location) { impl_ScissorIndexedv(index, v); debug_helper(loc, 0, index, v) } + DepthRangeArrayv :: proc "c" (first: u32, count: i32, v: [^]f64, loc := #caller_location) { impl_DepthRangeArrayv(first, count, v); debug_helper(loc, 0, first, count, v) } + DepthRangeIndexed :: proc "c" (index: u32, n: f64, f: f64, loc := #caller_location) { impl_DepthRangeIndexed(index, n, f); debug_helper(loc, 0, index, n, f) } + GetFloati_v :: proc "c" (target: u32, index: u32, data: ^f32, loc := #caller_location) { impl_GetFloati_v(target, index, data); debug_helper(loc, 0, target, index, data) } + GetDoublei_v :: proc "c" (target: u32, index: u32, data: ^f64, loc := #caller_location) { impl_GetDoublei_v(target, index, data); debug_helper(loc, 0, target, index, data) } // VERSION_4_2 - DrawArraysInstancedBaseInstance :: #force_inline proc "c" (mode: u32, first: i32, count: i32, instancecount: i32, baseinstance: u32, loc := #caller_location) { impl_DrawArraysInstancedBaseInstance(mode, first, count, instancecount, baseinstance); debug_helper(loc, 0, mode, first, count, instancecount, baseinstance) } - DrawElementsInstancedBaseInstance :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, baseinstance: u32, loc := #caller_location) { impl_DrawElementsInstancedBaseInstance(mode, count, type, indices, instancecount, baseinstance); debug_helper(loc, 0, mode, count, type, indices, instancecount, baseinstance) } - DrawElementsInstancedBaseVertexBaseInstance :: #force_inline proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, basevertex: i32, baseinstance: u32, loc := #caller_location) { impl_DrawElementsInstancedBaseVertexBaseInstance(mode, count, type, indices, instancecount, basevertex, baseinstance); debug_helper(loc, 0, mode, count, type, indices, instancecount, basevertex, baseinstance) } - GetInternalformativ :: #force_inline proc "c" (target: u32, internalformat: u32, pname: u32, bufSize: i32, params: [^]i32, loc := #caller_location) { impl_GetInternalformativ(target, internalformat, pname, bufSize, params); debug_helper(loc, 0, target, internalformat, pname, bufSize, params) } - GetActiveAtomicCounterBufferiv :: #force_inline proc "c" (program: u32, bufferIndex: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetActiveAtomicCounterBufferiv(program, bufferIndex, pname, params); debug_helper(loc, 0, program, bufferIndex, pname, params) } - BindImageTexture :: #force_inline proc "c" (unit: u32, texture: u32, level: i32, layered: bool, layer: i32, access: u32, format: u32, loc := #caller_location) { impl_BindImageTexture(unit, texture, level, layered, layer, access, format); debug_helper(loc, 0, unit, texture, level, layered, layer, access, format) } - MemoryBarrier :: #force_inline proc "c" (barriers: u32, loc := #caller_location) { impl_MemoryBarrier(barriers); debug_helper(loc, 0, barriers) } - TexStorage1D :: #force_inline proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, loc := #caller_location) { impl_TexStorage1D(target, levels, internalformat, width); debug_helper(loc, 0, target, levels, internalformat, width) } - TexStorage2D :: #force_inline proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_TexStorage2D(target, levels, internalformat, width, height); debug_helper(loc, 0, target, levels, internalformat, width, height) } - TexStorage3D :: #force_inline proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, height: i32, depth: i32, loc := #caller_location) { impl_TexStorage3D(target, levels, internalformat, width, height, depth); debug_helper(loc, 0, target, levels, internalformat, width, height, depth) } - DrawTransformFeedbackInstanced :: #force_inline proc "c" (mode: u32, id: u32, instancecount: i32, loc := #caller_location) { impl_DrawTransformFeedbackInstanced(mode, id, instancecount); debug_helper(loc, 0, mode, id, instancecount) } - DrawTransformFeedbackStreamInstanced :: #force_inline proc "c" (mode: u32, id: u32, stream: u32, instancecount: i32, loc := #caller_location) { impl_DrawTransformFeedbackStreamInstanced(mode, id, stream, instancecount); debug_helper(loc, 0, mode, id, stream, instancecount) } + DrawArraysInstancedBaseInstance :: proc "c" (mode: u32, first: i32, count: i32, instancecount: i32, baseinstance: u32, loc := #caller_location) { impl_DrawArraysInstancedBaseInstance(mode, first, count, instancecount, baseinstance); debug_helper(loc, 0, mode, first, count, instancecount, baseinstance) } + DrawElementsInstancedBaseInstance :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, baseinstance: u32, loc := #caller_location) { impl_DrawElementsInstancedBaseInstance(mode, count, type, indices, instancecount, baseinstance); debug_helper(loc, 0, mode, count, type, indices, instancecount, baseinstance) } + DrawElementsInstancedBaseVertexBaseInstance :: proc "c" (mode: u32, count: i32, type: u32, indices: rawptr, instancecount: i32, basevertex: i32, baseinstance: u32, loc := #caller_location) { impl_DrawElementsInstancedBaseVertexBaseInstance(mode, count, type, indices, instancecount, basevertex, baseinstance); debug_helper(loc, 0, mode, count, type, indices, instancecount, basevertex, baseinstance) } + GetInternalformativ :: proc "c" (target: u32, internalformat: u32, pname: u32, bufSize: i32, params: [^]i32, loc := #caller_location) { impl_GetInternalformativ(target, internalformat, pname, bufSize, params); debug_helper(loc, 0, target, internalformat, pname, bufSize, params) } + GetActiveAtomicCounterBufferiv :: proc "c" (program: u32, bufferIndex: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetActiveAtomicCounterBufferiv(program, bufferIndex, pname, params); debug_helper(loc, 0, program, bufferIndex, pname, params) } + BindImageTexture :: proc "c" (unit: u32, texture: u32, level: i32, layered: bool, layer: i32, access: u32, format: u32, loc := #caller_location) { impl_BindImageTexture(unit, texture, level, layered, layer, access, format); debug_helper(loc, 0, unit, texture, level, layered, layer, access, format) } + MemoryBarrier :: proc "c" (barriers: u32, loc := #caller_location) { impl_MemoryBarrier(barriers); debug_helper(loc, 0, barriers) } + TexStorage1D :: proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, loc := #caller_location) { impl_TexStorage1D(target, levels, internalformat, width); debug_helper(loc, 0, target, levels, internalformat, width) } + TexStorage2D :: proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_TexStorage2D(target, levels, internalformat, width, height); debug_helper(loc, 0, target, levels, internalformat, width, height) } + TexStorage3D :: proc "c" (target: u32, levels: i32, internalformat: u32, width: i32, height: i32, depth: i32, loc := #caller_location) { impl_TexStorage3D(target, levels, internalformat, width, height, depth); debug_helper(loc, 0, target, levels, internalformat, width, height, depth) } + DrawTransformFeedbackInstanced :: proc "c" (mode: u32, id: u32, instancecount: i32, loc := #caller_location) { impl_DrawTransformFeedbackInstanced(mode, id, instancecount); debug_helper(loc, 0, mode, id, instancecount) } + DrawTransformFeedbackStreamInstanced :: proc "c" (mode: u32, id: u32, stream: u32, instancecount: i32, loc := #caller_location) { impl_DrawTransformFeedbackStreamInstanced(mode, id, stream, instancecount); debug_helper(loc, 0, mode, id, stream, instancecount) } // VERSION_4_3 - ClearBufferData :: #force_inline proc "c" (target: u32, internalformat: u32, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearBufferData(target, internalformat, format, type, data); debug_helper(loc, 0, target, internalformat, format, type, data) } - ClearBufferSubData :: #force_inline proc "c" (target: u32, internalformat: u32, offset: int, size: int, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearBufferSubData(target, internalformat, offset, size, format, type, data); debug_helper(loc, 0, target, internalformat, offset, size, format, type, data) } - DispatchCompute :: #force_inline proc "c" (num_groups_x: u32, num_groups_y: u32, num_groups_z: u32, loc := #caller_location) { impl_DispatchCompute(num_groups_x, num_groups_y, num_groups_z); debug_helper(loc, 0, num_groups_x, num_groups_y, num_groups_z) } - DispatchComputeIndirect :: #force_inline proc "c" (indirect: ^DispatchIndirectCommand, loc := #caller_location) { impl_DispatchComputeIndirect(indirect); debug_helper(loc, 0, indirect) } - CopyImageSubData :: #force_inline proc "c" (srcName: u32, srcTarget: u32, srcLevel: i32, srcX: i32, srcY: i32, srcZ: i32, dstName: u32, dstTarget: u32, dstLevel: i32, dstX: i32, dstY: i32, dstZ: i32, srcWidth: i32, srcHeight: i32, srcDepth: i32, loc := #caller_location) { impl_CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); debug_helper(loc, 0, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth) } - FramebufferParameteri :: #force_inline proc "c" (target: u32, pname: u32, param: i32, loc := #caller_location) { impl_FramebufferParameteri(target, pname, param); debug_helper(loc, 0, target, pname, param) } - GetFramebufferParameteriv :: #force_inline proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetFramebufferParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } - GetInternalformati64v :: #force_inline proc "c" (target: u32, internalformat: u32, pname: u32, bufSize: i32, params: [^]i64, loc := #caller_location) { impl_GetInternalformati64v(target, internalformat, pname, bufSize, params); debug_helper(loc, 0, target, internalformat, pname, bufSize, params) } - InvalidateTexSubImage :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, loc := #caller_location) { impl_InvalidateTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth) } - InvalidateTexImage :: #force_inline proc "c" (texture: u32, level: i32, loc := #caller_location) { impl_InvalidateTexImage(texture, level); debug_helper(loc, 0, texture, level) } - InvalidateBufferSubData :: #force_inline proc "c" (buffer: u32, offset: int, length: int, loc := #caller_location) { impl_InvalidateBufferSubData(buffer, offset, length); debug_helper(loc, 0, buffer, offset, length) } - InvalidateBufferData :: #force_inline proc "c" (buffer: u32, loc := #caller_location) { impl_InvalidateBufferData(buffer); debug_helper(loc, 0, buffer) } - InvalidateFramebuffer :: #force_inline proc "c" (target: u32, numAttachments: i32, attachments: [^]u32, loc := #caller_location) { impl_InvalidateFramebuffer(target, numAttachments, attachments); debug_helper(loc, 0, target, numAttachments, attachments) } - InvalidateSubFramebuffer :: #force_inline proc "c" (target: u32, numAttachments: i32, attachments: [^]u32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_InvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height); debug_helper(loc, 0, target, numAttachments, attachments, x, y, width, height) } - MultiDrawArraysIndirect :: #force_inline proc "c" (mode: u32, indirect: [^]DrawArraysIndirectCommand, drawcount: i32, stride: i32, loc := #caller_location) { impl_MultiDrawArraysIndirect(mode, indirect, drawcount, stride); debug_helper(loc, 0, mode, indirect, drawcount, stride) } - MultiDrawElementsIndirect :: #force_inline proc "c" (mode: u32, type: u32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, stride: i32, loc := #caller_location) { impl_MultiDrawElementsIndirect(mode, type, indirect, drawcount, stride); debug_helper(loc, 0, mode, type, indirect, drawcount, stride) } - GetProgramInterfaceiv :: #force_inline proc "c" (program: u32, programInterface: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetProgramInterfaceiv(program, programInterface, pname, params); debug_helper(loc, 0, program, programInterface, pname, params) } - GetProgramResourceIndex :: #force_inline proc "c" (program: u32, programInterface: u32, name: cstring, loc := #caller_location) -> u32 { ret := impl_GetProgramResourceIndex(program, programInterface, name); debug_helper(loc, 1, ret, program, programInterface, name); return ret } - GetProgramResourceName :: #force_inline proc "c" (program: u32, programInterface: u32, index: u32, bufSize: i32, length: ^i32, name: [^]u8, loc := #caller_location) { impl_GetProgramResourceName(program, programInterface, index, bufSize, length, name); debug_helper(loc, 0, program, programInterface, index, bufSize, length, name) } - GetProgramResourceiv :: #force_inline proc "c" (program: u32, programInterface: u32, index: u32, propCount: i32, props: [^]u32, bufSize: i32, length: ^i32, params: [^]i32, loc := #caller_location) { impl_GetProgramResourceiv(program, programInterface, index, propCount, props, bufSize, length, params); debug_helper(loc, 0, program, programInterface, index, propCount, props, bufSize, length, params) } - GetProgramResourceLocation :: #force_inline proc "c" (program: u32, programInterface: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetProgramResourceLocation(program, programInterface, name); debug_helper(loc, 1, ret, program, programInterface, name); return ret } - GetProgramResourceLocationIndex :: #force_inline proc "c" (program: u32, programInterface: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetProgramResourceLocationIndex(program, programInterface, name); debug_helper(loc, 1, ret, program, programInterface, name); return ret } - ShaderStorageBlockBinding :: #force_inline proc "c" (program: u32, storageBlockIndex: u32, storageBlockBinding: u32, loc := #caller_location) { impl_ShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding); debug_helper(loc, 0, program, storageBlockIndex, storageBlockBinding) } - TexBufferRange :: #force_inline proc "c" (target: u32, internalformat: u32, buffer: u32, offset: int, size: int, loc := #caller_location) { impl_TexBufferRange(target, internalformat, buffer, offset, size); debug_helper(loc, 0, target, internalformat, buffer, offset, size) } - TexStorage2DMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TexStorage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations); debug_helper(loc, 0, target, samples, internalformat, width, height, fixedsamplelocations) } - TexStorage3DMultisample :: #force_inline proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TexStorage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations); debug_helper(loc, 0, target, samples, internalformat, width, height, depth, fixedsamplelocations) } - TextureView :: #force_inline proc "c" (texture: u32, target: u32, origtexture: u32, internalformat: u32, minlevel: u32, numlevels: u32, minlayer: u32, numlayers: u32, loc := #caller_location) { impl_TextureView(texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); debug_helper(loc, 0, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers) } - BindVertexBuffer :: #force_inline proc "c" (bindingindex: u32, buffer: u32, offset: int, stride: i32, loc := #caller_location) { impl_BindVertexBuffer(bindingindex, buffer, offset, stride); debug_helper(loc, 0, bindingindex, buffer, offset, stride) } - VertexAttribFormat :: #force_inline proc "c" (attribindex: u32, size: i32, type: u32, normalized: bool, relativeoffset: u32, loc := #caller_location) { impl_VertexAttribFormat(attribindex, size, type, normalized, relativeoffset); debug_helper(loc, 0, attribindex, size, type, normalized, relativeoffset) } - VertexAttribIFormat :: #force_inline proc "c" (attribindex: u32, size: i32, type: u32, relativeoffset: u32, loc := #caller_location) { impl_VertexAttribIFormat(attribindex, size, type, relativeoffset); debug_helper(loc, 0, attribindex, size, type, relativeoffset) } - VertexAttribLFormat :: #force_inline proc "c" (attribindex: u32, size: i32, type: u32, relativeoffset: u32, loc := #caller_location) { impl_VertexAttribLFormat(attribindex, size, type, relativeoffset); debug_helper(loc, 0, attribindex, size, type, relativeoffset) } - VertexAttribBinding :: #force_inline proc "c" (attribindex: u32, bindingindex: u32, loc := #caller_location) { impl_VertexAttribBinding(attribindex, bindingindex); debug_helper(loc, 0, attribindex, bindingindex) } - VertexBindingDivisor :: #force_inline proc "c" (bindingindex: u32, divisor: u32, loc := #caller_location) { impl_VertexBindingDivisor(bindingindex, divisor); debug_helper(loc, 0, bindingindex, divisor) } - DebugMessageControl :: #force_inline proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool, loc := #caller_location) { impl_DebugMessageControl(source, type, severity, count, ids, enabled); debug_helper(loc, 0, source, type, severity, count, ids, enabled) } - DebugMessageInsert :: #force_inline proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: ^u8, loc := #caller_location) { impl_DebugMessageInsert(source, type, id, severity, length, buf); debug_helper(loc, 0, source, type, id, severity, length, buf) } - DebugMessageCallback :: #force_inline proc "c" (callback: debug_proc_t, userParam: rawptr, loc := #caller_location) { impl_DebugMessageCallback(callback, userParam); debug_helper(loc, 0, callback, userParam) } - GetDebugMessageLog :: #force_inline proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8, loc := #caller_location) -> u32 { ret := impl_GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog); debug_helper(loc, 1, ret, count, bufSize, sources, types, ids, severities, lengths, messageLog); return ret } - PushDebugGroup :: #force_inline proc "c" (source: u32, id: u32, length: i32, message: cstring, loc := #caller_location) { impl_PushDebugGroup(source, id, length, message); debug_helper(loc, 0, source, id, length, message) } - PopDebugGroup :: #force_inline proc "c" (loc := #caller_location) { impl_PopDebugGroup(); debug_helper(loc, 0) } - ObjectLabel :: #force_inline proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8, loc := #caller_location) { impl_ObjectLabel(identifier, name, length, label); debug_helper(loc, 0, identifier, name, length, label) } - GetObjectLabel :: #force_inline proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8, loc := #caller_location) { impl_GetObjectLabel(identifier, name, bufSize, length, label); debug_helper(loc, 0, identifier, name, bufSize, length, label) } - ObjectPtrLabel :: #force_inline proc "c" (ptr: rawptr, length: i32, label: [^]u8, loc := #caller_location) { impl_ObjectPtrLabel(ptr, length, label); debug_helper(loc, 0, ptr, length, label) } - GetObjectPtrLabel :: #force_inline proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8, loc := #caller_location) { impl_GetObjectPtrLabel(ptr, bufSize, length, label); debug_helper(loc, 0, ptr, bufSize, length, label) } + ClearBufferData :: proc "c" (target: u32, internalformat: u32, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearBufferData(target, internalformat, format, type, data); debug_helper(loc, 0, target, internalformat, format, type, data) } + ClearBufferSubData :: proc "c" (target: u32, internalformat: u32, offset: int, size: int, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearBufferSubData(target, internalformat, offset, size, format, type, data); debug_helper(loc, 0, target, internalformat, offset, size, format, type, data) } + DispatchCompute :: proc "c" (num_groups_x: u32, num_groups_y: u32, num_groups_z: u32, loc := #caller_location) { impl_DispatchCompute(num_groups_x, num_groups_y, num_groups_z); debug_helper(loc, 0, num_groups_x, num_groups_y, num_groups_z) } + DispatchComputeIndirect :: proc "c" (indirect: ^DispatchIndirectCommand, loc := #caller_location) { impl_DispatchComputeIndirect(indirect); debug_helper(loc, 0, indirect) } + CopyImageSubData :: proc "c" (srcName: u32, srcTarget: u32, srcLevel: i32, srcX: i32, srcY: i32, srcZ: i32, dstName: u32, dstTarget: u32, dstLevel: i32, dstX: i32, dstY: i32, dstZ: i32, srcWidth: i32, srcHeight: i32, srcDepth: i32, loc := #caller_location) { impl_CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth); debug_helper(loc, 0, srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth) } + FramebufferParameteri :: proc "c" (target: u32, pname: u32, param: i32, loc := #caller_location) { impl_FramebufferParameteri(target, pname, param); debug_helper(loc, 0, target, pname, param) } + GetFramebufferParameteriv :: proc "c" (target: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetFramebufferParameteriv(target, pname, params); debug_helper(loc, 0, target, pname, params) } + GetInternalformati64v :: proc "c" (target: u32, internalformat: u32, pname: u32, bufSize: i32, params: [^]i64, loc := #caller_location) { impl_GetInternalformati64v(target, internalformat, pname, bufSize, params); debug_helper(loc, 0, target, internalformat, pname, bufSize, params) } + InvalidateTexSubImage :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, loc := #caller_location) { impl_InvalidateTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth) } + InvalidateTexImage :: proc "c" (texture: u32, level: i32, loc := #caller_location) { impl_InvalidateTexImage(texture, level); debug_helper(loc, 0, texture, level) } + InvalidateBufferSubData :: proc "c" (buffer: u32, offset: int, length: int, loc := #caller_location) { impl_InvalidateBufferSubData(buffer, offset, length); debug_helper(loc, 0, buffer, offset, length) } + InvalidateBufferData :: proc "c" (buffer: u32, loc := #caller_location) { impl_InvalidateBufferData(buffer); debug_helper(loc, 0, buffer) } + InvalidateFramebuffer :: proc "c" (target: u32, numAttachments: i32, attachments: [^]u32, loc := #caller_location) { impl_InvalidateFramebuffer(target, numAttachments, attachments); debug_helper(loc, 0, target, numAttachments, attachments) } + InvalidateSubFramebuffer :: proc "c" (target: u32, numAttachments: i32, attachments: [^]u32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_InvalidateSubFramebuffer(target, numAttachments, attachments, x, y, width, height); debug_helper(loc, 0, target, numAttachments, attachments, x, y, width, height) } + MultiDrawArraysIndirect :: proc "c" (mode: u32, indirect: [^]DrawArraysIndirectCommand, drawcount: i32, stride: i32, loc := #caller_location) { impl_MultiDrawArraysIndirect(mode, indirect, drawcount, stride); debug_helper(loc, 0, mode, indirect, drawcount, stride) } + MultiDrawElementsIndirect :: proc "c" (mode: u32, type: u32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, stride: i32, loc := #caller_location) { impl_MultiDrawElementsIndirect(mode, type, indirect, drawcount, stride); debug_helper(loc, 0, mode, type, indirect, drawcount, stride) } + GetProgramInterfaceiv :: proc "c" (program: u32, programInterface: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetProgramInterfaceiv(program, programInterface, pname, params); debug_helper(loc, 0, program, programInterface, pname, params) } + GetProgramResourceIndex :: proc "c" (program: u32, programInterface: u32, name: cstring, loc := #caller_location) -> u32 { ret := impl_GetProgramResourceIndex(program, programInterface, name); debug_helper(loc, 1, ret, program, programInterface, name); return ret } + GetProgramResourceName :: proc "c" (program: u32, programInterface: u32, index: u32, bufSize: i32, length: ^i32, name: [^]u8, loc := #caller_location) { impl_GetProgramResourceName(program, programInterface, index, bufSize, length, name); debug_helper(loc, 0, program, programInterface, index, bufSize, length, name) } + GetProgramResourceiv :: proc "c" (program: u32, programInterface: u32, index: u32, propCount: i32, props: [^]u32, bufSize: i32, length: ^i32, params: [^]i32, loc := #caller_location) { impl_GetProgramResourceiv(program, programInterface, index, propCount, props, bufSize, length, params); debug_helper(loc, 0, program, programInterface, index, propCount, props, bufSize, length, params) } + GetProgramResourceLocation :: proc "c" (program: u32, programInterface: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetProgramResourceLocation(program, programInterface, name); debug_helper(loc, 1, ret, program, programInterface, name); return ret } + GetProgramResourceLocationIndex :: proc "c" (program: u32, programInterface: u32, name: cstring, loc := #caller_location) -> i32 { ret := impl_GetProgramResourceLocationIndex(program, programInterface, name); debug_helper(loc, 1, ret, program, programInterface, name); return ret } + ShaderStorageBlockBinding :: proc "c" (program: u32, storageBlockIndex: u32, storageBlockBinding: u32, loc := #caller_location) { impl_ShaderStorageBlockBinding(program, storageBlockIndex, storageBlockBinding); debug_helper(loc, 0, program, storageBlockIndex, storageBlockBinding) } + TexBufferRange :: proc "c" (target: u32, internalformat: u32, buffer: u32, offset: int, size: int, loc := #caller_location) { impl_TexBufferRange(target, internalformat, buffer, offset, size); debug_helper(loc, 0, target, internalformat, buffer, offset, size) } + TexStorage2DMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TexStorage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations); debug_helper(loc, 0, target, samples, internalformat, width, height, fixedsamplelocations) } + TexStorage3DMultisample :: proc "c" (target: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TexStorage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations); debug_helper(loc, 0, target, samples, internalformat, width, height, depth, fixedsamplelocations) } + TextureView :: proc "c" (texture: u32, target: u32, origtexture: u32, internalformat: u32, minlevel: u32, numlevels: u32, minlayer: u32, numlayers: u32, loc := #caller_location) { impl_TextureView(texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers); debug_helper(loc, 0, texture, target, origtexture, internalformat, minlevel, numlevels, minlayer, numlayers) } + BindVertexBuffer :: proc "c" (bindingindex: u32, buffer: u32, offset: int, stride: i32, loc := #caller_location) { impl_BindVertexBuffer(bindingindex, buffer, offset, stride); debug_helper(loc, 0, bindingindex, buffer, offset, stride) } + VertexAttribFormat :: proc "c" (attribindex: u32, size: i32, type: u32, normalized: bool, relativeoffset: u32, loc := #caller_location) { impl_VertexAttribFormat(attribindex, size, type, normalized, relativeoffset); debug_helper(loc, 0, attribindex, size, type, normalized, relativeoffset) } + VertexAttribIFormat :: proc "c" (attribindex: u32, size: i32, type: u32, relativeoffset: u32, loc := #caller_location) { impl_VertexAttribIFormat(attribindex, size, type, relativeoffset); debug_helper(loc, 0, attribindex, size, type, relativeoffset) } + VertexAttribLFormat :: proc "c" (attribindex: u32, size: i32, type: u32, relativeoffset: u32, loc := #caller_location) { impl_VertexAttribLFormat(attribindex, size, type, relativeoffset); debug_helper(loc, 0, attribindex, size, type, relativeoffset) } + VertexAttribBinding :: proc "c" (attribindex: u32, bindingindex: u32, loc := #caller_location) { impl_VertexAttribBinding(attribindex, bindingindex); debug_helper(loc, 0, attribindex, bindingindex) } + VertexBindingDivisor :: proc "c" (bindingindex: u32, divisor: u32, loc := #caller_location) { impl_VertexBindingDivisor(bindingindex, divisor); debug_helper(loc, 0, bindingindex, divisor) } + DebugMessageControl :: proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool, loc := #caller_location) { impl_DebugMessageControl(source, type, severity, count, ids, enabled); debug_helper(loc, 0, source, type, severity, count, ids, enabled) } + DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: ^u8, loc := #caller_location) { impl_DebugMessageInsert(source, type, id, severity, length, buf); debug_helper(loc, 0, source, type, id, severity, length, buf) } + DebugMessageCallback :: proc "c" (callback: debug_proc_t, userParam: rawptr, loc := #caller_location) { impl_DebugMessageCallback(callback, userParam); debug_helper(loc, 0, callback, userParam) } + GetDebugMessageLog :: proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8, loc := #caller_location) -> u32 { ret := impl_GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog); debug_helper(loc, 1, ret, count, bufSize, sources, types, ids, severities, lengths, messageLog); return ret } + PushDebugGroup :: proc "c" (source: u32, id: u32, length: i32, message: cstring, loc := #caller_location) { impl_PushDebugGroup(source, id, length, message); debug_helper(loc, 0, source, id, length, message) } + PopDebugGroup :: proc "c" (loc := #caller_location) { impl_PopDebugGroup(); debug_helper(loc, 0) } + ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8, loc := #caller_location) { impl_ObjectLabel(identifier, name, length, label); debug_helper(loc, 0, identifier, name, length, label) } + GetObjectLabel :: proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8, loc := #caller_location) { impl_GetObjectLabel(identifier, name, bufSize, length, label); debug_helper(loc, 0, identifier, name, bufSize, length, label) } + ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: [^]u8, loc := #caller_location) { impl_ObjectPtrLabel(ptr, length, label); debug_helper(loc, 0, ptr, length, label) } + GetObjectPtrLabel :: proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8, loc := #caller_location) { impl_GetObjectPtrLabel(ptr, bufSize, length, label); debug_helper(loc, 0, ptr, bufSize, length, label) } // VERSION_4_4 - BufferStorage :: #force_inline proc "c" (target: u32, size: int, data: rawptr, flags: u32, loc := #caller_location) { impl_BufferStorage(target, size, data, flags); debug_helper(loc, 0, target, size, data, flags) } - ClearTexImage :: #force_inline proc "c" (texture: u32, level: i32, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearTexImage(texture, level, format, type, data); debug_helper(loc, 0, texture, level, format, type, data) } - ClearTexSubImage :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data) } - BindBuffersBase :: #force_inline proc "c" (target: u32, first: u32, count: i32, buffers: [^]u32, loc := #caller_location) { impl_BindBuffersBase(target, first, count, buffers); debug_helper(loc, 0, target, first, count, buffers) } - BindBuffersRange :: #force_inline proc "c" (target: u32, first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, sizes: [^]int, loc := #caller_location) { impl_BindBuffersRange(target, first, count, buffers, offsets, sizes); debug_helper(loc, 0, target, first, count, buffers, offsets, sizes) } - BindTextures :: #force_inline proc "c" (first: u32, count: i32, textures: [^]u32, loc := #caller_location) { impl_BindTextures(first, count, textures); debug_helper(loc, 0, first, count, textures) } - BindSamplers :: #force_inline proc "c" (first: u32, count: i32, samplers: [^]u32, loc := #caller_location) { impl_BindSamplers(first, count, samplers); debug_helper(loc, 0, first, count, samplers) } - BindImageTextures :: #force_inline proc "c" (first: u32, count: i32, textures: [^]u32, loc := #caller_location) { impl_BindImageTextures(first, count, textures); debug_helper(loc, 0, first, count, textures) } - BindVertexBuffers :: #force_inline proc "c" (first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, strides: [^]i32, loc := #caller_location) { impl_BindVertexBuffers(first, count, buffers, offsets, strides); debug_helper(loc, 0, first, count, buffers, offsets, strides) } + BufferStorage :: proc "c" (target: u32, size: int, data: rawptr, flags: u32, loc := #caller_location) { impl_BufferStorage(target, size, data, flags); debug_helper(loc, 0, target, size, data, flags) } + ClearTexImage :: proc "c" (texture: u32, level: i32, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearTexImage(texture, level, format, type, data); debug_helper(loc, 0, texture, level, format, type, data) } + ClearTexSubImage :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data) } + BindBuffersBase :: proc "c" (target: u32, first: u32, count: i32, buffers: [^]u32, loc := #caller_location) { impl_BindBuffersBase(target, first, count, buffers); debug_helper(loc, 0, target, first, count, buffers) } + BindBuffersRange :: proc "c" (target: u32, first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, sizes: [^]int, loc := #caller_location) { impl_BindBuffersRange(target, first, count, buffers, offsets, sizes); debug_helper(loc, 0, target, first, count, buffers, offsets, sizes) } + BindTextures :: proc "c" (first: u32, count: i32, textures: [^]u32, loc := #caller_location) { impl_BindTextures(first, count, textures); debug_helper(loc, 0, first, count, textures) } + BindSamplers :: proc "c" (first: u32, count: i32, samplers: [^]u32, loc := #caller_location) { impl_BindSamplers(first, count, samplers); debug_helper(loc, 0, first, count, samplers) } + BindImageTextures :: proc "c" (first: u32, count: i32, textures: [^]u32, loc := #caller_location) { impl_BindImageTextures(first, count, textures); debug_helper(loc, 0, first, count, textures) } + BindVertexBuffers :: proc "c" (first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, strides: [^]i32, loc := #caller_location) { impl_BindVertexBuffers(first, count, buffers, offsets, strides); debug_helper(loc, 0, first, count, buffers, offsets, strides) } // VERSION_4_5 - ClipControl :: #force_inline proc "c" (origin: u32, depth: u32, loc := #caller_location) { impl_ClipControl(origin, depth); debug_helper(loc, 0, origin, depth) } - CreateTransformFeedbacks :: #force_inline proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_CreateTransformFeedbacks(n, ids); debug_helper(loc, 0, n, ids) } - TransformFeedbackBufferBase :: #force_inline proc "c" (xfb: u32, index: u32, buffer: u32, loc := #caller_location) { impl_TransformFeedbackBufferBase(xfb, index, buffer); debug_helper(loc, 0, xfb, index, buffer) } - TransformFeedbackBufferRange :: #force_inline proc "c" (xfb: u32, index: u32, buffer: u32, offset: int, size: int, loc := #caller_location) { impl_TransformFeedbackBufferRange(xfb, index, buffer, offset, size); debug_helper(loc, 0, xfb, index, buffer, offset, size) } - GetTransformFeedbackiv :: #force_inline proc "c" (xfb: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_GetTransformFeedbackiv(xfb, pname, param); debug_helper(loc, 0, xfb, pname, param) } - GetTransformFeedbacki_v :: #force_inline proc "c" (xfb: u32, pname: u32, index: u32, param: ^i32, loc := #caller_location) { impl_GetTransformFeedbacki_v(xfb, pname, index, param); debug_helper(loc, 0, xfb, pname, index, param) } - GetTransformFeedbacki64_v :: #force_inline proc "c" (xfb: u32, pname: u32, index: u32, param: ^i64, loc := #caller_location) { impl_GetTransformFeedbacki64_v(xfb, pname, index, param); debug_helper(loc, 0, xfb, pname, index, param) } - CreateBuffers :: #force_inline proc "c" (n: i32, buffers: [^]u32, loc := #caller_location) { impl_CreateBuffers(n, buffers); debug_helper(loc, 0, n, buffers) } - NamedBufferStorage :: #force_inline proc "c" (buffer: u32, size: int, data: rawptr, flags: u32, loc := #caller_location) { impl_NamedBufferStorage(buffer, size, data, flags); debug_helper(loc, 0, buffer, size, data, flags) } - NamedBufferData :: #force_inline proc "c" (buffer: u32, size: int, data: rawptr, usage: u32, loc := #caller_location) { impl_NamedBufferData(buffer, size, data, usage); debug_helper(loc, 0, buffer, size, data, usage) } - NamedBufferSubData :: #force_inline proc "c" (buffer: u32, offset: int, size: int, data: rawptr, loc := #caller_location) { impl_NamedBufferSubData(buffer, offset, size, data); debug_helper(loc, 0, buffer, offset, size, data) } - CopyNamedBufferSubData :: #force_inline proc "c" (readBuffer: u32, writeBuffer: u32, readOffset: int, writeOffset: int, size: int, loc := #caller_location) { impl_CopyNamedBufferSubData(readBuffer, writeBuffer, readOffset, writeOffset, size); debug_helper(loc, 0, readBuffer, writeBuffer, readOffset, writeOffset, size) } - ClearNamedBufferData :: #force_inline proc "c" (buffer: u32, internalformat: u32, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearNamedBufferData(buffer, internalformat, format, type, data); debug_helper(loc, 0, buffer, internalformat, format, type, data) } - ClearNamedBufferSubData :: #force_inline proc "c" (buffer: u32, internalformat: u32, offset: int, size: int, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearNamedBufferSubData(buffer, internalformat, offset, size, format, type, data); debug_helper(loc, 0, buffer, internalformat, offset, size, format, type, data) } - MapNamedBuffer :: #force_inline proc "c" (buffer: u32, access: u32, loc := #caller_location) -> rawptr { ret := impl_MapNamedBuffer(buffer, access); debug_helper(loc, 1, ret, buffer, access); return ret } - MapNamedBufferRange :: #force_inline proc "c" (buffer: u32, offset: int, length: int, access: u32, loc := #caller_location) -> rawptr { ret := impl_MapNamedBufferRange(buffer, offset, length, access); debug_helper(loc, 1, ret, buffer, offset, length, access); return ret } - UnmapNamedBuffer :: #force_inline proc "c" (buffer: u32, loc := #caller_location) -> bool { ret := impl_UnmapNamedBuffer(buffer); debug_helper(loc, 1, ret, buffer); return ret } - FlushMappedNamedBufferRange :: #force_inline proc "c" (buffer: u32, offset: int, length: int, loc := #caller_location) { impl_FlushMappedNamedBufferRange(buffer, offset, length); debug_helper(loc, 0, buffer, offset, length) } - GetNamedBufferParameteriv :: #force_inline proc "c" (buffer: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetNamedBufferParameteriv(buffer, pname, params); debug_helper(loc, 0, buffer, pname, params) } - GetNamedBufferParameteri64v :: #force_inline proc "c" (buffer: u32, pname: u32, params: [^]i64, loc := #caller_location) { impl_GetNamedBufferParameteri64v(buffer, pname, params); debug_helper(loc, 0, buffer, pname, params) } - GetNamedBufferPointerv :: #force_inline proc "c" (buffer: u32, pname: u32, params: [^]rawptr, loc := #caller_location) { impl_GetNamedBufferPointerv(buffer, pname, params); debug_helper(loc, 0, buffer, pname, params) } - GetNamedBufferSubData :: #force_inline proc "c" (buffer: u32, offset: int, size: int, data: rawptr, loc := #caller_location) { impl_GetNamedBufferSubData(buffer, offset, size, data); debug_helper(loc, 0, buffer, offset, size, data) } - CreateFramebuffers :: #force_inline proc "c" (n: i32, framebuffers: [^]u32, loc := #caller_location) { impl_CreateFramebuffers(n, framebuffers); debug_helper(loc, 0, n, framebuffers) } - NamedFramebufferRenderbuffer :: #force_inline proc "c" (framebuffer: u32, attachment: u32, renderbuffertarget: u32, renderbuffer: u32, loc := #caller_location) { impl_NamedFramebufferRenderbuffer(framebuffer, attachment, renderbuffertarget, renderbuffer); debug_helper(loc, 0, framebuffer, attachment, renderbuffertarget, renderbuffer) } - NamedFramebufferParameteri :: #force_inline proc "c" (framebuffer: u32, pname: u32, param: i32, loc := #caller_location) { impl_NamedFramebufferParameteri(framebuffer, pname, param); debug_helper(loc, 0, framebuffer, pname, param) } - NamedFramebufferTexture :: #force_inline proc "c" (framebuffer: u32, attachment: u32, texture: u32, level: i32, loc := #caller_location) { impl_NamedFramebufferTexture(framebuffer, attachment, texture, level); debug_helper(loc, 0, framebuffer, attachment, texture, level) } - NamedFramebufferTextureLayer :: #force_inline proc "c" (framebuffer: u32, attachment: u32, texture: u32, level: i32, layer: i32, loc := #caller_location) { impl_NamedFramebufferTextureLayer(framebuffer, attachment, texture, level, layer); debug_helper(loc, 0, framebuffer, attachment, texture, level, layer) } - NamedFramebufferDrawBuffer :: #force_inline proc "c" (framebuffer: u32, buf: u32, loc := #caller_location) { impl_NamedFramebufferDrawBuffer(framebuffer, buf); debug_helper(loc, 0, framebuffer, buf) } - NamedFramebufferDrawBuffers :: #force_inline proc "c" (framebuffer: u32, n: i32, bufs: [^]u32, loc := #caller_location) { impl_NamedFramebufferDrawBuffers(framebuffer, n, bufs); debug_helper(loc, 0, framebuffer, n, bufs) } - NamedFramebufferReadBuffer :: #force_inline proc "c" (framebuffer: u32, src: u32, loc := #caller_location) { impl_NamedFramebufferReadBuffer(framebuffer, src); debug_helper(loc, 0, framebuffer, src) } - InvalidateNamedFramebufferData :: #force_inline proc "c" (framebuffer: u32, numAttachments: i32, attachments: [^]u32, loc := #caller_location) { impl_InvalidateNamedFramebufferData(framebuffer, numAttachments, attachments); debug_helper(loc, 0, framebuffer, numAttachments, attachments) } - InvalidateNamedFramebufferSubData :: #force_inline proc "c" (framebuffer: u32, numAttachments: i32, attachments: [^]u32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_InvalidateNamedFramebufferSubData(framebuffer, numAttachments, attachments, x, y, width, height); debug_helper(loc, 0, framebuffer, numAttachments, attachments, x, y, width, height) } - ClearNamedFramebufferiv :: #force_inline proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^i32, loc := #caller_location) { impl_ClearNamedFramebufferiv(framebuffer, buffer, drawbuffer, value); debug_helper(loc, 0, framebuffer, buffer, drawbuffer, value) } - ClearNamedFramebufferuiv :: #force_inline proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^u32, loc := #caller_location) { impl_ClearNamedFramebufferuiv(framebuffer, buffer, drawbuffer, value); debug_helper(loc, 0, framebuffer, buffer, drawbuffer, value) } - ClearNamedFramebufferfv :: #force_inline proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^f32, loc := #caller_location) { impl_ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value); debug_helper(loc, 0, framebuffer, buffer, drawbuffer, value) } - ClearNamedFramebufferfi :: #force_inline proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, depth: f32, stencil: i32, loc := #caller_location) { impl_ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil); debug_helper(loc, 0, framebuffer, buffer, drawbuffer, depth, stencil) } - BlitNamedFramebuffer :: #force_inline proc "c" (readFramebuffer: u32, drawFramebuffer: u32, srcX0: i32, srcY0: i32, srcX1: i32, srcY1: i32, dstX0: i32, dstY0: i32, dstX1: i32, dstY1: i32, mask: u32, filter: u32, loc := #caller_location) { impl_BlitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); debug_helper(loc, 0, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) } - CheckNamedFramebufferStatus :: #force_inline proc "c" (framebuffer: u32, target: u32, loc := #caller_location) -> u32 { ret := impl_CheckNamedFramebufferStatus(framebuffer, target); debug_helper(loc, 1, ret, framebuffer, target); return ret } - GetNamedFramebufferParameteriv :: #force_inline proc "c" (framebuffer: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_GetNamedFramebufferParameteriv(framebuffer, pname, param); debug_helper(loc, 0, framebuffer, pname, param) } - GetNamedFramebufferAttachmentParameteriv :: #force_inline proc "c" (framebuffer: u32, attachment: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetNamedFramebufferAttachmentParameteriv(framebuffer, attachment, pname, params); debug_helper(loc, 0, framebuffer, attachment, pname, params) } - CreateRenderbuffers :: #force_inline proc "c" (n: i32, renderbuffers: [^]u32, loc := #caller_location) { impl_CreateRenderbuffers(n, renderbuffers); debug_helper(loc, 0, n, renderbuffers) } - NamedRenderbufferStorage :: #force_inline proc "c" (renderbuffer: u32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_NamedRenderbufferStorage(renderbuffer, internalformat, width, height); debug_helper(loc, 0, renderbuffer, internalformat, width, height) } - NamedRenderbufferStorageMultisample :: #force_inline proc "c" (renderbuffer: u32, samples: i32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_NamedRenderbufferStorageMultisample(renderbuffer, samples, internalformat, width, height); debug_helper(loc, 0, renderbuffer, samples, internalformat, width, height) } - GetNamedRenderbufferParameteriv :: #force_inline proc "c" (renderbuffer: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetNamedRenderbufferParameteriv(renderbuffer, pname, params); debug_helper(loc, 0, renderbuffer, pname, params) } - CreateTextures :: #force_inline proc "c" (target: u32, n: i32, textures: [^]u32, loc := #caller_location) { impl_CreateTextures(target, n, textures); debug_helper(loc, 0, target, n, textures) } - TextureBuffer :: #force_inline proc "c" (texture: u32, internalformat: u32, buffer: u32, loc := #caller_location) { impl_TextureBuffer(texture, internalformat, buffer); debug_helper(loc, 0, texture, internalformat, buffer) } - TextureBufferRange :: #force_inline proc "c" (texture: u32, internalformat: u32, buffer: u32, offset: int, size: int, loc := #caller_location) { impl_TextureBufferRange(texture, internalformat, buffer, offset, size); debug_helper(loc, 0, texture, internalformat, buffer, offset, size) } - TextureStorage1D :: #force_inline proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, loc := #caller_location) { impl_TextureStorage1D(texture, levels, internalformat, width); debug_helper(loc, 0, texture, levels, internalformat, width) } - TextureStorage2D :: #force_inline proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_TextureStorage2D(texture, levels, internalformat, width, height); debug_helper(loc, 0, texture, levels, internalformat, width, height) } - TextureStorage3D :: #force_inline proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, height: i32, depth: i32, loc := #caller_location) { impl_TextureStorage3D(texture, levels, internalformat, width, height, depth); debug_helper(loc, 0, texture, levels, internalformat, width, height, depth) } - TextureStorage2DMultisample :: #force_inline proc "c" (texture: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TextureStorage2DMultisample(texture, samples, internalformat, width, height, fixedsamplelocations); debug_helper(loc, 0, texture, samples, internalformat, width, height, fixedsamplelocations) } - TextureStorage3DMultisample :: #force_inline proc "c" (texture: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TextureStorage3DMultisample(texture, samples, internalformat, width, height, depth, fixedsamplelocations); debug_helper(loc, 0, texture, samples, internalformat, width, height, depth, fixedsamplelocations) } - TextureSubImage1D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TextureSubImage1D(texture, level, xoffset, width, format, type, pixels); debug_helper(loc, 0, texture, level, xoffset, width, format, type, pixels) } - TextureSubImage2D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, type, pixels); debug_helper(loc, 0, texture, level, xoffset, yoffset, width, height, format, type, pixels) } - TextureSubImage3D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } - CompressedTextureSubImage1D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTextureSubImage1D(texture, level, xoffset, width, format, imageSize, data); debug_helper(loc, 0, texture, level, xoffset, width, format, imageSize, data) } - CompressedTextureSubImage2D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, imageSize, data); debug_helper(loc, 0, texture, level, xoffset, yoffset, width, height, format, imageSize, data) } - CompressedTextureSubImage3D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) } - CopyTextureSubImage1D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32, loc := #caller_location) { impl_CopyTextureSubImage1D(texture, level, xoffset, x, y, width); debug_helper(loc, 0, texture, level, xoffset, x, y, width) } - CopyTextureSubImage2D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_CopyTextureSubImage2D(texture, level, xoffset, yoffset, x, y, width, height); debug_helper(loc, 0, texture, level, xoffset, yoffset, x, y, width, height) } - CopyTextureSubImage3D :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_CopyTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, x, y, width, height); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, x, y, width, height) } - TextureParameterf :: #force_inline proc "c" (texture: u32, pname: u32, param: f32, loc := #caller_location) { impl_TextureParameterf(texture, pname, param); debug_helper(loc, 0, texture, pname, param) } - TextureParameterfv :: #force_inline proc "c" (texture: u32, pname: u32, param: ^f32, loc := #caller_location) { impl_TextureParameterfv(texture, pname, param); debug_helper(loc, 0, texture, pname, param) } - TextureParameteri :: #force_inline proc "c" (texture: u32, pname: u32, param: i32, loc := #caller_location) { impl_TextureParameteri(texture, pname, param); debug_helper(loc, 0, texture, pname, param) } - TextureParameterIiv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_TextureParameterIiv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } - TextureParameterIuiv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_TextureParameterIuiv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } - TextureParameteriv :: #force_inline proc "c" (texture: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_TextureParameteriv(texture, pname, param); debug_helper(loc, 0, texture, pname, param) } - GenerateTextureMipmap :: #force_inline proc "c" (texture: u32, loc := #caller_location) { impl_GenerateTextureMipmap(texture); debug_helper(loc, 0, texture) } - BindTextureUnit :: #force_inline proc "c" (unit: u32, texture: u32, loc := #caller_location) { impl_BindTextureUnit(unit, texture); debug_helper(loc, 0, unit, texture) } - GetTextureImage :: #force_inline proc "c" (texture: u32, level: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetTextureImage(texture, level, format, type, bufSize, pixels); debug_helper(loc, 0, texture, level, format, type, bufSize, pixels) } - GetCompressedTextureImage :: #force_inline proc "c" (texture: u32, level: i32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetCompressedTextureImage(texture, level, bufSize, pixels); debug_helper(loc, 0, texture, level, bufSize, pixels) } - GetTextureLevelParameterfv :: #force_inline proc "c" (texture: u32, level: i32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetTextureLevelParameterfv(texture, level, pname, params); debug_helper(loc, 0, texture, level, pname, params) } - GetTextureLevelParameteriv :: #force_inline proc "c" (texture: u32, level: i32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTextureLevelParameteriv(texture, level, pname, params); debug_helper(loc, 0, texture, level, pname, params) } - GetTextureParameterfv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetTextureParameterfv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } - GetTextureParameterIiv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTextureParameterIiv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } - GetTextureParameterIuiv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetTextureParameterIuiv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } - GetTextureParameteriv :: #force_inline proc "c" (texture: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTextureParameteriv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } - CreateVertexArrays :: #force_inline proc "c" (n: i32, arrays: [^]u32, loc := #caller_location) { impl_CreateVertexArrays(n, arrays); debug_helper(loc, 0, n, arrays) } - DisableVertexArrayAttrib :: #force_inline proc "c" (vaobj: u32, index: u32, loc := #caller_location) { impl_DisableVertexArrayAttrib(vaobj, index); debug_helper(loc, 0, vaobj, index) } - EnableVertexArrayAttrib :: #force_inline proc "c" (vaobj: u32, index: u32, loc := #caller_location) { impl_EnableVertexArrayAttrib(vaobj, index); debug_helper(loc, 0, vaobj, index) } - VertexArrayElementBuffer :: #force_inline proc "c" (vaobj: u32, buffer: u32, loc := #caller_location) { impl_VertexArrayElementBuffer(vaobj, buffer); debug_helper(loc, 0, vaobj, buffer) } - VertexArrayVertexBuffer :: #force_inline proc "c" (vaobj: u32, bindingindex: u32, buffer: u32, offset: int, stride: i32, loc := #caller_location) { impl_VertexArrayVertexBuffer(vaobj, bindingindex, buffer, offset, stride); debug_helper(loc, 0, vaobj, bindingindex, buffer, offset, stride) } - VertexArrayVertexBuffers :: #force_inline proc "c" (vaobj: u32, first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, strides: [^]i32, loc := #caller_location) { impl_VertexArrayVertexBuffers(vaobj, first, count, buffers, offsets, strides); debug_helper(loc, 0, vaobj, first, count, buffers, offsets, strides) } - VertexArrayAttribBinding :: #force_inline proc "c" (vaobj: u32, attribindex: u32, bindingindex: u32, loc := #caller_location) { impl_VertexArrayAttribBinding(vaobj, attribindex, bindingindex); debug_helper(loc, 0, vaobj, attribindex, bindingindex) } - VertexArrayAttribFormat :: #force_inline proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, normalized: bool, relativeoffset: u32, loc := #caller_location) { impl_VertexArrayAttribFormat(vaobj, attribindex, size, type, normalized, relativeoffset); debug_helper(loc, 0, vaobj, attribindex, size, type, normalized, relativeoffset) } - VertexArrayAttribIFormat :: #force_inline proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, relativeoffset: u32, loc := #caller_location) { impl_VertexArrayAttribIFormat(vaobj, attribindex, size, type, relativeoffset); debug_helper(loc, 0, vaobj, attribindex, size, type, relativeoffset) } - VertexArrayAttribLFormat :: #force_inline proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, relativeoffset: u32, loc := #caller_location) { impl_VertexArrayAttribLFormat(vaobj, attribindex, size, type, relativeoffset); debug_helper(loc, 0, vaobj, attribindex, size, type, relativeoffset) } - VertexArrayBindingDivisor :: #force_inline proc "c" (vaobj: u32, bindingindex: u32, divisor: u32, loc := #caller_location) { impl_VertexArrayBindingDivisor(vaobj, bindingindex, divisor); debug_helper(loc, 0, vaobj, bindingindex, divisor) } - GetVertexArrayiv :: #force_inline proc "c" (vaobj: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_GetVertexArrayiv(vaobj, pname, param); debug_helper(loc, 0, vaobj, pname, param) } - GetVertexArrayIndexediv :: #force_inline proc "c" (vaobj: u32, index: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_GetVertexArrayIndexediv(vaobj, index, pname, param); debug_helper(loc, 0, vaobj, index, pname, param) } - GetVertexArrayIndexed64iv :: #force_inline proc "c" (vaobj: u32, index: u32, pname: u32, param: ^i64, loc := #caller_location) { impl_GetVertexArrayIndexed64iv(vaobj, index, pname, param); debug_helper(loc, 0, vaobj, index, pname, param) } - CreateSamplers :: #force_inline proc "c" (n: i32, samplers: [^]u32, loc := #caller_location) { impl_CreateSamplers(n, samplers); debug_helper(loc, 0, n, samplers) } - CreateProgramPipelines :: #force_inline proc "c" (n: i32, pipelines: [^]u32, loc := #caller_location) { impl_CreateProgramPipelines(n, pipelines); debug_helper(loc, 0, n, pipelines) } - CreateQueries :: #force_inline proc "c" (target: u32, n: i32, ids: [^]u32, loc := #caller_location) { impl_CreateQueries(target, n, ids); debug_helper(loc, 0, target, n, ids) } - GetQueryBufferObjecti64v :: #force_inline proc "c" (id: u32, buffer: u32, pname: u32, offset: int, loc := #caller_location) { impl_GetQueryBufferObjecti64v(id, buffer, pname, offset); debug_helper(loc, 0, id, buffer, pname, offset) } - GetQueryBufferObjectiv :: #force_inline proc "c" (id: u32, buffer: u32, pname: u32, offset: int, loc := #caller_location) { impl_GetQueryBufferObjectiv(id, buffer, pname, offset); debug_helper(loc, 0, id, buffer, pname, offset) } - GetQueryBufferObjectui64v :: #force_inline proc "c" (id: u32, buffer: u32, pname: u32, offset: int, loc := #caller_location) { impl_GetQueryBufferObjectui64v(id, buffer, pname, offset); debug_helper(loc, 0, id, buffer, pname, offset) } - GetQueryBufferObjectuiv :: #force_inline proc "c" (id: u32, buffer: u32, pname: u32, offset: int, loc := #caller_location) { impl_GetQueryBufferObjectuiv(id, buffer, pname, offset); debug_helper(loc, 0, id, buffer, pname, offset) } - MemoryBarrierByRegion :: #force_inline proc "c" (barriers: u32, loc := #caller_location) { impl_MemoryBarrierByRegion(barriers); debug_helper(loc, 0, barriers) } - GetTextureSubImage :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetTextureSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels) } - GetCompressedTextureSubImage :: #force_inline proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetCompressedTextureSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels) } - GetGraphicsResetStatus :: #force_inline proc "c" (loc := #caller_location) -> u32 { ret := impl_GetGraphicsResetStatus(); debug_helper(loc, 1, ret); return ret } - GetnCompressedTexImage :: #force_inline proc "c" (target: u32, lod: i32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetnCompressedTexImage(target, lod, bufSize, pixels); debug_helper(loc, 0, target, lod, bufSize, pixels) } - GetnTexImage :: #force_inline proc "c" (target: u32, level: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetnTexImage(target, level, format, type, bufSize, pixels); debug_helper(loc, 0, target, level, format, type, bufSize, pixels) } - GetnUniformdv :: #force_inline proc "c" (program: u32, location: i32, bufSize: i32, params: [^]f64, loc := #caller_location) { impl_GetnUniformdv(program, location, bufSize, params); debug_helper(loc, 0, program, location, bufSize, params) } - GetnUniformfv :: #force_inline proc "c" (program: u32, location: i32, bufSize: i32, params: [^]f32, loc := #caller_location) { impl_GetnUniformfv(program, location, bufSize, params); debug_helper(loc, 0, program, location, bufSize, params) } - GetnUniformiv :: #force_inline proc "c" (program: u32, location: i32, bufSize: i32, params: [^]i32, loc := #caller_location) { impl_GetnUniformiv(program, location, bufSize, params); debug_helper(loc, 0, program, location, bufSize, params) } - GetnUniformuiv :: #force_inline proc "c" (program: u32, location: i32, bufSize: i32, params: [^]u32, loc := #caller_location) { impl_GetnUniformuiv(program, location, bufSize, params); debug_helper(loc, 0, program, location, bufSize, params) } - ReadnPixels :: #force_inline proc "c" (x: i32, y: i32, width: i32, height: i32, format: u32, type: u32, bufSize: i32, data: rawptr, loc := #caller_location) { impl_ReadnPixels(x, y, width, height, format, type, bufSize, data); debug_helper(loc, 0, x, y, width, height, format, type, bufSize, data) } - GetnMapdv :: #force_inline proc "c" (target: u32, query: u32, bufSize: i32, v: [^]f64, loc := #caller_location) { impl_GetnMapdv(target, query, bufSize, v); debug_helper(loc, 0, target, query, bufSize, v) } - GetnMapfv :: #force_inline proc "c" (target: u32, query: u32, bufSize: i32, v: [^]f32, loc := #caller_location) { impl_GetnMapfv(target, query, bufSize, v); debug_helper(loc, 0, target, query, bufSize, v) } - GetnMapiv :: #force_inline proc "c" (target: u32, query: u32, bufSize: i32, v: [^]i32, loc := #caller_location) { impl_GetnMapiv(target, query, bufSize, v); debug_helper(loc, 0, target, query, bufSize, v) } - GetnPixelMapusv :: #force_inline proc "c" (map_: u32, bufSize: i32, values: [^]u16, loc := #caller_location) { impl_GetnPixelMapusv(map_, bufSize, values); debug_helper(loc, 0, map_, bufSize, values) } - GetnPixelMapfv :: #force_inline proc "c" (map_: u32, bufSize: i32, values: [^]f32, loc := #caller_location) { impl_GetnPixelMapfv(map_, bufSize, values); debug_helper(loc, 0, map_, bufSize, values) } - GetnPixelMapuiv :: #force_inline proc "c" (map_: u32, bufSize: i32, values: [^]u32, loc := #caller_location) { impl_GetnPixelMapuiv(map_, bufSize, values); debug_helper(loc, 0, map_, bufSize, values) } - GetnPolygonStipple :: #force_inline proc "c" (bufSize: i32, pattern: [^]u8, loc := #caller_location) { impl_GetnPolygonStipple(bufSize, pattern); debug_helper(loc, 0, bufSize, pattern) } - GetnColorTable :: #force_inline proc "c" (target: u32, format: u32, type: u32, bufSize: i32, table: rawptr, loc := #caller_location) { impl_GetnColorTable(target, format, type, bufSize, table); debug_helper(loc, 0, target, format, type, bufSize, table) } - GetnConvolutionFilter :: #force_inline proc "c" (target: u32, format: u32, type: u32, bufSize: i32, image: rawptr, loc := #caller_location) { impl_GetnConvolutionFilter(target, format, type, bufSize, image); debug_helper(loc, 0, target, format, type, bufSize, image) } - GetnSeparableFilter :: #force_inline proc "c" (target: u32, format: u32, type: u32, rowBufSize: i32, row: rawptr, columnBufSize: i32, column: rawptr, span: rawptr, loc := #caller_location) { impl_GetnSeparableFilter(target, format, type, rowBufSize, row, columnBufSize, column, span); debug_helper(loc, 0, target, format, type, rowBufSize, row, columnBufSize, column, span) } - GetnHistogram :: #force_inline proc "c" (target: u32, reset: bool, format: u32, type: u32, bufSize: i32, values: rawptr, loc := #caller_location) { impl_GetnHistogram(target, reset, format, type, bufSize, values); debug_helper(loc, 0, target, reset, format, type, bufSize, values) } - GetnMinmax :: #force_inline proc "c" (target: u32, reset: bool, format: u32, type: u32, bufSize: i32, values: rawptr, loc := #caller_location) { impl_GetnMinmax(target, reset, format, type, bufSize, values); debug_helper(loc, 0, target, reset, format, type, bufSize, values) } - TextureBarrier :: #force_inline proc "c" (loc := #caller_location) { impl_TextureBarrier(); debug_helper(loc, 0) } - GetUnsignedBytevEXT :: #force_inline proc "c" (pname: u32, data: ^byte, loc := #caller_location) { impl_GetUnsignedBytevEXT(pname, data); debug_helper(loc, 0, pname, data) } - TexPageCommitmentARB :: #force_inline proc "c"(target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, commit: bool, loc := #caller_location) { impl_TexPageCommitmentARB(target, level, xoffset, yoffset, zoffset, width, height, depth, commit); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, width, height, depth, commit) } + ClipControl :: proc "c" (origin: u32, depth: u32, loc := #caller_location) { impl_ClipControl(origin, depth); debug_helper(loc, 0, origin, depth) } + CreateTransformFeedbacks :: proc "c" (n: i32, ids: [^]u32, loc := #caller_location) { impl_CreateTransformFeedbacks(n, ids); debug_helper(loc, 0, n, ids) } + TransformFeedbackBufferBase :: proc "c" (xfb: u32, index: u32, buffer: u32, loc := #caller_location) { impl_TransformFeedbackBufferBase(xfb, index, buffer); debug_helper(loc, 0, xfb, index, buffer) } + TransformFeedbackBufferRange :: proc "c" (xfb: u32, index: u32, buffer: u32, offset: int, size: int, loc := #caller_location) { impl_TransformFeedbackBufferRange(xfb, index, buffer, offset, size); debug_helper(loc, 0, xfb, index, buffer, offset, size) } + GetTransformFeedbackiv :: proc "c" (xfb: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_GetTransformFeedbackiv(xfb, pname, param); debug_helper(loc, 0, xfb, pname, param) } + GetTransformFeedbacki_v :: proc "c" (xfb: u32, pname: u32, index: u32, param: ^i32, loc := #caller_location) { impl_GetTransformFeedbacki_v(xfb, pname, index, param); debug_helper(loc, 0, xfb, pname, index, param) } + GetTransformFeedbacki64_v :: proc "c" (xfb: u32, pname: u32, index: u32, param: ^i64, loc := #caller_location) { impl_GetTransformFeedbacki64_v(xfb, pname, index, param); debug_helper(loc, 0, xfb, pname, index, param) } + CreateBuffers :: proc "c" (n: i32, buffers: [^]u32, loc := #caller_location) { impl_CreateBuffers(n, buffers); debug_helper(loc, 0, n, buffers) } + NamedBufferStorage :: proc "c" (buffer: u32, size: int, data: rawptr, flags: u32, loc := #caller_location) { impl_NamedBufferStorage(buffer, size, data, flags); debug_helper(loc, 0, buffer, size, data, flags) } + NamedBufferData :: proc "c" (buffer: u32, size: int, data: rawptr, usage: u32, loc := #caller_location) { impl_NamedBufferData(buffer, size, data, usage); debug_helper(loc, 0, buffer, size, data, usage) } + NamedBufferSubData :: proc "c" (buffer: u32, offset: int, size: int, data: rawptr, loc := #caller_location) { impl_NamedBufferSubData(buffer, offset, size, data); debug_helper(loc, 0, buffer, offset, size, data) } + CopyNamedBufferSubData :: proc "c" (readBuffer: u32, writeBuffer: u32, readOffset: int, writeOffset: int, size: int, loc := #caller_location) { impl_CopyNamedBufferSubData(readBuffer, writeBuffer, readOffset, writeOffset, size); debug_helper(loc, 0, readBuffer, writeBuffer, readOffset, writeOffset, size) } + ClearNamedBufferData :: proc "c" (buffer: u32, internalformat: u32, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearNamedBufferData(buffer, internalformat, format, type, data); debug_helper(loc, 0, buffer, internalformat, format, type, data) } + ClearNamedBufferSubData :: proc "c" (buffer: u32, internalformat: u32, offset: int, size: int, format: u32, type: u32, data: rawptr, loc := #caller_location) { impl_ClearNamedBufferSubData(buffer, internalformat, offset, size, format, type, data); debug_helper(loc, 0, buffer, internalformat, offset, size, format, type, data) } + MapNamedBuffer :: proc "c" (buffer: u32, access: u32, loc := #caller_location) -> rawptr { ret := impl_MapNamedBuffer(buffer, access); debug_helper(loc, 1, ret, buffer, access); return ret } + MapNamedBufferRange :: proc "c" (buffer: u32, offset: int, length: int, access: u32, loc := #caller_location) -> rawptr { ret := impl_MapNamedBufferRange(buffer, offset, length, access); debug_helper(loc, 1, ret, buffer, offset, length, access); return ret } + UnmapNamedBuffer :: proc "c" (buffer: u32, loc := #caller_location) -> bool { ret := impl_UnmapNamedBuffer(buffer); debug_helper(loc, 1, ret, buffer); return ret } + FlushMappedNamedBufferRange :: proc "c" (buffer: u32, offset: int, length: int, loc := #caller_location) { impl_FlushMappedNamedBufferRange(buffer, offset, length); debug_helper(loc, 0, buffer, offset, length) } + GetNamedBufferParameteriv :: proc "c" (buffer: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetNamedBufferParameteriv(buffer, pname, params); debug_helper(loc, 0, buffer, pname, params) } + GetNamedBufferParameteri64v :: proc "c" (buffer: u32, pname: u32, params: [^]i64, loc := #caller_location) { impl_GetNamedBufferParameteri64v(buffer, pname, params); debug_helper(loc, 0, buffer, pname, params) } + GetNamedBufferPointerv :: proc "c" (buffer: u32, pname: u32, params: [^]rawptr, loc := #caller_location) { impl_GetNamedBufferPointerv(buffer, pname, params); debug_helper(loc, 0, buffer, pname, params) } + GetNamedBufferSubData :: proc "c" (buffer: u32, offset: int, size: int, data: rawptr, loc := #caller_location) { impl_GetNamedBufferSubData(buffer, offset, size, data); debug_helper(loc, 0, buffer, offset, size, data) } + CreateFramebuffers :: proc "c" (n: i32, framebuffers: [^]u32, loc := #caller_location) { impl_CreateFramebuffers(n, framebuffers); debug_helper(loc, 0, n, framebuffers) } + NamedFramebufferRenderbuffer :: proc "c" (framebuffer: u32, attachment: u32, renderbuffertarget: u32, renderbuffer: u32, loc := #caller_location) { impl_NamedFramebufferRenderbuffer(framebuffer, attachment, renderbuffertarget, renderbuffer); debug_helper(loc, 0, framebuffer, attachment, renderbuffertarget, renderbuffer) } + NamedFramebufferParameteri :: proc "c" (framebuffer: u32, pname: u32, param: i32, loc := #caller_location) { impl_NamedFramebufferParameteri(framebuffer, pname, param); debug_helper(loc, 0, framebuffer, pname, param) } + NamedFramebufferTexture :: proc "c" (framebuffer: u32, attachment: u32, texture: u32, level: i32, loc := #caller_location) { impl_NamedFramebufferTexture(framebuffer, attachment, texture, level); debug_helper(loc, 0, framebuffer, attachment, texture, level) } + NamedFramebufferTextureLayer :: proc "c" (framebuffer: u32, attachment: u32, texture: u32, level: i32, layer: i32, loc := #caller_location) { impl_NamedFramebufferTextureLayer(framebuffer, attachment, texture, level, layer); debug_helper(loc, 0, framebuffer, attachment, texture, level, layer) } + NamedFramebufferDrawBuffer :: proc "c" (framebuffer: u32, buf: u32, loc := #caller_location) { impl_NamedFramebufferDrawBuffer(framebuffer, buf); debug_helper(loc, 0, framebuffer, buf) } + NamedFramebufferDrawBuffers :: proc "c" (framebuffer: u32, n: i32, bufs: [^]u32, loc := #caller_location) { impl_NamedFramebufferDrawBuffers(framebuffer, n, bufs); debug_helper(loc, 0, framebuffer, n, bufs) } + NamedFramebufferReadBuffer :: proc "c" (framebuffer: u32, src: u32, loc := #caller_location) { impl_NamedFramebufferReadBuffer(framebuffer, src); debug_helper(loc, 0, framebuffer, src) } + InvalidateNamedFramebufferData :: proc "c" (framebuffer: u32, numAttachments: i32, attachments: [^]u32, loc := #caller_location) { impl_InvalidateNamedFramebufferData(framebuffer, numAttachments, attachments); debug_helper(loc, 0, framebuffer, numAttachments, attachments) } + InvalidateNamedFramebufferSubData :: proc "c" (framebuffer: u32, numAttachments: i32, attachments: [^]u32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_InvalidateNamedFramebufferSubData(framebuffer, numAttachments, attachments, x, y, width, height); debug_helper(loc, 0, framebuffer, numAttachments, attachments, x, y, width, height) } + ClearNamedFramebufferiv :: proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^i32, loc := #caller_location) { impl_ClearNamedFramebufferiv(framebuffer, buffer, drawbuffer, value); debug_helper(loc, 0, framebuffer, buffer, drawbuffer, value) } + ClearNamedFramebufferuiv :: proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^u32, loc := #caller_location) { impl_ClearNamedFramebufferuiv(framebuffer, buffer, drawbuffer, value); debug_helper(loc, 0, framebuffer, buffer, drawbuffer, value) } + ClearNamedFramebufferfv :: proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, value: ^f32, loc := #caller_location) { impl_ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value); debug_helper(loc, 0, framebuffer, buffer, drawbuffer, value) } + ClearNamedFramebufferfi :: proc "c" (framebuffer: u32, buffer: u32, drawbuffer: i32, depth: f32, stencil: i32, loc := #caller_location) { impl_ClearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil); debug_helper(loc, 0, framebuffer, buffer, drawbuffer, depth, stencil) } + BlitNamedFramebuffer :: proc "c" (readFramebuffer: u32, drawFramebuffer: u32, srcX0: i32, srcY0: i32, srcX1: i32, srcY1: i32, dstX0: i32, dstY0: i32, dstX1: i32, dstY1: i32, mask: u32, filter: u32, loc := #caller_location) { impl_BlitNamedFramebuffer(readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); debug_helper(loc, 0, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) } + CheckNamedFramebufferStatus :: proc "c" (framebuffer: u32, target: u32, loc := #caller_location) -> u32 { ret := impl_CheckNamedFramebufferStatus(framebuffer, target); debug_helper(loc, 1, ret, framebuffer, target); return ret } + GetNamedFramebufferParameteriv :: proc "c" (framebuffer: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_GetNamedFramebufferParameteriv(framebuffer, pname, param); debug_helper(loc, 0, framebuffer, pname, param) } + GetNamedFramebufferAttachmentParameteriv :: proc "c" (framebuffer: u32, attachment: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetNamedFramebufferAttachmentParameteriv(framebuffer, attachment, pname, params); debug_helper(loc, 0, framebuffer, attachment, pname, params) } + CreateRenderbuffers :: proc "c" (n: i32, renderbuffers: [^]u32, loc := #caller_location) { impl_CreateRenderbuffers(n, renderbuffers); debug_helper(loc, 0, n, renderbuffers) } + NamedRenderbufferStorage :: proc "c" (renderbuffer: u32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_NamedRenderbufferStorage(renderbuffer, internalformat, width, height); debug_helper(loc, 0, renderbuffer, internalformat, width, height) } + NamedRenderbufferStorageMultisample :: proc "c" (renderbuffer: u32, samples: i32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_NamedRenderbufferStorageMultisample(renderbuffer, samples, internalformat, width, height); debug_helper(loc, 0, renderbuffer, samples, internalformat, width, height) } + GetNamedRenderbufferParameteriv :: proc "c" (renderbuffer: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetNamedRenderbufferParameteriv(renderbuffer, pname, params); debug_helper(loc, 0, renderbuffer, pname, params) } + CreateTextures :: proc "c" (target: u32, n: i32, textures: [^]u32, loc := #caller_location) { impl_CreateTextures(target, n, textures); debug_helper(loc, 0, target, n, textures) } + TextureBuffer :: proc "c" (texture: u32, internalformat: u32, buffer: u32, loc := #caller_location) { impl_TextureBuffer(texture, internalformat, buffer); debug_helper(loc, 0, texture, internalformat, buffer) } + TextureBufferRange :: proc "c" (texture: u32, internalformat: u32, buffer: u32, offset: int, size: int, loc := #caller_location) { impl_TextureBufferRange(texture, internalformat, buffer, offset, size); debug_helper(loc, 0, texture, internalformat, buffer, offset, size) } + TextureStorage1D :: proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, loc := #caller_location) { impl_TextureStorage1D(texture, levels, internalformat, width); debug_helper(loc, 0, texture, levels, internalformat, width) } + TextureStorage2D :: proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, height: i32, loc := #caller_location) { impl_TextureStorage2D(texture, levels, internalformat, width, height); debug_helper(loc, 0, texture, levels, internalformat, width, height) } + TextureStorage3D :: proc "c" (texture: u32, levels: i32, internalformat: u32, width: i32, height: i32, depth: i32, loc := #caller_location) { impl_TextureStorage3D(texture, levels, internalformat, width, height, depth); debug_helper(loc, 0, texture, levels, internalformat, width, height, depth) } + TextureStorage2DMultisample :: proc "c" (texture: u32, samples: i32, internalformat: u32, width: i32, height: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TextureStorage2DMultisample(texture, samples, internalformat, width, height, fixedsamplelocations); debug_helper(loc, 0, texture, samples, internalformat, width, height, fixedsamplelocations) } + TextureStorage3DMultisample :: proc "c" (texture: u32, samples: i32, internalformat: u32, width: i32, height: i32, depth: i32, fixedsamplelocations: bool, loc := #caller_location) { impl_TextureStorage3DMultisample(texture, samples, internalformat, width, height, depth, fixedsamplelocations); debug_helper(loc, 0, texture, samples, internalformat, width, height, depth, fixedsamplelocations) } + TextureSubImage1D :: proc "c" (texture: u32, level: i32, xoffset: i32, width: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TextureSubImage1D(texture, level, xoffset, width, format, type, pixels); debug_helper(loc, 0, texture, level, xoffset, width, format, type, pixels) } + TextureSubImage2D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, type, pixels); debug_helper(loc, 0, texture, level, xoffset, yoffset, width, height, format, type, pixels) } + TextureSubImage3D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, pixels: rawptr, loc := #caller_location) { impl_TextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } + CompressedTextureSubImage1D :: proc "c" (texture: u32, level: i32, xoffset: i32, width: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTextureSubImage1D(texture, level, xoffset, width, format, imageSize, data); debug_helper(loc, 0, texture, level, xoffset, width, format, imageSize, data) } + CompressedTextureSubImage2D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, width: i32, height: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, imageSize, data); debug_helper(loc, 0, texture, level, xoffset, yoffset, width, height, format, imageSize, data) } + CompressedTextureSubImage3D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, imageSize: i32, data: rawptr, loc := #caller_location) { impl_CompressedTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) } + CopyTextureSubImage1D :: proc "c" (texture: u32, level: i32, xoffset: i32, x: i32, y: i32, width: i32, loc := #caller_location) { impl_CopyTextureSubImage1D(texture, level, xoffset, x, y, width); debug_helper(loc, 0, texture, level, xoffset, x, y, width) } + CopyTextureSubImage2D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_CopyTextureSubImage2D(texture, level, xoffset, yoffset, x, y, width, height); debug_helper(loc, 0, texture, level, xoffset, yoffset, x, y, width, height) } + CopyTextureSubImage3D :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, x: i32, y: i32, width: i32, height: i32, loc := #caller_location) { impl_CopyTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, x, y, width, height); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, x, y, width, height) } + TextureParameterf :: proc "c" (texture: u32, pname: u32, param: f32, loc := #caller_location) { impl_TextureParameterf(texture, pname, param); debug_helper(loc, 0, texture, pname, param) } + TextureParameterfv :: proc "c" (texture: u32, pname: u32, param: ^f32, loc := #caller_location) { impl_TextureParameterfv(texture, pname, param); debug_helper(loc, 0, texture, pname, param) } + TextureParameteri :: proc "c" (texture: u32, pname: u32, param: i32, loc := #caller_location) { impl_TextureParameteri(texture, pname, param); debug_helper(loc, 0, texture, pname, param) } + TextureParameterIiv :: proc "c" (texture: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_TextureParameterIiv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } + TextureParameterIuiv :: proc "c" (texture: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_TextureParameterIuiv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } + TextureParameteriv :: proc "c" (texture: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_TextureParameteriv(texture, pname, param); debug_helper(loc, 0, texture, pname, param) } + GenerateTextureMipmap :: proc "c" (texture: u32, loc := #caller_location) { impl_GenerateTextureMipmap(texture); debug_helper(loc, 0, texture) } + BindTextureUnit :: proc "c" (unit: u32, texture: u32, loc := #caller_location) { impl_BindTextureUnit(unit, texture); debug_helper(loc, 0, unit, texture) } + GetTextureImage :: proc "c" (texture: u32, level: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetTextureImage(texture, level, format, type, bufSize, pixels); debug_helper(loc, 0, texture, level, format, type, bufSize, pixels) } + GetCompressedTextureImage :: proc "c" (texture: u32, level: i32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetCompressedTextureImage(texture, level, bufSize, pixels); debug_helper(loc, 0, texture, level, bufSize, pixels) } + GetTextureLevelParameterfv :: proc "c" (texture: u32, level: i32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetTextureLevelParameterfv(texture, level, pname, params); debug_helper(loc, 0, texture, level, pname, params) } + GetTextureLevelParameteriv :: proc "c" (texture: u32, level: i32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTextureLevelParameteriv(texture, level, pname, params); debug_helper(loc, 0, texture, level, pname, params) } + GetTextureParameterfv :: proc "c" (texture: u32, pname: u32, params: [^]f32, loc := #caller_location) { impl_GetTextureParameterfv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } + GetTextureParameterIiv :: proc "c" (texture: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTextureParameterIiv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } + GetTextureParameterIuiv :: proc "c" (texture: u32, pname: u32, params: [^]u32, loc := #caller_location) { impl_GetTextureParameterIuiv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } + GetTextureParameteriv :: proc "c" (texture: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetTextureParameteriv(texture, pname, params); debug_helper(loc, 0, texture, pname, params) } + CreateVertexArrays :: proc "c" (n: i32, arrays: [^]u32, loc := #caller_location) { impl_CreateVertexArrays(n, arrays); debug_helper(loc, 0, n, arrays) } + DisableVertexArrayAttrib :: proc "c" (vaobj: u32, index: u32, loc := #caller_location) { impl_DisableVertexArrayAttrib(vaobj, index); debug_helper(loc, 0, vaobj, index) } + EnableVertexArrayAttrib :: proc "c" (vaobj: u32, index: u32, loc := #caller_location) { impl_EnableVertexArrayAttrib(vaobj, index); debug_helper(loc, 0, vaobj, index) } + VertexArrayElementBuffer :: proc "c" (vaobj: u32, buffer: u32, loc := #caller_location) { impl_VertexArrayElementBuffer(vaobj, buffer); debug_helper(loc, 0, vaobj, buffer) } + VertexArrayVertexBuffer :: proc "c" (vaobj: u32, bindingindex: u32, buffer: u32, offset: int, stride: i32, loc := #caller_location) { impl_VertexArrayVertexBuffer(vaobj, bindingindex, buffer, offset, stride); debug_helper(loc, 0, vaobj, bindingindex, buffer, offset, stride) } + VertexArrayVertexBuffers :: proc "c" (vaobj: u32, first: u32, count: i32, buffers: [^]u32, offsets: [^]uintptr, strides: [^]i32, loc := #caller_location) { impl_VertexArrayVertexBuffers(vaobj, first, count, buffers, offsets, strides); debug_helper(loc, 0, vaobj, first, count, buffers, offsets, strides) } + VertexArrayAttribBinding :: proc "c" (vaobj: u32, attribindex: u32, bindingindex: u32, loc := #caller_location) { impl_VertexArrayAttribBinding(vaobj, attribindex, bindingindex); debug_helper(loc, 0, vaobj, attribindex, bindingindex) } + VertexArrayAttribFormat :: proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, normalized: bool, relativeoffset: u32, loc := #caller_location) { impl_VertexArrayAttribFormat(vaobj, attribindex, size, type, normalized, relativeoffset); debug_helper(loc, 0, vaobj, attribindex, size, type, normalized, relativeoffset) } + VertexArrayAttribIFormat :: proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, relativeoffset: u32, loc := #caller_location) { impl_VertexArrayAttribIFormat(vaobj, attribindex, size, type, relativeoffset); debug_helper(loc, 0, vaobj, attribindex, size, type, relativeoffset) } + VertexArrayAttribLFormat :: proc "c" (vaobj: u32, attribindex: u32, size: i32, type: u32, relativeoffset: u32, loc := #caller_location) { impl_VertexArrayAttribLFormat(vaobj, attribindex, size, type, relativeoffset); debug_helper(loc, 0, vaobj, attribindex, size, type, relativeoffset) } + VertexArrayBindingDivisor :: proc "c" (vaobj: u32, bindingindex: u32, divisor: u32, loc := #caller_location) { impl_VertexArrayBindingDivisor(vaobj, bindingindex, divisor); debug_helper(loc, 0, vaobj, bindingindex, divisor) } + GetVertexArrayiv :: proc "c" (vaobj: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_GetVertexArrayiv(vaobj, pname, param); debug_helper(loc, 0, vaobj, pname, param) } + GetVertexArrayIndexediv :: proc "c" (vaobj: u32, index: u32, pname: u32, param: ^i32, loc := #caller_location) { impl_GetVertexArrayIndexediv(vaobj, index, pname, param); debug_helper(loc, 0, vaobj, index, pname, param) } + GetVertexArrayIndexed64iv :: proc "c" (vaobj: u32, index: u32, pname: u32, param: ^i64, loc := #caller_location) { impl_GetVertexArrayIndexed64iv(vaobj, index, pname, param); debug_helper(loc, 0, vaobj, index, pname, param) } + CreateSamplers :: proc "c" (n: i32, samplers: [^]u32, loc := #caller_location) { impl_CreateSamplers(n, samplers); debug_helper(loc, 0, n, samplers) } + CreateProgramPipelines :: proc "c" (n: i32, pipelines: [^]u32, loc := #caller_location) { impl_CreateProgramPipelines(n, pipelines); debug_helper(loc, 0, n, pipelines) } + CreateQueries :: proc "c" (target: u32, n: i32, ids: [^]u32, loc := #caller_location) { impl_CreateQueries(target, n, ids); debug_helper(loc, 0, target, n, ids) } + GetQueryBufferObjecti64v :: proc "c" (id: u32, buffer: u32, pname: u32, offset: int, loc := #caller_location) { impl_GetQueryBufferObjecti64v(id, buffer, pname, offset); debug_helper(loc, 0, id, buffer, pname, offset) } + GetQueryBufferObjectiv :: proc "c" (id: u32, buffer: u32, pname: u32, offset: int, loc := #caller_location) { impl_GetQueryBufferObjectiv(id, buffer, pname, offset); debug_helper(loc, 0, id, buffer, pname, offset) } + GetQueryBufferObjectui64v :: proc "c" (id: u32, buffer: u32, pname: u32, offset: int, loc := #caller_location) { impl_GetQueryBufferObjectui64v(id, buffer, pname, offset); debug_helper(loc, 0, id, buffer, pname, offset) } + GetQueryBufferObjectuiv :: proc "c" (id: u32, buffer: u32, pname: u32, offset: int, loc := #caller_location) { impl_GetQueryBufferObjectuiv(id, buffer, pname, offset); debug_helper(loc, 0, id, buffer, pname, offset) } + MemoryBarrierByRegion :: proc "c" (barriers: u32, loc := #caller_location) { impl_MemoryBarrierByRegion(barriers); debug_helper(loc, 0, barriers) } + GetTextureSubImage :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetTextureSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, bufSize, pixels) } + GetCompressedTextureSubImage :: proc "c" (texture: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetCompressedTextureSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels); debug_helper(loc, 0, texture, level, xoffset, yoffset, zoffset, width, height, depth, bufSize, pixels) } + GetGraphicsResetStatus :: proc "c" (loc := #caller_location) -> u32 { ret := impl_GetGraphicsResetStatus(); debug_helper(loc, 1, ret); return ret } + GetnCompressedTexImage :: proc "c" (target: u32, lod: i32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetnCompressedTexImage(target, lod, bufSize, pixels); debug_helper(loc, 0, target, lod, bufSize, pixels) } + GetnTexImage :: proc "c" (target: u32, level: i32, format: u32, type: u32, bufSize: i32, pixels: rawptr, loc := #caller_location) { impl_GetnTexImage(target, level, format, type, bufSize, pixels); debug_helper(loc, 0, target, level, format, type, bufSize, pixels) } + GetnUniformdv :: proc "c" (program: u32, location: i32, bufSize: i32, params: [^]f64, loc := #caller_location) { impl_GetnUniformdv(program, location, bufSize, params); debug_helper(loc, 0, program, location, bufSize, params) } + GetnUniformfv :: proc "c" (program: u32, location: i32, bufSize: i32, params: [^]f32, loc := #caller_location) { impl_GetnUniformfv(program, location, bufSize, params); debug_helper(loc, 0, program, location, bufSize, params) } + GetnUniformiv :: proc "c" (program: u32, location: i32, bufSize: i32, params: [^]i32, loc := #caller_location) { impl_GetnUniformiv(program, location, bufSize, params); debug_helper(loc, 0, program, location, bufSize, params) } + GetnUniformuiv :: proc "c" (program: u32, location: i32, bufSize: i32, params: [^]u32, loc := #caller_location) { impl_GetnUniformuiv(program, location, bufSize, params); debug_helper(loc, 0, program, location, bufSize, params) } + ReadnPixels :: proc "c" (x: i32, y: i32, width: i32, height: i32, format: u32, type: u32, bufSize: i32, data: rawptr, loc := #caller_location) { impl_ReadnPixels(x, y, width, height, format, type, bufSize, data); debug_helper(loc, 0, x, y, width, height, format, type, bufSize, data) } + GetnMapdv :: proc "c" (target: u32, query: u32, bufSize: i32, v: [^]f64, loc := #caller_location) { impl_GetnMapdv(target, query, bufSize, v); debug_helper(loc, 0, target, query, bufSize, v) } + GetnMapfv :: proc "c" (target: u32, query: u32, bufSize: i32, v: [^]f32, loc := #caller_location) { impl_GetnMapfv(target, query, bufSize, v); debug_helper(loc, 0, target, query, bufSize, v) } + GetnMapiv :: proc "c" (target: u32, query: u32, bufSize: i32, v: [^]i32, loc := #caller_location) { impl_GetnMapiv(target, query, bufSize, v); debug_helper(loc, 0, target, query, bufSize, v) } + GetnPixelMapusv :: proc "c" (map_: u32, bufSize: i32, values: [^]u16, loc := #caller_location) { impl_GetnPixelMapusv(map_, bufSize, values); debug_helper(loc, 0, map_, bufSize, values) } + GetnPixelMapfv :: proc "c" (map_: u32, bufSize: i32, values: [^]f32, loc := #caller_location) { impl_GetnPixelMapfv(map_, bufSize, values); debug_helper(loc, 0, map_, bufSize, values) } + GetnPixelMapuiv :: proc "c" (map_: u32, bufSize: i32, values: [^]u32, loc := #caller_location) { impl_GetnPixelMapuiv(map_, bufSize, values); debug_helper(loc, 0, map_, bufSize, values) } + GetnPolygonStipple :: proc "c" (bufSize: i32, pattern: [^]u8, loc := #caller_location) { impl_GetnPolygonStipple(bufSize, pattern); debug_helper(loc, 0, bufSize, pattern) } + GetnColorTable :: proc "c" (target: u32, format: u32, type: u32, bufSize: i32, table: rawptr, loc := #caller_location) { impl_GetnColorTable(target, format, type, bufSize, table); debug_helper(loc, 0, target, format, type, bufSize, table) } + GetnConvolutionFilter :: proc "c" (target: u32, format: u32, type: u32, bufSize: i32, image: rawptr, loc := #caller_location) { impl_GetnConvolutionFilter(target, format, type, bufSize, image); debug_helper(loc, 0, target, format, type, bufSize, image) } + GetnSeparableFilter :: proc "c" (target: u32, format: u32, type: u32, rowBufSize: i32, row: rawptr, columnBufSize: i32, column: rawptr, span: rawptr, loc := #caller_location) { impl_GetnSeparableFilter(target, format, type, rowBufSize, row, columnBufSize, column, span); debug_helper(loc, 0, target, format, type, rowBufSize, row, columnBufSize, column, span) } + GetnHistogram :: proc "c" (target: u32, reset: bool, format: u32, type: u32, bufSize: i32, values: rawptr, loc := #caller_location) { impl_GetnHistogram(target, reset, format, type, bufSize, values); debug_helper(loc, 0, target, reset, format, type, bufSize, values) } + GetnMinmax :: proc "c" (target: u32, reset: bool, format: u32, type: u32, bufSize: i32, values: rawptr, loc := #caller_location) { impl_GetnMinmax(target, reset, format, type, bufSize, values); debug_helper(loc, 0, target, reset, format, type, bufSize, values) } + TextureBarrier :: proc "c" (loc := #caller_location) { impl_TextureBarrier(); debug_helper(loc, 0) } + GetUnsignedBytevEXT :: proc "c" (pname: u32, data: ^byte, loc := #caller_location) { impl_GetUnsignedBytevEXT(pname, data); debug_helper(loc, 0, pname, data) } + TexPageCommitmentARB :: proc "c"(target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, commit: bool, loc := #caller_location) { impl_TexPageCommitmentARB(target, level, xoffset, yoffset, zoffset, width, height, depth, commit); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, width, height, depth, commit) } // VERSION_4_6 - SpecializeShader :: #force_inline proc "c" (shader: u32, pEntryPoint: cstring, numSpecializationConstants: u32, pConstantIndex: ^u32, pConstantValue: ^u32, loc := #caller_location) { impl_SpecializeShader(shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue); debug_helper(loc, 0, shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue) } - MultiDrawArraysIndirectCount :: #force_inline proc "c" (mode: i32, indirect: [^]DrawArraysIndirectCommand, drawcount: i32, maxdrawcount, stride: i32, loc := #caller_location) { impl_MultiDrawArraysIndirectCount(mode, indirect, drawcount, maxdrawcount, stride); debug_helper(loc, 0, mode, indirect, drawcount, maxdrawcount, stride) } - MultiDrawElementsIndirectCount :: #force_inline proc "c" (mode: i32, type: i32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, maxdrawcount, stride: i32, loc := #caller_location) { impl_MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride); debug_helper(loc, 0, mode, type, indirect, drawcount, maxdrawcount, stride) } - PolygonOffsetClamp :: #force_inline proc "c" (factor, units, clamp: f32, loc := #caller_location) { impl_PolygonOffsetClamp(factor, units, clamp); debug_helper(loc, 0, factor, units, clamp) } + SpecializeShader :: proc "c" (shader: u32, pEntryPoint: cstring, numSpecializationConstants: u32, pConstantIndex: ^u32, pConstantValue: ^u32, loc := #caller_location) { impl_SpecializeShader(shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue); debug_helper(loc, 0, shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue) } + MultiDrawArraysIndirectCount :: proc "c" (mode: i32, indirect: [^]DrawArraysIndirectCommand, drawcount: i32, maxdrawcount, stride: i32, loc := #caller_location) { impl_MultiDrawArraysIndirectCount(mode, indirect, drawcount, maxdrawcount, stride); debug_helper(loc, 0, mode, indirect, drawcount, maxdrawcount, stride) } + MultiDrawElementsIndirectCount :: proc "c" (mode: i32, type: i32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, maxdrawcount, stride: i32, loc := #caller_location) { impl_MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride); debug_helper(loc, 0, mode, type, indirect, drawcount, maxdrawcount, stride) } + PolygonOffsetClamp :: proc "c" (factor, units, clamp: f32, loc := #caller_location) { impl_PolygonOffsetClamp(factor, units, clamp); debug_helper(loc, 0, factor, units, clamp) } } From 8a2c829e07763173864b73d3b6ca46e27f810e72 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 21 Nov 2021 14:06:15 +0000 Subject: [PATCH 0043/1258] Patch odin doc binary format --- core/odin/doc-format/doc_format.odin | 2 +- src/docs_format.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index 8fa9f453c..c80be2489 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -11,7 +11,7 @@ String :: distinct Array(byte) Version_Type_Major :: 0 Version_Type_Minor :: 2 -Version_Type_Patch :: 0 +Version_Type_Patch :: 1 Version_Type :: struct { major, minor, patch: u8, diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 4cdb19a68..1c3af6257 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -15,7 +15,7 @@ struct OdinDocVersionType { #define OdinDocVersionType_Major 0 #define OdinDocVersionType_Minor 2 -#define OdinDocVersionType_Patch 0 +#define OdinDocVersionType_Patch 1 struct OdinDocHeaderBase { u8 magic[8]; @@ -175,7 +175,8 @@ enum OdinDocEntityFlag : u64 { struct OdinDocEntity { OdinDocEntityKind kind; - u32 flags; + u32 reserved; + u64 flags; OdinDocPosition pos; OdinDocString name; OdinDocTypeIndex type; From f40f12d480173274fd64a04dfc7414b7697f5a7c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 21 Nov 2021 14:06:32 +0000 Subject: [PATCH 0044/1258] Minor cleanup to math constants --- core/math/math.odin | 31 ++++++++++++++----------------- core/math/math_gamma.odin | 18 +++++++++--------- core/math/math_lgamma.odin | 8 ++++---- core/math/math_log1p.odin | 18 +++++++++--------- 4 files changed, 36 insertions(+), 39 deletions(-) diff --git a/core/math/math.odin b/core/math/math.odin index ef89562c9..caaa6f51b 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -607,9 +607,9 @@ floor_mod :: proc "contextless" (x, y: $T) -> T } modf_f16 :: proc "contextless" (x: f16) -> (int: f16, frac: f16) { - shift :: 16 - 5 - 1 - mask :: 0x1f - bias :: 15 + shift :: F16_SHIFT + mask :: F16_MASK + bias :: F16_BIAS if x < 1 { switch { @@ -641,9 +641,9 @@ modf_f16be :: proc "contextless" (x: f16be) -> (int: f16be, frac: f16be) { return f16be(i), f16be(f) } modf_f32 :: proc "contextless" (x: f32) -> (int: f32, frac: f32) { - shift :: 32 - 8 - 1 - mask :: 0xff - bias :: 127 + shift :: F32_SHIFT + mask :: F32_MASK + bias :: F32_BIAS if x < 1 { switch { @@ -674,10 +674,10 @@ modf_f32be :: proc "contextless" (x: f32be) -> (int: f32be, frac: f32be) { i, f := #force_inline modf_f32(f32(x)) return f32be(i), f32be(f) } -modf_f64 :: proc "contextless" (x: f64) -> (int: f64, frac: f64) { - shift :: 64 - 11 - 1 - mask :: 0x7ff - bias :: 1023 +modf_f64 :: proc "contextless" (x: f64) -> (int: f64, frac: f64) { + shift :: F64_SHIFT + mask :: F64_MASK + bias :: F64_BIAS if x < 1 { switch { @@ -708,7 +708,7 @@ modf_f64be :: proc "contextless" (x: f64be) -> (int: f64be, frac: f64be) { i, f := #force_inline modf_f64(f64(x)) return f64be(i), f64be(f) } -modf :: proc{ +modf :: proc{ modf_f16, modf_f16le, modf_f16be, modf_f32, modf_f32le, modf_f32be, modf_f64, modf_f64le, modf_f64be, @@ -1127,13 +1127,11 @@ inf_f32be :: proc "contextless" (sign: int) -> f32be { return f32be(inf_f64(sign)) } inf_f64 :: proc "contextless" (sign: int) -> f64 { - v: u64 if sign >= 0 { - v = 0x7ff00000_00000000 + return 0h7ff00000_00000000 } else { - v = 0xfff00000_00000000 + return 0hfff00000_00000000 } - return transmute(f64)v } inf_f64le :: proc "contextless" (sign: int) -> f64le { return f64le(inf_f64(sign)) @@ -1161,8 +1159,7 @@ nan_f32be :: proc "contextless" () -> f32be { return f32be(nan_f64()) } nan_f64 :: proc "contextless" () -> f64 { - v: u64 = 0x7ff80000_00000001 - return transmute(f64)v + return 0h7ff80000_00000001 } nan_f64le :: proc "contextless" () -> f64le { return f64le(nan_f64()) diff --git a/core/math/math_gamma.odin b/core/math/math_gamma.odin index 0a6188a9f..6b783cc25 100644 --- a/core/math/math_gamma.odin +++ b/core/math/math_gamma.odin @@ -68,17 +68,17 @@ package math @(private="file") stirling :: proc "contextless" (x: f64) -> (f64, f64) { @(static) gamS := [?]f64{ - 7.87311395793093628397e-04, + +7.87311395793093628397e-04, -2.29549961613378126380e-04, -2.68132617805781232825e-03, - 3.47222221605458667310e-03, - 8.33333333333482257126e-02, + +3.47222221605458667310e-03, + +8.33333333333482257126e-02, } if x > 200 { return inf_f64(1), 1 } - SQRT_TWO_PI :: 2.506628274631000502417 + SQRT_TWO_PI :: 0h40040d931ff62706 // 2.506628274631000502417 MAX_STIRLING :: 143.01608 w := 1 / x w = 1 + w*((((gamS[0]*w+gamS[1])*w+gamS[2])*w+gamS[3])*w+gamS[4]) @@ -113,13 +113,13 @@ gamma_f64 :: proc "contextless" (x: f64) -> f64 { } @(static) gamQ := [?]f64{ -2.31581873324120129819e-05, - 5.39605580493303397842e-04, + +5.39605580493303397842e-04, -4.45641913851797240494e-03, - 1.18139785222060435552e-02, - 3.58236398605498653373e-02, + +1.18139785222060435552e-02, + +3.58236398605498653373e-02, -2.34591795718243348568e-01, - 7.14304917030273074085e-02, - 1.00000000000000000320e+00, + +7.14304917030273074085e-02, + +1.00000000000000000320e+00, } diff --git a/core/math/math_lgamma.odin b/core/math/math_lgamma.odin index e6cbdf6cd..98b2731c9 100644 --- a/core/math/math_lgamma.odin +++ b/core/math/math_lgamma.odin @@ -197,9 +197,9 @@ lgamma_f64 :: proc "contextless" (x: f64) -> (lgamma: f64, sign: int) { } - Y_MIN :: 1.461632144968362245 + Y_MIN :: 0h3ff762d86356be3f // 1.461632144968362245 TWO_52 :: 0h4330000000000000 // ~4.5036e+15 - TWO_53 :: 0h4340000000000000 // ~9.0072e+15 + TWO_53 :: 0h4340000000000000 // ~9.0072e+15 TWO_58 :: 0h4390000000000000 // ~2.8823e+17 TINY :: 0h3b90000000000000 // ~8.47033e-22 Tc :: 0h3FF762D86356BE3F @@ -345,8 +345,8 @@ lgamma_f64 :: proc "contextless" (x: f64) -> (lgamma: f64, sign: int) { } -lgamma_f16 :: proc "contextless" (x: f16) -> (lgamma: f16, sign: int) { r, s := lgamma_f64(f64(x)); return f16(r), s } -lgamma_f32 :: proc "contextless" (x: f32) -> (lgamma: f32, sign: int) { r, s := lgamma_f64(f64(x)); return f32(r), s } +lgamma_f16 :: proc "contextless" (x: f16) -> (lgamma: f16, sign: int) { r, s := lgamma_f64(f64(x)); return f16(r), s } +lgamma_f32 :: proc "contextless" (x: f32) -> (lgamma: f32, sign: int) { r, s := lgamma_f64(f64(x)); return f32(r), s } lgamma_f16le :: proc "contextless" (x: f16le) -> (lgamma: f16le, sign: int) { r, s := lgamma_f64(f64(x)); return f16le(r), s } lgamma_f16be :: proc "contextless" (x: f16be) -> (lgamma: f16be, sign: int) { r, s := lgamma_f64(f64(x)); return f16be(r), s } lgamma_f32le :: proc "contextless" (x: f32le) -> (lgamma: f32le, sign: int) { r, s := lgamma_f64(f64(x)); return f32le(r), s } diff --git a/core/math/math_log1p.odin b/core/math/math_log1p.odin index 07e790666..a4a1aa2ae 100644 --- a/core/math/math_log1p.odin +++ b/core/math/math_log1p.odin @@ -100,11 +100,11 @@ log1p_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log1p_f64(f log1p_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log1p_f64(f64(x))) } log1p_f64 :: proc "contextless" (x: f64) -> f64 { - SQRT2_M1 :: 0h3fda827999fcef34 // Sqrt(2)-1 - SQRT2_HALF_M1 :: 0hbfd2bec333018866 // Sqrt(2)/2-1 + SQRT2_M1 :: 0h3fda827999fcef34 // sqrt(2)-1 + SQRT2_HALF_M1 :: 0hbfd2bec333018866 // sqrt(2)/2-1 SMALL :: 0h3e20000000000000 // 2**-29 - TINY :: 1.0 / (1 << 54) // 2**-54 - TWO53 :: 1 << 53 // 2**53 + TINY :: 0h3c90000000000000 // 2**-54 + TWO53 :: 0h4340000000000000 // 2**53 LN2HI :: 0h3fe62e42fee00000 LN2LO :: 0h3dea39ef35793c76 LP1 :: 0h3FE5555555555593 @@ -128,15 +128,15 @@ log1p_f64 :: proc "contextless" (x: f64) -> f64 { f: f64 iu: u64 k := 1 - if absx < SQRT2_M1 { // |x| < Sqrt(2)-1 + if absx < SQRT2_M1 { // |x| < sqrt(2)-1 if absx < SMALL { // |x| < 2**-29 if absx < TINY { // |x| < 2**-54 return x } return x - x*x*0.5 } - if x > SQRT2_HALF_M1 { // Sqrt(2)/2-1 < x - // (Sqrt(2)/2-1) < x < (Sqrt(2)-1) + if x > SQRT2_HALF_M1 { // sqrt(2)/2-1 < x + // (sqrt(2)/2-1) < x < (sqrt(2)-1) k = 0 f = x iu = 1 @@ -163,14 +163,14 @@ log1p_f64 :: proc "contextless" (x: f64) -> f64 { c = 0 } iu &= 0x000fffffffffffff - if iu < 0x0006a09e667f3bcd { // mantissa of Sqrt(2) + if iu < 0x0006a09e667f3bcd { // mantissa of sqrt(2) u = transmute(f64)(iu | 0x3ff0000000000000) // normalize u } else { k += 1 u = transmute(f64)(iu | 0x3fe0000000000000) // normalize u/2 iu = (0x0010000000000000 - iu) >> 2 } - f = u - 1.0 // Sqrt(2)/2 < u < Sqrt(2) + f = u - 1.0 // sqrt(2)/2 < u < sqrt(2) } hfsq := 0.5 * f * f s, R, z: f64 From de435c93187b042c52c6555d95efea97f908e33b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 21 Nov 2021 14:52:40 +0000 Subject: [PATCH 0045/1258] Remove unneeded semicolons from vendor:OpenGL --- vendor/OpenGL/constants.odin | 2 +- vendor/OpenGL/wrappers.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/OpenGL/constants.odin b/vendor/OpenGL/constants.odin index c70fd4d95..28c923903 100644 --- a/vendor/OpenGL/constants.odin +++ b/vendor/OpenGL/constants.odin @@ -1409,4 +1409,4 @@ TRANSFORM_FEEDBACK_OVERFLOW :: 0x82EC TRANSFORM_FEEDBACK_STREAM_OVERFLOW :: 0x82ED // Extensions, extended as necessary -DEVICE_LUID_EXT :: 0x9599; +DEVICE_LUID_EXT :: 0x9599 diff --git a/vendor/OpenGL/wrappers.odin b/vendor/OpenGL/wrappers.odin index f3bd9166b..10a601eec 100644 --- a/vendor/OpenGL/wrappers.odin +++ b/vendor/OpenGL/wrappers.odin @@ -1,6 +1,6 @@ package odin_gl -#assert(size_of(bool) == size_of(u8)); +#assert(size_of(bool) == size_of(u8)) when !ODIN_DEBUG { // VERSION_1_0 From a55f0cfb631cc9e25d0e2de7f5ba0d047232237d Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Mon, 22 Nov 2021 10:25:54 -0500 Subject: [PATCH 0046/1258] fix memory leak in path.join --- core/path/path.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/path/path.odin b/core/path/path.odin index d54106b3a..186176b42 100644 --- a/core/path/path.odin +++ b/core/path/path.odin @@ -150,7 +150,7 @@ join :: proc(elems: ..string, allocator := context.allocator) -> string { context.allocator = allocator for elem, i in elems { if elem != "" { - s := strings.join(elems[i:], "/") + s := strings.join(elems[i:], "/", context.temp_allocator) return clean(s) } } From 9246e89c4a0bb35048253c1c5bf6ea86c146b289 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 23 Nov 2021 11:43:32 +0000 Subject: [PATCH 0047/1258] Fix #1328 --- src/llvm_backend_utility.cpp | 18 +++++------------- src/types.cpp | 5 +++++ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 46f7a22a3..0350f7287 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -179,32 +179,24 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { GB_ASSERT_MSG(sz == dz, "Invalid transmute conversion: '%s' to '%s'", type_to_string(src_type), type_to_string(t)); // NOTE(bill): Casting between an integer and a pointer cannot be done through a bitcast - if (is_type_uintptr(src) && is_type_pointer(dst)) { + if (is_type_uintptr(src) && is_type_internally_pointer_like(dst)) { res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); return res; } - if (is_type_pointer(src) && is_type_uintptr(dst)) { - res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); - return res; - } - if (is_type_uintptr(src) && is_type_proc(dst)) { - res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); - return res; - } - if (is_type_proc(src) && is_type_uintptr(dst)) { + if (is_type_internally_pointer_like(src) && is_type_uintptr(dst)) { res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); return res; } - if (is_type_integer(src) && (is_type_pointer(dst) || is_type_cstring(dst))) { + if (is_type_integer(src) && is_type_internally_pointer_like(dst)) { res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); return res; - } else if ((is_type_pointer(src) || is_type_cstring(src)) && is_type_integer(dst)) { + } else if (is_type_internally_pointer_like(src) && is_type_integer(dst)) { res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); return res; } - if (is_type_pointer(src) && is_type_pointer(dst)) { + if (is_type_internally_pointer_like(src) && is_type_internally_pointer_like(dst)) { res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(p->module, t), ""); return res; } diff --git a/src/types.cpp b/src/types.cpp index c8bdbd72a..2b7ea93dc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -697,6 +697,7 @@ Type * bit_set_to_int(Type *t); bool are_types_identical(Type *x, Type *y); bool is_type_pointer(Type *t); +bool is_type_proc(Type *t); bool is_type_slice(Type *t); bool is_type_integer(Type *t); bool type_set_offsets(Type *t); @@ -1284,6 +1285,10 @@ bool is_type_multi_pointer(Type *t) { t = base_type(t); return t->kind == Type_MultiPointer; } +bool is_type_internally_pointer_like(Type *t) { + return is_type_pointer(t) || is_type_multi_pointer(t) || is_type_cstring(t) || is_type_proc(t); +} + bool is_type_tuple(Type *t) { t = base_type(t); return t->kind == Type_Tuple; From e5f961b48f52f8346f00d43fea4700c8513c53c3 Mon Sep 17 00:00:00 2001 From: DYSEQTA Date: Wed, 24 Nov 2021 11:10:40 +1100 Subject: [PATCH 0048/1258] Removed '--help' from help string as per request. --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 7896756d4..99a55b2b6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -545,7 +545,7 @@ void usage(String argv0) { print_usage_line(1, "version print version"); print_usage_line(1, "report print information useful to reporting a bug"); print_usage_line(0, ""); - print_usage_line(0, "For further details on a command, use -help or --help after the command name"); + print_usage_line(0, "For further details on a command, use -help after the command name"); print_usage_line(1, "e.g. odin build -help"); } From 5e2280a78704fff62d4445015af3558babe74870 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Nov 2021 16:20:01 +0000 Subject: [PATCH 0049/1258] Fix `set_file_path_string` and `thread_safe_set_ast_file_from_id` --- src/tokenizer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index b7ade9d89..624aea2aa 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -295,8 +295,8 @@ void init_global_error_collector(void) { mutex_init(&global_error_collector.string_mutex); array_init(&global_error_collector.errors, heap_allocator()); array_init(&global_error_collector.error_buffer, heap_allocator()); - array_init(&global_file_path_strings, heap_allocator(), 4096); - array_init(&global_files, heap_allocator(), 4096); + array_init(&global_file_path_strings, heap_allocator(), 1, 4096); + array_init(&global_files, heap_allocator(), 1, 4096); } @@ -306,7 +306,7 @@ bool set_file_path_string(i32 index, String const &path) { mutex_lock(&global_error_collector.string_mutex); if (index >= global_file_path_strings.count) { - array_resize(&global_file_path_strings, index); + array_resize(&global_file_path_strings, index+1); } String prev = global_file_path_strings[index]; if (prev.len == 0) { @@ -324,7 +324,7 @@ bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) { mutex_lock(&global_error_collector.string_mutex); if (index >= global_files.count) { - array_resize(&global_files, index); + array_resize(&global_files, index+1); } AstFile *prev = global_files[index]; if (prev == nullptr) { From 504ea7deeb8645c441047b5a986c4eae6d8fdf93 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Nov 2021 16:31:37 +0000 Subject: [PATCH 0050/1258] Fix `update_untyped_expr_type` for ternary if expressions with an untyped type --- src/check_expr.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3c884d117..560e5e607 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1837,11 +1837,12 @@ void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type *type) { } -void check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) { +bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) { GB_ASSERT(o->mode == Addressing_Constant); ExactValue out_value = o->value; if (is_type_constant_type(type) && check_representable_as_constant(ctx, o->value, type, &out_value)) { o->value = out_value; + return true; } else { o->value = out_value; @@ -1866,6 +1867,7 @@ void check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) { error(o->expr, "Cannot convert '%s' to '%s' from '%s", a, b, c); check_assignment_error_suggestion(ctx, o, type); } + return false; } } @@ -3204,6 +3206,16 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint x->mode = Addressing_Value; } +Operand make_operand_from_node(Ast *node) { + GB_ASSERT(node != nullptr); + Operand x = {}; + x.expr = node; + x.mode = node->tav.mode; + x.type = node->tav.type; + x.value = node->tav.value; + return x; +} + void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) { GB_ASSERT(e != nullptr); @@ -3252,9 +3264,18 @@ void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) // See above note in UnaryExpr case break; } - - update_untyped_expr_type(c, te->x, type, final); - update_untyped_expr_type(c, te->y, type, final); + + // NOTE(bill): This is a bit of a hack to get around the edge cases of ternary if expressions + // having an untyped value + Operand x = make_operand_from_node(te->x); + Operand y = make_operand_from_node(te->y); + if (x.mode != Addressing_Constant || check_is_expressible(c, &x, type)) { + update_untyped_expr_type(c, te->x, type, final); + } + if (y.mode != Addressing_Constant || check_is_expressible(c, &y, type)) { + update_untyped_expr_type(c, te->y, type, final); + } + case_end; case_ast_node(te, TernaryWhenExpr, e); From 70d4bc8573f9d339a18980ba3e85ae9b8490d77c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Nov 2021 16:36:34 +0000 Subject: [PATCH 0051/1258] Add nasm binaries --- bin/nasm/LICENSE | 29 +++++++++++++++++++++++++++++ bin/nasm/nasm.exe | Bin 0 -> 1388544 bytes bin/nasm/ndisasm.exe | Bin 0 -> 952832 bytes 3 files changed, 29 insertions(+) create mode 100644 bin/nasm/LICENSE create mode 100644 bin/nasm/nasm.exe create mode 100644 bin/nasm/ndisasm.exe diff --git a/bin/nasm/LICENSE b/bin/nasm/LICENSE new file mode 100644 index 000000000..331e2600a --- /dev/null +++ b/bin/nasm/LICENSE @@ -0,0 +1,29 @@ +NASM is now licensed under the 2-clause BSD license, also known as the +simplified BSD license. + + Copyright 1996-2010 the NASM Authors - All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted 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. + + 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. diff --git a/bin/nasm/nasm.exe b/bin/nasm/nasm.exe new file mode 100644 index 0000000000000000000000000000000000000000..a2e61291a44de39cdca5803527e545c1e5f4ad68 GIT binary patch literal 1388544 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

Geg{3eu40*nIX9SD~!$gK*W};CtSnx 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 z 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

-()ScYqO0n3^JK1$ePNIQ8IM+y;#~I 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

|(SHcZgYmJ#IJ zKu#fP9m**LjqZCx3b#Vx5-`K*N{4s=otR$$&`F{0$P9(UDQ#>jgTa9VV!;6}nM{5T zHb}{w7lGIT&`t-w3YDfPS3PKA0M?-hragphkRws06*hAMj0}!)6)G*0X=HHhtWYg< zXibhztPztr7ezW%0dh2CnSfC{3reDa(Tt3OX@mJ(Q`e%#Q9CU-M~BgEx~3k3qi!9? z3n05IDINiUl3_Vb;5v*I!0TdVAPZ2pJe`)Su?3UMYTaUu*y7ex5$C!M7+9@P09AB` zNC3ug3eA>t{leg6KM)-+1HsT%OpL&FeoO#m+?dlaviN?MVU$OCNjbPWxbmoRxdNn; zat%0L%Z=NDAOq-`zfi3*L6 zu{CITCVW8Q0~%lDF$Ooj%G-P-Tym_O^C@%MZ_PSiU9+Y zFk&H-F`#9d6Hw+kg%)eh76`>S%IcT^VRB`Rl!|b*Oz&eSlj~&yM1<>RLWwWPSF@D- zfvnahK`5{DZ;}y;O3EoJkyezmt|pueg_EH$XFQyM3Uhgd*S5300ALg1=KB>94(CDG z6uF5JMOcX3)CgKJnM+g%Uu;rQq0w|eKK*nH2Hl7xy(Sq#>}; zh|>eZ98YSr@T6te`O0oxclIrE!8*EQN>I{Pk1*@ zJF#*3+t!MRg}ND`Za{>(8R2b0-C*N#S$(r?_C)B$>qa-0b|Mz)#&9C_1*);(a`l&O znXA8^4<$Vxns`2OCyxa4eBzD|Ej*vN<3k6}CoX*G=Jhe$@u`F8N&THZz`Z_(J9)1U z{c-wG#_40YllS_7@AT2kw*>M8U1%1YN}ljGPARb=;cc8+>YM4MVy2iUyc?&Q*o3+< zVqP~R)D5HHbu+@-gu1~d)QuiM9VW3WSEe<^ylzH#-$LDBqq?Q)8`Jy(1lvlQ9D-w= zxPQVddQxV=pPj>v20f4)Er!?CAzO{)a{ zt>RxnzWn;ai+Fo6;;xXQNm4$T#2w!=J;#@QOMT~3@>`??3ky-0OX8X2m&qZpFxx~f zRku>42&n_0NDzX?h=V&`IxtnhE*${!mVg~E0O@cO8oSH!+06r=fFlU$9|}SNL7bKJ z;mFZWq+(8r>yRqXHGIRQ11NIRMaAI~yQeI16R8VFFqI0S<b4-p!4`m7x-iWD;AX5D!41Q#DGbj1LGtzD>hnHc~Sbm30!wg(i+mrHoB)jUA$r z>BjBEb}Sq&g`G5VYjV(wMdkqCYI0Q)i+n*XBZDR9x)w38(H&POh(WXto2ju?KAARH zhv^ZL2E-v&u2(i=TS`|FJ1pyQZ97NP+&kCHZE-M~VS(LYy+LLr*G@Al={i#c6Dz2; z0jCF>acbM@Tj6_KJ+}DK>=F|yf{%I#ki-=j0O<@ptbq?rMGlDzg7dcUg(vN>TRL4r z46T`yQ&c2@QUW*Dvwn(MFJ`BhJuusZ--h}^983HHjG`ErDyIZ+s0lHckb((5Oz^Sa z7JQiC!vr5D`0ZG2hXHOoCJ0~%kC`KUB4S5G?1?}o-Q3ccL7gxJGRlFBB2I?>3x{DS z;$#?>g=FDaC>Dkcx6qC(7X(F05!C19z1S`Xj|q%|Eh$K2P(~}Ykyrr-AIU69rs*aL zBdNex^I@n?d#9=@XaQ>o;x*Q%IU|JvFA!BnW}l?i8ip$3>p5<&$35`bbV&}4iO*0T zH!x($gO19#?8I;GnSyvB3AlI4^*COXmf67F4pqA#Pqj>8A6O(m7->UL9c0FRu=G z-U~yp{%DB-%p3r-2m^Dv5e@B~cI1XWIm|CSV55(7!~I|qZ}7aIKtp@)C%Bj~8R8S0soZaFf*64QJ$NvE6h z#QET&Df-w;N?aN)&h18QumD=(9-)wM*oGK}#zHZ3)e>iLkjglB8L2?R zaqcqmVpAz|mvQdIxx6AI5Wy%T8#T!igdEPMmByPTx{4I=d^1rbkZWip-4u@rKMND(JAfwZjjfuSpZM4V{a$)>%qtQ|rI z>x8C^tr!Z=IqdQ-fmt~6L6|7n<5W`5IPp&Hc^R;DImH)t2)nU;idOixh6I37G8zIY zqa%zQ)YfEEW}6aQe7%AT?^DwLI-I^3E-`et@G<71##r4E5<@Qsm95tBvMt%(#DEQ@ z6g#C-CIwMTaJ&_LpjDd}YLnJpc}}cNCIX~O+|6&8z?Y-ESuzztffj^sL`BG{>nJJ_ z89^LJWXRz=6Eg8~lL6v5CKE3gnFih+EJBJ=N-z;qj695o_%*3WIy}M`Y2%B(X{`R3 zhK5pFQ4u!OaZOWlO;<&|tm-RDa4UPaVQ{Y)1r1Z4lmwGhJmkC15FF6T^@c)Hx;0TU z>Q*~M-d1}=A(`z~`$T3NwUWLP7t^d)BdB&`h+4lzP~l?mzdY52$v^?1`2BaXF^TWr z_%Tdf5;cqyOSsM#1Q))r+1b7c$LGqeyqOOb7e~*^XCi=QCE}v3v85@<=(m^nj0;~w zW7O59--hbKr{dEy3zyOhGj?GA&%} z7spMEG`qy?M)s!C=~^6WfF5LR3jI-m=#BD|b`A;@;zLFF4pIOpP6LC1sTX_&fr~u_ z$8L4;t0yHp3{IA#+6_X}IN= zArUN7BwU>L(ZD%$O319Yib!>6M)+0u#JMnV7(PQcUfg5F9xL%!smIDZcCg3FJvPZ> zMUgRA}io$S;!hnjxkdSyzxuP(vqA;+cFtm6WT09Ib9)=bVLyL!@#lz6zVQBF% zH0=3uI>f`!io?)~!_ZI+oosO!T5%X!aTr>07+P@{T5%X!aTr=j7+OgfT1gmMNf=s5 z7+OgfT1gmMNf=s57+OgfT4@+sX&72*7+Pru7Gus#{!8*!_Z2@&`QJ5%EHjf z!qCdX(8`MOaUAA1PeQH3QHV!%;hxD%Uw;g+0?!)Ye4fN}yFKRsx~CVodlo}}E$HZp zD`;GC4FTp|?T4lvHM>5%2R?>lyyPTg9LJQe_x;F`aTu24U>w|poma<;OL-6%hUzO~ z=t8&PfP*bKlaMy!C9V{Ke>@UvfFi2kX58US<)*fl#ugmW3*Fs?MsgjJT!NI>602`% z!sSA8c(e)9NA8isK|nKS&33olgTe`PMdi+chC4tVQ?xA>@xdhwTC~)0g(u*2{?>`2 zaGFOj$}b}AZ*9UoA?1Z~XQZAkL_ujN+i>T-o!{-wBb&RJ(ZiY^l0VbF9Ebf>;|NBa zH;#|45me9C(w%oaeHlTVZo-p}lAFtW>Ud&PU;lPFPpUcOIecP{Os<>%Tl&8V|4HcZ z13U|%AEA3D=g^K%I1F~D;30JUO}Te|JDE*EC$lN{o02E*zX`v-W+l$;5R;!#*5kXe6SeDZKrub7%SODXz3Zqs3M*janl&2i4MseOsQSfRq0c3uikmd@OjdU>6RW;e|TmD(4-_ zD9Eo0r;K5_FEtMLFXTyU%3A@NaM^Ry_*iTl&SF42Jrx8_{(b1`_5I(&laJ>HJh$Mv z3(u8!79fD0{2ty3+trq7X>Ewv^;?tm$lw_`T_39kvAhmkIK+G0Vl6nWq#@tV^TYA~ zN42CfT{X!gyBbm}#4+N+gVgeP`4NV)IFc}iewg`U>WA(YV+9xeJ?B!+*5ol~G2AcF zi~Fu|`y-aSdeDxhF&Ws7B=g6$aq+jku00t;p2|h)dG-FF<1M*EmmB%I5(l@1@=mY# z_3Qg{pW}`9I3V$J@f38(X?wwUZdl)+``m84DL1a~C;kc^=YK971jcT72HP{l;84Kb z@eISWJ)Yrsw!t$3&vtl58YGW2bBlJ{;&FELmu?An#KSN~;~{S+JUiP%{(gAKFU3Q8 zhS9T(UJOV#ON?J>@Mu8#e+(Xm&GVM&Pb;1n9v=3)Hy&OLMqL>X%CEvholi4(Iw0-O zz(e~p@z9@(@r=iFmC@G#Qorl*FuWV_Q0}*QsNdswX#X4@+V74;VfygbkDp?p*&1Nn z5#W550C#N$7h=<41%+4ez27QJ0p zcDpwwhn|u{XL9I@#%%Y!E!lKO4jtsQv!iq9-E-)|9J-=9+yBCx@Ym&}*IH}eeWX9g zPQQvXv(smEj(uScU6Dgq=g?2)(5pYp4)4j2v+1=t^tv26_)oU{=o~thOP`k=pC>=b zc3=2uHr58ke>3hG(_HWh3Z2F=cdQC1J%=TGBq+(Duz3R2>@Kz1Z zwqKV+uN{$XKRTy;EY2xEpXHQ~k8|jCIrQoZwn&lRHre5=$+5pThmM_^<9^$0_xIkN zZNK_~9Qu(Q`uS{nZ4OjwtPhn9s3~1K8LRUILCg+Z2i~d(D&xhqeo}USLD#u z8?*h74Q9(9{w~UquNabTU$IlR|7*UQO~>BJmS4AfwtaPueeiy^d_@kuYF&=~9@+j~ zltZu1p@R>z-4C*;@}0upPzCaiCAz71iivnYKj@xr`EKTWkMH3ao(eo$`qBUYiTlAm zG=wse!As~aI?&5$vuXP!lQsQ13|1IiU~t1EOJAe6H@J(zy$v2h{5~}JAA_G7TyLmZ$;5G)gGq{7noeb`3aCd`y8Qj<4{s!|5jx#vH;6#H*r#1Xyqst6VGC0NH zG=mieXBnJpaA8XQIl}1NbaC`?b5w4XF|I#M>C=q9$>`IK{+ZEd7`?{mGmXC0=(CKz zJ%_$GhyIh%-!l0pa_GP0(9h-2ujbJI%%R^m`fT(6!yNi^qt7w>z8reQJWY>t&3?4e z=NY|g4!xJr7n*%6hdv;OF36!vbLc5XpKt!nHu~E}FEIK7qmMEAJ4V+TeUZ^kIrQ=z z+Qb4U@8}ihmKHwT@%+jUcV1q7(LdJw=lm;9T)gb!<_j;pZN?AM|17`vlj)h8?z(jC zohM&^;AgK5J*RYN{=N?%lv%u}YvZoXx4tv(=Iwg+TlUQ#t$XV1cTOESX8RwUxUu2z z@^?OBVamB+sjXZYRMMuB2`l`;Sw_Sbp4|-oet^N1s9MV7X zwX|MrhAd~!tk!u zdHdb-okv!!`}0>j-`w|_9nYP;|BQ+4E4nUdnR@Qfy~a=ecR;bm zfB6%`Kdk%P@#oF>P0xPKEAHQU(vdsdbi%xCYyWZ3S;a&4sQl>M>-+938-K+aN51^o zW#j*`=F>qJpSI85PxYStw||d1YvyUO-F{i0-md4DZ#A~;bHc9&JK6}>bhS&-qf@B?YHAE%-CmR!wdV*9DK-oGoSqMTY0H#FZZG<&wrV6^~EnP+2ig}b6Zj1A04wiZ`W^(J#O&QUsqkdcEz^G zKJem`Z?w!msQyUi;w1x@DK{dim3nZoX^(eJ*_HjGD<$ z|Ga7Vhrj;G;oCk}chI}vIDOi2KiKoy=Z`pi;Tf-9Jn36|?flBWTi;sq>w{jnrTD9t z*WG^poP&?}Xzkk<+;zdBmz=x2^XY#-`_~P_cmC{+7r%DH*T1>jv!Cx$_Lp>V`|*!` zedDz^&wKr$@1}1kzW>217v4ClZPs4D`^_Uq{A~OsKfCm?ic@~{kJmEqANpeKu{%L^mUdi>_Usdv_BYrmMdk?(#&Mz08w$JhJ{qT1i%SIlQJmBs6 zGw;5nYsx9#*lycD?pd+jZQDN6S#raF#_XKD{;dTQ@7?u)9xIbKe+P8o5`Rpb02EX#s2h9`yUU>f7?@ZeL;~Qrz`^Wqn zR(*R``BTq)vu)kdNxwe)ya{DBQ*L|o{(JV`xYO&8J^tS6XP#}i^^D&(UHbahzLNZW zO5dMuopa{U?m1l>&%EH{m$v)uZU^6eV(Z=Qk6%6bg71H=;VW~79{=~pzrFnrr(DqT z?(n{6*OssD&dWdNtXpP`pY@f0es;pMkN)awbM9^_J@(g!jO*&!ks?Q%IdtLdFhkS`qk(!j#zMF?Sjkee?GM2xuZ`$a@Vd??wP+$ z{x)ZQ?Sls&nDVvz{`0{3WoURCzWbY<7p?ob;#eZ zyyJ<7f4*DK1%J7B?iW|SJR)(^5r4n#&)@p~)UolU-~VFa8~;3E*4bB{@YE?+-Z6QH zn_BnSVb1-(y!4Z)Gp^2`|M1@TZ-4Il|0#Q{=%oj)z2e6!eslZ3{&Uj5PaZPu>%aYR zeC1cZedte5zjXbmKY#MV>v@0u-n_paeqHP6H;$jQL*ckj7Tz}Wrp9}YJoOvjdhGe% zKaf~bzwphUy?5S(7mqw;;!9=gZmig`pl88}r@s8i{;~t*pD~<M^|^^0E|hZoH)x4nGu{)2zf*7V@;1wXlb-L&aPxBcPC(GTqK>Db$De`e|n z5583S#-~5O_5DwF{ra>E4w(4M8|MG&sKHe?ocaAT|L~pOg02h8_B!^HA06Fy=kTWw zEO_Ikrq_=;|E{?$KYs72##w*5YL{#7fBYBC_dI_5^M`M^YV{Ml9Z>nyk01Z+#8ZB9 z;IfN078cy_^z(-t^U!O*eQ3=!ze;|3&_nw^df@o@jp?I$=2Wg8aoJr5+%o;>3wE!% zXi0xZ!O;BnW&4jE_2aA4(}Q0xI_ss~=I;3L{g?Is{DB3x9DUsTdp$G1_v)(;I=H6l zxdWbf=+3J54mfd_{v97Z`+NJRw>x;u@1J||xb>4pyz}^u*F0I%bo8xNO$9%BYe~~L zC*HI4n5Azndj7B{{v7-JUrrre{?*^!JonoZ5Btff<$rnNj(u1C?Z%mZef5UtZvOeF z+uySMk~i!AKCx%axuAw>Dd=PS2W_KBX{`QD;KVAuN-&wJMSO* zd{ET$Ep%q(^Q?YnKQE5S8sp}j7R&1z!ZFpbQ%) z$jA8D(2S)3KL+~?uL%w<@;D$IIN%T|Kj@%H3(sDQj!8tsxZ=xZhIG5_W#hM;___F2 zU$W)#-CKLA{b=)N@n9XdtupxJAf?wByw~_^46ZhQ%)$v%RD;ySarOw@X2=-y7A?cA1Hm1!F8`I9c<>8{KLhs-hWK(i0QB&hi3?$L3mc#yk+iu zC9HCO2}~gK;V*%onu9hlr|^VgM=TsSgTk;NK}a?9C3nmQ}U+7kYTm_6%})+WWA#MbPcoP$FRDKW@8 z${*(+`NM>u{M;H@0oGT^;9A@el-YHQwSB5ST%ia@4ClVWcn)&ylD}L?|7*afUekiX zg9?vPe-|IQY5%vTzth{nZ2v?3*ZgSH{>LuY_HmU#>Ky&e+(zwB8L9BzIqJ`$t7mF29XOfb5@U}28^ z@N#vxt-)Ok?rCt0!3hRS3{E!~%g;aXzyp^pb9&*MeTNEU`C$3y&y^vT8?GwxH%x() zRae&BJA?9HHG9V+bnhze-{6mav46?1SdRJ2<oHFj0O@)%=XWKbSp@y|-UN+bH6LLombvz9(k@&)@ zxT7U15j~w-YONucSzMK-y~>1oDK7|qKf<|D*8^i7x>PJ%&iS0pRo}zVRm!<{(1rED zNQbE}p}qPO#@E>>UtKv~)Q`ul(Nhf$9OC?);u=kO`8DIJT_TaPmdMFEe-*lv3xb=) zT^O3P+4BoZ-Zb)15r;~S-x`>*TaQ-9`XKqmZ$}ZhB zp*1=TLwl7Bg15v!b?>+gc?X}5iA1gGK>IP$qR{nx^Aqm`Xn&d1Z5P*+8F+kt|qGnqoDl=kr)hpH6=8T zwC}f+S!eM6QE9L5&f?!Z&~soL)t}lp`Zefy$*>zxZ*SSK2JNBx{Vhq6AB}tvZHUHK zP3KDC2Nn;F&0s6P=fExfQJ=0AEwJa=TD~9{JM?dm{OO>d!u7TrYX+a(H__)r7|P}5 zw+nxzwPKWTu_iu3V!n^GiKio3K?jU7)RdHnrS z;zY?IqU(joP2S3&aSB{9m*Ef7= za?*^^C)+*)|JZs_J7;sB(2feBlW|aO=#Cu1E@%|`gLj#$^t$0%aix@+Ix2NSpK;{F%FbsHxMe zANBOQ5&NL*zx$cv1;M0Y)t1gqSHin3^(c3$q?WV&CrWh?{2gzJQ#S00a$dQ<2J#pI zh%cX-&gAgtTs;NJ;l9U8?yLRdq*i?-WqHYA}LGH2qw%)Y@Z zlJkdrh1{!s-hY7*nI0}p6<-bc?JYOe7fSp-m@*8~Z;P`FnBOB6&0xvf+>N1(uRayv?0b23Tvi6WyHrDHiMfWhu>Z=OL9i zYvF$DkPd$wMe4_B(Nv>Dp~1#M(-9KC;&}yAKZlD8v<(|C8M=4Gwe!Wn%1-__*8hj?=4{+mTx$#P zBly>XR5-9NJ@{VZClVJS#`>Eqwg3D@@`FRhzQ}YKz(+7rqb1>&f z^cMurkNBgPofL_s+HWT{J_tS;`O87m2AwS_G~QZ)uY5uoO_T3!{9sVNA5Ww$4}&1j z`;8fxZHAA`AjZFryh+pt4Qq5({aRx=#@GxWdQ))m7e@{+^}ccZc@}IIBPC9RKA(v+ zz8UMk($e;HpIS(7DXlI?`=mV09CRymX&W)u(t_b&4O}!Y9D2EhbZ~I&uuh9j?a*%p zPr=O#QYs516@Dk7)JU#tEYM@$7zFpBe!pveJht)UVK;bfb^w=QIWv*i4t4pSU>HK_ z6x|1VS?44AMExiExT{$Tj)c_1L+gB5q|`X+mHuwf$&mf% z^RW>ZwAHdgY$mk71=>6^a=N+KG{cY*D>U3@2y*>{|qFrR!I9Kvv!|;nY ztQ~rw*Ccg$y{ugOY-Q>Ct7W#tO95y-hKk>bC~%Gc3BvG_@?w;2>{GZIqgiw-*m z%e{Z!9dh=NJ4ep;dEYst95Q#?EY7--2f}6tDT$+pdKu#t}l{ z=kHqzT_>7fHKGeSA0PG^d|Nzh1^N<+#89-u1tar4a>Dm z0$ra5H6}z-!W}7`=W?3@>Mn()lq9*_Z}mlm1K%=L>u2PQX@HXdh{ho#F_-6Zhc-^E zdm1n<%xwj}3g3>czn=P7586&vap*|m^D5}&9EC84aGz6F*f{@{D(#|dv-r2qq5fHP zx3fFsJt*F2F3Z;q$ZffBYr|XCZdswOvudkr@aN@`9&iQOG2M`Ff&N>d?|yYVfURcK z{e9tufIA;N8`tKgv>ot$1$3CpeUNWc@@aje#81F1HII72bNFU$-EvU>^}63tuc)nc z;s5c5uu9fX#DFZTS(<4{|iq=k>cS`3`8{P}RS_tAsn>{Kt_!zJu0nZJXBJ1%2+=bdx%3 zuRpNqUvTtIu3z)!QO!M}H3hy z^?t)WK)iB<@_X!0r(+tgfYOEe$7p5p@1|`RpI$%@!rBihyn9I&Zlm*0p>!FzKDBw} zx*?GU{s1NA>5p*j7vMai@bCH+7GIJ-7#Q45{BSM34IO_<^X)cGzo>Z2D7b#R52Slq zmHwn^<8IGwq>;NDPpm&`{-lNl&A6tEOZPMsA!>gJ%swD?pET?Sh;3~j(a8R~Zk&>_ zSK%nCu{8AhkNP%&xHFtT3bXW|3itimPmSRPP_M16cl~IkfhT~|r)nO&QJoK}+bP#& z@j6hN%k4^bYiqkl%`@0ed*j24zll~shbfD7tLqQ#AB5xA=nC#mx3zr^*uz!Ht?;>< z>Kn^-8r^hQex&L*mmAXZvy!l_?fX1NROkbK6#+hXsQWUv zOv}$o`q%Q`7mSlPq2C>IbrB3P%Ni33@jU4ZEb&OTB2cDLzp0{R_@Qa_+{h(Agk!vic?P%~4Q=*?|8VCC z>@KDquGb5j!Lo=Tz@gR5|WQy`c1ar7G2t0eSzk?j9(?bbEXiGSd&sxydv~}I5g>Rwelf><1=w(d9 zE`&2g%|?eVKBw`T{I}FoTie6=O&fXvcb(8i_sQgrBXc7SK(K?qSm;Qg4Hhk z-yZ%$j8<24J>8bu>DHw(c{Ch;$Ax<^uMJd)r4r34mn%Z~N)bbd%yf*`C#fA~JlY)o zW6u8(2j8&6{nxGFKc+oU2soZkV_3h-)7I7%%65cbguxd0wsu?F-CyS!$i5k>fsL_o#kHiXPa0ikc&M-a%xIil4dMezZ^A74FU+gE5U)F==Fd zq-$yhn4Xf?FaIW9XK9sQ&aZUo-oICpfBK>=Uo&a$kxF&8;wRr#CV*p2jI1 zm!IRA{*N_E*Z9oLPf*XEm;tu?O3embqU-L~+$nz{*g+>m?Ap9c{uJ_l-PP`h^()`Gg08Vje3Tm@v*&5`l!SNRvh4MS4JMBd-^BL z$C%y)%e)I(Jfgl+i@wM1-MB)T_gxFHx-RG31D;>0{1$dB3med?lWQRxY?sU3YpfEm zjIZ1n;bIA$b$yDgGSy{7F|f#x&|V{`mN=c&izPMvm6osl79+TCznBcM%Hck^C}f} z^|h0uxYQ0igKy=3h}d&&U2oIIBh^}n`}zaa-mSx^%;mmaxLBA}@q--Bji;SStDE;2T@I46hzWK7z-vYhv_%5{>74{artmP)aSi4BO=t z%KEf^do9A$k}(6$u>~f5{zm;EHIqFCnrC#pi-2FNQ*nyRxW$AY_0cDb8tLsXJnxvW z@0;^~Y&@oUM~ae~4X!m|#ggyYxDxQ?GF;DS40v-$%%I4i9sd72icuw|h&>0aazOrE zIAS!;+u8=f;pU)8y)GI|`h{K6vb8Su+zNi5%e}qSNbr`;Ipc1->^J=)GsSpCp}QO-y>!;gRm`3*a-{7#COyZx>OdT(y2R zxW=4eRS&%W3pFq`Db4K!XNN4lj>_PD{8IAsTCW^qUNtVOv|ThRweGTl4n| z{}}D-_FZB(;KsH0ZEm6Xpk+Kk*$Z1g4&0Xq23YsGNYejP+WV~GQYGJ$5#w*`Z)KZ3bUG;zHovC#>E5t;5 zaw+#QaN!*Vd`ATLQHq2CZ~CZs3QxZH&ViV~b4OK&TWeIf|1aQu!n}rJWRZdD=)>IC zAkBWt8(wL;0eEAJXAR4|rI7#GyhXtrCCGA{$e*-E?o&O#2V4({G^C~3F?VhKWhC{B zxfP&><~5{gw9*vT+Fz~mPHUb-3`c;^4^%jhFWN@U&CF z=IzMy2IQtHO}3MUU?0b5fh|7~x3%4>ddI6;bGh6m^DY9bU8?NSSoj*o z7Qd4NBvcPSD~Ub>{p^z4U$LG8J?*ZJ?g4*T5bQfqhYb&y)?J(wE}nEJVo<^n4_D7jO4arY&60frcTR);$r-h)8Y zpPJ{wm06M9;F-bVG0<-PsPAJJJqT9RI#}4aLGumdkG!i3?>bQ3EhEeIps@x|FhJ*L zQ43s?KOf=#8A>%O@@RtHJ@B%!v3^#=hf1q$ZR0`j*B73xJ3;x=g>>Jtk2?DRJQH!Y zf&ZAU&*Lt;P8$EMg5E=18szGtw6zHO-V^?_XTkF!#S3@$cBsF-@iUO*y8Ph9S1cSm zuN795xg73tT?*~Hmoda%@U0Qpom%`A%*#V^2Q;ipz3aYrP*(v}^$T|#P4fT+(?S&= zet~!XQ4bdZZs~p36Bpf2qxeaMwh>&N)VNF(QSKy7=W=sE>h1D}K`)0XtsJi8n9=nv zrHxP3SuXd=Z_m!3Uw1ljfKilxqZxN?ZzIH$T0SIJ$Yl{6<8#6u3;11s*hk2}MEdOs zmO|OqY}iPZEUeQr)X`0s=Nnp91U>0=SpDn39p1;Kc3gfkus8>L=((t{cv}@!jszdc zE2di)ULYRFK&vzA9#d%AzVL=3NIjagdoS7H-wT?+*ETV%@>=7VMPut`Q;D|1KNsVu z+fCU5_n2WdF@L4`BSHEN>VM9EkY8J^PV4HoP%J)#e%^-qCsNFNyJ-)_AReslR6C7$ zr@F4o-)Z=3ZfD^39APyrS~Id2tP2|cKy{y5+>LCk+x^sO-G(X91`)eMwC}5WJ5@=k zYv|9tRjVf>*6?jHg`dkk4EeQ6`rGoCkZm_unqy_J(`b&e)g*C13G>O zuI{qLW_etPtW2}$1&a9!$^v^U?2QzQE^6I&YSR;HE%P?XHv|xV%|E52(%L|t&on)s zzo76WNj^m1mt5A0Dq9f=G5%l{IH^My9yJdr>(T%G|cHK$owtuACU7{;+ zSFjlG9ync77_QE8x$W~WLj7Fs^v36#mnEHGE#&(O#KM#64=&6GUwZ+xHUs|O0G7dD z*Fejz4ga-V_d)4h4f>5LT-}{lxN81Q`CIB|K@GTK^o-}F^b4#~u2i;09Nxi(ds8Tz zT=x&?@9jlPs_WS1%EFIo-{366U$Oj4Lp$&!3VPG5HgCpfh&QScHzJy2@#;EIXI0fo z*F+RNx~uSQ?iZM$wupTDWbmp@h(QlSKVQ#ZnBNNY($-Pmo&Q^MW zcTM5i>5KLSw))xEis~)}k@Y_PC#vVaMA5uY^W>IcAPv@dB+@I4*8Cw*XJ#Jb(Murz zef94~vi`i_k3YOmBj9^rkjt$EBk9Rze1`<$df}kvFPj>H!I1iTz}T|kcl9SU>Ya*S zb$_KkZUsN+zUVY1>n8OZ0QMa;BJ$AVAt243O5@#>zw}c4A!07vGGc*!-CDNO zxC!B}4DtA&rj_cJUNo_AaN{b?6XAUGeCJMM7EUg-H>?&R-l~{B(C|kHqY?S(h^%7`c#l;&z`>t?( zi3M%&iPjqkjOT;S9)Rn^pss$e660VlcUu0VMPI2NpNA227vaATvK>niX}!j-jh%tR zTTrVzT%QI1H;45aGQ6d5dEo`ce3kqI>Wwsfhk2L6O-)-s?SDa?ix+K}8>i}G{Z|Ud zQV;MwfV$o5-^%T$q-zFU;CGBM;rr2eKlecXNptW z&BrLYzWr@?s+9)>+*??=LAOJ+?|{j^(EpuqZ9M35Uug41Lu16~l!p6(=ieGv2Ai%` z->8rdtNVT7lze+rSB0-QL7lCdE(44cfa@2Kzu53siU*n>)>^LVeUj)s=;=5$y71~i zs9&CzgZs}7>mGwzoX&(g$0%M`Bfp{ zdNDN8G98Nm%oEBVupS^hYH>mczUX zeY{jS9Q2^maU|24-QgSU(BIFwwG{jB0qvpYWlEZB`v9)4*?bOR4Xi&IqLN+WRXx}No8 zmBsf}wHCvBs$CSH9rNqwHiM&I$sg7s3o{btb0R5qX%FRjuquK!PnBsBf0=B$flyF2 z_iI_V{voK_1bV))=>jrIXGq24TmF%4wu4(8W=^N%f>gB!yj^Nk8JN_GuEqEif zS?^D2--aFH!mRrB>NitNPg9&m<$i4Vy*i)y+g^>E=J#m6J>ohPkPZZ?--iDFRDYS0 z{pW^*ly_E%8Z>PU`{g8ujx5 zXZgZ=3he->u?v)5S~p_R?v48Wj5A@kbDnAmk!baf@B?`51NHcp(lSl&E$#(c!#jeb7VH&Cb4~MpxksZjh-Q%< zH0z%lcO$G9npSGL9(3~G`u4?t1F7y;_SmTrS8*E|+J73#`_;eQat29$K3u;@*=q$Q z$K!C^u58@gwH1C}1Xtzh5)2=e@OMi%VHrZmGAxJC6(u~EW#)CRh-FxBO)kKkIJSy1 ztY;?f!z^RGREh6EaT%fMO&=Pza55`xZmFy^;oTOWn2yGw5ng9Dc7IcYK3d2 zPMHh0#XP#s4WNwW!1n_<#g#E$t5J{j%=NK7a>VnfFFMCE#(=|ID}IR73g@aGDFd?z zC#I}Ao=H}BRwVtI1h8M3qLvYXlCDam@C_tNM!kqvbkUI4FffT^2nkrwv1)JNp-xmX z%D8QG4Js(zVMRk%5f@RWphQ_Dv+7JyQJ8e9GOQ!(VINr53jd=7*aROHAwOBh{7gAm zO!)R(d(^n7k9xC^DhHcfU zQO1X|UQVPUoVQ|``oIG`BpyX|syMTtaC{wkd%(NTo0MBI^ z{$adUYNs;7Hmy{oepO#ox2z4fhqg-BMq_NF`i?1UHOf$@Sg#B>hD%rCVm6K1PW zdcgxD;pN7nQ2>Y7CziEB9wo-%94;uiq6&JvFc+gZS42S|nYt>f5?N+|!*x7EnN&OD z684K_X8&kIbuQ{D+ln%i2Q&kIlnez%*zJ5Vmx~T>DlhBW3g_+RWvx)wYLuZcSWlKg z5j+&f51ra6m-STfWpoj;A|19GWlCYCD*A{7DU+GXTFttVz(!$FAGaDsQO8DEJ0G|5 zfmVk)6=e-Ys3Xc6W6GcwB!e{^7GuhkeN{PqK)qHt#Q#x3-K!J0$cgI7KJap@*)Ozh z)rI(}6SP%wnDwYkwpFspdaVcp4LHGJYb%~~ER%T3*F?P{HdP}<9jL=rb!a$rbQm2N zO+d&f@iFK60_v};aIjV=Yc-l^XyHQ+b&_D=$;ksJ1@l zlGf5GaMrdo%HS%NwVG|Ao~}_|Pxn|}rX?sZ%c)ep;AhptI5l?g)*{W@A_Ln!xiaC|a@Y-X_ zu&9+BA98gTR>UKfij+rvfNnaJwZ@bIfe!TmOIaW4M=jvE zLm6C!V)`iJkveXrJZcN)%2et?5wEIx9m=4Xy)J6o8dHYti}-=5s6KP;kdZ$`Wq3uF z;khhpjVZe>)CV3wiYaS{j*ECrec%BkQ5M-2uNCnFbcuvH75PBtD`HmE$7P>I z-KZQ-m$jM|ps9ve8H7bj$F;J-z zTx!>ssjO9rxMgs7zNVuh&~wFKbKn>eMB|)78k-R7Uk0V(RHQ zR^GN%o#F>HY=sO`dn)ejHspFN-(^acL=A_Y(``$ihV!#CFc2`})d#CVLu zc^WLNa}wckea18SnW2E|Rmvx=UYQ@_AU_+ty9kf_i{n>X405f?`F(`P92gIIAr9x2 z5z4RJPk6jeV?0xT9p?RVh_bV(gx5%=jEB4shx4*V2`3K|9=yb$l8I;fVFEyfWl%TFbLj^pRze~icdn*6X2TYhH{KX}bUC5dP2e~c&n zkNw1!Upw(zB8H!f|1qBQzXpl}=qon<(o(1WkG^u7WBnl>+QSyFE8(%8Ogxm=7H?U? z!@nGdiSY_~_z596w~-awkD~drqd)5%fjT8M)=Za{Abyqc(&2Eeb1ROwX0nG(^n-7H z5WkM&gYmfMbom7p$6K?Cr**VcPlpEY5D>qPZt_{Hz+Vaob`u?H*^kQc8rc$}!tQhbbhYOtzx9@RDR(4X0_Q$VRIqY3YPYLKx^ge<5Lf$+Fb z#xwcZjK5ig$1*V<@H~X*EjLdMyyA^UM(L>{>(lh@sJmpGi66N&jO%vE_F&@#FQS$d7>WG)*Z5^-OUU9tf z{gO@egYOR#zmDUB@j7xyDw$Mqyz%{#9lvdfU&rymcu8zJUc0x#ctd}-^*uy?m*Tx# zAC$%$TfQTgxDp<3mGR|^^mhs#_ z87uZrOgx;AcwRDfo^(9E#``BPdD>@8i}s(Xf&AxXPkz@2=J$dpzw-j~d(o5MC4u?9 z;>qvk!2IwpSK``Q&Yw`M=KZ9xjMut7uJ>0%jSu`yb>zb9E!+K~2kCx^?;jYCaX3d= z(xit7kLxm?$&c>^xK2_&SKNOw9`ZsQ&XX|AYhMr^moc8n&t`uAmhf06#zS6+!#Vd? zE&ng!@%|Iznfz?-n0_KWzQ18SzjCJBi18dua-Yb{v5~8#s3(O`!)GtAGZ9a6F=VHk$ATL$9U5J*iUTvJx%<0 zf5+tK;(v@M{janiW9KhJ=>DJgKbfDo-(ll_hZ7#_$;3l>5z7YeSi_bY9pAO0S$jxQa@2jf|ggQ~Ao9B;f|X~*w4 z;@5F}FrFR1*%ihc`m?R?VbAj^-plntX}q!J)A8i-Rv9lH4%a$~^cRPR%xw2RdHl-x z+>8g@cba?z@r%RL@xabsI3CFP9QkRyG^|Q>+KHdUK}`>hG4o`orJALjU7!d2HjDLdN4+ zE%f;78NJy`yzLY0H# zNS`dfiD$}R1tz+DGU3%q{>we(-$=-B;VE9yQ2%KAGsLze9!oB%ZDQ7?1TAhi9X|p@H>xho}Ay6#A2Rw)$f{ z)?XZ+js6Y@tiMT~`rBoFJ$~P&@qu{ienP~9w0dkKy!TV!rO_kfeGq8;-tMWt?S%fa zjxYGPI@Nlb>`|bc)KN7XMEp2DOFZ5euL?vJs^Qu4+p_{c=H-i*wLPSs?jrlR^4&}L z58~nYi|}ZlIjtTJBs?B}ad;A8_|NsiJ`&H?e;AMLW8%5^&&>(^T>OXe;`q7v&mF>lOnF`Whw*CVKP!R%fQws? zL-zM3dcTK%C)32U88?jAneb{Q|H{xYjvtO2w*KCo_;UPZJjUUi<*Sx69{VTbnf%c2 z)25yY{9MKl<0bL4vHQxzkK-@Pi+XbzKa9uz!+7}I8s|Z@HU3YVCe!$q^73r5w(vj3V;s(*n^fr?;eU*0^0OHqA13f~86O{|;Ab;F<`N!{50=+;e0)K8 zJU$rDb$oOa{%qp8jE|lPcrN3kci{1{3V5xI&pa2Tap?aF|6@EJ7o4ZT!aCmx|6@GY z@$pLnKbP_GYYKig<6{xw@%UhQUB|~_!sGG5c&_84ukdFR&t-h{Pr!2-9|Ho9kLzJ! zX?}l!*Oh1=l)qYff}Ur-P8Cf&lo#w*9#TX+8?lq{cs@bgv}wB-`?9=^ewLsFG-^!+cclQqB97}zl%Py9F@WX*4NM_%0Q7UIY8G;4m#vEbaH zWxf;fn@R1m=C_6=A6b3O7UlCt*8J9#9a^5>N$*>5v#j}T3XT)454aPH{BGiR9<|Au zAI`Zx{BB!E+xL<{{5J5^--UtoceKMA$TWXf8oxIM(qCV*Gl%2PHw!y{k2LJ-a=+D? zeqUxuT0mz#KGt&3nb~9l*_Xd(o;AM>4gHz@rac}VczkRO{Cv_K#P3%EK|C}y{(hCi zayK`Q@aDzf+1v-ROgAU+bMfa1g!dbDkhQ-sZ_d}|1IPSG`unKdJZru)!QL2R`8k2@ zeaX889lu5pL5at>%)eUBc>BlTq5s(O`#6Cg;-%e3X5Ne!#}EC{mfx4ekKgYw^@n(A z_obO1<8fHX+F!UI&ewqh^dFWR`Pxj`lPG?3Y+yXb;hg)cmNOpLV?2|eON zlXPZY8z6q)RN~qCALDT!CLa39l6)a$zFx-u$9UYm$q)U-mfuDh`yb;;|6_l# z|6@Gqe`@~{^oKrZ6aNO${<*Y=+P`$b+mrC5{?z`Z16~{9NqJp=-*j@tc+bB_Y7_l( zIo2PyD)}?xv1ZfdTUQ)!{ClJ}(Jz-{dvuJ?jF*lV*V?Y)c;nwAwd2S3?HHdKk9$s+ z?_6QLq5s*A4eW9E3ic?CH@18_ewF;CgqIG7YaK}AgITcuAs&|5{=R7?e<|T{&*}1^ z#83Jk;-RP5@~h-8CA@UJxYm)xPx>Fnd0U^Uz{SdpGP`Y4TCi^!v1-{=Uu(d#Uwy88{{`&}#p*v~iRqxG zu!=y?3nLI`+xjA3h{jGF)XmZNHN!w z1(xT3B>DOIS=RQM7USO-AJUG$6$AVC`j+~V)rXS)xIAn9ZR8pM=LMcWAC8ItMOH?N zd{E%{zp{u{*H^25 zo;8M@?whfv&bJq{XWeGz`-amF^cTm^W&AN-5qG9rPW%lKnF=9l$)L0hHtxgi{~f7^^} zMp&N4BmNE>rmXpH8Z$rJ@H~wEeq*TbA3X-j!|`W6AGh(JiGlxq{*33V ztnIsrJ2lmE8u4o-oUHk6>d9|bp|oBl!T>wBp| z9G=a3ZgdJfoAEm~0T1Jpt-Rw2@4gs$8P6vEO%QllkB`mRzQ*5AOKV%KcQnQ4Q1?#* zJo%j%`0xL2?#b_z!2Gsgel#c=$j)hPd`4h?TQWaK{~H;Y-&T^JO>hAvpGW*cjgQCW z`UUve#Fxpme)$VIMAq?TYpFj=|GPM_eYf%CcST_PKEd`i#;=Wi9}H~YBI}RV2fU6> z8()rV+FMno=Q_eR>K!oAEbN_)pgMp3d=s>}#vPRq6T5nWR67XRE(7csBa$L;U_q z{Ib^HcEbN`*GD(f__#a}zbDzgj`4MEVPA=7>n}-oF7b6O;&&G5&*bM4UnO4F{z5dP zYzI&OnHYF|vpw@O)(;W+6bH8i=C>pBbDWH3UlPwYJ|y9}#D`18{Au!Yi4PJlYkSBc^)L1xvXAZjvVn--CLYRfi`QSo+tBh4 zkP5LppGo_h+$?Lpn=`Ou{vz??_lvUTw}m4wZgvd)eh;{xN?G&Uk~?zDj}Oc*Yk8%Z zq4BqZ4$*e_9M@)_oO#Y7|781{csBP%j5nL`x>Et;;e7&3Mb_z9dVbw02G2#_bJx)O z32}HX@?J=IJP(@kV*IsDqX{q6`vj8D)=+@9ceT%(BL13qF82A8c%RP1bFt4UgvasM z#B;IF>4X>Rd78A(&b)qeT>m~8c>Ozr#x?Jo;d-Meg-AGmD)961L7w`XM*0i2KmT-$ z{%rhwW?=nolVH0vm)@oL(3>h}Js)O`CuJG~{^RpL_#k>dJ28;_S9$Uq9GG8d`~3g- z(qqfdL+htl-ktT?9EuOCP|K|O9?lcBH8b5{I{hANCtM^!%9`IWPkzq?=68fAzZV1Z zJIa&aYs4?q??)f)$?wg;{7wOWFoi_-kLo^#d|f$wm5;u8eLuAnwK4H<9rOP+UjGDs z(f*)?yaNcYOQ3il)qSd`eFhTWuEf{GbFoj>c!Lu7x!7kg;dQH#eFlQTaQxtZOq}bp z>Yr!P{bV1in)Up$E#RUmYGy}opRa66trLOg8C zc$}+?DL(F7PtO;O7ux>YrQnoQ8iuvM=+?T7SDi$3FVIO~{LQKKi>e2CtHC(v-IZ*5B@) z`kO4|MLZw#cYeDwE33|=MOq$%$fSbuwZ>TiaS7x8@b z_goBK8a-92(<89{_VU!<%R*kn^U>eGWAG~JCQW(I!1}}87oYj#O(8Gh`RMPx7`!xk zs#K>}VEy6h%}0M933(CEM}MEk;8oI1n)2R(^|ue{&vpM}HR8wXXA{q5|D$gOJlFf< zugM-JKOg&kAA^_1j+N^46Y^%gKK(t}*HwSN2!BRAAN?(e!KG_{pB~+ z_m_PCfp|XpYmC85qo+!BHV&-6eMx_=@nwJ*A10nleA%i3p6mGNME2nLg8Y2!+cgHS zlI_xz4;1od9bfiKLn5Kh4uSdoA))Uymj)5P)v0pU`s2T2n}$nVo!tZL?|`^YEy{Wb zf6iKe2Lcyd|GCDO!9sr~o=bdbtAOYF{APKfKj!BeuU3x1)A33h)%N*K96z7^C|I{%#_>}BFL$j(xnj}UmF+@(&{Y?=3OgtC;O%ixn%M0R`rDMv@>`x{K=6kF?rLq=- z#riI5eI5tB`K&*t2>qFOF8(uB;AJgunR4Oecu)DK3BD$ti~Q3Q@Lb~041t%mK2I?8 z=OXV+;@6i9W8yVanN9X$0-lThW(mBk^>?D7KNopt3;UXQF7|j+;AJhZwB?^X<$qW3 zHSt{JpCj->%Rk&x{!av76VJup=O*B_O5>$C|GEO6>weq5Vm?H9ebRS=U)J_M$%h=Y z{V6cNlc5iu|6QogBYta9=BsX89<8TpUe8Ir{HJexy--4D&V<3 ze>_mkm&niO`BWSp>d$pPKcpf*Z4F!8VKI0ve#dQk3wvZezx@Su=b^u2guIC7W8XMD z)`d$RT7PG{kTTkg74P$AZQs8deYqSiBkY?sKmOf$7jD>QyTJU~U5QbB(=k z!13j5;K%cu3)Mdb*55gv{7xr+q3%Ea=E?7@!1_Daliw(zKgKKMo1K1d`4Ylgo187{ zctx;L_V?(>?VxYq@pqmZt*BMM!2HgSdU8AHPy9l?A3e&AR@7?a!1}u&>dEb3Kwy3s z0xh5Tzg1v<7kTnKF>rjn*v+g_tAT;_cS+Qf+rbXRFI2p~)QwiuY7p@Y6<;okdU8A1 zJutt~ZnUCSg9H2D<e?$d@!Et{nN#S7ivD1wz%4m-^IU&3;UROF8+N=1w7aN@5_ZhB0rz~ z(KtNxAJ_46bwz&K8n(FC$KXku+nkRO_Q-ntU4y#w(BF6=FXH*wHxAE6U$Sm!{f$N4 z!GG8951c9NYvQ?#-;ovYT*vRN!oJAQ$G&lRKK?hcB0snBdru6W^eLP3bA>&!9>4f^ zGkx?oMaYYIKK6~nv(cBV8(M$Y$qp^gM+LU;^}xr+z7Laq`Tia8w0+&i$Kx@0mMSZ& zelh8f`DHym#(C=RUnK8p#2WE@^fxmGuS_A9C!yYM4JQTWcZ(;#$$|Mji^19>4WYju#qTL(J$|=o^85R&gBK1~(k&zzv*tI@li!HI z{I&yrXkz|5PPTu)x%=w+`x&A1Hx$VE@H>|N-W1*!V#?aShkEiG9+=-KurIC;@b8~B zC=J+s)c4o+T@gVbnRt4|rOVTPwj|)W?5B1iyk5jFYx`c{slOgVUK7tne=8*5x#+KV zVEtX;slNw>ye6KD{-!11x#;hy!1}w=Q-3psye6KD{$5VNbJ5@I!1^2GslT^{ye6KD z{^lg$x#;h+!1}w&Q-5Czc}+YQ{r!-D=c2!Pf%SK_r~VcTc}+YQ{S`JSpU+J^7yWf2 zyioJ+HJ?X|*Ti$t-TkS|*Ti$t-)#waF8Z4kSbyU^ z^>?3;*Ti$t-_!&=7yUgRSbzWU)ZYvtuZicPzvmP1T=X|9u>NlL)ZZIIUK7tnfA1#X zx#;hs!20{Ar~c*&c}+YQ{e7E&=c2!#0_*PaleslWb0UK7tnf14)Yx#(}J!1|luslV-nye6KD{stxBx#(}t!1}wx zQ-5tjUK7tne+MSux#(|bVEs+>)ZdXpUK7tnf5#`_x#;iY!1}w>Q-33bye6KD{?1Ck zbJ5?qf%P}ZQ-2o=P4?8^YrU>kslTy8 zUK7tne>W!Jx#;hf!1|l!slSOrUK7tnf0GmNT=e%~VEsMjslRDLUK7tne@`Xgx#(|Z zVEsMrslS(nye6KD{$?lOx#;ih!1{Z_Q-5=Wye6KD{ys~(-%-!q>2+g-?O;<@N=p9DM? z{p}xEf6sdA?_eRXiRYrfVF`FH`a3qT{x0*>-$)VfO*|L;qQ8p+&mW^b^>>Ak z*Ti$t-`E5^7yaEBSbvv$>hBgIuZicPzljNWF8Z4sSbw*s{b9Ze_5MV^-?wHohQ7b-NA_hr#^IbUSIro2U4duv zvl(|Ih~Ihw4|yRD=T(VO1;%53S^Kl(al0(AJU^MnUxC_X&36Le;!kJd?}MTr*`_J< z`@`JM#B=$*(XZ(D*yHeQ{D#|qM|iA1lb=hx{+aM#T2d)%doXX#?|=gz`%D$~G4WjN zGhf)p#B;GvZZjQ!*ghtni+u`&$M!)y^lOe|9EVuH)$*$;{j?+_nfakk)5Nn0#BY75 zj|ut3V}G{QU!Mx{mhiICUkT4nf7SUVsx7*h zq(5`~rq$mRvhM~l`YXpvH%b`Kj92W><#>Ai6bV-0;1S}N2Co7{S#dQyv@i0s)t?!! zOnFOq+32r?XQ#jF{L0i+@gzxqD4}iqn@;xKka{%ZUpZbn{V|>y@7W&Zc<%|{&OdAgsCN(U*OOx%_P2vfyu-}`EApSgx8%K zGM?-H+3(1II>q3jy=~Jk6fffNT;yFyc)YGO<+Y29T9W!T^?pxh5-ha;gvLJxCJy#b z7yWKRe?MzUa?q^#9&7M(vDa3_uX7-NlWZMa)E`0dlGl$}>+denpY7?a!13}Lm}J!b zRafPPIsE%==!ZD>;QwlA|HlTaDmX7-%36OH0|_;65kLMrbIgr%-FwH+{>1Ngx`cSx zhH*IW*fPFkDm{;5ysYJwz1}SgEYD|?|Ag}Idw>rP?P_+YMEgzR$Lp!A^*Omx$0^H0 zKR>%KC67wg{vy_US?llKN*$*x53RrZQ}U=(EwuioRO&co`B`LNnm#j+uMec;QK{Oy zG=4Xs3R(N#=^U>?0XQ%5IpS>-&u@ z3_Ln?%DM`Eq5bDUV5#j>8b3t~=DkV&O{tBE$K%HZZ!^LRE&myw@ndNbKTJH9-$I?a zZZ(b{58IH7sXK?_J73D$UXL)aWBv*83$>s0s3R|KHkbJE{&3d%o5meE=3fW4?_~+mW4wNZ*Mm5e@pIU~OvJ;9 z&@!z+^ELaQ$2Fc6& z@uod+ez#3qlDx}N!!kSvdE@X<%vA{AR^)y$_GLVzXN$LC0v=LCJR7l-@X-Hk`3;D% zFU!mPZ2US7FAqTK{>+vfv>QnNf*6?CUtIBaBs^Ykn0O5i{B|Wg&90nZvjg5wZI` z{@95u@?%x~8U zcxt?HC5wD;0-g)M{RCdt_I(0m^RaIa;>YnmYktqs^IsL39USKSg5Eznoos00xx~|X zgvasE#B+(Kxkk+|4$mc?HW41jQlFh_Qz2CzA*UJIr!g&V!W7mF7e^=1U#4cFeL%cB|bbV@Uk9na(q8**axq1 zT;N>Rm*;GsQ2z6XCqK4#D1KiW{9OEJtgyF<=i)y%CE&S?zuOYCqK4#D1MK5@?-xA#qV)Xe(aB-_&wptkLQZSYzu;So-OaMSYZS_uzuaDCK3IUJ@+%T~Zc{qcGW z^R#KD3V0}|!UMT&{AD%5>ktnJhjG*LTc;9U*8B`S8~w4o9Ivuo4?bzkAE>j2cDMQC zLuiYM@yz){UrG1L^M}MkyJEucf!p{C$NMBaoB3nx^ZNTN9qp zsvYxuD)Cs4w&REAmn1wJc`M?9y zo`A>W#b*2sOu$p?uXeo-ODpfr0xxTONFGlc_Q7lH=dxa0Qq-%^wz%$2RTD*3F7kd1?WY`Bey4oj{|GezUkL?|b-z%Q{*ndLto8`%m{V^23 z7l9wo&!+#S^+TSoLh<{r!LQC3A9#%atEKU@-}EU}H1W*%l@@P80-hPa(&9}{z%%1l zTD++OFLeBR)vyn$nEfU#U$)POWS^}0zUIk~?H!8WzdiY}|AgW<+mj#rV<>*#8T{%T z{BOD#FD9N#e3+Sl=Mo=gCE&Tlhc^XY*5i$aag@Do*ar)3;{)3#l>fZp$&c+Fir;@c z`LX|m;`gQ}KlaB^{JsZ%b>w%PN6wkz;5>0ZVB(qaAqAAGa!CT786VQ(jY+^W<3n1! z>jhru`0$otALPjKAuV6FPbmL++mj#LI~2cnJo&NzgyQ$ECqMSbQ2c%XetiGKL%y9zqYUz#yJjP+3m{&`a1zy(U`8`8_$c4u*=hgU0{bkMXeNTSU z9$EAIz>{BS`~GO~<8fiyxte_+67z|P$Np@C_jm#xk2f2_4ISeeB7P{V^23pA3F=;DGFRoJ)U|=l>St z#l&-o4{s;nxx|ML6YyN(!(4%v^>~x|{lu^jUSqp(F6+y4wofSk`P7pi+dCA$&pi3D z|AgZAxhFsN$58y9k`85gesHse}Lg_mS|uGMhAnejj2hY9#R(H!UXPZJmIZ z=01Y^W4vt=@Gvf>P3zI`l@_UiDKGM})!$*HzkwC-Z1u-@aq_D9Byacra~eDw{cVz< zKg6-s-_fMMZDaJO<~xuV=c%-b@ru;Iv@he?_+J`48~sVV(DUao2o5Sf(BDTu`><|E zMTyxtf&aevGhko%r~JmoE=>C6we|ON&Y*&<^*IA@mHx;Nt^J#RKMQ5VWa7ERn-d6+ ze~&P0c{R(@=b7~TK1yyDqI9|H(IKmA`z%Xsv*!CWFz~U@$)wNiND>pz#XhGI-u5wg zF7fe9!rLJR591=rZj-9XYl~M+URyjVZ`S@Ib@hxausk0zK>K$eYL_+NX93s8zt1NB z;h}5dx%l^agjcKhGt<%@viga%zTn^I&kFC7K=zjWpMwG)`=3Jc!)=yICZ3D^&q%;? ziEkqbFVyeTJr7c&@7vDXT3fl?Mda^2sUYj|{Q}_n*!MhP4-?PDz85Fpx!CuL!1jF+ z^yg#W(Shyzk|)2bh~JLne8qPpyQP_4w!mfeY=6{Lr6m)0WHY`5EIL zCKJ!*zD>8z<+dX{j4PP3mRF;eK3|4IAOF5i__vAY;y;z}T>VGlWv$OwN~&}^`i}no z#k$lwYksqwSd|+6MErIN#P8KoS58Og2HyXC&52d1(LB;0uaB~}@4ri3IUOw|excS! zvz=I#8s)dq@s&%m*5B&@jPcL*K9c#|MDdT$5f8B#5C7hmO&q+1@Q@RxI6Rwq>JGwV z|BJ)3nWye1yioq4r7nHG0f#>JxnI}^@qFwvRoEvE&&EEF3H!w1+1Tf)8r$bTp7wcG z*az`^?DL|qPaK|&eO?vziNmw8&l@$i&zl+B2l2ABPaK|)ed6%`m+kYGr+s96Lp&e* z$oLkAXJa23-{SCW>{ILb_BQF0?>}t!dB)QI1V8_lc#I3(q)Lp(&%fjFZ0y5${5&`g z&&EDmiRZT_9`dr)-;JcdfutRYXRANPi<1}mA)bx?(%{+XZ~FxOA&#y7ZXx|`8>2tO zv(+Et6%+7m^p^(DMt>47>-z-~JIdaHBaFAKM_c<$B>V9C+{AMkFOw7ST>R%j!V9(D ze;0Iz>w8!CLa2WE#7p(tJVJHYM$~>5b~RNF7i*VvHX{Tq0RVX`**AU)~xqehLb~^ zc<4WDf4W>XyD$Nd^@(}fbUEQ|K@GAVKV4XV^!`$T^0fTMucP%B>Ur$~7}v_aG?)u% z2DL%{QsQ?(ApPwk^w(gizo*vK`nxm`zh_y0#0&Wq4gFL*oE`Z6uU$R$HtMIimn zjM1Ns3%(s#fA3W@V3q6BXnn)+B`ds8@j!~Ro2UQ09C-Xa7vn!gDMZ5goWTCGyQltU z2OfXV$LP;y{CyT!fA1&QF3qJmw0_^2DkGj=&o=AdbA{(8C~qNuQ>yhW;|+?z!*vHf zk8!~Zb^r4L@pR2TCH?I}0Eox>bCH+vI3AjKT5opxW4t(iczkR6nEY(~xq98_3?@b*gJXEWZ`Aw0e7m+KIpM}oiD@Oz5xpY$wOj)%N# z@n#aZ+Ty)kfgj^APf~By?86HD zOgtO?&8fhTd5z4qTIsJp`7?iCgyRe2Fm6>rslp}|@OU0aJX~+3Om=o06JE#pL&pK+XM^_*;mP^j)Srz% z|3G+hK0;oI!+Da7=CvOQujBfle4TH$NjmOaaeYAh%D~gcpBaz)oC62gp8bUN$k(go z#f0(U;(v_C{hIvHPi*<^K>V`uKgN^($9`hVZx`a1mH#nbCI7SW6|_OO1ph<(+T!h* z;4f%jTfE;V*cZodU9Je9>C^s%_j_t$`k%&YO%Db&51{u!D&twf(zRgzN{RvNwHxrM!r?Cv<$??W|x^B z%;%NtVdB}yEA5f>ewftx9-u(fAwSo(eg5}0?eFvR9L8fD#+Ch6I-eu(Ld*XGjcew~ zyesjOp0xa01YT(W`4EVy_(4KroVSsG zG0l%{Bp~B4j_vy#g}!>HMdC3I&qHbTc?ivC`^NA?KV;mrct=*iLwjSgjTg^1YI!f$ z&2y|j#$jB#Ts3>O3Le{~DiBp*Jf0tzALB63w0JBpo)Oc6#ahF z4J2UJdE&ob!pFiKpTN=+4Gp77^ZpK=Kl7lr6*lO+njsJkARIe&6qy zpX2*!Q;8qHKgW2k>$ArNUe^8?8HNsec*;LR@MSz#`JWefq2+%C#*d0`WPe-#>=$@F zy(ifR{vS4^qxb=Zghi zX!&0f^4s#2@@LI=FHiscLHHBnv7BtDO7@WD^8{Yj^2+{R7WT2_E8_>_F%IiN_FL(^ zK=Jbost{WK!90I}9@P5AGCnO9_A>EY;@wqE`hMlg8p%J4?e8dmCt)uW&qe;t=>BSC zjpXlUjDPIX)?X(Dp6|!9f0AF~xGEyill}K-M4QaGnitiyo;ANu7}zoILGQ2d`#OlH;vuaQZ1>9x6t8(aGaloxozv3oB=EA<-;u)q zcwa3oze|bVjnp7(en)xo8xxq{r)d>cpo@j0w6D#Sw=BgMzTam& z#$ntF;&mwQCGfJAS9bWBEU-N9MfTxlS@ZoIfK|K!JK=i^w)5$-v|ien2ueJB9)$R5 z6XS6_H1W`Ha9*{+>qY#M@NC}K=#zkl>p5F~eF=}ppD8cn+3;I01s>`#Z90tJ=VN|Z z``=t3!v4qd{x9*{8^|es#(Z2%t30UJP0XK+$Mc+R{90DvWo-{B+P`Dsw~hRLM7(7@ zSNZ!2ywLK00SaONbcv4}(|F|gDDiCLBja&AGx1#F;}#;G#o^h+pMeQ@Jibw%Y12+3 zo|*g@&xYUb0xz`xTnob1gRnf#+3!&YY4k9Z-j@rtKl>%{fFW)@Z$T54dW-dmiDzRM z#yg7U8$LJjY~}@Se>~ywcro$Ne{9o9f#*ZXXCH79^b_envR=S%pz z@R&?Iv;*RC98Y7H*@TC`V~#0nduY_s=U1ger=vepyx5sqBc2-1a2KrgsekVzEx5!B zE&tbPiB+ig7m|M$x{i20@=LtX@_z$-!9|_t$B`s|Cz9X9bD1Caq4i4~UYhYpG@@*O z!sGjXlV6(g7y;42!GzbD&O_VhTS>t3{O@ERZiaYlZx{OvBl-6yKoif!KF22Dx!7ko z;f1=NXFYQMUqhcb?rqbBV*HqRF828|$pNs!79`|eV!#-^JT}%A<`^yr~*8dn! z`XBp=Ex#Ly-x4IS$aGxxbUKmvRmS6*>GFS89B=x5t4>9&bXZvH zRN~ihd@x>mEUY=9;&^LT%xw9cN&GsF55}|OcUOh+#?Q5E{pC7}_j3L%jW@P@I-We< zD&wWY;acaA{^IbEnXNr|{L1;jq({r;MiW1Y z$MMTHURCm!5}uATX*pK%mlB@c`md6|l<@3+pRJO=lub6Y(D+Jbr%4{P6d>k(aH!$8D+a7g&}!JR5oYiRWK&csBC(Cp=z1XFc9nZq9$; z1IPS)`uoUzsD0Lae{|%<%{C6KPyXIN_h*|AAbz3r_ZN<@>A5|rlByCNBN(rvHU-SL*V?#@3q_d z|24F}!4IOd)@S=P3VbHI{#|r~I!7`6E0>`PZ(o{P;4A&-i>p z$RFW3%Ac>X{AYpi_-sJlKcG(1q@MKtHs3!-ctZZPc)ba)R`<_&Py4?o>>uF?`P1kU z>-4X&{p&pC|3t_i;W^5`X^rKt2l;){R$_lN>-m|VOUm(?mh+^*>xV_2{_|J*J%9^I zpa{>=f3~Wz|M2@auJ##7-`_uwlF7JJ&~Tw$LG&(S{H)!07Q^ZX|G7P>a48u?Si z{s`jXT;}?`OyXs2Zy6WH#mHZTN+<*Vua=Gu{Qay;;bD}IK2M%FScx!|1j$;T7kly> z8kpZDp8Spp% zIDR*I%Kw9qKf-gAzpcjd-vEy26CWQH^HE4-y)++oUEUX5D%yutJP|L^qC_TlgU zn|S!XIe#yR-#;()9Dno?;k`kZL(9LUh;RH}c09X|r3caPzyC21-y1#c^M$aFiRWUU z?`mwH8#%s#op6cG`%XA#;{R&t+Hv~+bRtz`JhU^m&kB$I+!k*v@w=1wW$o`bk^cDm zDYpFnA@r9uzwrh?<&U&3K-=K|YH4C%{UHf;f5ZMq_jzf!A@_@D|M(&nMB*9pa+Rd~ zGs3%yD;aoFe_SOgXS}Pql7Z(k-lhnDVg2EFgRLg(@m2}Xb-djl+Fw|Yly?^Mi|zZV zg91MvSpw`0|2jPX7GhL99Xd_N*HF)Imh#l!;K2Ip;>mCS!2G&;@*5hMUpG&FM+fGI z>u{g(F+4E8?wmVn4jbO4ZkCP{C<3d=P2(AgjcKgHM+4?=Sov6o`_7WvBf9X*uU#NvuZs43ZC-cE#!~z9OXZ^#`53E@*8}M@urC_{V}kAPV(e8KQO;W<_GIE974QK zk5yJo;dS(TY8TM84tQjjn5MBs7n1*6LRYh1PsvX2X88^Op->{L#-6v(_iyeA#P^;U zet18hHgzR_lc_=0`n)TKAKuTWO?AZYZfcM!y$#2iV{2uh=H!v{2hhq5IjNhG! zU#Ri>a16g<+Q|dz?MwVZ?Z5Q)+`pRISARb))bCfG$ND3q+U_rIP3ud3J|E#3>meI^ z>_B+6dOp93r+sDxem>jBli%Zk{in&(e;yF`j}e~XKNiC|H@e36kE?pxrxp8WPFemwrN z=GV`Y-;luidxqCvz!T%YZCpHw*2njgeN8-!hlpnr7e^4@lo&jWhqiICo$wwYysYiJ zuBUy6l6{F@=D&xuo+rOyfyc-C8S&%!E^GVt_vCkUVEb+W{9p)2&oyoL$JQ42j}e~Z z{nLaR-#={#@}r4t@0)nMy+G@wP`~f-tHBTLWShG7*ZZrZsA1OrJmzl{ujw!Vk;X9XS~x52^~D5~-6GCqdU-$Q)kbuujhNpzngge65$#07s+;MvVCg&{AGEN-~4`;`TKHd_%0y(^Y58SJf64G z`aa`bL!D>s?^31}Jms&a?;ErH63aCpe}v~K z|A{r0e`8oY`S||^;{H$KA+}8#KzOTAqX^H?rw!gCV!b2rZ27HB@pvqe2t9xH0)oiV zcHO`_>K2&qCZ7IN6#gUeZ0)m?@Sh0J(SN23|B-mM{8kTa54Jn!n|j)34`CmPXDff3 zuup{NXrC#{`0=@ABktnZ?C}i;B^b`M;~N z{40ZlqK~@npY2Ef%J1Jsc#iV_Qe*kI@wERv!u}DSqx=hNEPv5c{uzD4e*b5nC%*@U zeIh(Z`_$9>xa{wth2T+j+`AL&zWDIm+Lq#`16PDgO&X{s_-e z{x54BpO*5RpGMO2r%>-R93dK*2zK934a zJeT*=e@}Sl6JF@}xr68Uc}ncs&qsH-LM^E|R67olQj`H`evHYzu<1>w& zxXv1Z`R?RtpE<%l5uT%cRtPLF>y`7JJ>~yg$RFW3%HOZX@(=Qq|63t{gy$&#fEvr+ z+jD$w6PWKVp7!}!*eAksw9kft<>hh7`K};8{B!<(;PK-9cN5R%dm+qcxcEMTiRZE& zIfd}}`vZ)J-!pOfKIH54zAW=K@m%D6oACJiNhY3)ydMyrl-Kq9fv=122Qoj`?+0!y zzRy>}bNhbaeHHQCz8|=q_q@U1SF@$m`a9n=BOZM=O^5wEM&_s&=!-xA)zG5lP{?~fJn{P-P`F~5#@U7fyv zJdflZ8pF>eUM;GK=cd0TelGTv{Ib5E-3=#Sk2I3vL8$NF?(WI&T;j*`Th{v9!;{~r z!1~+Mli$U}k6k2d{q5z+Z**Y$4$g=luZObM-`<}5#ss$SKEMyx2CmQl7K;0u2+#5U zW``Qz-~68B$MwEmBiXHL#tQpLyh8pmt9947DtNZ*xcbfY^EqC>nfy@FI?GjDGvRT( zk$AT9cCLbFEAR94JTgvRoZoHbU7Gmu`rMQk@oeQ?whErDyt7E&IDWX^vXys5;>YpO zlo#=A1J{s|?SXLwXWFY;1_!(3!Yrb#B@UvOR?i83` zn`e9-FXExZv-QVYs^HoB583BaNZof9OpZS@Ye` zliviIZw?E@uRjD5pYikEYTAE(B7P>Gi~szW@OV6$crN3c`TZP7f9r7|CVboM81g@s zH*5dn=w@o}7IeBOR_9iNw^IFNOGIo{ysV&7ef zU*|yl_9t92k99Vg;@^sa?0bMGzd^KqKRggW91}a%BpB0LDKJp($^6y$B`49D!f4Yz#@qFYT zQe*jtdCEVNF*eB`fn{6EZ7 zei{D}&qw}R$NwWd<)1z~6t z<(KwHJRkXMZU2Kj<(KwHJRkXM9siC5vbgu*`hM4oV*ZnOw$E#4Rl&1;UV9vkCw~9H zTY1~7;MvMMU%Y={ z^27aFTY1kVe!QNQc((FhPzBFc-uzm6zmfT6z28V?ju<;K!|{a2{2K!|6yFQP4BNC`27+f z$NXAt$wB=G1CNgrkeo+4=uthtF+|qm<3!+xo%E%G*=ipP2ky?oXa4e!Tvdc((GsQU%Xe-j&7uiOEl| zgV4(9(`@3$_a_q1R^GR&;MvN%T8-~d{^S|I4yE^(k0ldi9lwTq#;>^|-bg%Kdw*R8 z&(_}WlmBr1GWog0ua60jM})+)m3M9xJX?9!7V*pE=MulZA$}acB%ZCjKUBf9mAAi$ zUnW17`1LFC{)&l*_Tl{%#7nb2 zUQBqk+Fv=59f1eDW&TOv_4`Q_zxnS}q8`zw(x$pCw0&?72@~Tn4(Ix6_0M|3Jec19_lKA0!(wIznUHp&nr2ny>*z)T}{P24Om`r{y{>OOI|8O2bd)UsW z4F&Cg_?|u{=7)HwKU=&`gvWX^@lak{yrl^bzvqC7@e287YbXc6 zn^Yiv+{)y~_OQWQrs8;OCVSXKKNwHMujBY&JR5eo+zJ)PTQfZ;vg6mC_;nl~jAzHM zwZeES?N8a^?Md-o&cCJc#+FZq%j2ywUOF7E)syrWhlkASQmrZ(Etli*i@uAA{n?BM z`bxUbR^k_jr{jU0zi>Q|^EvX4WB=_j$@lQqBp^W?W0#Zz7n zWzFvtPkw6=KVA=I&F@rCe(MoG_K~dl{h0;l4lMKU=>EJr$(c33KY8-|GVuPv^S}>9 z=XhnQzTCxY>-F=-)R6IP@7uUv#tSvxxF62{?CIYJQheQl0JFjyMR-~JBg@VCX&}Fk z{WqfVeOw^EcY`C~yvKjv*7p5_BWe813B>OnPkzS-<~P}s-^qdb-3$D1?Jn(`cCB;N zsyhCJvhRJK`Wx~8*n1CfDY7#Ezprw~LC1iZQFjV;T`^#!x%B+nlKJ#%;*>}V;UGEW{m$6-uK+Mzx|%7bL#Zr@&7!(dS>c$_pSQ$ z_f02t-%Dlxy|Yl?<16cXS0uiR7dp{)JA=oQL7(N7^aseR-M?-%R$9GF>u+8O4w~*R z!0(43FZc5({C)`XQtOV@-6Ze9IJ00JgF~dAM8e???Gga^q=Keee>W+ zeKx+SdA^C(7rcKh^?8oZmt3A1M%}?Ysn5qH?eF5>w@06hZ>m1#_386*Nz?a0(#QMj zY%j-ksm-!gv zF?QR&YwY~#80;@1FEuaOFMk=}<&HONY5jaTdIPD?j|29cew+&XZOF^D_htjUTzelz z^{CnF$ALV1Z$nBq_^888alkrXM7n#TP%si>zzSe`0%izOdA$#e;drtABX4afIz3tWN9C-1*Z*Vg4j}){nXKr%N5@`O}?D$KdQA z`TN1IIFH|7eKvIm^X|{TMg8~K{ok9M;Put|_j~@==rjL?^*OmAxw$)yuMeo?zsFl~ z1;-{B|K}aw#})eTjnx0J|0FMO=H#6e&h2L^l^Wa%Xg7#hBIKrm*SbyI7WZyr0n!u80`|sRi1MxmXH`cblE3EH_wch>*SJJz! zP~QUSTUANl6AJY$lD>yj()UE8&r0O^BfU*>^8x68ByUXr7~_rYAKwTXznp&iI^@4v z^Vjbv{Id#i={;P8RKDE$)pQ!xz zPo7q&Z#mTmcT@9@@Ag7{=O=x*JY*Ylk?_KkLVw zA@4r4zh(D8?ZG_eaO;0Me7-O7_)6wUeK~pkWs0w+&vLB39Nt;P>(iGr&K)EkYhZh= zF3aJT-*2e>2JyJRXP)$5&iwwn#N*#zW1iJzIouBE;-7zyc--Ghp3FnOeyIK6DnEZ= zpCixe%gJZv@%u`ijS>5ie?HXSpYmDLHzxm>$L}lk+4soR_Yl&@pWh)bH~*N2`Nw&Z ztM3t{k3S!i`o`oR^DzJH=S(&pHdk`;*LSCa(VY89{Wl1ti8Fs`w)+R zznytwf4}`=G#{GH=W)N^zLE6BdB*6BHQ{?(@5WJeK0RWoVoPz(R$QAI!_s_oPU@*?i8;J^Ri-qW&Jo-=%uv$fxP#dW-YYIDFLu$$uKpD$D)- zcCKF>&t-qW@14>&o?CsMm!fLvn#YhnomWetRrm zmUwydzgWI3@$!DZJ(e#^yu5vrzI@4zg^lu0sD5kxe)~ov%IX@se}BWu`}g0Yes8S4 z`&Zt-x~t;9oE~9a<^B6ZivMzY{4JIJ_bk$9>#Z^W^WRxF50j49(f4;Y)7A4{pFi8^ zGyl1HeUqeU`l9VLp4Za%oI-uiuB`95)_DcT^GP4C7v>$`9fkUSd#YdmZXp}zt?zk- z`c~38PfOAO8Q<vZn=z`l4?<@3t-ua9=9&ZZU&ixmi7iL?$9-lvm_Gd3iah|u{u2A12NZ-mz z`nDD7du(NWPbk#)#LD`fSg7ymmG!;Qr}Ep4DYJ-1af#&zQ%rF;D8__u^~%+EZpKHh&~p4DYJ+)537kC|u6!X1()^RSO0fA)_(`Df$HcFTME9>2aPUu-;b zd2jBCuk~LpZ%;HHZt#Czqij@vp;)x)PLjlQ{Nx;-?;tHGb8@9^B9|d_WzvY z;}Lr;&*on)?{TVxU*@#`yD6J-jjgT&3{P2RYBzP(E`0)Q->2!uq*RWxX%`JJ3lgUmaLcs$>gyqs~LdF%h;|NY;m z(F^nT=gTM`!}^Gx^ZO6A|3v-cBj`fr*?mdQbK9mK%;VqpW}eiS6Xz$;_op;{mSc5} z;q~du$(!vx`Ygxl8^c3=91r$mYCNtw=lC*D(`Vz5tM9oz{u>it=4twD9CG!&xJTcZ z_%e_6&AUIqytuLGUvu)1Iq!${zvY#z|B+YQ{=1vb%k^Vo{noN^3GMAFuit*a{p?76 z|66(e_8*1*yJKbl{jkt~Pps^}|KxgU-8SK5(Y8&zA36nca>at*A3U$I(;oA#mwOfJ zTV7e;Jqq<5nRx##ujIee3iTbUtnZ$M`i@rCx2aIy0_9(=_Q`^)J*eGi^uj+1FfM;W>So9Da}MDm?O^yTtg<9p>NBnY8}l z)YY!I-|a$3XlBf z?u&64iu#TzJg2YqcPvu7%(m30`Jec+)pwfk-@<3T{|?hd!GEoPA;zK0C#Ou&CX?mB zoA-Fc@5}8$V+-Yvvo^Q>ZVdToc`iO9=UX>dc$7b0UuNChM&UVqnH=`l9TXn<&s~yK ze|) z&*^LZ?Md|~h--+)^%wj{yoCA_w8>;G@M_oJH;gkWf1D0ke<}N68zCPp&&5a7UkZnV zcbdYB<+sMQ`9rRE$aUaPq0jx?=C{UiKQyOPrf8GNdf?TL&o_-TWARB@@81{vX?fh4I+|dM&RcJ}*&tCGmNc z!Yhf->ws4~K4%ri=M&4P*I$-b5}(g0yps4Vl0V;11rYR&te=wct`-!{m{pl@XT zZC7|D^|wRemDJx(g;!F42Z+b@7yLJ}{tg1KcKv;+u>Rf%^(w z^o^{)Un;zk`dbD081#*-ztsw_r2f_@ypsA`tME$dZx`{n{(}ET*57X6)vmuU7uMf< zpTiR>E2+PY3a_O8_7IQj zFZgd{{p|%_?fUy_VZD4G>Sf+~zh?ANe*1kBv#)7gYjeQH9Z@=kzsRL5vgA z_a6$+>1+KRxc(c`cOT*%rZ)`!BOb5+kVBW7{pIP;CmsyEdFKniFSoxRlRwrNIvxf7 zw7ksx5wyuZ~s1y#n&*{tLu)aSkJXtT; zfAf9Zy8hb=pkvc#egA!go(uoESGfP?>#@b}Cu~-DvR<(Np5;xZzLBv-;gSEmzGm?A zTVd^FvQ^5Tr{M!a+AlHkAAzrgjkM3{br{@V_`+VywHc!%<5RQ)ZS zZ+idS@?3nx=eOjFX~QGWPE>f5KcnjJf(p;+8(DuBS9s(QB%nlbs5W{O9#G{(X7gS+zay#sgvEP^$MqNd zN4$jk6ST=>FYs#D-*=2NDSw=f+;QtIFdkT*i_ggVd#A#q{PFrS>*oCmkMhUyO#Uo% zKJ-cFk0?CypSwS){;U8x_CY=h|G6s?>QB%nll=;h{O5SN=NB;Brn!NGvpu%(d zT8FdWKX*s0ZgBiNL_Ds);J*Qme;51xm}bg85LXb7>o4ddUaXE|`c?w3cK!WfG1Q-v zl$1Xt$VxM}EuA@AZ}a_kEK~ZvTb)Yn*@CR1@juog&VMV1L%~s6TXGHvQLvHGPP~$Ri5R z>7)MIHBZqAF{lX_$*g=CGlCI z@Jiyd5_q-a^TUDoa6NH6v0VjvEl-Qj5Qn*|6<%L_xSsfaY}Y6}Ej~jW=B@=^?fCqt zFh1)*ujQ4*XT8EJiO&XwR}!C%z^fgf!^WTHzX|7${rdwgCrd(mP1ui`x86UR`3327 zYV3TRK3Z4R+4+w=HqiLZ`^$mX`m1tz8;QsB-Fe$9wcE#k0{e&JgZ6KN`B31s{+)7p zn=8+UysD-1pV@w)w_E!0%pFubfX0VSO}j9f}VM-bepF>F4MN^RD;5u|DyAp`8A02joxSHC}LT|F$#6 zYsc|+)y~HgrpJe&_+tL;CVjkqpD>T?&E@SOUaj@EkHXS!9dVb<);GhWyczNz=Fc(6 zAED3Lk;_~7{Pg!J1F!XN$>l949*>8CNA~9C_llUl#_P-Ft&H)=-dx@)u(x*oonz`x z?uT$b^1iS4O8oriS4{6uTAulD^!L{mUpdQ@`ysr~u#EPPM(DBP>P1j3^N9Qjv_PWF9oOJ%-)ERky9OAY9_GPve zpQHF!Clkv%UFci(Y_E^&Z{GQMN#ned{Cn&f)A?d~F22-Xr{*!+|73;d^ijU#=HIgw zp3^rn|6Z){oW9Omkd%KS?iZl=^86;mgL#eT_U519U2=%m63@2cKL0A^pLqSUmGkeP zjq{xUV0^cEGcXl%lFxbFbpBZ$=3fej?fHSd@@s|n|NO_%8*Zci>-@b* z^FJFvI)3>)KmPLkFXVIQFEI06cO;J=L%f!FwiW%He^pt3Jm2f9wf?w-NxqW&y9><6 zEw7}0Hz_=)Z)E-cx56u_--ju@|K~r>-r+Xtzs}#ARKKEbEo(=RV{{N@Sm^%S1dM-W-Rt-{0ogNHnKdj1#U!Mw&pddClI z5FL*m;6FMsuP{#jm0{=HV=IejDZ@2v{2B>&!{@SMKR z$2BSc#Ju6zkS`$~%xgTiH~$3hB}2THc(xVy`B!J>FK1NFzkfH*bN*BI547=@b#nXY z*H7o4M%;n=AY8iG}`qAB^XgSK_~qD!iEgQpVqRSN7ipdi>XN zQuMUf-!+|omWTdJ;qY6mQ+UpQBm2KwE4-5a?~V#D7GKToneq39)8lW5N9R3~yZ`d& zAs&fJ9)F2fYy7=YVg9}MwbS`$c_sO`PvMp1-=`H`N&bCV;brHa826qH`4ZxhlYfHu zk|AD7{t4b0mGkevd-6{k-+WarouBrG>HM=i%)b;46L%=QSbR0^%=lZ`e=jNY->2R< z?LW&a@!tW37xQ1z_*>b3e>289eaifgN`+HHZJ!3~LCZt`rEnO&L*Y4nBgfyDDmH4+2 zlKfkt@SMJp`FFCyE6KmhDLki-^MyL)-tYg3@$GStFCiYxYbNeUUH?99h}RO&wnB%0 zb$0#xyvq4^H{(3#Kc)ZE#y8fLjl7B5HMNf<4ujQftQaJn;IQ|BGBl|xbe}ld`jlV%( z=PgLu|FaIF1IOPPUgIz9?f(Q1$KM%VOFY}g`ai*|J^o&$r+!JQ7aTd`_-lD3`G@0g z&^I#waQqGWM&=)mzd>K;9h8)RBJMc;&hQ$~?ae>I!|`{9*AmaR;y(ZC@gINh+LM3U z_{KW9#qrnjF#l3G%){|F=HV;vuk#+3{d3azTiJi->hWL8Nzv1O5%yy(5B-7xAiYgopJn~!1v`tJUV|{?)ZD&AztgbspIcO ziC1gksmd|@e-$i=-N2S84p|(GT^`PaU|57*%|Es8Cc{7d05?mWX0y)eUT{Dr;!pWxy8 zcZSyz&$hAtPw;B5f3IGcf4Kg&ypsIG^>5HOGXHS>8}yCLKV1I?eVvbMQvQj!l1rivNFc}&vOZe>($pFEpZ^uc-w=<^-$$1x-+Nci zziSre-@{=)*78d7?|&6uN&Y=W;W>RH^Y1wdFFXIlxc4B)mk^Jf{1d!K4e?U)Pw<{l zIsZ=U$vR5&%%_Cl~9YkBCu6b{2zDm>>u>aTM5pD(NMO8UPmE4)~IHM?iV zU)Zk;@#wrqvd7;c9*IgGe=G05+_W(No(uc2mRFL0I~86@{+*%lO7ibb3NJhV#Q63g z$d?e0oct5KM-A~(@=x%dP&xk|(vyGM_~xr}>HHhmFSb0)zZ4D=|Dy0>@zuC9<8NjE zy|U1M*M|LK%PaBUjTK(Ze@WwSW&fSK$A45RoEmD2>tD-5|D|vkj_co`Z{+xk>))Vn zK;Eht_8&hQ$~?cM*g4yOaxzcaknUzj}pR-XT@Da=1y|5{#2{^9yJ=o^`T zxc&|LM&=)`e}lfx$2BSc#Q28m-x*#*`C{76Kb$(d`J~|C`gexc`rCW+Pw;B5fA86o zf7tD;m{7d057uUZ*U+1ro@zuC9<8S5qeO96WaQ$m}CH}+pZ_uasFKPU( z?7yEIV~xq--zzflb=jZ#@5bC5{yiYeL;tltb&}4vQ+Q6_$o}t63eV{q+5g>B;W>Ss zH&50_t5}Td-{-==7Zc*ayv9RP$KRI@@mk{9R`hfJRr>tRI*5+fRQ~rrE^VAwl7AnA z{Rqn|$-mDjJg0AD{(V*9mE_-d6`s@A`G6(mpNRWgAzwl~nAdo2Z~h71dxv-}@oX#Z z^RLc+{`-;2`FCsMJm){ne!gKx`+5bIM;g$4% zk5PEB_-b~~jKA>r{zE)E?~&a7=a&xgNL26o!#aqL*Hr%doNm_qc2hoA+-x*%x zFYH}^2p+C~XLv2~Y%BUX|LXBy|6Z!6eyzlz1J}QnSCW6Y{tfy@<{z$qgT9gZhwI;< zuk)Tt%0CfzT>sAS8qe*`Kf%NG?+mXco^8c_{?+5Z{$1abf7rEr*s z>))WS^H<3DYTTLexAOY!e+vDF>tD+&@gJ^#gFeN7N#k#2|NYb$YfK)!|J=ZStmUEq zTAw;e=hX_&=^NSqT~pyXeIxt78!9}fuk+@~`e+r4asAs;eEHwc3-MrH;~~BMpEZb% zTMzMCe_`+XL-78sa{ircoL7>6r^9}%<(1^$ZiVOcjm*DyD7=#Vd%wbS`Z^!ir2G@( z-aQ~+LOht)cy4e03EusNcrEd4EAI2J&W^tit(~F;PaEI7SC-D_h5cg7!~9F(F!3S^FBV^oJ2U=P_TP>||J@q) zi!HCje|J=PG5;lvzm@&>6JxB?r_BGTR5&%%7T3R)hyF|9FdWyvLEp&n7uUZ*AMwn* zexc(xPiS%d8}t!G&QDu~H#7didSQmwcu4R1!#bP}T>sAST7O~k_*;4Yx3Z^xNh(>U zH@N<_ypsIG^>5HOGXHS>8}yCLKV1I?eVzADQvQkY4cEUjyvB2T^H1<_{X4^JiDz4J zpMUlEuYYgZlYiRy#yYvh^{?e&{-to3hwI;Z4|Gi$}Iencs zPu54PSd8QEHJ&s5_a{Rcbyw+csI{x0Ac!!DqH*?U#xipP&UP=C) z1pgkr<(1^$#T1^?H!}bJLE)9;-#;llr?2zjNXkDk?%f{pCB%byjpz2}pWxkPh}RO& zw&Fhj>g@P?ugdv%d*eLkKV|))jc=@z+iSvpvE^a@rEr*cLxmTMug1mk_W_mt_t--J zJrwqfEw99Xk5PCr|D}w-kF4xJn|w~6l7B5HMNj)?_RH`@at< zypsO!lM2u2>%0X?{ht*;$J^oGOAYbp`~^w-e}ebEAztgbspId*D*yYJS2NCY{u`Np zSAqRl%PYyh>nJ>@Z)EEnE%PC518|NT7VONa;a8p;>b(o6mYI=lI# z7)QT8#B2SHz4<42->;m1cQ?*+{!{W#8{ejkH%~qSfA!KL>rpGy7@_9lv=(i~G+(A3<{0zqtQA z!)v^#-u*x8a5`}Rd4|{e3w!%N!K=Ohd`eIKl2o!xZ*c$F@=Ed#_n(8lk@<)F&q3eF z{KNg{ps(}(Ny*rYar~{l|NNLj|Ka|#<(2pk_n(74#eXT|Z|(i(^Y-|!^&#&) zzX84vY0G5AFY3B>Wu5(YrJ6k^WPAU z&fk`_{;&qoaf2aV>n}_me~EXP`1Ah!_xgqTcg5FE|N9!2SCW5g6kbXG-9X`$%pt@SMKR$2DpGC&st$K)!@{Ft734 z)b;P-Azn*7+X@~2)!Fs$uPW!?osILH|CIhu8{b$bx6g#nYb_7+FNMRr7b?71d^IkP zzkjamzb6;^@3ZiIDa$MI-&Yh~%zr84?+KMZ|Gi+3|5{Fpp7!qWd8p-~|57;o7XPL2 zoc~7le-Bc4CH>$3D7;vFHM?iV-xp4gzabu-_el2mJH#VV$>T5aYK^})F3i7g!Ftg0 zO7ibV3a=#pey;FJ^6&QwFFXIlxc42%mk^Jf{1d#xL%fvy6TDwl&cFNj))VneosfI&l4Kc_sOW>))VnWd7m$H|QIg zf4Ke)`a18ar2G?c$Mx?Fukqa8{1ZG}|IYAQ;@MW*=U+Yk>)$)|X1;rch|>--fmz8ZIC{H?tHeNv(SaQ$m}CH}+pZ_uasFKPU(y#D=*G1izo`uBhD z4g0Z{hyH7Q>Li^XsPLS=k^SEz6`s>Kvj2O$!gKmMZ=S4=R(=V@SMKR z$2BSc#JG1g$d?cg<~5$%n}33L{UKgUJll%<{HwF$?@cS`-$vs+=Ralrp^a~>liOFq zezE0Y{-to3_j-jFi?7DT@%Ofs{rA*D|9uDci!HCje`hPanEz77-#boinS|0i@g~M;LUEw+ZjqLxPr|?Spzn3YzSbR0RXU1RJ-{A2##G~^b$=!cGd5A}% zlE>f5`!A;!=HCQGoyp;SC zyqi|ezX$Z>pEkbvs$4q18TN}U5A!dD!^C$fyjXlS?#%dG*?%uB^xscmzu59h{P$ah z7xQ1z_*>b3e>TQCeaifgN`+HHZE^i;dFa0s4#RQ%8}yAFe{uaA^bya@>lZqH^Mn@H zzd;{ClGY#AL3H5ycZS#a3wzfef`{wh8D2{~+lqe9zdF1BTzma{rJnk=5{C|4|5{#2 z{^9yJ=o^`Txc&|LM&=)`e}lfxdnzgaMBH)xJHu-{w>SR;57)mlyq0*j75Dj9kN^7j zE%4igK3c_M zT>pL%{$5{*2lE;a>FxilL3Dg$h}ZfHQ`f>o--aE^nMyl7IgO`>~c+l7Ii9@SMJp z`F9_MSCW4ZR(MWd=i{1`e`4JGIpj--2lE=w?ae>I`@;~gC7x}?eg4(i@%LPnKfk<# zah~&^vi{Jjh5maH>=#>JiT_@u@M8W; z8GkQc*?%YX_^;)p=xKimzYlA9=)V*Wzr`_y=lnOa|2r4#7YBVK$KUfQyjXlSyJyB< z_=#=e=3feji4RnGvG{7- znen%>|6Ww+zt_NivE`Nc?=1>1=D(!zx3d3!Ym9aJl=&Z(3a5tJ;`-O}(0?f$hU5A- z=o>ly;`%q}8`=Ni`Zwt7yah??59=U0aQ!>OYy5@1>kq-h_3sR?C7x|XKj&Ya-G8pV z{=HmJ{aT4b2d;lDuO$C){TuX+%s*WJ27M#*57)mzU*|oQlz$@bxc;5tHJ;m>e}aeW z-x*#@Jll%<{Hw=*{kx$j|FrRqb#jaAU(3V%OW`mN*S|qu=dY0Q)wna`Z{_vd;|u+V z>tD+&@gJ^#gFeN7N#k#2|NX`oYfK)!|NM5?kF`AXU+YsR>AY9rIejDhzmF(9r*CBc z_Zfxf^mX1mSs$%pF|L0**slxmU|!=Pz5Smxh>oWZ@mhaj>iYKu#5+vN&ekN;W>Ss4^UG6iE;0hkS`$~%xgTiH~$3h4MV(^ zc(xVy`B!Jh-*;5bzkfB(bN*A-AKLiFI=Q_$>=#=e=3fejdACz|vG{6S9DhGh*?*5K z^xuh>w zr2jix;l<*s**!D{*+4(2Ny;nlMgm~oSpWwY=h?kOog7=Qf`FG!*{L{uaUzJPeJHURiEg%^vj#+?~|EBo(-h5maU>=#>JiT_@v@M8W;8hy>di>YF|I(9x+W5vgxyALbNwLJ7+>r*G` zya0dSBIq00|D9LiIejDhzl$h5=fBRIC+nkCEXMV3L!U43@BapSnb&woZ~tcvqT@)+br??3j`ua!7-;P`8KCHaTr zZ_qa~|8V>b`bOp-j=w=)=RK8_eg@Wr_V|0p zp8V6sH`d85j=z?N`Io|B9*)03U+1ro@zuD;d;Hy2=sz5PEw99XIQ|BGivRu|#^3Yz z_^%1>ejms3(0?f$ev`{6JcAtl?+;!<;W>RH`@gFzJg2Yo7RdT&{Yz8lne{Jy zzn#~=As(H-EouE>4Wi>pL%h~s*t`A^ylYqf{{0OL^X~=ld8p-;mSQzR3DxNZ%HP=k&q&JH%mqTNR$u*ZC`O{6#K~ zzi)l>^uK=;;=#Peb9wzS#Cy*WuO*&sO~f_c>GnlB&LrMpdOq*(Ki}L0qa^>fK|Cz4 zB>%Q6ypsIeq3}xbZ>Pe`&Ob4}?T35`@#uWO7aQO9=AYnwX^7Vn&$hAr6TEL$&cBED z7sp@Di&%Tf)2GK@%dIE6Kk%D!h{X`#*)3oqr-2MSRueChPzZ4Gh7GV7w^mYCU*}rI996!EQ*?-S1^xySiy=r+S z{#&Q;405ul_%CJs`{T;~TkP>)>qFjq#_`wk(0?f$eiIyjgT6V9zd_%e#^0c?^A^bZ z(Ci)>e`k1&=Z+nJXLuy4xBs&Nq@(uud#%F!!|~VhO7aiK-=J?~{^9r=^o`6v9Djqp z&Ic?h|HSx)Y=koTUiea7_q!}8F7 zDI9*28!J469R2z4KPx<^Z)E@XFAC4;>%0ZBK3f0M)Olw7eev}AH^ig!w@=x%-R5|~)^yHs5zIm@Kolk)8+gcvxUkZnb7gTt$_-fpl@wc-7URCJ7 ze}2>S_+fb^{`(h&7xQ1z_*>b3zcj`=eUZ<9IWJ=E{owbHED!zH#%@+#-=grGzLD#X zM=Lz1Z{+ycNuVy!nzu$ZI^!OX%(Rt@2^?%kNI?fs5wf@4?@%J~xt2O@qgK=I- z{vC$-kmZ%+-%*9<^o`8FKPtSE{5v=N{!#E>=i{0*{}bceUm;&+cn#%?X*>UL>g@7a z@J^)Pm*npg&hT1)dvE>;-i0gw{^f0Z@=qJzri?dF8rXlfJj}lo4s%y4JePl+ze2`W zB|0lbfN!FgZYN#mH2P7!i)JYW&FKDW&i!c80+-SY5cW3^k2)#mC)k&8}yCr z|8V>b`sOtL27R43PS!`O*gG`-&hQ!!>D~Xc4yOah-x*%(FYN9A1h4k^dzqg4C8=bY z-r)Fac_sOW<8RP6GXHS=4f;mrACA94U+4Xklz(D;!|`{9*LZGk{s|tAzcaj+c(xVy z`B!K6pKFi5x9Q10ZG2;$+~W9ad6<7G9OmKp8}xPl3K?IGd%VZrt%d%>@z?T7{DSsw?NiM z>tC8W&y2s%pI-llcy#`@?Dg*uul3yI@t1hD*1y*)%)e#u`#6?Yl7Ht{cqRFFafMfs zf2SzC?EDks-d`bKLOgQvPw-BJzdt#{OUXaMyKv>d|My=#`KOIOB#PG`)^mFy=%{R2bVhUqXZH> z_lo)bqluO$oNu_RwfggZJgU{-FTJmSbcSNT78ksapSNJY;JHhz{r$X-QLbHcob5mH z1fTCGnRjo^|2%(iVw97uZ+WaGy}aKjd7ZhC=MVB8`51ZYdU$rdwAjkKXCEVPJ@}LL zv7Ow`lKd;Dzz;S=^s$}X!foLx@;1hJt-oc+UgT{8d*}W8V!;r4u)HvTHiP|=*O~Vi z@+Zc7OAl{M{%i$*vOdlmZqYCN9OJVsqL1z5mhZbM$8^3lbsMBq0fo1yf!Xpg1lWZ9zkOJ zRQwjFOir89x4Uw@U!%mg&tBHa?Y~1j0*~Ws+Kw+yXzw25iTJiX9E`^vh=J09*K&rn^`i(cVFfBKKeZ2^Ajh5`@>jX+x|;hym7(LA1_W>X?ZmNcDxv8$zDmD zOg1SzlY(I!;r=xi7u2^|;W>ScR}kaG^lediPG9Tq;Ql%mXVkY<;W>T8i*aK5wkbTP zkLn{gzS|XENql!Gyps6tRCp!v-KFqK;=5bnmBe=s@M@3muQkR~yj_Kx{FxemI1gj( ze?otaJYKiN?#I`e_aXWL@=X7brSHEJ^mQnr=Q;B}Jgd*WlF%PocZXv?j3>fgcTGb7 zHN`s+<2C**hx?n;rg#S{k58{F%)c!VU*zTHAM-f>ke8c(k4n(j`OqYtnaBAj^tt%@8P0^2|L@$C9R9_z?|TpvMSrF}M|E74GE64W@N__k30|W9bh)3XYd^7ul7sPlXzJ2;||7i=vL+JDI zH82Vdn&zG(Z)=Q4kl}neeJZ}&D#!Ptrhhgeo^ajr{Mk-YrY0)R+S$|AkNWu#_s^1N z*jgEz_UZvOc>m zBLBH7V?6x)CT1_Mvxe+NUd&$0>&*W{_Fm9ksY*YyNft#ec1;%)f~J;V#n0^P|9P{Pn~A;q-XC zJH~5?XWOYB)W6PW^xq!h)tVn&Q1M?*{_Q1woPUAWc#CrLZ(oep63=iu|4==n|MnBF zR{mW`@n5Sd^Dp9l#{sZ6@EU)8LjKvVHyj6Jyw+c`%(ngcH^nxAWiVfrJlhZC^3EXMndV-5NFM3yUBBXN zcHxWD^AE`*eObKaz^gsJztP0U&R=<+$!)4%cSC$E&lYGd$Hu}QZ&!Gv&;6X|owncB z#sNEjZQYgrw4$;sL7}A%@;rB_^x6G*3@|!u_ew^(62)&^BFNMRr z&ni5%{-SYd8Rgp5kdGo?+|NTjN9~>FtpQ%`{C;y`et#MA(eg_2`x^?cB)^CB<>q&) zzSR6a1o^1>FDJhbE4-5YUJLms@?}(huLEA~{C-O;zs)=?rGNYd`IEnYZ+TPsoyc*{ zGN<1uJT*Qh=$bw|{&x&B?fT08d@I{a{h^&VX}W}@sfT|7dnM22buMq&N&fSmGwEF< z&+4-Crha`b-RYYR;6KSDeObJXz^k3#7g6SCIreV?y^=S^{>{LvZU5UiKTTfRi1NIA zD#$%g&PVyg^^H6`KD0getYo_}v=5UL=tudbA*kgG8f4c3S!?CS$K31!$FaLJOc!pz--2B@^ zyu<$XxqpA>;)VX(OZqtf081ZV=$0Zg2wW>1zBKmLP zfZspn{0qFsU!R+Q%VWHjc($GLkbj-e=)V=jtCfE%760Yr-%8TQ`4@PNwoO}tw9w}<;@V})JU*#5cCe<=E&pg)y7%gN|1haE5I zp??9+IDT&-y*z#gUgK}f9e=jQcrEb^xAPCxGk(8hTV;PNM{l@M`z}s|xKu1bX{;DfS-$UTym?YwTZUV#jgkmd7od+%m!O z`{66-``16A_*+e{kcA0HW4GrnL4)K2KZ=VGJ4RGl48GWY$uXg_YpK&I|+x2QDe_U(gzCb3hRJFYs z%RxZ@I#A z`dWVn)*o}YwfasI7Ox;4k6%Gw>+j$?=KHZV^F={3-{%8f?fQGCF`n{gRQ=r(^3n2K zerMJ(`{h0g&*>Xke-Bi6PT$D-d$__Q|2Y$q>d$%FTf7SLQTWeYkWhbuHkqtec;r8? zukr62s~cB;g1AQEk^j6t!|Oa!J>z<9t-^EqT7P>|{Rw^Rh{yF8{71Zm`V%zseIMY} zuD^E~<0*ff4mob=^Sx;|KL+yA^059=I81$l!Xtg|5}Dr`*XB>lFw<@Te+qr>Dx2RL zhY_bt(I%6Pz^fgfclX3cU*E8D-);wgS{}wHg~Qb6D!f>HG%m(x6Zli;b8l(mqj6Xd z#%D9|YRBg>=Lz-WB+2}2S)^#Of7=UxPs;KrKJKpE{&%0kbMa}s2s!_0{Yz74)VE*Z zIem@4&GzH1f2f|Z|2?4aoIZlc{#WCozJm(S>7$!%|EqB(bfCUNz^k1j-t30-mzO(7Yz-#;qme=`*>KS?4W4zYi?)sT24^3l{w}W_x>9U}Y z?B)5`G-c@-@`mhPY?kiT9wBeYUY_r0Ec+Vr(B66HGwQfPVgBrdcn4nN-zhhLcExz@ z63_3D`sa8?f9{6-3HnCn&yc;j`7>m1ZvLRXwex2$&Bu5?YwUN`ojTt+T6wBGO@voWGC@CNiD?_Qvkwx9bW@xqqMG4df@r`vVXk=7oHxJc`vf=KIGZ`T}o2AM!pA z`sN)EALXUpWzL}AM^89U_bLh zK2e-f^Yc#;eStTi5A$=`TYZ1Q@va@8t8sir=I8lIFZb`v8=IdO2VQOa-^cTJGiyI_ zvb0Yfi@&*K>Np1TcjnpsCgQp4Q+cO={gP)(h}Zk2JR6^R=&K!{tDF2>ChTVW`Ew)m zgRS?*zDUOv$)7yFS)N=E#W;LFe!pdn!gKl>e+RE$`1AiEeK$~eP9O1NoS43wDLkjI zC4JN`v#rTdO`qIhye;v#zJvb;IEL;H{C(_y2VU*`xyG3MaVvPQ{~q8^%gf9kL7PnO ztMIb(M-U&P@G|p9&?b|u3NJf<1n~*P z_QzWNbS&PqF95xkhxwy%7;(x((k7Ev0I#+%pkzh<4Ww!4J?eDITWLEzCo;UcxBpI_)=5b^p`fmhr9mlxXqP|zEABkkV` zyxR8vsK)A66T-XHepvvoCe+`Y2C7x(CEhs2qm-y7l`cq8-Y{xKc} z6X%yG5$BhC;PV=x&)vG%cmmJkhIo5pyw=~z`v=SH^Qn>1|J>?3&34Lk?1RsL=AC~p zDva-)ARd7?GQR&2 z@Vx&BV%K3B&*n3^#$A7?vc2w2#OXUd_NVl(w+H(L&%KN6Z!{j-f8;pZ|FRzYTj8hJ zL!AEv-pKmK`A^_c@<@Mb`mp~#3iTLxjkhSNzD0j~EXE@-N%bvw3t#s8frq`Ex&QsG zmlnns=XZfOGQK#!3%s28ivDpq`R{DuXPmzZp1Vlao5sWbYgJ`?mz4WQ-|w+s>u>RXoF5C`jQtu9?O%PI?SEB|{Vf`+ zJbyXNrvh(eeZM-!%c*bCKdym#6#9I88gEqU{CjPT*LqHF|GlnqykA)u-)BQS0&iq| zUl`-%#8>o>>meROp9{!hu=PfY*6g+oP zZvVZhvb{^n{i7fE*st}sc>jNc{em}RzsAGey>NLR!x2gEs9Z|z|D|%6yAF7@^Lw?)M=d@!E_VE5 z|FS-8*MnZmlkrLAFn5E()AX?}=JWm7Zd7R7%wNjg157Bd|zJ}U+ljFZ)AM2{|>yI_=@`21@Q>HhU$&l)cV~W z_mlI!69|s^FLf^z5N&U0n9gOjE;wyNED#!PYh4KA9#3S%V#`j2!mlI!6 zA4eb_LSK4(1@CB#mlI#XJ61WquPux(&YuHsWPEY{TzmcSnnL?=ei?Wp?Z^3LZTsI+ zXg~Jffj82A?7wT<|K>vbv40D^k@jQ%R@?q7_v~-kE{penTxY19w!?mp<;ndRyKj`j zVe}4#XF_DhS=TFaYv#)fop_z^$9AW}bNYyv%3pP_IH2<;R*nYkr+an53`Y)Bk+@lIl^WP%WH{Xx#F@-1nm&#%8!pD#A=cDg3 z#+Uf>ikF=J{l~zI^tWthti3w$YS;HW3++D{^akEY`&R+4w*5zY?58DBEL86GXTkR` z=dJgbJ^K1SmtxURsjTm9J^ES}(bJv;@eaI^`E!vNFK2x#_6HWu^8FG2evQ!QtXgcm zab}#DbpGMg89zT*9^;Z}q$j>9{omuEe-S)qu$iB@!_0G%e*bk%WqZAv zrSmyG_NVl(j{^Gz&%KGXU*qBT@7Eq@`~R=U{&vYt(MLG{3A~Z@jq{(t%c*bCf3Jgj z47|phv`B4leGA_D7_TKBwY~K%cpECm`yGYx#ra*}jf^kO?*cC;zM{X~2=NF!ifdAQ z1#eS~mlI#X+gv%mzvziCxzs0SRa@W+n^qWJ|CaP8&&i#C z@2DK_cNfO@x)6`R8yVjl$9OsM75(E*h=+}gSMYXMj_4)5?{T(&PmldA z8mm0V{gc2OS>L#SGVlEaG~w-q_T&CS;El8&_ZMp0|Fa(ZQ|cer-}Bb{(;j_VJz;!t zeLQb{dwcY?C`NgX^Pj*QnLjxHnYX=Y!g~wt$N53vjkF)<2es}0ZIAsa^@HQ*y!HO3 zM_)?);P^IgefxU!rPR-3VLljmBlG8pz?-+dSU+bL+W#QX8+aq_e+2Mq+yDMT`%eSC zfj83r`^I=V>kF}d+z0Ccq0gnlV&gNScYPsv`(wP;bCT8N?Ub^m_lhYI71<5S>`j4zH)ftM3sQ6J06e`ot}P6ChOnp?js zV!WLA3Vkap$M>U!@qG#Or-3&zzORb$a^frMV->_h=yMTIim%|Uj`4EhD|l-v$M++J z@qIePBk)GXcSnqu6JJpuYat#&UwV86Z(WR+6JNnwUpc-XEQ~MCp961Xd~yC+p5{OH8{5zKW4l@5N&lsCn7c*cY5rrs zvHg5Mwp$gR^j|86x!ZtOJHM}P@==Qq$A$gN`mo&&dM!`JCzZq89STp2566Z5%lBiu zQ{l<@q;i<=0Elu+t2r7 zdqm+$|D|%6dsN|R{$szf{d_;R#}uCQUn+;W3!gZ?zrVM}tDp7_|$zga))!*(_3wLEFR^UL>TJJX+X&vq7_arW<$ix+Q|0~r zPZY-Ybr6rh8yVlX#CSRJ6+4NWAs#}X3rJFY1#e4?mlI#X+gdrkzwe1}O8>VT`WM0T z{v(JP|C4_Ibz5b7eU&Ypf7fGwO8)+{{8mjZ2xC^>~ELc6n%vApTHYg z-#GsXyqx+L{p}8@$G~g6NlEoBcspafmUz^r{{HK(%JKemVSI6Z7kDG%i}Sm{%Zab( zA9q7M0kK&p%J`3L7%JKbEPkhOx-Vu>A&R+%3-C@>m?nv#w_f@tR z&G=)F{aSyE_v8Fn@Z6=+evOCy_x|H-{}+1fZ_!xg`A=a!6?h}-``0mEPJN61_5jqQ z(C6dRc%ypjTksCXc&+Co)wkdssvPgn7smHH5Rbqc8Q&kpcscPE{o@gchtTH&ve@{z z^u|~4j>dSc=Oo2f@QziE@85djo6>)O9Oj>b=M0wpm&U{XYvHSPzt8KVuyp=wkNsMI zyL6|2^dYcc@Z1H`evOCrFF(%q@9(j{MPrrcxPKCOBkLRYPv*U!g(iHe(0<%s2)vQ@ zE~1f!3Op7-cWsUIBQ=IzgG8GR;&!sn1?ymYf4 z`*~d}UXS@;J$zngdGhnLR1WhuC_JYxl8=k@I^U1&Muq3}(S6HI+nJk&ILzIo@HGFS zANhW4H!D2pzf=x$w2)BKm3m%A07^j|86_3cr3n*Z2uY(L+R z?Ouf^{g=vN?mpnv&hP7(eAMD&^U{ug>|fT0?S9Z}c``n!9OfQSc$z-e#eBXW+k*;E z>PzJ?_Ym-E$LG2|@v-AS>t}t~9s#|UC+)ZXOW`p0sKOhHPv1P{n8K6#*gn?DI%4g@ zCy(#<=MEakiW&Og8hOwW532j`_~_5`@dFL-#GsXypi>d^Pj-Wsc+FgZh(3W zyvAojZvVY8#%qa3ZEt-GeVZ!B`>TcV#ra*}jf^kO?*cC;zM_BJ4DkrOhT=hOYX7|@ z#-q3QU(P@o9WSd+S^9cE)(E=Oop);O(j$ z?{5^w_nHuoz#AFgwJ}~!d`17b8{#4Kxqu{%&w{rn#>IcWqdFwr?M_)?);P^Igeb+Pk zObUh1Amf7dB@L}!{>FDCqGY1_@w6LdeCcmGCrvs*0Vw3Y4PE>uz&e}Y&R-A8J|=Rb2lkG&3~zRxmn>!|D|$R z-xh_Z`H%g^_VfMNZdG{Ff2kbiZUbKJ{9bGFQHzhwOFRCte_0>4+d;48$@rvln7c#a zY5G_f^Z9;kcPc!oFO|dGUBIgypBwbV$BzH3pY>t88}wS9wBPzKg~QxE3U4Sree;yP z3Qy`|`&cLIh_(BGS35q}I)VJzc|}I&q%{xi7N6MW^FK7_3r>AIU^02{TmAQyj?fh| zyk;`#%+FGJ`-XU}fteXvD(}<8JICB+k9qs^+WGzyyK9rlm%-i{UNh*wDc-k+c&%|l zzyGFqKdS7%>nQ%S{dPRQ=7-|=d1ZaqRrJ~ZAXVS*E9<+V=?|?I+0V4XKSK}ia`GMA zC7-1WEzc$Z^M>xnpWjpAIeliGVXs|g+755(d43;-=kyV;=T`Mc4+P%4`vZK_8x_Xq z;h@*@O5*bvg;x@vCn&s<_-qGW?fBeSiBHPD3CH=lpx5$B;`3tQ)wcgs#s0qe4%^M` zD?zX2mDvAU;MKPONk*@nubnh$+~-88{ok=q`}xo3$RUA8{Zru4bM{-TUH+L_9`*0; z7Usq7zaakLZJx*9-?aLu-beA4$9S!O`Z*iRLVXt|-eJ06-tm5l5?`C&sqtM2 z@d&&S-*)17iSb>n@G!o8^@sku6vV^on~ty7$Nt9_d6$pzT7TzBW;UOr@2ZvKdp$Eh zv;ECb-m%?i?{!Jv&*_4B=il{%zJ9;O^xdSgzO_PM%D9LAyH#aW9s;}0OL{M ziSfPL!1w(EkL+D$+K%qk8sr^}@mhcPGTYh-SL8Tla=JAq9EU1@pRCRI z-<0|zU~k|x-h>4IP4SM#crEd4J9USDozKR9Q$Iac*?;Sd|7iW|B$$4{9X1cOe$akj zu=AI=^TOBs`m$F4cheqyT0evOmRHtyGtkHNYl~p25Xfg(Z|{WuD)1VA1Lt2V?}IU3 zOFY|}42$!o>-Q6t`@fs#`){f~z5w#Q_v^~~+Vceexw!E>$oOx;h8p#mm!^)5 zfARg_U+GoLllzIO9ENUEcrLz;%{mijYE8ee(3$5$`Zg;(r!SLZ-`gHr6kaU zv-#K97wK64KJUN3(R1NH_eySmdIyC^{&PIzKhHI7XC4jdyPLuz|Mha*56ubt`+F-q zr?2&QEK(cmXV8BSB%aTX$t3u1faBk7R^KCmH}CZfzc05pEv&z7kdKyEQh(bO9_7!d z`rD!KO6qT?!gKm)vL^d~n*u}m{dmYn;XfCm-1>W(!Xy7V-eTh#`#JEWGY^OK?NE3n z_4iVR=k&Ekj5%`a@72WP`V0PR9WG(M(1_k}GI=xbYS-V*pJf|;{!~Cl&JnC=UC0KuaAGfyumd7rtXCD8A z|J-Fk+(QRkni7oWfQBwv5;qaRpaN&UT2;W>R&FS+&iT7_3q ze{Tj}?f874Fh2hWdM&RcKJQa_CGpv(@JizIDd5$P&j$UrtnJQGdcfse_lI2A2!Cj`7ieGiTfW5`~3Qy z#~;g+{><bCipVh#tZU1_<-`H!9-2A*I>E++gu)LD|yrIH#{YUHMEv=su^YiB5&!CTZx%qiJ z;MI=LtvNnuf0LGOsKKmwWytu!&ypsCdqVP)U^U;t`L0{|4o#fW%6M;X+y2|J{l;E<Q(wm!~A0fRwepp^fetrgcwe3ICh;{Kd{k)Bs+&9)fANEmQI1^11{LUvdH9)wchm#(tZaR;P_q?s2iodOyPP`8)OJ$5(8 zrSJ@LCeO{j&qBvH^|YH6p3_J9lgi<@c!iov`;UzkK*tLD zek-pZh5y_YF%I94-%nbp@W_Ae7L$+eFm|isHtJiY@W_9?9RDt}-%nbt@SMKZ-x21| z_PLu;`q%kv^_?#Kw}yC!>4MQ`y@}=M?kDd?tXn9zFDI7+>RN;|6cZtkzjcfC# zW0+~TfIo#kca_a=jl+mjrf8GNR^Zi+&!>Chld_)M1^%==j86)O{qY8c7mJU^#rSLk ze+qpeJ{pJhV0^X%uXcRyZ=G3ioO~nydHF74%vU&_J|4ymw zzt8m4Uz_02w?VyF9@bw9hu`Ym3eVNw$oa_!6`s>ayxjT8#}r9aPV} zJ`nzME=ic52-;+_Q{j>S9M8<}JlC|He>inUeY+GM`On=KTW2s7*Dt#jp3~R*JCf!n z!s0!|J4|mF{71Zm`H7%SCVPQ5@BWHphUT-zc*>ud`3ad2uGJoV2J+GJTzp2Z55A=E zoW7CucTnL`{y2Mc>+gFCkNoG{Bj-<=|6G2%clO@g2l*)c=PpR7KS7&J_A5N{pV!y; z_l?yJ>N}wD$bVj+;dLIVo=yEt={uYH=c!+phf5CsmOQ=6Vn@o-XuXg=? z&KOVm<8?dJ-Q^tnrAersHtKb?Rc1%C>C?yB7N!7<>~j?d?N z;?p;8W*7Vx{Aqa@pA-)B{;cp~@zJ;#pM|gc?-O$U2z?W)1a+6HU3Vv8#(+Od23?4mUz_i{n#RJZNy&j`642wp5xy` zS{KnLK3|-=ADlG&Xb|d5q`;Y4^w}06b|abD z*f*b^j?QFqL#Q|AEhA3u{N<(*UZ~$peY?Paias={_xWz%%{w0W=3mD6Bz`W(oc{uU z2Hwc|-~(bj>TibE%dE_|d!Sx~K6gQG|GGEEYyJD>_OJUY$NMZLz9iKP9ymV?;=#PJ zYvS?F@JW%c&)#8nQb%jXD9fR^^MJ+T@ih3XKw!Nj`7IO z-2B-C_SVjye=E$Ny`-1NufS_eoXx?0_0ML{m_Pesyw=~Fn?L)B$Kx048=F4|BKp|Q z-26Eh<5_!6o#f`vA+Wc0{(RlcPtAYfb4uRtlFDKJ!Z)VBzrsA`q~;;>mIJSL{(Pe_e?AZKvAmM}`AUQ* z{Mj?RU@tDU-%@xb`LhDzBkXl=$~u=6^gmh|;V~ySe^vpncK&=bl0T_+j`?GGGJjGz z>}AX!q0e2y{^XYLi?yr4pF-ahFLpn^z6N-;QA3py9)Q{!K_@r`}drpMM zoZNUHRd_~X_&sHgGxJ$TtX&K75%#)UQaQ|D7vV97_3`yX?RwzV&Yy1=<`2&QEUzSg zaQ??U;m@q`;SZ2M!d@2&jt}#P;}S1_*I8bs{g>_Gkv>CBKQ>c;#QWQd zzI2$ma!U^{WxoaAY-{EI^7~wW)Gud0EbwSE zAy?lvh)3Wx{ta^VZIAKVC05eQ@T?1S=My_29*RCg zO+R+^@W#~d?#l7~VPSkvg?LC_XWW(>-&^$XTFaw4HV>1IJrEB?UlNBe+S|h$6W@K6 z<9kTNw=+iM#skO8dCwQV1mlPK+#~7lx^O(!)BO6Q^aAsklRLlu*9ea}_ItxQDR^h% zeFXK5Tu8 zZBOXkk8TU&q2s@QyRV&koUZUn?0vn$E3x;j5gyxV#*wVgYu**% z@p#1CnE$Z9S`Ych@nsHkV>}$+Hz+)cheI%rTjZj?jS8=1{M@AQO7v}3cqRI_0I&A= zegx_{cYOZ<D$JYM^G`>3%wcZqeti8vgva@uJO9{9@#gsl z`_JfdNACEvEyin!XWO2LVEt`}d<^<%JZ8H+efEsJ9Wi~4znATvCHYs7w=>3TiASw} zHhV_iu86(1KeVVJd$B*<9noibo#i#=)N>$jPY*9;e;0Xs!QOfIH|G@gFJFgxW8T>Q z<+~A{iG!;O?iYGOGWDY$M|jL(?$k{^Pkt8Rao*+jFZ&>0*ngaNx&6!j7_aq4<*siI zK>h`NBm0+wF@25K$9DT?vuErN4#jva@u;08`B#v4Bx3K_{^e*y-`M`;SPySZ|FZC{ z>HU;>_b)#&{mU}rYEvJse!1oT!Oq3(|FL5g{CjVfXZ{PkR1Wi3D?F!<`WKUbQ~k`4 zzTNx1|M>d?L0=|^_3Z)PyyL;|!|fJhpf%X$S5~j)cDl zWSp6^K7Q?ay#LN1=S!aLViygMy4s}hyoPwMrmJh`&%>?p1;@22|NYNL6zaQv<-f1_ z$U=QLuB`8;(BESJJrw%iz4W)FY@TT6BaO(3ca zj1$whO5r(ut-oWD+SokS>N`#NZ#D4_``ahMe*+x4-2D4tk~W#F0bcF?^=HO-${#l` z$*r3UK|WeuN&Q_y;W>RH>+c^F9_5d-m)B_=kD>M-6(0G|-D>>jj#%Be{C4l`uUiZG zDE!yU@prp_A5YLGlXVJ@{O4{-sy{(oukbSKPtYcl4GPccYrRED^(TlMiO2O9{71Z4 z9s75){yR<3CX-FTt6hITH^x)`I32S7Qs!k>fqb+)tiKcv`{P;)kMy}qWPWR0o8K+N zOuHHUDfGFkY@KKvMw~K5Gv7Z4UhVk&q9;Bn^Y9yhKP?aAlfq$ttW$Wg_-I^=&sOlK z&==yPaaa$=XB+Tp$LD{HGo3$8^;n&}PGWsS?VDkJBzZP3bHA_nrsKRmdXzQ3;J9h! z_0d+N&vtBM*Z*&+yuSWrPkpxue!Ugcqvg4Lr2QzTOiOcapv)j#oM9yxf{^AHZK={wS5}QY{zi|DrL*bGC+$~A-AE9rj!Xy8A zea+DKgBn4bOm-}Lm@b_wB^A_~qZsMKeZ=VGJ5iiD}%gy{}THhYv)$YHK8sjN{ zX68R+0!vlfdqX~2o{P`O`n$ivbNWWs-$NB1<&U#Bcm1(d;gSEGf0F9Yy|Z`cUdTt` zKX*Yw{R!G+vQOcW|Gd7&zi({a?($m@_ba^2`V+LtAvFD-s>x})T4m_Obkp;iMb#by{hS%6T%si@@Oj`RuIVA7s z5U=$B>sNZ{Ul3=>I|jUY`}0>Od0ak@>~A`#=fE2|K7anwJ|6seQQ*<|JY3Jhk>=qM z%18eDbb;6S>tc1x6kE^oI2z-%{;J`6k+jL=81a5eFV8!^zbTCGvmw5LH!{B8g7^kr za(rcVOePE8_Mb1FP5ukK#=kHe-)Y|R7_TLsZKrxX|2m)X-;-QHyu)*J|VAAvWrKE49=5qQb< z;r-0#HRM0;{{pY^R}9CONxoehuX#S{kyZMZ==F<@g3m!cbWbCVw1vi`dWWS?)-c+@wh&M|A;p{-c#R(>hI+W&*>Xke?NeF3HnCX-#H48{O4SnQh)4w z+irz?4EmDmPtqonZ3>V4=PpdypOVDw3NNqzByBR;q41o()?b%Wf0DS9cwB$Mf5aQE zKS?wDXTYmne}6E>Q~r#qzYjybSYAo}eL~?meIx7dZ%{8m-^ltq;WE?fPvJio$dvk% zJ??JE$Dl8{{v>TO*`x5te_mhX^DQ>7!|`vg!pp0_X?^SyuQX?-&cQ0sPXS}P%oBOQh#SDJg0AD{ap&`CFmPjf0tEw zZ?CVT(9u*>QBg3eV{qS%0^HdI|bQ*57Rv9{JBDP*VL_ z2hp(^@-gU3uRlRE-ycg?!po~aNi+LH3eV|l z{dFnzCy9HB$MetNKjID7pQM@ZR{^hf{r%M#Px&*d{w@ObVtFO?ce28B`bO5@Ca9O7 zZ)E-5PvMdOTp)AnZ$IQ?&^NOF4k$eGpV!y;e2a}+_+cBh zxc-9wh?iS`M}b$n{{Ci+r~DaJf2*KgEU%>guBh;wzLE9!V5pa%Z)E*FQsI&RTmt3R z-!aI?pl@XTEqvGS-|=`F;@ePuQ=3|U%N1Tp{jE@V&VMcGqc&DI*gvc!9@k&+-vGzI zoBe*k^sx$grU0j}nDet`W%YM;s2BUkO8!6Q-ULjKqqzT{HCo#;<`7^&Tpn?YD+m(8 z5(p!1am$!vxonwp31EZ`SX_R^Ev_ISfFJ>jaEXuvaYjJ+As~RbMF>G80Ym^>V8G%Q zSN>gHRlPMe)icx6+dTjGk*527cjhzSy1IMjefQm*`n#3E%c;L-sd@?eCf48c3|>zC ztylRN^i8b44F-?==MyJ&{kdT9a_VoR!ON+?O~m8+3;t`cPGWV;Rix{0v*MMW|9<0) zr~H{T|NWP`Ujn?G`umQ-^ZF*vf9qAf1bq|h@8$-N{D=8HP&Yc>iz*+3z5z}wf3_Gr z@*nD}@yN0B-;%-0slTlT&+BVYSL*t68}YdQg8zt@T7TOWuXO#*x%tZdi+=tSd=39& zj}7Ykuz*MT=@n|{(`~t`Xco=#NDU94=d+k#T zZm$=EK2?93!+JFDCkBuFhx%$flIu@%HSgC3Pu6pc6Vo@hw`;H0*WeMl{)Y6OL_Ds) z;6LJV{b^22-xU?Fbp0LYjFPNn#wS&g<3uy=7QGEO>BYq#n`O|0+3idQ;+9yBF?AOQ3@qWlTG#QYI7_xVPHmz+O>c+B8= zeKi^on`hWQ{rwYj-^TSH&xgT(4IVLSeh~Ur6OZ#J_>Xw2pl!{dcplzreQOl2bp9-6 z=FeK?PvH6ZsOtx|SGU^!bp|gdf7Tnkoc!5f@RG+Lkv|K>H6XAYCRD2Ob#Y3}o1idVY+<}>T> zF{)mGms5XFGwMn*>)oHl^(cRz4)7=+Tk{{p4E_&2_82@@($zfG3%73FJU4T% z4{`SzJjzGZHwzm3y_TCt;!NbN} zf5;Q;E1d5SnczQpM{Ymqoc8+hcmG5J>u-r*Q8#eaf#q_F=UHoHIr>Rsa0N@6$*dWq+f3KNNV@{4~U2<|c#ZkkR?c<+q<__;}qOQ16EZeRLep zb3+{F9#p)Qjt8HI+Y_Ae-u}q%pAXH?o0UI-XT@iT!+I7Cp4UhIoL7Dw;vQ1|4Eho| ztnaYmm5$Go=iApqCp#fx_+weo_A~3+-&dh|W9x=b5ap3SQ}ul*rjO%IdCBJ=YNI@H zJ=Etvy8@L!Ee;Qh-K-kKP%nZ{d7JRZM;KC&17{#A;;buoQ{2lW_xX#b7j zofw0;*QfAEs!1KqtMTwu|E-VtPw-OwH-?wuzcIWN|3!JtH2-ag<+I?W_-_m^#eZXX zDgM*Em7Y(|HRg{#dogOu+wZFJS@Tlok0?*fA1V5N7}Ga#{)qA@s4&0v>C@xO0_8Jb ze+K{6=;Ku0#u%@e#@j@^i}3I&=p%bwe0v|--pw(6HDXeEi!oj^jkjgUUN>K+#CIvC zkL^w5ZH@8R-bCIuW$#LlFAsOu$FRQOxX#bqlZ3~1()SZOCh%%}A(giy#%reWb`tLr zJiJCmzplK_3~(;}+7pTW#-wn7$g1 zP30Yo@tSG8Lqqnu`6DI1hhzHK-bCJ!7?15uyq z^1$Qq#pQE~y=!9n1TSTMI)+E+<)jro9girl#)IH~Ns7H|WA+MOioIiaDfUKr%`|)0 z#qve)QtTbWOR-n;R(d=|uPtw1?UF^lU%=y`tHU{R$@0!d?>+y3^~`^N9C&m+;xf_Y z;z$moKWy;4J{}LLUFF&tAJo(ShIpT(eS*G34xi#u??QVekNoF%;q?cMV+|kF)86)F z$on_iC+MT38Oz~Q+{NIL|NJiVHSX#BSIw~7yM3v_^YL}Z!(%K5_pYkf7(B19!99lF zKV=TL|4qD4(F?(U4Zg4nTAzvdd}#Z9#VcKZuUwT^e=k?{0=%61d#%CCslTtO`V0Cd z*59`bUQYd8N#$eEH?jV%W$<$9?~w*Cr~aO3@N(+!eZ=GX3;u(;bC1;e`>5iTuD@4h z*53uHUVxWVe|rpGPW@e^>Luu#Sbs+iUQYepP~~ILH?jV1VeoS5?>vK-Q-9Afcscd= z8RBvM1^+d^{F3YMD~eaT{&r^8-!oOc057Nho^SAS>hF`PUV^@f_4fsXms5Y0%EzE@ zV*Q#{|#}Nzs2BreN->=s&0n3OT_ymognB-q)-; z3;I<34RKiCDF%=H=XY`b^AEmm8{%He;K_O(%fYi&)eQ`u*Vo`4`ucB3-_41~^%wj{ zJYIheaaiAi;+3wy+t2scAJ-%6)9ryzWBq-eegHhH{)RZrJ!tSKe|$Z={K2|*?aUp- z&-r-W9x`~8KS>4?FT{u|3-eMb$R9pYVYh}SrX zd&I^Kt?y=qzprWc1pmq3m-%zj$L|k!c(pe-+{d&0Cwa{fuOS|^uEK|Sn~2Bn53h7S zp6rS*r=FjpexDV1U{mV2fL^JpXBxbmdj5p^eb%5)jnjPoq4u)|&+D7vk-C00PuItK z_5Mf`rISGwL%&GPoLnf13*)eG=)>hE<1FQ@*#rRpWW} z@3o1?_Li={%VpNzn^e63FQ@+AX7Fg*Zh&| z?@YITPt6~+2)B19y}X|2@M_$z&!3Wa`Vg-n9<&jE;vTqtIPprYC$>!RpPUaKOZs>| z=+ zJAS>su>T%0!GF>LZy|kLza3sp_PTb4-PTrLU;NV$uffCn{3lQFFT^WVzn5|A1wa0& z`*TD0M`g&z`roN@Z`W~4%{(oELPls2d!^h_14~BRR z@t_@%k3TP*kB^$*Ke;~o1L@=STZdPZy{?^Mx3%@_58;OscVRw9c?}-kH-AcfS0G-g z_1mMT_)iq}HI%&_UQPD8c81;7Rg0I?li<}@bEtW$rIe0cszfu^!WVP3I3Dy@gUO2_159lWUp&y*llff{hl?% zYw++s|4Dt1Ctj)gU7F%QQ6EoL_I7wR+3VUFc3WFrzq27;gNOI}Pw0DbVgEgDg8!rg zUQPPAemlIH>~-x7yREIR-!~5N8a%wufAR$HAYQ5Z{i{s>y+_&G;nifXYiHPPZMFYC zGQ?}}@Ui~;RAK*JepTM}>p!aNP2fTKOuc@6pTWzye*LYw-VFLCUcVl9t@ihw1^>-3 zuBq=I?@-s99bS#xvFqoZL%fD~(28{(?)<`sna#R5I4yZw&Do z;z2vY-tQK!H&nB{y+UUF9Z>ZGyqx;`vcb!#zpJQv3Hm11-?a>0>ir|RKH5$B&Fi-i zj~T{jzQ(pMA0=l)b+m;w9R9-0SiBmF->W z^*(xkd3(jo`uk5+FTl&Gzi%46ocg<-s+XW|V*TC3;3e0eSYPi`^%CMS!x)XKKf&8S z#A}e-xBjXH?|`bmj=nMVCwM1QesleGcs1#B?F_rEt-jv5@({1V!^hfN|B>tO@tN!Q z8_0JO~_)pFUcO!kAj~!l3_PTb4 z-PYFUqnO7|8{##1c%T2IzK0U8)O_&7DgG1n{AguwhgXxmuAO1Gwbk|fq#<5|hxhtV z=zDr$|D8R-f6@WZBYj-I9bQfLx^{-$)>hZ=%ZGRk9^U6ad4kswuT=f6S(SJF{b99U z03L*Y>h<@>4PMUrW3^f@1bq|NAD1_Hsp}6J--9&2bN+>R%y6&y8r#10Kkk9sLqoiV zc+iS*6JPCKe;+0u=U+$Pi1i1vp?$Nej}EWKy~o=7t|4ASJZMMQ`+>sshH93#C#m{N zegAlC;rC}RovCkIVSP`^9REM2@~6YAF;-*q@v}p`hIr79$j7f1&d042{3q8(-z0s! ze(UgRve&gU?6$Ug{dUn1uffCn=1-~br^G9@etYs1|B3a{@07hAUQPD8c81;7RivL7? zJV4po;nifXYiHPPZFT*gImB!5@LvB3eUB^bzo$;{pLD>vq>t;j!>h?&*Uqrp+Uoj! z_7JbZ!~6UvPw*n*m8##TW%}=x%H9sICVO2w!)|M<{r9&+yao>+>%X@Z_TPD#{(HBw zx5KN+Uf0gB+uCaXeQ1c+;NfHa_sPQk+cv>}a(wErpM!>h?&*Uqrp+WPTNtb@Nk z#B1>IKL1I5-yvS9`QzzR{3pieid_{YO>e0Gwimux_+-T#B1>IKL5!RT#I<6=8tDi@Sm)Y8~-x7yREIR-}?^n8a%w$ ze?s4b3;XZc6Z|I~@JQ0f_1odqWUp&y*llff{XTJs*WlrO{*xy-k9ei(_xw!%JxAHw z;nifXYiHPPZMFYiI>c-6@Ui}TO=17dGW~afvbV#l$zIpau-n>d|GjgF*Wlq}{rA4Y z{@Xsme{y{ODCy(*qr)IK1TU+lx!TbIYuffB6{U>;r6!zb9C-_e~;5Vd?=Z_ArCVO2w!)|M<>vz@P z;d(d9Yw++s|H%_vmUyM+kLOMBpRA9ol0L5A4zDJAT|2{WYpd(`+C#hs5AXAz)OQo& zm8#$8Pw}6qk6S5wJG`3gb?pqht*x%#W{B6|;l2J7`tDxXe=nHeKk0zeNgvl+hgXxm zuAO1Gwbk|e@F8A>D^EWhTYay`|p`Uyao>+>%SKi z_TP&#{iomm?eJ={*R?b3wzk@T`u*PyuffB|`mgl+zdI)QPma&}{of9+CVO2w!)|Nq z$3Lh?& z*Uqrp+G_vl_kTOQ1`i+WztZpjz9Q3q`u9OQyqfHF?F_rEt@fY(eb5fC!NbS;uk`PO z?wsI1IX>&(=j-rlve&gU?6$Uk{1fXx{rh|!UW14C`A_OA{rh~coZ>$*KI`Ad>hNl^ z*R?b3wzl4Xf~S8UtHW#X@LvB3Ug_V*desE~NeAfPzv}R6ve&gU?6$VLe)aEPb$AUP z-seAgg3`Z#_38=!ll7s0|Ej~Q$zIpau-n?|`qjUG)!{XGc%T2IzS6&c^*2-eC+b80 z{#A!plfAB;VYju_^{apXs>5sW@LvB3eWic@>NOMmCmo=F|Ej~Q$zIpau-n?|`qjUG z)!{XGc%T2|2}=L|)oU~Tr+=TO!>h?&*Uqrp+G_vl->2#D8a#Zg|4RQp&FeD#r@ue2 z!>h?&*Uqrp+G_vl?+@(o8a#Zg|4M&<;I0Y&ljF1g{=g2eCVO2w!)|Nq$3LsNn&V29V>;eGy-Cn){>fqy%}f3iOG_Xl=(HQDRh8FpJ+ zUBCMK13SD15AXAz)K~iZ1OIM{|3rQ0?+@(oYO>e0Gwimux_)IK1 zTU+fv{r!O*UW12^^A_By;8x%~UT zL%fF!@fzYm>()I(yhj%P`+a{u!GCB0Zl6H<`12bbUXAc*;2W`ZExCd^} zCtj(~Z@guK|K$AkBGSj7zv}R6w4={|lDBh+*ANfdi2o$-^~5Xn`Kz~1@t-K@zgPBl zcs1GU+L`MP)!VyN`|^)j(0+P| z*WliL{=+?R`(@&ls^7O~`tOjkx5KN+Uf0fC*UCTK1GnE9;x)M6SpWU7u>YEQntvmI ze@5FYZH4}7_4ks2=f6*fc&XoqvPSV%`uFX%{*9UTuT^@1mt+4r#Vc+9oln4=KG`{@ zasPS!rTxUu^?LK*@A322b8ak!hvd!N^ZD9sdLEj0sD}sR^?cI0>*& zjZsfkKR6Q6$98h74hv5;?`VwI;2}fyYThwrZ|VGbhZ}!kjF_4~N9g;hc>N@KGshkB zr;hj09^RDvIYvBQKe0Z}8*VXL-K~z#-2b+}-zD&BJa))l&08JgHN>M9pLMsIw}yCZ zZ|VHmlbJtjmHm=8bLI~DQ|HgR9^RDvS+D%b`Z#a6?M4P)(ec?3(Z_ajJC?T)<26V~ z9e*||drRlfT~5dwf9C$sp1&k-=3Fr3Pn|!jdw5gwXASXq{$hQcH{4>hx?7z;Ya{yD zPHwv-d`0ut#dr_ z|D7`J-=y>cFUS7PidWkHJ7?OzsPqCa$NnvfSK9u&WZJ)^^a3x({;i5v+Wxy{+P_Wd z1zwK*+ZC_0{qLmpC(onqeucjdj?aHJT}k2|n`piB6FMO9YJ6dpYiHOsx2INZ-sTvu z!Nd8!kqL7zYThF8E};Wf+MoZB?mxI(4390!-oUGIml6JJ@s?t|hIr7nB8ac^*7>i+ z+gjLv_jl`8suwR|C=X%%B{OF4|Ka-eQe+eGzes0h#%8SosrpIr($M z;N|4cQG=J0KgSGSPX5eQ`1jm6e}exe=Fe)yE1f?N%*>xPq?gAZ;N|4cT7#F9KkE!$ zPX4SncscpAfq0xh!G9C;XF>5w=g)&O^Jk;-C-8FeXOqFp$)C*zFDHK%4PH+EY#|=! zPw?Nw{8>`G()n}cRrLO2jjJ-ZzVI`#TNljDD$E7&ckHoS{e1%9QM{8l%-^GUrR{(E ze4hOWKa1!rU#GPG{h_aC>>`ur%_54^PTgCmdac7sR$ z^gE1M|4QNxgO@gbNLp3xG+qeFe#9hSuDZLo{H^5m4rE1f@2Rr#*R z57rrNuigH8yuhRQw8oF<@#+UB7`)W{k=J*7$e$O|d4xXy%Bni;{=!~^mzqCP-#+5; z`-MSYgMwpuh(GOKKkZk%()sg`nd8p^(#zvd;JLWKBXztu7~?e_7e49M@y--Gid&u>9r!u712e;29Vq`jbJ=(-ry`}H*J9v)i^Uh?&bATAj^ zudl{aay)_n)zR_YYVeY;M})p@#FO#x`Wn&)t*>N!uD4p>cEwxi_1`I(5x-8eIgi7{Tkvcbz4|8}bJD#T;r__r&@8$bTF zvh#8@zVLV;^m*@ay@5~RzkaxUZt<=f<288Xi1Dw*Tc^gqpf6?o6T}^AJP`Tp1*U#J zW2eDO9{+^CT?UWx8THj^_hWV&yyWpu=-Wd)9{+;>8ZR&W-WxvaZgsxwRlJoR|DHCV zcfWeSx?e4L-nbF<(JGr8srm@K27NW6K3cq6s`?1L8hP{7vQB(;dF$_Q2;x4KFThL8 zKS8Ui{RS^N{{-=X%9o(8L7Uir%NDkKdj37Acq^TM=c)X2@$l8;;xRXCOEaHcR^9If z9>pVx!|+oKUe0)RNX1v^^QUxnRx>`i(dzNwu)#~t7cpKPQSlA>8Wb}kUj(hHjw;?t z=ZkjHHWzP-Pb=P#1EMVSVd41!HGT=6--qK9eOc0KV*y?^n(3I3BS>J6li z*XMy(qy91ele~o(uOS|_eg2cYjl|=8Ug`XM{}lg;3fZLW4ZND{rIyD*e06!N>vwaE z*WfYp)b{#M=vyr8zYk3DpP2EsD0>61CVQ#v^`GD^#dzemQT`LWt%d#f!72U|@!h8E z4ZIZp3EuV?FU5a?x1+HC{$+yyD)HD!`uP2ez)SF-z*W0qyax9glYf%8n|P((zu1@Q zzdg!c;6eC@=5e-B&%b*OUh4G&v!UH*@Vven_lk`x_)}P~wIBNpUh4IOBpx6h$2a(| z!M#>NE5;*yb$P4x9aOxPo-dcrjJ>;_fbpLC{Rtb?@83$^%$t*^LJtr8 z$o0p^>sIqNs^8~jeVpIiY7Rfw@!1s7$98hd$Lm(}Hph4k9yw&M<}E6FOXtsr)Of*p zr0wSCTJIss_X}xsq+wac?eG~I%$llca8L~Guf3&@& z^XG0SbJoZ67Ppw4-K`#fwng-@o!oXw_=@Ij zkMSDZKQ(`LD0@ri&sA2@{VTV&fRc3n^s6;kV~WclG{)HOrT1GuMn99h6Wwc5dHjAl z^I#mKb@?QHnm6w##PiC>+Iw%hAA7N3uXAO%ZdeH(`ESMaQG8c~C*qOCE1lnKGxPg^ z%5Ubu?|V(jZ{~468oVTbK9KV92mYw4T4{e?jr<4pP8lB#D*qY0Bzw;+Y%jSnG*`{c zpMA=H$(xct%;Wr#yeaY7zry;Mr}e>jLE~f6_#NZH_)WZ|{8>`txAfnX@wSgQWxS2? zg#T8|-YNcj@(TN}k2l4Cnzz#9VHg;w^CI{DslR_l>!y>dx-~E8{q^&O&*AkE|Ndy; z(dQset{UXgbA7yizRBRpbq?#($MJK$o__|#`$F0Q^m$&5FR(s7UbmX}ycn-x-pt#p zIs9DnUPio&Xor=K_lu4A%5j!;#o9#`kH8D@t#Mu*8Q&#?r{fFyVh`=V*Qj`azIJ?3 z-&o$8V!Q?kkS{6v-cdNdJB;|sc{ye`zrIn$qsycErSXA}i?y2#o{lf*i#>FF_o{e+ zzBUi_jpcnP#;cKVa+OxUpC}yPml*L)soyOs9)TC?7xQ_3Wc_Y6ci3(4<9j!@cjD*m-*q+o{Ql?Byb5@*K;`=u^z!KDy^6Qe^N|*^ zDbxNBDZRkUv46kfmA3!xnf8B1=>=Yn{a;eN()M4&E#l?+lk;}$@9*7M{XPfqXgmTp zRAV`um$xu@^!~T!@i@84jh8b%sHfd{Ev!#o9|wKzcsOhMg$CqM6_@+s(>n4b?&ywdTxXJ&qWSLGA%a`N+s zidWkHdu7`HQ>7PpIrbk@ywdjHJJbH^>h1Lt@N(=wLGeo4f1gbIFRSzdFUS5<6tA@X z_sz8b8cHwla_qm3;+3|4bEf?_QhI@xWB&%lD{cSPGw0`Ps`(UnIrH;%4PMUtd`mT- z27R>;Q}X)pHi}m|KBr~o=dD#f0WT*%Z?AZz?Z029{dZA%ftO?dy%evs{nyH@r@N|p zT4}wfXU6ArfXwmZNvhs~mot7mP4Pwr;D79Kh(2G$p9cb-&!_Nt2|Rv?!~DYr&(a5cBH-w>HWQn=>#IaNgO)7y2Rj7e33``#^&FUzOkH`zS8w~U1z+N z-=KR;{v1>F0z6%RV>oR8+{f|rN?gw|ef;^@q5K}wHlp5kzOkGU`ur|3 zf5zy$w2HUzpXa6OyOQFS&Y$b_vx;$1>7t+YS? zHQj$Oq=m;iWpCisxXTFtwRr1eyoPwtwmgKd^HzV~*oMOXd!V~srTX)#!uaa0-#{uq zXMMWeq5hsM@Z|W_FYt2g->7({?feo#Nqn` zvFlLyew12V@hs5w$6yym zGrY{;d42SLw##RKo$TTou}#rcsccVzQN0>zrRuS67)^1zrQtjIrX1uM&D--Iyl+7!pdpd% zHPqiT0iLYCu^h%<$KYA@2izGS)YIO`;8Fhgd2}p?PqD$^fj+jA=Y4MZxLA9-!2^Ao z7du|R{t$!5`etrtH~-;%c53zU`uSM~kM&8OJ}&lrN%2bO_p>we`_@V?@N)9|_69E} zzwcu3a`O9L29NWnaY5z0<~9~*e*H-XkMl?Jc>kgHX$Ft=&D_DM`TcBz$ND61NEiS7 z`HELMzi;T)J3fEt^Nt*svDYuJR_h($$^0J6Vf)`;@T~k^<;EZI@6hA#)p{rBo49^@ zr@(G(ChgFYCRG34RF|Q%{yrD$bYD>#v`5osu^}$Tg^LU@MwJS$Hh1d z)x5(7&+BXOh}7$sBgDIyP8j@0ywvs6QN=4=e>cjkzjv#80bWl1ebC_L)ZhP8^%C?= ztiMkgywv)u{R##X<`~7BzdtVM8(n{rR#kHs;`<+xms)?4xZ2>Q)t{tQ)f$7BT7Qzb zmUtIY{RRJxu0Khus&$H2y8b?Pe3<{d1!KnV8UjF%^~#^Xqx$oE#O47$zVmq*gO{8? zLf?YHOUxfZtE!C#FFAh%aTD=4e}exS^w9A5Eu&FYn-#Bg{;ba&zu&CJTj2TlO#HsE zJqC~Rr*+*ncKx(hjkiJH#PR!I44&6Vbtwe}lf!Tj39%c;NJ1}~@n_7IQjFZgd_{q0q}()D-K z%=-I=su$qp)Zbx)ms5X7RJ{a!6YK91gO^%=a>cxl;?36^LEq^5lQj4D-VI)A{Yl~h zgO^r+l2%m*4PI*fN#Y^m@%l6PZ*=`hT2&oZywdfzKlA$Ki1H`!sQ&!Ko_hUq)ZiuO z4+x;gF@u+wKZ542&o63Up9lXnc)~IFpK3u|O+3z@;6LIGub(8%U7ssn>HN7#=J@@2 zHQoZx$7ka8%fA~u%AZNsFaM>++n{ga`28J&=k-mzepyTL=IfWBZ}j+0g+k3bgO^%= zlDOXBrPZILRn-QA=k+zX-A{+5Wx^%wj%vHrFy zUg`R~d1n2sx*~qREPvkw@N(+!(grW5{;qgx`}@g*zKQjBHG`L0e{#jVjpEJMFG1hv z`ja$w|H@|4F`2zyzvCrTo=8vGc>vMyboIiqifOwog!G8@JFuZ=M1@q6`n#E`7vSa8-=7)0ocg<+s+XW|V*TC8 z;HB1|Trn?Dy!rYi=o?*slIHF|8NAf`lf+F1FRlJ0&3(Sc;HB1|BrXz<*Pp?E4OY}} z{Yjep{D$I{uD?&X>y706fdJ5BN%<3aRDXVt)a#e61}`~(guZPCFEM`v&0U`xyyW~5 z#2v)r{0aVR(7_|}N6_5$x#E@1pIc;(-?bWVf#>5h@%rTk29NS*()G)qsPQ)Fn>c>o z%HXBeAC;bOc2T@}{S@?#9=|2c-9IsSsr4s`dkmhBZ;gAUUcc-$c&YU#_3a}bub+bd z8qx=C!u893#VcKZpXBj&hI;w)hxlxGdqDZK!>flGa*u;UyhiRl+&@&O z2$|C1)x$Q*J&p|V8oBpy|0wZFeIN3t*nc$M4CSA`-akhAc>USo)%`YV-rNt`pO5J9 znl#>O;_>{Ern?@ak#yZj14nX}s;kD>eUpHq(DQl)ZsB(SJK*yovtXRoH)@%kW%U!aV*wNry+*&D|sI zSMH&%mnDzZOG)}PZ>7gmZN=v~zi0T9q4lCZejnuzkFOnGt&iw`zJG|<^dGN(dVqMP z#@8>f|7e{w-)<{eY^mae}qX6Db_58Kz19bVmUzmE6n7>_tZ>ut?j zLp;tO)(7#X`Jh*zj?dbNKHxR(f9mzcx*pyPcmVBrXnpIIy`}T#OPTqzLD}Eo)jh_$ zAL)264Dp&Y-bUq5))&SL8h2w<9iL4ReIXy~7ztn3yv;ql#vPKHKa0xV()sh{%>3D+ z?CwmROsVm#su`BU?DD}S=S5bwnCXHP^Q@EZ3&b^hAh!BA zWaiI)Wq*fP_ZaVfq~m>Hh}Wd?4k~}LK8W{}_4A>KKHyDRKOgSlO<6x5QTCS3pMTHH zpQFnD4zEs&_pum{I79WQ^KtHCT;KEhne|N_e^wLkLNZJ88uwc2__L;mHv=9(dmeiH zS*z?Voj+gA%%642{tmD1G2Z=1$9w${uSw%=Q2u0nVZ2D3zZN3;LO$00`gFWE_VB>e z)co0`>@A%?|B;zLn@KOiDy@hc^QrKzklKAGaxcOXtt6+#=vOr_bFt^!JI~=Mm>%9v}O-yZSs?;L&|-j?-A) zqPm~0d8{*=M|lIEzwEPD=i_#Y&xIsF=<}}tuP-GvZ%2&R;0cC5A4)=~*-1Q}uS@68 zpBwq(UK;(_tnw%DME>-}N1y0Sl|P!7nmDuYPpA@2K)8@F;(r{d43BeW>~TG?hPrC*s|wPse*N`IG0@z^n1}sr9`t z#%qY@xHIgUTdi+D@pyh+>G9$=nelzJif`aejPFxad;@P{d=HTScs>X`7YBHx#`j>1 z*LYl&`g!0(#49x)+&VM94^r_ByovFBjEZmIO^okh6_3EHDIShXp}`l_R@d8+7>^*S z@jY5Nz6(ZtQ|99{RD1(Z%_P=SyP#ttMWn@j%DxYnj)lYn1&RUaimAey-!Qc8J%skJryMZ=Lcd>x1ha$QzfB zy$^l;w?3keucPMcUR>w%1RHvIjYFkgpDrkSS9-mmt^3c+{Mo4N@9=7U#`bd^?@cit zafbYdrRlf*E92HtFphtt9y)h zKhp8uHpFYvc-xgfSs%pPP2I`k&yI*b;Q8^acAcJwj`z+U9;9|^{_Ilrmd>9;nfbF@ z+27&SJv|c!hGm>9~$B{CMLY7d54uhSzj1066dcY5q%*a>mbGK=y)IP;Wdtsnm@;s zy`}T#zcTY@?#Foj!1tdzyxMeQcu~iDb&N-xA%AM#8sc3{XJmaL-ii6MHlh!Bjr*Uv z{#n<y^Ew^XI=ge`Y9h=z2t(vO(G3;nn(x{^turyr%zn{nL$w{rNxa zKgz=)|LOeRr0nhRYHd;bx#n$-@rW~&kD9lr{KxvH*58(hzNz)M)We%OR}I;#>u;;F zw{-p8)-A$w-d{ae-9HPwiTBT*tL~p^Uh4g`D39s|?sui!Kifv}xsb|0=<~0n-ap$O z<287K)cf;0i1)|3e|9?~f8e@q?Bf|Ke*#bBPhWiWd0wpYNAptiC(0A~(`T<9&vvSK z3w_>{)O_3(<2C4+)O_6iN6w$WF!G07t3zu(e}c-Nz?=B~%rjN~1fGa@pFSP$J>*Yb z-v(a29G}Lt3}4i|y)hm^Qs1B1N4$$k!%ELLO=f&wq2e2O6XW|P72m*{7~lQmKb{W) zuSSQaj^77jyovEWNW4<>!Cz*^_c^Tp|; z?y{3aPwSieN&EBiD?Q$eQ~T~+UH;Jb|EUebS!iKQ(w> zALZjbk2|iN^>Fw{Z&Udg^d)kb_m2jT{O5OZ{_~I6yaMsA!9ny`P4VXWDd-#E@bUWZ zL$5J->^i8b44;#GH`s3I`yFl^g z^?%Sey8a~1eLu6oORYai++^_5>QB<#_cI&3)cTXeMdI=GN$_8Tdkxp0q`B{BR=m>n zw=uK+UaRT_cscd=MuV4Ae;-%%67)^1zXJv@r~Z~yJ_dag>u;;U%c;L@1}~@nwi~>h z`rAP~uD{^FiS@Tr@k-a<9W(3iy{cY-ms5WqGI%-l_hnTtLEpss`%iuUy3YqB=MMyc9>+*8e}5tHsQ&yOvHK8wyuLo4y9Dn)NnUdP z2z{#!USj?Tn*00b1}`~(1aU3#`1=)u{~Gkr@bybAXzu=o;+4*yJ7tdF`_*_0JRcwN z``qLTPMO~JGX{_H2k$Q?j=SGf<89EF$YIgnGkB@>$1G^qQ@r{9LC`mP{FXHL_s*Wcm^p$VuLAs)2i`Vn7U-s<^!JMoUEV^-Rq56Sf3Zqj!G=?lCXZA$guo*1to z9<&Mm+e^F?3;FM%nf}|S>~-x7yXIEs%l;Uz!NZ5=)Anf&6!zbPGyS)N^l|+L zUQPD8c7|PZtNph##%u8KRR8TFUa9)MTju)Xm|8CYFK7KxT?xli{`(d|AFUVW6W0wV z*6sB|(3i;J;9pMhR(d?;^KkoZcRk?eXIhVpTHlEAZJ(O&fk*N2rx>2^+V{uy8@%N8 zjnH?%;3cka1kK(5G@ zL38(44PJ8o2;wn==k?WS!0`H^y?&oNiuXS+B>RK^8hl}%+F0CSK9I!K#N+%4{u|)n z*}9)kTBCTS^XC!s;d=mlRq*Enxpm{m9GSwBTkWO;=+Dp7tHAT|ru&OyISk!w@Z6LW zzJF5l_&Fc1+eL#X^|5_J9OiCOywdUcj;e1S&!GlHnXo+gJf0Zcs_IYP+s=33`TC*x zCdOf)UjN+M;K};tdW>#I>gj1$v$cZ28kHFyNqb&RX^-H&)&-@$*xi*aK5 z9;$ey^XGrl^9M`{k4Gtg0uOd@_2M6?_CL|!CFV~{-_s19*H=%|H#2yN`P0(3gLs@j z!GFy(eXmr!()sgUl|LMJ9*5A1<*lC|#R#-k&9}hw@fm;rP0-x?Zw621kGp>G4<3h> zm0?foTW|1W{=_)U)#JqmgD3N6)cQhLyg)q8pWwd+6|90*?2oT5Z?(RSidQ;+zBeU* zLTt9 z>#I>gj1$xM0fQ&=XI0~lbn%XHwZ8vHJkFosKj64WjDtVzem~V`6t8stT$r9eU{ZJ- zRQ?1W>@YQdzG3hZ^QWcne+{13SEC8gZykUyhpk@UUu^Ia^QU#XUl5P;C-|>H390)2 zpm?S8=OUFq9Csdvf+MM;*B9H=cn&sA3@w_ z@Vvg7;^W#GcFnEJA3>|C{RS^Ne+2OW@i>2i{~DCD3ffkN;Oo5A`VJ~y>HK-*eEWWy z8+YbFvKv2oRI~c3diK@v{Sm%D2Rt7ib$@R8i2mO54W5sW;<3(tT2;N&;7NUBIeea1 z89b?vd2kMqCVY6OT~hb^wExC(7`#>SO6Sj`GV|y4%AdfK@fn+kZ2xY9C*#9BjuRgj zYu{n;q`t8n=Kr(7llqu9HtyS0ytV(va#-JX#VegZkIu}W4=8^EPsWGi&Grqo|7!4L ze3-{^8sdG@;7NUBIeeba89b?vd1K?gL&aPBZ!CxP?Nq$d`SX~}{P~LVC-7u^INogE zPhmVR%Zblr4W8Fm<9f_pfBALUD%Z}~X+7IRE*F^ItW?ZtwPp!SnHT$HQYR2lsZLUod!HUxRxL zUB5Di+hfGz-+u`HBi_*U2XnZc`zgMk%e>O{_XE1#Jh`eT{k@VC-q(Krd70Nt`g;MF zkMd^7Bfql0bgRGbbuIDu`f#QF`9tA9C>gFlt&5*)eb-j@c6c=(X}6kp<0!B3f0vT; z+on~WzaR6bh5dK2@ZX6}RI2}Or|ezkQU1|5HrC#|M0u2db&Q0s>v-I!u>XD}{5K{4 z9;EDD=25;R+Pfvnn@!5U#})S9W9QrJ4_<%qI;20^RrO=Fo&%m-e~jhud46H=XnyzW z4(72=J}%b&&frOXV>!&f)HT}on^t-}<@0d6lo_9slwROT``Mp-zM*!F!OMxyRSllh zml~f_6|Z!B9+w%P>npv$llG^^=cWcPCq92_@T9)f`22<9m5$F}Wya?YN-yxF{i*TU zWbkt0b62o;7R*a<8${D!spxl)b0G~A5M4GxE|O7|M{WczyINf z@cMO*-faUO`O_Z~<1F)PIuc*`xxsU{q$y$r%mzY0- zR#i7Lc**%Ah_^I&iTNXFRdri~mz+O>cxU2q{sjMx&mTdns(UM5>HN8uinktrIM2D& zBZ^l#f9^dce?-O~RsIBCV*UtPRUI>U$@wFQbN|=Q z@1U>72#m-dL943O1}`~(1aS@VIDdk^@%bZYRkc>}O6Si#C*%+3KD0YkynzP>jURs` zt*Ukzywv=W#N7tZ>#K3E;rx-bs@h}lQu9X=_Y#luC-|=+ebBa6VE8(3VZ4=(eTr8) ze>S;z`}v#J%{uPjYnk9$@B7vI6nNgB1M6_MS@S+>@KV=5%!c;U22bWA=a06N8Cu_$ z4PNT{huP2`A|B^Y@Lz*_@jN(I-**(RbpAYXKE&H+IbScjJnG4Mv<!{8<6 zkDyi6Hw|8L{s`iQ#N+%4{%g>|Bl1Vks_GKOE1f_0Q}K4=xqrBEvmz7l1=_-TNM`(I zbv*_=FldOwP<{QqXz*mb=W9H2m1}3%ZEdx_Ee6l)bH~FY#=)On{1L?6#N+%4{u`e^g66J|6|Z#uoHikUIQOAlr~C;#AD@A7j2Zg+ zZoR=v%^zk%yTRajeKqbioIki9Zx;++YW^?_+Kt5H{0aVRaIe@nhCl88{`V%uE1f_0 zaq;%^H^p1eJK$@X;5yz9RO(VUq5XBs@Ouf`+v{H3{C-;%+T`N;XBIWc`t zHh5lNL;9%YxNEM~_YC53{sjLGaPVy1{CS?@mCm2LJL4(dlkN|kqJCchc;GX>E>6Av zyoSM}c%#0=-y68D`h9_*FOkFXy0O8N^`h&KkKf4=%)g`Y>|@Bi)aYUIY^qh5;!$MO9+{=VM8Q{%%}-Vyr!u`kf60#DU*jHj;$&rzQz54;*rz;PYRduEK+5D!`x z*Rj0k7yf+uJu~CGPQ^FyCdT)uif`bJjxYL|w=XCE@%SHjHSRGSUnXJu+8D1P9<;sj z#r=4D0r7ZzUFq@gUYYS-ui_hc6XSbK#W(OK#&?g3N8r`y;neuPC&p`t2W>)pKU_Gz z_g3*uT^C+Qtp|YzV^b;zz2iP#X7F;>m$y*s!Jtp&AD@4yT~NH0t~Y)D`)0=H_R62Y z%Zblj3|>xr?ydY8^i7P<{S~iteD0GOpAE{Nz{`oxtqopId>ZA?pl@P)?y7jD<8yju zd>*3w3A~*6oMrHQeAM?B!8zdn&|{05U$wrm96ryI!87y6>23I+p7wDn-a#Md&qxlR zVynTk^o_N9-DmOog0Ba(zOfwEx8C4UeElv%*N^)8d4aBXFQgL$eQLeK=hv;~Z8Uh~ zKh#$vq3``Qd5%p64}3O1z+r~gx7px%eGMKF?msyD=_N+_R`V8#$G=}6{6`1J>}06s zZ83NTB(3ja@r`j}`o3WBWPFF$vvupP!Pg9)jBl#GZy7upU%syt<7)q1 zM7&shW1N`(jw)X1`Dt@xej3uv`ZuWY8hCIlufNA~n73f?D1UrjxVrZ3Sniw}4}-o$ z4(nTO@KWlJIo$q+;?39hK_88;W9?+#rQVP8iR7i!A9J`p+2Hy3*0@KizEccdO8v1e zZm&f=zW)&X*G$uQ1H~&{fA^2nAK#~BJ7evVTF(K`$A{K)V>!%!lEI_=#`+`f*tl<1 z^{n-c<*>eO29NT)H9m~B`#iOt3;HIm56?GvmcFreZ&2fn);E^J{#!736koqf>iTd= zt(StniR;6y29NxQ`f9X<*E#rXd8^k;+YBD~%*`YI5#!)byYIhlH+WuOgGZ#U4|foc z*AKye#7ot;)8NVYGB1`lZhZqk3Xhx9c*yI+pl{^-q~oz*@ML^PtPflI?qKj_d}DU9 zfm+`^44#bdi1lGh-|57Q#Wz*o!xXRd{B-_&-uwSAy>|QWQv%P&XX5S#4W6vOFfP{P zK0mt0;F14OUxdRtwZ6RuPu5=;UmHj85oZ#%P|wnT`-sQ&7yQ@Y{#?)ath?3v_A6fL z`kQ6e-|JOA0xzfjb{o8$`ul*v%c;MAHF(MO2LkAEK;@(GpWkCd{Rx`;`>h5qx&8$4 zkijGWp}yL#V=@o^UXY+w)nS8|Tz`Uigm_$k!G8@Z7*T(M=Dwd)@k-aygH z-QfB7(0VNOzTIYZJ+AeER`@^mv1stTK3b2t{7$m_q3U`(=u70V{zn)*OW#<#*Qo1p zt#2%c^{q8{6koqf>iD%@)pO7{as1j~@W_9tuSQE^^Qshh;8cB^4W5iI^J00U^*x%dCwYDf`X*lApKb7D ze0e?@tM5F6C*vFAa8R_p+YO$KFV812uI9a%c(M4#I5B;%QoPdh(*rZ-r{}Br1b99^ z6R+=IYVat(Tl43TU)jGq)qJA$jpZK($)IoI{Itd3k^fL%jh65@i_ey~dVE+ic;K_C^V3#? z=k+zHA$5M*Mm)Yg3;rWs%uYO8cmCXN@ML_M7t0%czvXXfJdDLR#);{BtHG1;9iE@$ z-KDDfCxa*Bo2u`F22aL!cz$Z@`xxF^ds_*|4uk`q^ zeLjp2t@WYHqq&Bi*wcPe-7f~7kI%&Q>*ov})Ags zHd^07gXi@%cyJhB;kl1EzRp{%?-230{(}GDc=zCX#%JBF)^}L(O4r{d6Xxd{0zi)= z%Adfa`ty5?$R9y-?++NfcF`6Fm9C4P?g?|D5N{MR6FRQ?F!YT|MJ z1pg6lME(d`RjpCH()n|ALjItqaJ!cD^8G8|`S?s+->oxvsre)Itv7gHUyXYW=Z~bh z?@KXwspF3%E)b9JUj_d)qz_tS9K)Y>um3hGUg`XKfVV8wu=hh`~&Q$-s%-~u2 z#@fA6-EY$R#&Xzyn+zVs*Y7fB{lqM2H>r9K`X-KFn++cM5B1f)fw)u+c3WG0y|HNU zz-M6{7U3{d^R^f~udl%)!u%KEYTgp@c>D_fBVNqTn7*wBPsW#dvAogxPW(Xo{raGf z;v3_{^sO;?GQK>Y#JF1D)eN4DZ;TVucO8Q#H;(_r9r7#tcdwdHw7#(%=It|hl;4x)r+2IQByGTHja>`)`NAqxkw=Qs<{_G#>KxO3+8+7mtU0e%XE?>2ZczRZi|jlN&-moy&6;v3_{ z^xf6q$@mV>Px9_fRo&O%$@r$~TQqnwzQglVTi;p4i^Vrp-(M+S>G|oj$ow>mcEY|JQ?4Zoot}i_iqMI#&^W}u%+*d#EZo@Ro{OqUg`PiIrDk<*T1da zZw8)^&&2uZLW4*7(;olb_&wtw_q4w=cwQfm|06kkic4Lm{rj%Me}0!SzD>;3g329Nyb4~=n{tMwfrc?!@5dQDudhLejH*9DTu(f%m*79*ji^6CbMJpEUg`S#>G7fdFg^ou z*XxM|(#zNP!1M7L;Gnm=_y0B;ywv<*Hnf`zp4V67Uc=)z?#J8B1}`;#m<8=3@%Z{a z_^-jehVuva21mof7nv!Gp4 z^&Ip~9KW_2Jn|pvt9>*2^9kDw9{4QGqfTdoNOP;l>+J^5>mx{*{~}z?+d(`Yzk>gW zH@tpt%id}5WPF(y%Nwol+jKq2^Hb1A@r`jQ@-xw#R?=p&4dVYFn=KS_$A{*VvDYc=kFOX!%AfZ5 zKk~Z#^J=^f`gr^w$zgr}Zt!INrH-$=)OZv0O&ni$8$4NmTsK^YY!|mWzxNnCAKw~} zh;d@Py#`O#Ul?B-NAMA661H03KH_ox1^>bE?!onp&$?U9+pl<~>+j*2^>?AF7vSa8 z-;WJmPW@e^>Luu#Sbsk;c&YU#?++cIc=Ppr&^NmNB+Y%llfg@^KS?}f@Y3o}(%knu z8NAf`lf)y$;+3wyGc)V&Qm5eiE&TWSfal{gas7Fc!ON+? zRqNXC2L*i->+jMAFSY(SH=$im@#gElpl@{jNt(MqYw*Z_e#bHOCy5INFRlJ0&HX)R zgO^%=lDLU@y#5USYjCgO`jfP(+N^k`>u*bD{jE{;0=%61yQ;yDj$QsiS@U|;N{fclEKTVzpVx@r~bAPkLxe^Z({vzSG>~ocUEToovP{ucsccV zeS?=%f3>QYpl@RR-N4}G)ZY%3k3rwW`rB#na_VoF!ON+?-3BkG{`L@$>o53kV*Tw^ zywdgeh|K!Csj3&?<<#Gw8oZqPyP2w&pl@RR{h7hbslR5J=TrPA9I!#z8+bL@OKq?J1n)L6UPC-;`M!kdKf$|WVgEfObG-gnHC_ka#PRi$ zinr4Ff>BuB{=(&tA0KDVJ?ayCM@Sl9gX#?rw@vFnD(Xu}ON#4Q`uOS|^5&ucvM&gwkzkW5ve`0*t zr0nhRYO>e0Gwimukbkw{Z64w^csP$=Etq?vd5eYp_v;D%lbW}XKED6n;nlczU;atn z(h#p99<-7C!#!}jm3XD<_gJR?wkdl%yc+Eo>%Z+oyoPwtj_}`(!v6cs1pmqLWhd$5 z@vpE;l2J7`t}v}-|r^)PdZ>f>ErRQ!>h?&*Uqrp+JgV&KF!M*$ZCwT{nS8Duw zsxKR5Xo>V6^cApEHuw)qYQFX#TpZPoq4psyx7T|48Gk7(~`@N({d z98&ob^i90~aoFJH-2XUY@O*r0bXII$V^`|WHy$;3USESp=<93daI1O8h{yF2{71Z4 zoyB-_zixk?dZn)y_`KXcI`Vp8w?C1^4+XgO^-?Lf<0sxc-9w8qx=?xSqjRm$&-!p<5KMbp1Ulv;H=zdI6q~ zPvSb3J#t@zms5XtSM?I~O{~Ao1~0Y#*j8wlDBgVi6ZDO)KS`^qtp+c({v>gm!Aq+@ zNvo>u1~0Y#Byk7vc>Njt*Wg~M>(8BvSGxWln^}M7sCofjPW?UI;N{fcxvE}*zKQks z41=#^|xQ~O4r}xGVAZJRlNW& zr~Y1J@N(+!6{=o>zKQksT7#EbfAWgs0L7cH|AM~J^(SfW_wNi|YW+##A%mAzf0E{Y z|IXm0)}JIEAs(+kga1a?pQO3pzf-)@_4ikq_4jwGUVxWVe{V5(IraBORWCu`#QJ-y z!Aq_`a1cF?seBCj#@C;qRn^?F_V3??_||yBd1_g1Fk?`S=cS@NCBK-x<8* z`V;!r5|8UI_^&|)!|Tsl(A@nY#VcKZOPTezUDXTle0(Ne|GmiI<<#GERJ{a!6YFn> z!Aq?_&P{07Q@r{5FX$Uxf0E|z-x)mepWksz{Ym12!Aq+@Nptsy3|?yeN#Z8r@%l6P zufe^B>rc|${UOCGU4M_ytiOLy^#Z({`g@PT%c;M2sd@?eCf4736|Z!Bet&#;f7U0; z(C72?=UEpipLl%>Jc^I!@#k#YS-AX6fB)zfgO^(0a>ch~@Y3pA(%k(ggO^(0lDLg{ zJiiA2HRz+^`j#|z|4H#m=g%Leu>K4PJ8o2;we-=k?WSKy01I z_UZfIyA57){s?`0h{yR8{MV2^XcO+w?^V3g`SX7+-fl=w`+UBz|DGSj_4pAqw*sE` zr&?dYA>uIFySskAzrpkRYCL3~T8_Ks>h=A@4W7)$7>5Pw{CSMQ^ZFXnN9`(TUED2w z7YIi@iFiN2!^USj?TT2=j>!As5`L3|tWIDdlw#^;ZqRnO#Dlg~G59)fHSa*-`FvHn|61w~DtiO3MvF%Huf;nQ z<2A&Cwsi!)&Rgfd)=v)?_TRj!7nz5&gkfpEh4qDe98vm!r}Nq3Fhlc>DqiXOJHE$$ z7&r7o>piCQ0#Dm-ahR)lbHBm$ zMfAmuP5HFa3q0-5F&yT7QSnOKe`%Hfe7_NFfdBfT*GKrK9Y5O_5n$?K1?yzj+$ z4e_9Lk&5#!XvzL@;q~yz>Hcet@4r&^23}3}x_0KeaeLeAt?FOe_j3ZTaS-?5`7zGB zprvm$@%Z|5rStJJ&VR0C!u5k*ziFL%{JnzG2RwcK1oMyPfG^;o$KR_f-b&kxXIiBc} z7_T87v?v)-{Pjzeg2#Zruy}y84-$xppk?km8lL|H+y5A69w;Z=(H26tA@X=Q#VR z{(ZdU`oFJkA-3>1s`LU+=hGMt(yHp1;+3}l+#dV;>X!A+eFE2;{Qc^{)AoV@3sAVlwROz`z=n){=JG<+WxcMdV}=(yyNvd>lPg zD)?`JL%X~Cuaf3||4s2q=g&2!$_giH!c5uP*~sfgT86`_p`$KZXonc$-mzf z)^|gpZ%Y2n@5A+CsqtmK(+BH?sq^n;N#BK3K+8OuFKezWyVdn}l_+mEY5uK=cM+X_ zrN`$R3IF-|av%w{z3Y{|%RHKY6M46Y@@W1|jK^OT_TP=2|J*H;im&UreV>lJ{|_dBxRyZoTt3#Q&szY`$47lX&k%>1 zYYm>)NAIW1tM^rgxa$la<&UomH$TqJ+{uSHtZ%)+Bmenb`2IuebMSut77qQY%17Zp z&x>(bkADB)e+(Y^5B1e}WNcla^?l#q<<#F#44&85pssmpd)F7jf4?RkuWy6@1~_=O z?)w{aAHwSm=9R9$r#j;)e|$cs*53w|kHE{RzXgNm^-Zk5jRr5L{x%sr@}CdssQME# z;z<>QB(B>WT)B{D=B#JW+4`3F0*jUSjKavlf_O9H zalHip5ieH9c((5P{?8S!bp1We84tsWt~=H@)E-suR|lS&r-nHE^Iyk!bREq3$ouP7 z&j$dK$M)A1R@;qzSE;Kkx&admvQDSrxm{*(|Oi^FG(Xu`4bBEWcR;M zC+pSidgafR*89w!{AsipHR=VCuW@w(}>V@(L^IP552|GqQ_f+`^ zJRhG#4&(1<@F;&K)!%~+9_5ecx%`=%@ySQDTMQog&mS%4|Hk0?{Pt(YAMR86DE#Ml z7*T(M=Dy#|;F144Z&dvW;sJw4{zHAWUB~{1ZsV>m1kL?@1%v1HHF(6R`V+)M#N+x4 z{v+Oq`V%zw`BKFzU4PH+slUE;A9|~*9;@;Zc)I?^aF}_>5UkJyrP=csf2~INn)q^DKiGi;u)D}w)s zH@tq8H23#W6tDF7`+Qd~ls}W|@3Sf&f#>5h@%r(g!K3^^eTjARb%RIw<9VsqkKZzQ zkkCb zW1GrH;Xl8}i24&W_xEKCUUK~j;tqpH{zHAWJ&%%kaQ{Zo+~0pOc**rAh`Wf#^%wlt zpn?(gCumi*Tk%TQ-wQMA@3^b9-!BH9kI%&UZ?(b8slUq`Jg+Zt9_4(xior{+KQZF& zQTZtR=TAAJ{sgV6_8Pq8`V+)`29NxQ`s%^@6Et^!*We}BpCBF}9@k&+U*qM4?}No> z-EHUouHu!hzZYfJ-?dae0xzfju4nLa>hC57FQ@))Y4DQk4+PNT5XGCn-&y$2?=hnO z1kK%lH+aeQCx}N39{CUT)r0jXXzu$L3|?~m3F0y0@%JYO|21CTnEDg6s+#*f-hX9Y z>H6D|S%0@t`3O88pNaF|MuV4Ae|Ix@Uf;y|?>+`Ex&FlXy_(|9^(Xv?`R#6oQYv9W zsjVKr*BHFy`V;!r8a(nJ>Z=FqPte@`A%mA(e}cH4cw8^Re+@cn#QIav+~3btywdge zVplIYkI(%{d;Pi6dS8;M?_gnlZ)!y^-IGtbE&A_Pbm&U^?=MeC*CdZPm-M}mUR){O zmB?=^ZLic0{WbG$PIK+N+nlI>IO6#gu7>e>5$!8^Den{Usn#l9Y5T8`X@9NsO5POv zZ=iUk?cbeQp9>Af{}B|xmDYRn%=$c=>XY+xrS)Cl{0A;vHL-qfd1Lh7S%v&}j`JU^ z2l(@;sdawZ^-iKOW^rehn?;_su-uqQ0 z<2$9E|B-lZSn!Y1`TerY`o8haF@LzeTfCG+BzyaK6L8fA()T6eOMR;*0Q-0;c};Sv zKkw0Z;skwtyp+6VeYYchUpD-A`3d?ouXKL@J&o5qj`29j_6@bSr}6e_w4>%RcZkD3 zXWrQc5Ar8f-OE!@sQT$!SI+`&-b8uw)6onwLb1iJWJn{ z@n$pec<7h@!+J{_Z%!j#x85-SQvLTp;_-S+>YGx(4L*v`@Vu%_cyTHm!Y^bqiL|Ghj@ z-$T^>ua&NkAGmQZ=W#sgdmcenTHo6;^?jD&%QmjGzPJAWT;JQBKDo|KU2l9-tv8s* z9B$daL+!WJdV_g#zT~-ihy_1Co8~uOZ!iyZ0f*Z$EZFBs#N+*$C-tSQH=aT~wuyP5 zYsz}#sl?-9g?Un6%6j7&#N+h_^FZH}_3kr?$LkHrlX=Mg9co{8Dqe4~&ovKprd)3^ zkIyT45F_>@|9q(ZU&?1o-<14g9-mk0gL95KD7_{ip`(R#!CL&qiEZK|pdlfG_!FmI$V+U-}-dc*r* zsro)n`nvVOyfl5ki_{zB-;{jWPUF3vf0yfxBR@_j*IS%7j>CI>hWuyouzpi!%c|n~ z)$_R=5BS_;+Aonli-+Sunm!&6^n5PImod6{pRbWV&ExSaHD_Y^vdl}npB>AWWnS9* z*|B_C=3PE%1dQd&GB53ZXJ5Xg#sXseLaN`(QovXG`sm?K6zEF*-T;zQEz>f3P>T%SIpkiPSHA;S(yY=1@9zo$4m;jz;3{kh`;n)BJ8Bw@4lc=X@%=$Mt( z_lrz@Pa=IUD5UR~nflHneJ?De?^l`no<{m!R7l^&nfmTuIRAc>sqgf{`S;^YeGe_1 ze?Q68_mIN*cS)wcM-=wo(M)}3753jxGxa^Lu>XFRsc)&U|9;u9m59GsU+q6yI%`>(k#CUZ4JTrvJ_){~avkKUg=zy*s%6 zg1_wuSNpIAUPJ8_TnnFFg3m*r;{L+}N*=DM;GPEDH-Kw%xR(LAzTutyk8f~&Y(Gk^JMj#D@W~tF>sO`M zKTFU3L2h$U{rpruo_08-e*R5*&cj-LBji7v+MU$8!@&jB&D77Ir+$7L_4Cc@=XX&* zKTrL<*@3_B-5ka16p|g9w_O|ceT3RqtlH>*b_uobz7#(H_S^5^U!NV1&!0r?CCB0O z092hb>pS^Z9z!j}%{^}a#arX+-=_8=y1{kQ0=|9~YA=5S1a6?`4Yjk^yw3mNTz*dN z1uvNMufL6+zmwYL4v?Ky^?rK(A!@7Izg&Hto_~{HfAydFkGz6d*aN8WAA%h&|}^>?e+KSr-JH`eZc z?z;VRce<}j%?o_*Zm!3#&4t(I!fTfguU$U8wkEu`#=UmEz=Iz0@HOD!YrwRh9`c}vyyILC^+6AL&_f>dkOw{FK@WM* zLmu>ycPZCH9`uk0J>)?TdC)^1^pFQVdkOw{FK@WM*Lmu>y2R-D? zyB_kOhdk&Z4|>Rh9`c}vJm?`0ddNH8^^gZWdkOw{FK@WM*L*5Clhdk&Z z4|>Rh9`c}vJm?`0ddPzw@=kO;dkOw{FK@WM*Lmu>yx7ziP2R-CL4|&i- z9`uk0J>)?TdC)`NNv?-H=phe!$b%m8pocu@ArE@UgC6oO?Rvy2R-CL4|$hyJ>)?TdC)^1^pFQVd zkaty2R-CL4|&i-9`uk0J>)?Td6#oNdkOw{FK@WM*Lmu>y=SD~3 zK@WM*Lmu>y2R-CL4|&i-9`uk0BP;5I9`c}vJm?`0ddPzw@}P%2=ppY4u7^D6ArE@U zgC6prhdk&Z4|>Rh9`df}ddPzw@}P%2=phe!$b%m8pocu@A@54Ahdk&Z4|>Rh9`c}v zJm?`0ddPzw@=kF*dkOw{FK@WM*Lmu>ycV*W@9`uk0J>)?TdC)^1^pFQV zy2R-CL4|&i-9`ulRRo6ov^pFQVdkoW%)_TF(; zRp%G?-Ip0)Kph4cq%#9trPwP13TQM~ehFg3f}*G>U@w8FI5P-XvDcWWu}48PM#q{# z1ZjpDW-#=oCV&krlnDB+wVri(-~V1e-u->nv!7khKKq_??wt#*sE=0E*A71 z74^}I`e;Rcw4y#*Q6H_SuRW}&k5<%2E9#>a_0fv@XhnUrqCQ$tUk6xGAFZg5R@6r; z>Z29)(Te(LMSZlQzK*b>K3Y*9t*DPy)JH4oqZRehiu!0peVt%MeYB!JT2UXZsE=0E zM=R>174^}I`Z~jk`e;Rcw4y#*Q6H_Sk5<%2E9#>a^>u+2_0fv@XhnUrqCQ$tAFZg5 zR@4V;Vw#l(==yJB;clyFx0Pn5F3#O;745dr7w4icw$K+_sQH-PHQPeXwor5D-8I`n z&9+dpE!1oaHRp48*HXIMYPZ`e+1-2O4v038Yb(ZEh>^#5X~lSH#dwvgaVU4U72~BZ z#!D;4ODo1p3pF1zB+-iTDp$Q%?rtl_OJ9taR*aWcj90n4>x=O!cegLbtFjuUb1`08 zF_l#eOO$Izn~dKA+vAJZ%!LyuzUQB3oEO!IsUJ&K`6 zF?-}=_Q=Q3qZoP=vu8eL&wLC$ilIj_d*x&H%E!>77_oR2Ba$Izn~dK6QVk15H= z(4!c76w@*v(=s1Jk7DRiOsjlMt9%SSilIj_t@AOh^D*=&h91R~=3`3pG4v>g9>uiD z$M8%+){sPxVs@W9d*@^J&d1QB7g9>uiJ$F$GK z(4!c76w@Ie(;**2k7DRiOvijo$9xPuilIj_o$@iA@-g%%h91Rq&c}4l$Izn~dKA+o zAJZitLyuzUDa-FRFk-jqp7+2Ak7BsnD2BU@V(3u}J&NIOqZsZsilIj_^eBeAjbgal zD25)z(4!dcHj3eHqZoP=Lyuy(+bD*+jbi9g3_XhBZlf6PHj1G~G4v>gyNzPF+bD(} z#n7V|?ly|yZlf4_6hn_vh3 z816QT;clZCdK5#CVz}EVhP#bo=ur$kis5df816QTp+_#k7BsnD2BU@V(3u}J&NIOqZsZsilIj_^eBeAjbgalD25)z(4!dcHj3eH zqZoP=Lyuy(+bD*+jbi9g3_XhBZlf6PHj1G~G4v>gyNzPF+bD(}#n7V|?ly|yZlf4_ z6hn_vh3816QT;clZCdK5#C zVz}EVhP#bo=ur$kis5df816QTp+_uT0z=+*O9_}sjaBq=^ zJBd8pN#x@!ArH?Bd3YAc!?Qphu6cR5=H=lEmxn7{9XnD9S01ia zdAL^P;mVYUD^nh>LwUFk<>9K6hpSE=t}%JI#^m9Ol7}lw9 z$iwv`57&=8TtD(~{m8@hBM;Y)JX}BWaQ(=`^&=10k33vI@^Jmg!}TK%*N;40Kk{(> z$iwv`57&=8TtD(~{m8@hBM;Y)JX}BWaQ(=`^&=10k33vI@^Jmg!}TK%*N;40Kk{(> z$iwv`57&=8TtD(~{m8@hBM;Y)JX}BWaQ(=`^&=10k33vI@^Jmg!}TK%*N;40Kk{(> z$iwv`57&=8TtD(~{m8@hBM;Y)JX}BWaQ(=`^&=10k33vI@^Jmg(Y5ALYLLxY}p8p@9$5c3fl^|MeKdK5~dAfKfNq4elEC=ERZZIyXx zVp^Cw4QdIaFmDuvp~nKp#&Bk(W7Q2j9taN&dGMGZJT%}zJvFJFDlEzyh4b^C-9}C7 z5HSmEl;(rm<&DyLF4bh{!a!U0>^AbH z&{mWxpOf}RJ$mACx~2uk>vT;54ncTm$b-Wa9vbpsNrZ=nJXjLpp&<{JM0jY(Q!*!= z5pBVUdh(tWo|pIp=2B$6#0M~8pwTeURv2g^4AdM3Y96IhsE5YRm#W};U@(nR8M|Jp zYM1vQ2wCtH%J}7_s-nCHF>@+2;RyqtPx2lZQO}&Je2fgn7#jON`LTzAv4?@Nhk>z&fw9xT5uB6u7dQfQ)2zO6n{bKZlt>{*cd=G*F!<)I-@F7KfsPtUxEhCFyeH~^*m=#d7__wZnzyF^yr zz&wWsD>DqN%rJ0t!a#+`o<3{)5fx>2Akte-H@jWE!9QWk>4fG3mpgi-!+YOQStGv7uA zR$Un7vr{QOmE|>QHcG_`zb}7&!HBa7Mw}O6;JkpBa%%7gm4%7d2vQP@fOPs^22XiH0 z6k(wAVRW5kW1qayD{pkm8~f&s-eJT+nVO%d$@z(rhZ7|a=SLnI@?a~t?p~InF@>eD z6@-U|JlG1tLqi_S>UFAzhU&qrhKGhcnAPym$hUQkN};W5|`SS)kA0D(G1{w_mZSBq)qAdk6L$Jd2=}>qO z93BLRhlXO%R(NR0gGR$cLmspq9vbpsk2*Elf)VxPJvb@p(LR5s4745w8Vv(&g@Go* zK+QCCop4sZ=CkrOhX*y&qneBIHHU$k!$8eVm4%waK+QB%bMt)7&E-Lb&E%m0PwX3i z)dqrn14dj&g$F_5!4(mV*ll*l%$a0Q7}#w-$$Mb= zfq^Wv9$9ETvT!{HLyM%FMu8!B)3`9?@X(M4hafyO6n6e76>kB$$O#Xw zcCL=L@-es~3J+H1H7Z3zF_`f1(2xi793C3cR^EfIh6f#s7#h)5-h&>x)U0%EzK7Q; z1|16zjVP7(poif>$F9rw@H)kyW8tA84>}ee8uFlH;h`Z9Iu;%p@}Ohkp#jf(wb|l# zr<7*it1}x+`X}2@(ofPq$$pZ4us&N{JUIQ+>|{05` zCWfmn=BJ~1r#aQ!!+bBZ#r<4vhR$X}XPuv{@i<9w1=a=DjjbD77g`ruH?eMF-N?F; zzHiW{VsNl>aAq?eU=`zw1bluaW{byFl(u2~xWR4qmVZy@?_mxy2b$&PvF2W8k=fL2 zZZ-pJmt#NKGB{IbHjtYKXGHkfp9>v7!W?N{1jc+%Hm782mqqzHv%!>q%b<+>p!^`~ zUxVXTji+nmGgaj?)5;;4r$y{@RXJ;t8u_c7zsmX2$d^X`YUi(ZzBKZsk-x_IYn(5Q zeCeKUk7Pcm`blfm2d(-*l_v-5ap9iWQuwrRPmG6;{X&D%a|ALStNms7dRA)&r$;DKrROjsCa8Z77c~A8c_ve0DK|ba_5IV10aa z!1|B1KGvE~5}4121g~RWPVx9p(fG^LUe4bO`E2JxbA&n4yhu#C^Jc$z2VRZ(c)Lwa zvVV+U4CfKTUj25k5zBd%`T5?SLqUK zknJFj`&V`9YIYM@o_9ndZiqx&xr?|=CwUhm;wFaVeV1s>dn0Pz8YvF<6e4aZ6lcvF z6Zvs%F5=Q$`PRIdpyn072+jHCb!au#d9Yj;pVYhv<-G73l=H$%P-;`cWUBle6B?eB4gWr|s-tp`JkVxbaCezvk6vEA}~a z(F$vG#z~pf@{X>V87H+cp>MYaxehP)I=tNHVd%mXx+GmbYy#Q`hunhrQfp8;rORCY zGM5ism_nDN%Uu34mk(Wva;z_d++#XQ7+oQ%H^+8`I2;%U7A9tbhFFf?DC-tQ|OX(v&-M?@}WynF8Y6~%irq$-Rk&T zoj<|(6P!Q6`4gBwIFtU$e3JQt3#>uu7U{2y9}FtKwKeGS3%Ng`{6g+uAaA;;dCx`7 zTQ_Rnxlw;@{k8SC*56uxXZ@Y^H`d=+e`@`y^q*v+SU+O@u=T^%FIc}|{g(Ax(k;@np5JFZpU*n~S>#t^zG^T| zaUkBOpg*$y$a7NY2+GAnU>VSiGO_WA5ws z^PJz$LA{^n{QeE<{W<6NZ_qm4zY%ZEXM((*<0CkIaYR{({efhT(pJkAkF0 zYCI5-CaLlCN1CKAuqLVT4>QG7W506ew6;h_8ObbOdL0ko5xMWaS~h2jQG9H z4knHt=Y{J+#PJj1zsY_PezC<&T(BU%wb|B0y!@y~L_ArAuadMP@l6sDUnC*gZ?Wb7t5q)hNz~WUgpPihm`5E~%%g~T z6yg6P`vJcQzleU1qaXbi(Qgs)BH~5Fi&>AWvDwVTe5pRnmx%ciF~2H@`4ut0BH~5F zi-;F7FZ+4EL}>XjPa?)EKgKUY%MTs-ZWrrX?PFbwjXd5aW^)tAQ~5ZaB95ns^)6z) zi&*cVj?+y(P9lzzh~p$;-p==ac|PMYf6^p1=24oY#{5W=)R-q}k{a_RO;TfhNR!lP zUz)_cRiWOwB+dsB`^fFo*hfU{BO>+-5&MOR{Q}f}{FwJ+5%q~U-$a~mBI*}W|Kp5D zeImyHlFN%IFQUAN@*>KMDF3p{izr|1@*>KMC@-SCi1H%JzvJ>E%0J@rBFc*>FQUAN z@*?72aJ-0k5%D78MZ}AUf6MVA;zh)Zh!+trBK`@-i-;EyFCtzKMC@-SCi1H%JzvA*D%D?OKBFc*>FQUAN@*>K==kg-TKkD)#%8Mv3qP&RmBH~|k zyoh)a@gm|y#EXc3+wmgeMZ}AU7ZEQa{z=D+h!+trB3?wii1GZH@t98$dc z7g1hBc@gEOxx9$-@4LK+@*>KMC@-SCi1Ht}yomCDad{EtMU)p&UPO5j<)3nS5#^`5 zyomB5%8Mv3qP&RmuerR4@*ldqi1H%JizqLmyomDuba@cp=bMQeB$H2k10ibI4R<~ zt|z~}gX>5U*L5P|!*3#9I^%K$W>Yicas_5n6Y(mCcoFd;&WkJAA8-QOZ&jOGQtxec zFw?Ab75#-~kqQ5;EC;^`zleS-9^(|zZxMdw!!N=wwsQX7W(N~~<-;$+FJ_(J*lcFP zuYCAL_{EmaZ)3JM;a5KVBK%?_=QlB%oA4_iei42U>!c>NM644L?Q5NYS|_;Pnc#7K#(J>cTTp`~>}RW*)PmzDbzan@l4C<7 z|D{SCCygJ+NyKpy;n#TK7vUFi{-}OX^=Dl_sq@VBL#uv_Pw^O^i1CRy&yZS53POYZ0|c~v%lDHq)BS*H_{|E_8V!E z8vBhjNsawRnxw|OOOw=?Cux!z``(#u|4eGMD@{_PU1^dU?Mjo>Xjht~M!V7^*H`(h z)RD}YJx#nXbfzEg3nJbZMD(W%{b*lAyCUl8OO5&)3xGhcrozen^v! z|Hkp(I9?j@(uk8L9lz4?D;+P5cxl8*la62I_*IUVM!YoQq)Er`a{MmGOCw$yandC7 zF^?-4Pf}wZrAcbcqcrLGHI857cxl8-BTkxRKIUDTq{h5Ulhl}ZY0~j(5AkXbanhvY zr4cWUREt%-6;8n;5S& z`YocrBKjGAm&3lR`mpbUcpv&$_vclGW|4{KVZ6Vt!t*H+&%;Dqj|`LF#Qmu>;=^wu zKJUNT^@#9`Eo#QQ{F#y2*bnRtK0eyRIq5%qJAAW)PE%WtY1X^B9uUWOPP&WN8+e`|;&_P| zZ}?4&R~qvy;<`j{c~O4LtO|`lhj4l zr1EE`Ba{y+-x}>mqaMy9%Zn%{`uOnuLdWI*bA0~b`4iDE5%D78MZ}93hst9dBH~3{ z$EY2gPa@7I5%GJnza;yMa?&I<%1e{fXm=0I2S|u6fvJ7`Z+;<6ZJ`BoVR*DMbslAUPM1c#EXbmIrLvd zeAMH1FrR7<^C@DUwLVDo-x_h!h*Lhvb%^zTht{Ks^)8KdEn;1ZSl1%@`5Uia5&aa= zPZ9kT(N9q4_dh&d5q=TzZ`v=yFXFr`;Cz!TkMmQSr0!`=Li0TS3GpH|;-pDx#7UDZ zkNEzszdtqNq)BSTNt4tV@6n7Wsd0RyNotH=nxw|Kq)BSbhcrozaY~cW?Dx0s|F_iW zhcrozen^v!U+wtSj+aKfG~%R5lho+9G)ayA zAH(`dYV<>zq((oaNyqnbd>_Y4BVHPD(j@cI|D)Xhqo~nuX_6ZKmL{puZ)uVm{gx)F z(Qj!In)AO2^^4T#hcrozen^v!U+(zjj+aKfG~%R5lho+9G)ayA_htPgHToe-!+KSaC; zznJ~hezTd0_(L5pB3{fcwBKxIBA(BUSigvP5q=zh`9=6eTnCA`4ia%4l=rI~{384! z;x!KVMfmgMI>h}HQNNh|SFo|!%tU_pfMZ|~SM11&bQa8toh!@eH@SEsQ_-j&E$BT#;G2ZZ-7;pG%QqJ)r;ziUSeiQYF zzb18eyoh)a{SUv1{)fLNl{sESyomb4Z=!zba*UhnA!qh9%h6x?&7NjC%E@o`H1RoX zj(&U&E8=rl5%Jv|FCtz2&Gn0j7jeA8Z{m1`zb2JBUPQcz`onLc{_xk}PjI9EBH~5#Kl~>8AAUTa za=eIm5%q`PME%k@@3gPryc2QW<@cF`T#tx)MAQ?06ZJ@A{tx#2i%nq+y@JCXe%sZp;q zNsW4?NtQ?4kF1}hMw~QBjW}tN8sq$m@gz0IDNRyioYEvU>Xjy`QLi*fje4a?XwG9P z`%hA%UTKmV^-7b}s8^b#M!nJ`HR_cnsZnoh*Wa2N^-7b}s8^b#M!nJ`HR_cnsZp;q z3C-iRmGeVV<2Xr^)HqJkB+DZ%!~T%eh?6F%5hqQud|H&gXZ<8~p*2ZeWKB|+EJ{Bx zo}@0dCaK$5lhB->-?Bd>HReT{q{h5Rlhl|OX_6ZAB27|bUZhFIyhxMOm=|dh zn)7mk=jQ}!%!@Qhjd_tKsWC6oBsJzmnxw|ONRx`k=K`Le62)6%exxxk$|sS}d0FTA zSx1d|ktV4zFVZA6=4G+xXE8PAMVh3>yhxMOn3sCSlhl|OX_6ZAB27YbevW7VNovfC zG)awlktV4zFVZA6=0%#M#=J!)EK8UNsVzzlhhdJ&x|LjF-~cc8sn5Esj)9? zaDO&XqaV^FHToeqjd*FqNt2FW=J;ifmqxra;-pE( z?{NGM$4et#8gbGj^7&kDA3f(Wi%iV#zVe%xPif4fi1`ySZ{c@2tP9nL^&n==#wI>T z48O}YHu3#6)r0SWiTECvi0^@g-{tW6u*&1}VUow|GLQE%k5?MwmBu)wN#aJ)3)q1FEH+`fqNBH9FS=6Xknxsa((j+zN zl_sfCuQW-GdZo$1nYsKsO}y{UGwT=NmjeKf# z;;qpiY4k(+B=gaq>)fB~sL>B;k{bPxCaKX6X_6ZKkS3|o4{4Gb^$&6VL#R=&G)awm zrAf!1>iAO~FO7I<#7UEmAL{s_j+aKfG~%R5$Dii-(;P32cxl8*lUkp%_;)o}pC;C= zG>*H7c@;6ABF1}$;!V^ejrkHWPa@_A#Qe-k_xid`MEzp(Me+S*@Ndj-v?#v648B4Q zKl&+Re04mpe;O2jj}6Y{?@;i3Hy4<5`S;oMn+r_Tk6*juypZe{zSl2JQsevm(j;}( znxw|{pYlm+Tn9>%jvvbU5kJ)N(ukKvoHWUN^aIy>>W7GS!RloAX6gd`5gI7|IL&*5^jkIryab$o4<`X90p}~>B;X|A zd_9~5oW!DR@h6qsr~6dlXHgb3Do$%MwfK3FEV>k+Y7`21r#5|pDR`$2D9^mp08Gnl zMrBvx*Hi#}DUp+0852TaLI_MqWlTtAIh~c2D2J-Ypd2tVFeGG7m-#tzgQf%tpx5a3EVUiO9QyYqr#mVfg2hE_bCK!CkWgn z5V-g!aE(rUH&{nyVjL9$M}@#qnHWc9VjPu;Sf<(H=kV|DVDS++rUaa?hLeDk;E|pb zbrPtPK%JAK&Ph?{Bphj!$L9!}Q7Hk{3O$1YxG-m8*+3Dfn?Ti*qiOR{kxb7uzdCUck zcbCoC;yL)yod$4vWuPK(oA5~h*F_A$udpdH@X16SfVFWPK38S4Q5gb1CU9`Rjl9)? zO@ZYBJR@fa9$m7|S@`81oUk~@2%K?S&_RRFY%!|_@>Tzckobir42XXijUP55;Jgk$ ziv@5A16<{F2DoLDo$&F3e!pju=AK* z6zA;LV|?QV3F9$nY)BoE7oh4C3ZUv73ZP1%04i)>W5VMq3@D z1vpxO{lxA~tO{VwQ(@aCu!+B(E$8=9XAq%Qg+c-5;kzNsLpiE7p-{XUO2ua3;8g#xI$ zg#xJd4FyEG)1%z!QBEqy>qPcN3ZUv93W#!NM7cAfoK%k2i!3JvL^-MMRMpwUKYgyo zU;Z2ILbV4{PyRV{b?Oo5%0FVQPWuGP_@}ki=!DQMocjjK`RBjFTLUMt!aCQ$g z=Yxjo)Pdl9p2IN!RL%Lvw=)Q;4xs?5W}yJ8_Mrf(UQr9cs+&a%?E~e}!CatgbZMVJ zb3PPdUxa3X_5_dS`7yiaQ{_SdRAr$6s_vlxs@|ahs$QW0s&f1)idNmtRJl+9Rku(8 z)xM#CD0fSgyCup=|AR!T^GNW?rLr2`|6K=BKrFBe2#q;mW#FV2e;K-E1IK-D`GK-DW0Kvm8^*5cVX zoGKRzpehRmP<0OlQ1uQ4Q1uE0aM0!aK%2ndTXA7Z;IYU&COYP|llVc0wo%bPtsC50sckU>n5=#9sFf zr%)EEJHbhA!7c%e6zIgC714>yJ357~(ZPKJU886F#K3w*EdXl~c*Il-z*>y*2q_O| zE>td5S*Ws5-9vS!;)I+XQ+GBeG8YP3+gUqby7 zsv%TEsINnP9qOA<--P1ZE(W$T)T&UcLahkJcUXk*ZI=kOHq_cspNIN9)b*jR4|PMR z8$#U}>P9FGtS1x^c^60C#i1?0ZEk&g$qckMxk&4$-{_iFggpviR(zJ#-VT>N!272t|K{FKS2?ZR}gu) zs$^vUQ2iqk-;-q|ZU>lmbmSc!dAx8z-s;FZCi0F6H6YZ0P<=x6iE^8w+@{DoD)Nqs zyycO%Jo5TRUf)ptLiNL-(d@rt?6`pB6yO4qzy&0M3rGSNkOVFuiGu>TfTTJkfD1^f z!vcp#C-7w;4(y9)ws|y*%WO{Fmy!2ns3oD6MC8DT#Dym#e~i2zBdY8t926fWd>IGTlO28BAeKoOz75A}VhA42^QYF(&xq1K05AF3`C zo&vDW#i165st;8kleIUIO8_IcN8a{O_&Aq+*%1mKepCG~6h7Lf`Z?5wP#Z#R47D*7 zK6GZ}(ooAnEenMQXw17T6h6MBx;)hAP@_X#5$cLi_~4R}BSPV0L#hiy;X_KQi$aYJ zH8#|Dq43axZ(yep-3e~SczDSlMU}IRkNlViFmGt&$yv_FynI&^$^zX9Zt!>%%=ap( zUZH?!Z~8<{@_EsT^H?Cq&ye_=UQ%VD0OoZM1w_?~>>a9CG}`_f)SVIbiL&7=ri zW*9l=vV4hGCC=De3RtEEgl0a!7@pmwoCzJ$A1Bt(J!91ZPP#Q@5 z{R-v@C4tgF;%`$hPbdkL1`>aFf_Xwopfr&98#AxtC*_31Uyh*?5`PDVN=W?lfl5gH z41!8X{Dl)LA@O%XsD#8{`=AmMf4hT9Na?9iLgMdgFi%MQl?*Ci5uQ3s$Ah|n6rSEu zRYqP_sH#vCLrv64*^1|8;!j*vpO{H4D**f=Edf;-ipZqO2&o(hRS*iG%A|_OtB5?Q zf+Uqm6C-b8L{^2W3iVN_k3!7~H7nH2P%}d<2(=&--aFXr;!yRW>O<9qstbiHIYzDs z^;xLTLj60`zeCLlH7C?3p*{(PcQw|sF4X6tJ`aWWIOeS%n0W)Z51R)u5NMI^!)`+i zR^9`V_dw)55P5L2+=G$#VB|d*d2llC{>ZyO^6rm3IGOiYP@p#y5qY|| z$nh`YS#D=U?hLgnl

S{Nr}kqPvM4|8$+IAtJvHrMrn7|LmN3x|@ina8N5Fa#iH% zZX(A&ux2FIAX{G(N_P`E{_!;P)<&N0CUX4CXhvQidDn-!A=C|_ZVYuJ6o%OoiikYj zP2`g9CUX2US+=0Ni5&mPmP&UMxwxAEq88m12@F&w*$Gj9RMP4b(GWXK#qT) z#?k6_Ajdy%qtfj_j(?0s)hEhrigLOg$ng)!n0HjZ?#&Lv4+6x*f>zi{EU$De{O=MWJ*%kc-;^ zAZpR=KrU_va{RtH`|^F{>2@H;FMG3}x*Y&Q>2@H;FFG?%w*x>Z-45jVrC{dib^r*q zJzCfvYDcIYq5c=@f1!R3^>e5Vp>zX~OZUA!pE+mz10CN21BGrhfMK=JsxBipf&2?9g8H`KkEdW5vc zHzx2=rqN+=2H$qmuZk!9t03r7Dh;#_6a)(KFL@|WD8%nwO9`z*6$DyGWC6hk(70YA z?&q^n{cJOViy=OTRvvzXnR$))6V8P4T0~xp$ZHjOts+ksX4NSZd6~%5RTr!NO;jzk z2$dmT$M~?MI6k3upnzbx$D*8|t1h-6g&T*+6Lj^&JSf(AGV5#|C; zB#|ey4pl(#;CwPgAHeRwmz(g>A}|+Dd_+Glz|R{O@eD}(o*~ahslre|EQaa$6rTkq z>4V$OasL3+q4?IQ8mPwFJ+T5v1Xta8T&<1xArF<10vUqeM>?6{KR3hT*%NDkY&u!r ze8A&td>e^rgVI!i-w1y%RWYqiNx4iLWT%P>YG`=R;Wd!Xt5$QSKn`%r?h@S`n(55 zy-A~HS|=MGje3(ty$PdUj8CueT@t0}ZP=N~>^V~SaZLytDMo=5AN)_>K>wTaBZVI+ zJpYgfDLhEw!4)LRB83MjJa5Q@6dt6kZF6R2witg$jIV+qh20ffPd>%5hK&m^d^hWk zLHueK(*~t!4pznH_;!}QI0E}B)R`^DXH979L$wv@Kh+{^vPuDLk~Z#Ya>yvO<2O@FRt%QXZu6AcY6taY0$6@F0Z; zUyOkVDLnkQ<7)9wDRC4`8h?%As zq=-QZPewC_6r)25KT`P9Z5#zsc#tx(k{+atsbsHus#i=KWT%Qr>J?H(L{pytxZ#q)+udJ z3eO;Ukivuh)bh6#Fk?&`l%@*&D+-t~r1%oneHCm4muc8qk;2B2MS8l@1C`>c51##% z?xz&{CgPF8j}NYqULX%r*jOjXMG70Y4@faHNO6gW6rYeH#b=>NvAU4rqfErNP$}%R z@W4hIHr5+*k-~GP($nNY3J+E$a*@KuiiM37HXa=##oiAOQrLK$i?mc}Yo%u?#U%&) z|5dyH#?ex-8npKl&)3!xzg*E-k|hGr57u`MCqkUe^UCb($z{g zDP68K#`}frFO@D)`lHgXlx|hJMd|lSe^81WC-iE)(mJJ!mDVfWu5^b|+yEgGH$F&l z!-EtzI!Ko)U8WQ_H1Oa?1}Sb}kmAM#DQ;MhUa0gUrDK(TrxYs|^N$oUXDB^gDb_8H z!hbZw=PCv^Vz7pho}(128a8rq^x;80NKql~Yo%u?tyK(C_hOOt4)O-eT? zWkivtM9`y$)J?c+8^#>_ERf_E>Q6`Y2Pr-3Pe=6!DLv{>NA(9OJ?c+K^#>_E>Q6`Y2Pr-3Pbc*UDLhEg zpHAuzQhL;%PU;U*deomz>JL(S)Spi34^n#6pHAuzQhL;%PU;U*deomz>JL(S)Su4k z4^nuLqCdP*R7#Kf(^>sNN{{-}S^YsukNVSD{Xt5P`qNqcK}wJM(^>sNN{{-}S^Ysu zkNVR^ts{j8Df-hzts|vJt#?uDNa<1QUDP^KdenLswT_e?wcbUoBc(^JcTwv|>6wBn zJzPlE^5e5QCJjt#Qz>AvN&zv_x+L7F{x*=IQ@!|F~PkjM#=;}jGPH%72+h18U%@?fk`cY znyijV1C!cxG@Cq{O&&cBpX%Ws5KC1^R@J2!Gpiby)FR0izkuuA^h+g5Y{LvO!NvFF zOq$!aG?P{~t;wXNN{V2uhP5ucVtpnpr*AoZ%bV8HV$yUjEhHX-wdr1LtW4^eWQ+Gy!n5pG zo@Gcd_t=Hf==YIa#%EQq>e6Lp$beO!E_)UKEFm5n)TTO~`}I8cVb#%Upw&Pt)!^9y zLbzMhbGLwn5bhwb5TbeBf!z6g67~@rQUX~|tAQD*Mo${*@CK0T*>PB?1@8*9P)h|u z^ys0EL#W3lonRrPk|9iBWs7g(C~sk~o=Vhlan*BnVIi1P3=6@xAq0;p&~dKzdMeGF$H28&nPIvIIK;q`}1cG+gUu%$1>aa)OL zUOf}LBv!{7#4KBz$u6IXR~=sSGT9ZdSHNCDdl`JoP!6ZSO6*8W>EDvcuGs?LMEI~( zEk(>~yq5in*H-wkqpw80t9QVj0(%NdW!vCKnKgK=K$$gsA$AS&SKze@ujLrqYP^=C+-kg* zp^jB}t-zvOhCVFg+XDSqG0QgLwGpqc@%jd@ukiX7eMdbj(cWsz!?Ieue!y!xUO(aW zJzhIeC(G}`oO}WPg4fS@{SWn`Z>un0tLk8*f2;6Xfq7WPxkSHKqTK3@u+fK==+o+T zD2F;$fh*9LHF&MUYdK!azQk)DUO(c6d0d8h-HP#UMcFTS3Vws*{tb@%Kpc0x(iQMs zkx8FoZ521gd(k5J7GaGnf`1WwP4Fs&ZyJ2uO>zD_ox?wx+dY%+9Gq!7gP#UGkG$uR z_dMD`fA_$;{15lr?~upWRj{whtiY~a+jJP(9ftjW80vinub0v0g^0NjF&D!AGweUZ z#tWaD*Wp!rlK7M*b|k z79e&OUJJ0r&O(0|AQs1XF1{a=h%E#_=7ULASA+0-F_Uoee4R;S@$U@dpBBcy@|#I`6S^{!c4hwm{~L6} zsIo))lpS)=AqOeA_JHHXdh;`LnYq$jW3D&9G&h*vnBSY*%$;UBFxqKsHaA$Xn z1I-i6lg(4jVde;PlzEjo&a5zRH}5qcGM_M?F<&&Nn}0XoGiRD}%!TG+bD6ou{KDL1 zZZWr+yUc=vV_ut?C1xA5quJf;WgciAZuU2iHBU7E&m3wFGcPbNHLozQH*Yd4&B^9n z=Kbbl=2PbL=BwuGX0`cG^Aq!5<`Q#-x!&AhZZ@}>yUc<^V*Z+&EzGuNXS1u>!#vPD z%(gvuwlO=J<>tQT{^r5v5oSMgfO(wxTl4?SQ_W%K zdFF-YCFW@JD)V~tW^;;pkNKeaxcQX%ocTBNb+g+1(EP}pW6n40%w^_!^FQWS=4NxN zxzo%Z7W3TH+{-LAJD6R}oVlNQka?Kd$LwbgFpoD+HcvIrF-MwX&1=nZ=B?%wbE^4> z`4{s!^JVij^B?AW<}7o8S#Pc|KR3TJe=vVG)8R31P0T&bQnQnpGkco{n@5^Qn3eqnAjzcYU_e>Q(L zn;sGK)zWNhb~d}4z08BmBh3EhvF2d&cjg)9aPwkwta-ipNAosws`;4tSMyc#E%QBd zra9MKWG*pRnxC7S% zEc0CR0&}E!nR%sot@#J@X0yVaWZq%kV?Jm;Za!r`Z@y~2ZvMl3*Zk0&WzID}H5<&O z=4$i5=GW$C^G9>L`HNZ5CyqlivxV8(Y-@HhyO}-A1I;7Nf#zWI_vY#5F!Ma~Lh}-H zw0V_zy*b{z)tqeJZ9ZT=YCdT`W4>sd3W`FZI z^CWYKd9Hb>Io7<^9BActIe6_e6!wMX?|&bYi={MN5}a0G+UYN z&2Hv?=Hccs=5Ng*=Go>&<{0yO^A>Zmd7t@&`J6f3eA9f_tTE@93(dvmGIOo@Uvsm$ z&D>=+Iwr>7)GRjJn4QdSW>52Av#)uad7?SgJlDL)yxhFn{DXOmImw)AK59N`K4ZRQ z&M@CLYs^o~MdrWFHRgZJ@64afoo2y+n3v{eiP_dHGxss~GY>KQnuE;2<`DBN^L+DC z^J;UvSz%5wrYd=!~2%?@Tav$uJO zd6YTOJlPy-o^6gWN10ceH<&k@6U{r#`_0G9XUxBue>dMZXPf^r|81@{H=5s@Kbr-E zydKP!W?Qq&>|q{c_A!q!2b)99^UO=lE6p3so6U*l-R1-4}4Kl{>D7j9By82-e^uVA26RXUoqb{XPXPnrRF;G8*{6fJ>KVo+0M+FhnW4% z6V21i5$0&~Mzg}a+kD)7)|_F!YtA#5nCs1N&246*6QaL+nC;D+d9Zo3d9pdoyu`fL zoM7H*K59N^{@tuG7n)1W|CryHJIw5Fqn~@3dz;Y-@Hm_c!~QCzwOc^Ubm5cyqG(p!t;fidk*WHXF=! z<~QaJv&o5`SF^p@%{iG>|+ive{25U9A;i zn~$5%m@k`em>-z4%}>oG<|^|`^BeOgbC+2-B*wd^S!#AN_caeT`HFYK*U$+0txpb~SsMhnPp11I^!> zzcbG;&of7wqs?o~aptY&Wb+>LVe`-C3+8L)yXI`O)?8`+*ZkhxWfl$f`D(T?JDK~K z2bz7%LFP&3Y38}+NOO#Noq3Zv(Y)Jy(0syt#(c?~VOE5-ym_iQ+`QZzXHGF6F`qZz zG-sKM&2{Ex^H+1PGoxRf%wFb^=5NeX&GXGM<~Vbb`GEP9`KtMjImfIw*P7p$|1+DM z75!>$mYWBd{mjAU8RmuN73O$zl6k-RXY*zAALdN+Q*)X5rMbo2Wfl$daW%`${mrAy zjulc0;viX)d%d9n5nVZaQX2IFfzY?>v+1u=69&ZjcFEGcNlVF}Iq#%MW?QqXxu1E2InW$z{?0tp9By80 zjxnz_Z!&K)?=c@S|7uP*-!}nop_BT&7hnU065#}iKTJu)(F7pxd8S`cHb@Lr_ra8}SFxQxy%%9B6`O*L8W*f8I z>|q{g9%lA62bjm3Cz(UcGt6_%k>(ilT64TP!JKH`Zr)=)U_NR-X+C4VV7_9$ZoX}P zXwEll&Ckr0=6Z9Zx!K%iW-f?%D>7S|oy;EQq2>Vdc=KfQRP!uzxH-}sZC+!JGjBB~ znRl7@n~$1*HlHcxz5~V{$TDj3rEEK>}Bq4mYF@xL(G2W zvF3^95c4c^gn7AntvTMTFsGPP&4}4Kq z4m3|PPd6_xN1Hd8mF7L>W9D<_4D)?+u32xcHaD6-n!lROMn?Zzn;p&W<^g6O^91vB z^CI(VbAoxd`GonB`KDQ8E;N^#pPS#BJIsQMqn|C!GV=hlzj=~5%)HdR-kf0GZa!c> zX})N_VSZrFHJ6y{&F{>eX3-_l&o*W^^B}XY`5W_h<}mXjbBuYdIo_-^?=bH(pD>>@ zr<>L0Tyv?p-u&9!YGy8t{uh}o%?@VHJkUJKJkC7DJkuOujyA71Z!ssE_nMEJ&zjTB zx6K-Jp1IguVSZ_TXYMc?jf!#YVYV^L%wFc<=0Njg^GtJuIoiD5oM7HzK4d;+{>^;T z{Lq|hE;d)08_XZfU(BYL`8+T?n){dsoBhq-nnTU=%#r43^BQx!S!v#3-fuo;K4;D_ z-#6!)i_E3wI`b>@C-WDx$>lMw7G^uMo4LPvggL-G!5m_qV~#Y(n&Zsd%)8Bp%qPv~ z%xUIZ=7;7SbCJ2!TxV`Fe=vVG8;y?fH8)$Eoy>jA1I<3>AoFDN4D$l>a`QU#7IU&W z)qKQ!-h9P;-K;kMX?|iZGCwm{nO~aUm^;kEF)_{(vy+)K_cISO`|!2Z9&Mgto@jI>Y4n@{ond666hJWwJV1kMzi9WGk{0*@GNFjv((Rr;*Q) zi^!GaS~5y*BX^QtkO#@1$v?X zYsd}c2jm_yMjj*2klE5?{|k~O$m_`}WF4{z*_!M^_92Io_mB^gGswB*67m&tJ-LAj=YJiNqS@p@(!{mIhY(n-cL>^pCT8ME6H`_d*u7%hh*f< zX7PVt9(_;Jd5feSvbj;*-7Fas+YGi_>mna!)PTnr*wvr6BA=^rZJ4i$ZV$dmLxE$PjZ49}N#}W-^cG6nT`L(S zL+hyL{DwHMk+-RPS2D(VjBS^8_#<+sq`ONpN_xBL-$Q;zelF>LAsHo|z0&r+qHZ7k zUrRds>5tKWfc}G$kwcQP?R7%=TY01d7lHPTaF)~_4+R^LjFDDr;FX>doZ<36WZe?kQsz^qv(qB!| zO_Yq1v6|8j*P_2R?WvNX>5|T4k`dB-9FItP&r7;XB%`GBg0v%~_oB4J%Ozv9-4$#{ zhF+4k_ll(RvSftxR!ciZhSx~jeN8e-hF+&`qonf&`L1Lr=WX%pvXe_Pl%IA%Nw1J( z%w}QQ{x6p`H`o6KujUpd9sgIxnp=d7`M(C%+}x|EBSTk9+wp(ds<}l-&;PAe<`yHv zrKRm&CmD4mL)S|>W$CYgSCot-;x+MFcpXWnEtw+e`oALB+@hp6SlY26lHpWIXSif! z1U{Pfy`=w3am_8_|3X}I^U@__Vaf3Q_zc=lNV+p6qhx4~v_nrxI?s@E$!E#u$oY~H zn-SUz$mhvL5K$;exh&PGXZlVpqxzb9>Xvt*PE zZIQOKRWd?`{a>?dZm$1}cFiqHI@_ruV;@O7yo0(ulA(Q)j{nQ4IFeo8WO zTGI1>Nw>LqXC-4~_z!8j=Om+K>~Cp@9bN}z<8@CC$q4D?ly-~^=aP0fH+A`F7n6)$ zAsH$m>0B)tDJkidk_=xf>AI59GUWASS+bmDs62TiS%Iu58L3QGk@TvO31p&VEQzcx z8M;~0xkWNUdiALz!wsbEHk6Fo^zdeq;r5cTmXe`1WJgJd*P{_$Uq`Hbcdy;*~?qn~ruVi$fq-XahP1?=~>PUAq^<-#_w8QsGy5l8d6D32BN;;28Mo4dl zwB4EHEXnZG)XkHOJ}((tBI&&(8D5Fgj{5&^K64BC|J%9vZM9^?rvHEPGdFLYWcW?V z=v$JZ^^(rpk`dB-hq@^Fv1Dkcq_ayhLVBM_J4S{-mA1PZ|3cFFK{9egGW?^YcT6%y zhJKN@>$HsTe<+(|IDzN4w(aD&I!QVmB|}{#-5!$Bkfb+6GBQ{)Mmt)9*L7F(danv? z`@UqNv}5;6x|1YB4@yQR)Bh0t57Yk${Zr|mM*pMqKSuuy`X49fNV>eAaCzV1*!LL` z=?}jk8Cp*JW!kSu#@0x>Z_wUAoA(XTd|dDRUwt3H@x1C)=ek#e{+9ILMRt{p+$|aE zOxyoO_vRMvB^l#+Hj*ao=vYbT9?8gK)FrbHnz9Z?vJS||3f95vlA$+fvwmYA(YEXJ zFzwUSpOJL#mGd5|&g-Nak`dD5^`gW2h&~|o(fimgUD63lMo4d>v}0uWerdaG?~SLQ z3{Rk+aos$!e^D}&m;JTR8&zeVT>p2pnp=$L^Y9DOj&6_)e@TCgJRlkRj{IIS@&n29 zV=TYiU#zfX#6Hh&le!og`iyaIqP_~_43c#f=|O#n>`DC{r2jt~Ft=zY$#8#3XP%_@ zyJV~&<6lM=l5~0AjFpyl^ajaDRY@<2Iv&rVt61+moc6dB{ zJf6c-=;v|m@ObukJcp;#&*R$R@$B(<_INyppOU)p6Ot~EOC=+uw@lhG z(tT0dQPNpK{Y#SGO8Qsft0f)Mi<2bwn|6VeDine_`-y@Ho2-j<`B*#%t9?vn- zohI!l>2ke`wP$|@vA<+&u#6Mqc`{nQReZgMZj^K?NXC*R!__6-8j_JolHP-oF`JX6 z9ezmCog(SXBxgxRNN1(&xA&@KXqN0}=t*)m`@K-o-9>&(?v#w~CO;uRm2|$A4E-t@ zE5JM#A&ZiilOM~xILnw%u0x?dvVEkoWVjCNr>QVE|>IPA>YQ|k#xBZx*V_bIdxx1#>mKi++HUSN;~|mq`y<!<#UnHhvFXZyP~bAFU|QQW7ly0N^$}mJlUi_lta?VB^k+0`v%EydD^9DUq@D!bgN26t4W3uCB24{ zPJOaE*;+E%Skl`?Zp7atm*cZq$Z<}S^nRiL3$iW!jp(mOR>FJG?o4)J+{T$JqV^{a=wC=uf8q7P1Q7i}qb)SH>+&+o7&JS%OTX zZXkJ(`

d#FvnB@G#?!Wt{EwzefLa_*uLK?V4;ifOc={^WxW%AIg+{| zh%WVE_aOO%ZAy4S5M?Qng`&;Uudp`_DD(i@E5N_&W8 zw4G$AgJh(WWb97Ka2LsFS4pS4WTc0r*OUJKl5THFCq**WSJF$B45iT?Dd~=;eUD`1 zK1t^R$tbVay=k-`lMFpB>CMKUk_^uypO*~Hmy9i?y@>Wo+RMpT@ejz?@O8A;(~i>K zM0+c_1K%YX-6QFKBN;h>ACnCIM7vsRd7qOY>9m%NkkL}o_9~OEWb_6}=Vr<9?PLSI zv84AlxsiOCJRlkRUeY~8`#bvomUK=_Mt+lwWp5*|yYfngb4t2-Btr$rVv?~!^k0rw z!f%v})Sz8o(yb#IYDE9-^e5Bbn*KZKZ%6-K^!K5^JN+Xhy~iY@k4QSx$(fR|S(5JK zl93g(mq~_RBv(m#uS$kjl5a^mYsn3g-ZuI-;yY-sAwQG!&PqlrwvEqkxT<6*LDEZ- zbZg+XC8ISZBMr%Ml1>M*uB6*UGBj8+(uMx%y_JmO?~xzkd&nL5C*+rs;h)H#CB2;TIfR!>GWH5NJaW9Nyf-fHQGs%;Tn=|ZL$_whpbE1lZ@1--H3KF?b~R#pxs6?N;)ffzqmp& z^b+q2X-DV}6_LkhC?Aj0f@ChT82x4V9RE6==Mu>TN%uxcuN+yLEF~GMEa_AtYmzl2 z-DF9xv1GV4*-A2YtEAIR(rZL|l93jY(dLrjwqzU0(A~7}l8g=}2T8iUB)t&XnY>dn z)=$#uOAaH4O1h&Zy^)gPFqtkH8z@jV2a@i)lHLaL4f1u#*cM4=Gx;&OL((ft z-XIyOE*VXdbZ#OmO2)30^vGy6X-BI{Mruhqq}PM`?vkNY$>9i%=%XP!)AQ^g7Ue`KN$w)r=d?;o=uWcvW zxdZt8h`*%{7S<-u0(w!#hJSG{LLH|qiucCi7{cGsoMgMO4Kd1i-+TYOL zFXx&$cZf?m?e)4LvBzX;4iY!fDOI}C1WEt{$@&>Z3WMrSDcU&_3t7P<)r1Kl? zZ1VgZ$|33Gl8of$dE5VAVVPSjAN^O;UlOk^??>J53yEjNL66v43y; zCXe6slCe~Ie0yQZ=mJS+xn%ed{vFBBBY6D1XS6Bz>q&Y|B%Q{Rp=OfdWc)VC=qwp8 zG+WYnQZhn%bEF+3!%s=u+a`bC5hKIzOWXZGGPGUN`AE|HSTaV2cS_scB^f0{pHTlL z{a?|)Pcrn4WbA-s_@Jcwtz?vRzL$1{^bSkg`B5@_MAAJf86`u<<2anNQs@53_73-7LarCltNA?ZCP}Z7WQ4zu zh}586lm1#H*PC!1X-Dgl^&~?#leb8Ew@ZdwNJd-I--`ald=9mg=jqoaV{b^h>u7JJ z{hnlKvt(oo{aYoS?f4!^_e;spUi>S`=r@v1Owv0b=^mp0d-AZPb41cRDj7aT|BvKP z~ekca&WyP-Q3c4@<~SWlLaKb%Oqp=`ddWW;mal6Vv^A-B%P}yy^`cLc6N`xi;)grxVYWQ+`-r0x`TXCxz}myhR_ z{A2;1pDrT{OS+enMJ1!fBqNO_W6Ah!l1>Xrua#uD4ebTAKa~u9E*be!GWL~Z^m|F? z2TAXUWca9LNuJJR2Y{yXUJOn(>p@1nme{oUyAPJa*jL-hBezc>AT=ue@) zAN~F5A3*;=`UlfLg#J|ehtfZs{xteW&_9y?(e#g@e=Pmu=)af#@$^ri|33P|^iQP! ze)=Dv|3UgE)Bh0tQ|Nz${*v@xLwhRiX_C?DlFnoF&!GQtd=CD!WOO0E7=HzS4Sxe) zD;Zu#|C{u$$9Lc#|w9DCvG78QLr9eIpr;Nk$J!I^WTMnEoU5AEWN%EAWcUm%hhWw5E zQ!;v9()pWoudrl{3>T5Md%0wk3>B5O zQ%o{Kdc~z3zJmHIB|}$9Iwd6|*U;aZ*Zch3akv$)@A)~h&`{nltdrM$&M;|5_<0_O zpPP(!O$q4n~Z)H69XUXtMNv9qARfpG=zw!KDSK84(c%G;2{Uz<_EUqteCA}{s zo&A#0D>-ikIB%EHF3x!?BIy;yZ=_v{_O-OjNk&~s=LUQU_rHw$dy)Hp3E#!zZI5L1 z6G>+`UWIXfXFkqK#%R0z98u&q=7|h%k$HEw^1h99Q>7i+Ch5E{8ROrxh8Oety@QMw zCBvhn?eTN|;m4)z-pRTkWBgot_zu<$<9i=+KQm;z2tSwX@qRk|lDvNP&XLc`>zq&l zSs$+bdHg-Hedseu=X1s*y)WpG(SLw`(mN>a7#Y5q^>d44_;yLJv!v6P{t@&~r2P>6 z4@-KF&~8Axp=8*Tj5eab3H{0RH>JNB{kPHI9B+ZQ!dpv*+tA;Z{`T~DpuZ#io#?+4 z?}Fcj-!18NqrW@-J?QUAe=qub)87a0hxf+^NIHY)A58xc`cvs2M*nd7)9_LFXnc%h zbS(Y%(0?!e(kP{C<2A{-9)dGVL^3m*Gv)cAsFq)NLI9{HsVU$(=V#4yz~W zHkS10cc^z7ipMwh|Hzds>ST{+-i*wd#lzxGw)iHwE|uBBj%-JLM%#`*BRY}v13KWC73|MdPx*xw@T@Bf+1mc0V|86jox*VX^G`}1ZTzdcUL8OkH7 zE%TNwyR2WEW*+Ul+4&5%vt=(U=Rc>MuxzH&zx}6~D}J{8^Y&lnM8}P<)BiSe70DaF zFy$&D7pDIrt*r*E}W_b=`&b5{RFkvR*8d-fVJbnvK=DVLhKjQ$H|?(m3_X`_0(iB*y~Rc=E1 zr|GeBW#gXOb4ZF?E-}4p<^W0E(gU6K`~x|hlG;Z`NwBB8+`XCGPv|jXz&$B$%J5Nc zg|bxw+g429rB1)UQsO&fhq-V^*nGsuo@pcF_ubQ9ELD;+*4fAbLsCY#70M-MxuYtX zcO2icqT8pJf1Kr#%-#?1ci+v}a~a^m{lCNzyUYlzr_9}OQ-=;q53{uY&AH25kp4Vx zPUiqB_=ix@t>RYj_q=S`if%b`Ocg6;eB;W#$M3mUmKpf(?sk$tUe_@_(^3bd_H&1g z8qvR7X0ysYDQQD}@0OmHGNPBiOaEryGPfKybXYfk@&50M!S z$DbvpZ!@F#t7qf@^JvLh2?s0t4IbL7=imz};b3K&|Hv4SmeS{f+Ki51b?>1=hL|g> z+54*Cc9vXkNXPtXdb7WKet8&%@;rI+L z^E>r%W;y(LL6+m~VfV;QHEs$<4a=O4%x+&zXP=>C(dAB6z-aLNNQU(Ve2)5r>`#|w8_7^Ge)fV&$UNO7c z5qz};sY5Sb68Ct~fYjc-2AFl6aqW&j@%&J(Y@d{2<|$`W{JZpW4c+)RmHi8px!C&4 zt97Fet$MU-bbFijvV1bzW|?FZG;f`?z_fz}9Xd5`rD`k%%i1>T*yOgBP48&hGH`F1 z7%c73x>4H>x3%HbP<*#61-(l*UK$o&N+P?UMUrXX zw1#JGj>y`KU-0S#%Hxn&OH1`6EwyTBsgp3|LQ2t;m{e!*MXZ0oMvd&7We?)*!NHN@ z(o0E}ee^4;C+TgfCuP}Yz~G_%l7fT8VN768;?P$^Z(x6q9(MZW1lpG0pYC`1Q!OrY zZpfSsG0uxYb4~;~I|k*<2xpw7jE=-wfu8teWpq_f3UtNiB%`ZVjX+oY1ZH&kCoj+^ zr!vr)lBLtkSw^Qhp@Ck`Z?L<6)^2mEO?UhxN>}{bAP?pa;~nwSn6X8#U|0Nn(q#`k ze(Ey^Gs__3URVR?1!6o+ zxrsG1G4QsbA6E`6tDWO?H&4h&hSt|U4a<5OSnpm@HLe1-g`)h{j z)S;>WHo9Z`rnj17_n%WUK_p)|BVb{BtD9f_%QxAGR_!Rh8g3^ zC}Uh1WQ;3gjB#ZMza1aJZ^sAl>*D*-%k4SX-=D-@Zf}!Gz1%(~tM_tynXJ*v-`;#v z(}(yswR{<1q_$rg|Hhw88DlVG3}%eMj4{}b;e(9fi;Ury${79Kp8fqn6Z^ZpO(yks z`oh*cZQS#yfju?X^vR%*<`8Ck3~SUsp3bYt;yL#;>fI zo&Lo%*elo8V0TK^ZgX|b>^9faU_aN_ECu~lfw{t(g2TQ1CsO_PuFn`VJHcc0KMb%h z`ZF&~Twr2;t$DaMZ`P@G6En#?eB%($ z(p+2vTlW3ey;(Ljm*2pqy)U|{dy|{sRx+~@-_hP`n=AunbgCJOF+Z*R_Yr~VG0lwG zv3;jAKatG*bTXmJB|q5Y^T~vS_tj_e1e{)Y$VV=^}(ZkZ`8Tvhh#@`v@690}=sVbdD{av<;_810I>O(^>}g;}{UJv78s~qwIC9L;v_9$f z?VkUJF>ukaPi}tN`R&lEQTvYZPrm}QoQWB8ok^xnK1~}kw2%K`X2yq-@%Q%TLp3wD ze4uuFtF}El-qyaU|Awn&{KJaGT7llgTK+5Z9*K?p5#5Bbb>+EHHk7Vg{kP}l`sRNo zoH=Ioq)TokT^HS|R*g$;C0&87%)9)4DXA%G19}JU_kv@o6X^W6hmyom)~Q=LVQk+E zXQ8_7@8kE^uHpaTFOJNEmho!@i+V}X#Vc!Gs?smN$VAur7v-|Y^1*xX?IpseCv$!6rBElyCyC@{jzD+>93{lT8gqvfBYOJU82%Xf87Lsq&gX= z^it(nr(ed5??UDufwdqzbK&$edgeCq?=ILdV*+ajy8i9M!%ko=vv*lmkZfuvFy4Qu zB0GVZMVG3~*vT64PwfT;Pxb{5#Q*G~a_J+H2id_2cI3Xu8H{d zCc!*ABwbi!AA<3s8d7xe>x8|AT~Mhn0CMkHu3>e|buU5xalyf6xrW8}IHBf0+Aw3i z2G_vAzn3eNYwi^CthI-ydhQ|6fK$t2W6^%^M;A zoyjE!mA`n4zeG3X^42Y*Y2LP-zTk%-F7k5`=~;f*!5qUD*xT}f4HN}lH5VH%sVL8)xR(P3aXoV6KdB}{0Cez_Tz%GILJO;&}WC}X5LEK z36gs*_YdwlJ#42TA>IEWn}4+r@j|&9vmoOWQ_ufPUh^{`@(?f|0@!!UnIGctnRVb3 zhpgX58#al9*I2S`WyxVTk`*LF6(u8{Veo(z-0vCQ}0iT0YZwB188ZaMP!(#F!iOmZjf z80q3g$f&K)GU|nmwqG-@>WcX%osYdTf7Y++NdL!ax}_iPmo{|Nu;9-p2-u%a7&a^= zt#{86DS?llx{k^~s#3-d8=4mUAwmB~b>c$*fFZgck^b-f{fqxyOOxc3-toWKO!QY= z=K5N4O6KoXav^CB(=}hrzdaA(Nli_cv$L}oPtVR{y3CK;MSN#F$yGfhDyXH&HUzGVtCBt}; zQ}}tw&}qpS^>+VeP!~NZ{hl4)k=yTi<^Ia#ldMbI^t$Gcr^Q_|^ep?=qLJynVEwtc zJ6ZapGbQ82=8q?&ZTGM3qtYJMRnoKLv%wVhXEhnzKhLj;v0u(JvR@hd*PijzOJ{abw1X~|fg#&(lN*y{*uSL zONMCM$A^7>Ynx0x_Ul=1bI51^;rfd{ zEw5|!{{2s{zs@|LO(ff?=eOvI4)H^Y@%&+*-@-93?t1_JSD)V^>iNxOe_C8*|I8lj zyu|)R{x|L4ns4RxfpUOVW;=yZHNrk4wt>-A#T)#wXYR<2l+($d%+9 z^b&L5?RMARi%TlJiJ=|4V2uCs&hik=w{m$i3tN z@(B4W`6roksvK8A@=CG{Y45)h?L@L3*@SFI-c6>EL&(u&n4C(^BIl9I$Tg(B{|&Ua zkUPn}w3G!KT5xJav zo!mffAwMSfko(Ak19{Po8}F^A*gMH}7Tn^ZL#FdGqEkkpHsW`SKMikk4-x$d|7`!2*Ty z=FFWZSMFT?Ci(N`&g*}dGf%FZx$@-CT_9(Ct33Xn{@8g66qN7s|l55B}$qnRY@&ocyavy2;&*Af%wxqXMuEViKl0|4I zkglyG6UZXu@g=gIOZ_T5+%k)&Ix3Vbi`Z zvu&ErB--}*Vv1@%PTT)S>oZLK{LJcTi?vjLK!pnXTHo&MVWSX zzWM+;{kHiUPTT%l?D&sS`ELGgv)Ly8!&QOyQ0mRUF*aXgReKz5*Y7i5_t5tI@6FdR z{~zo5|Deq=|4!fBe7fLf_S@{68Q<)e-51yY-doS>Kyuid(hhCNn$A1Y_BY9Ldy~&C z-yt`V+sLOTC&%k|(B4gcMII!Nl351#8z-vC_U0IZw_EF6+}q%0u7kIZc#a_Y-}lDN z{FwW&+YMB1w@XuQ>+ex+>mN{V?|!OsdwjF-Tl7m7DWnZk?2y^I>kC@to|xIUnZMO}RZE zy_DPY(NDQKALce#xji4lm7CusVQ!<9o8Kv6ZucrTzgxoG!gy}>-&{k??IAn|ez~wS zRe4eTG3Dm>IGEc^<>vP~nA;rX=65}q+g#;#>C9JdekX*vEyV5oo8J>*Zp-j|?7#Wl z5$5))a`XEn%xyiMi+b}rCd_RkZs)=L-U)NtqTKv03Um8FjbnZ{g}Lp-?K;0s*!fhA z`lELn3|?o*z%bYvOjjRmU5u`WpD{ zxZVGncw0O#UBlb?|=5>*9lOyH4ui!&Lpv_(2| z9DhsI-;TeF+v{)(d>d}pVM~0cs&9pVuIgLk`*FLj+TcH^`nLFS{gh8- z9OrM`o=5rA&wpJyM`qlf_l}I8AGhOl!Y^0#ci<&d{hj!=xV_)b_zk$7w=Q@kHU3?A zq8g_wUQ5;Ajo+fY8{QbV$JHHguIhW>ZE(B)A-toi?}^`~#_xsqRQ0{_e#-mcL)17a z_()aX7r#f<_roXRcK`e1lhrr_@M*X`F9Y#es(ujuj2eG1K3~<_AJSNi+xbtWeub(Z ziodGrhvDmRdtDulzm41DO~W^;@kij>)c7OukCl(YKT|#$|62JN{E+go_%Yl*?#AIK zaJ&Ea;AfQIi=R{DjK{M*C68-6&lB*x%J0Jq<92`2@hen)7%zp}{hWxGQT6xZ6_h`K zSHtakn}pX^^$+3=luyQ+;&%TZ!ds~NDR_HT|1jPexBK%59#Z2>#rvsorr|?W{d9b! z@<;J|aXX)n;bGkF&kTGDZjbkI{88LKE}p=jQ1vtMr*OMYX5sU3yFat>MQWTU@fTJ7 z9Q z@Z-v#$4{$q7UJh|dmb0zIi8lsuiekZcmdp=-z9iq-0sg(yf|*hUxt@d^)KMpDSr_! zi`(}{%kdj=yFV-NN@|>!@C4;6@tVqC#_Or^SK$qCdt9&J$!eTe@#d<2HQq+mufaPi ze+}=V{B^uLZqL^ncwgME=e76{Rlg1&rN(~~zX!L+`xYKnz8;^f{B3-i8vh;qaaF$o zpQAjA&%^C`e-~e%#@~o9QN9UZuEu!}e_8ove6{i|_#3#LpRM@Ys(u^(E^g1u`}j6h z{{g-ow~wz6@m;EZJHAKNe}wNTmU*Sp0_u;jae~s6} z?f!g&H^S{a@5h_t_I+6lZ?DEbfZu`J`8kMpRsJm=!tMMY!uu-!4j-)idpu3~VSKFe zAMpEdI}b-JCl zH&uTg|4Y^Xh3B4|_4UTzcp==*oBhj-;<#Ps*|Nz7SF8H$_;t#2;N_I(#4F+UxN_mu zmFLE9R-OlMqFjE2p^-oFg`(zUj%

z)mOuNC{MsslqceYaJ&CW_)y%Qm+JUf-2S~l4g7vJeocIe@>=+#%4_4Zl-I$ZQC=61 zD6fYvQGPSNLisKDtIF%+Yn3;^-@)xVY>02h?RxX@k5qjle7CA^jPFz41V4n^b(oAF z#qD`%il0*64F5~{t$5yf@_4l4+=drb-W)Hb{C2!NZr6Vcyb^Brza^fC+xcvT*HPXY zZ>Yv;gEv+6ZSj`M+u8c( zc&Fpj)%cI%GgbX#_*1w&FEjA@xP4xJ9AApt`F{dmrRrzmYt{I(@C~@#|JnF^xSfY5 z@omcI;M>(WPvN^%{nPj!RsRgWSNU9gzw&4CL(1pjM{v7Np2L5^?L5!Nwc{-^Q< zc=q{nJ+brlJf27SLcE~zMfl~o-Ot5%301!YFNNFlvJ`g%E&^Ayr$H8 zl|X&=fL9OH=LmScKz+`DdjZcC@MZze9q^Wc@y#yU{pk>>&l~VAf%<#_4+T7b!299m z@lqh*Lj&~%13o%Xe_6oq3)B}1_=5p29PnuYFB0&Xf$=X7_}oB!(SSc6s4o`q7X$Uh z1O7_DuL$_sfL|H#4FN9^@GZDmhgSuBd%&*__$PsJN(TJPfL{~vSYVt|0slVWr33yW zZa(+(+4+F={0nZ@zv-}kGEi^Uv-LB9db6Ib{}HG+>)HDGfSdJf-HFKK-RzH9&(?F` zW`E2sTF(=xH|yDY{y@E1&(;eC+^lEoMR9YTG3(iSi9o$s&(^OA)SLBe-3`>6^=!Rt zz|DHLULoLSJzK9F7~iaC>xqGSv!1Qj4Ah(TY`tEf-mGWq4FYb~v-QRSH|yDYvw)lR zZ2flJoG-JUt+xueSdkt#{%D}y ztY_=90&do`^=EMNd}P+M^#y@?v!1Ol4b+?UY<*>*-mGWqYXWZ8v-LLvZq~E)XkdJ^ zo~>^U)SLBe{i8s=SCG>>)!|5tY_;#;%5Dr^=$n_z|DHL zekL%ESzf(htY_qY!J zRlgiBhuhb^EAT4HU&3oDUy0XO{xaTF`6|4X@>lRqxP86-D&AfBYP_HFHTW>)ui@jA zzmDIp{0)4n^0oLZO=_Hj_=mVXU*F=pl^?>tR^xw%f2+p-9zTZL$Jb%}G;ZhT z2mDXm?#~fC*Ft%G+4`e+LFLErVz`~3AMvYkdmewn%cyaF#w*}GjCinmhr#qdt5zBqoj@+VO%z)vc#h@Vq_6P{zSJYMYmR>BM5_VHL5FRr`_ zURrroyu9*ics1n-cpc@5cq8RW`0dK8;~j8&erw>}mDj`v;C7wV!iVDaJl4iX<92@P z;OWZi;!~8@!yi|EGyaV7TkwU->*FhwH^5(0-VlFBxrc96-U#2RyfOZz@+SB}+&*t6 z<3B2Iil0&540o2u`n2QRis#4e`MM1+qP#hNrSjYHQp#K4*DG&{S5V#xuZr7s(i*R+ zybXSf^0s&r+^(y3cuQ5^9`AtLdFX(5QQi^nf!o*fo$x+t{5$YL%J0O}ly}C*;dXzz z;OWZm!XL!#^`|R79k=svH~ysZZuopPes_Gas_%iXR35_L!0mbLiNB+~7rt3}Z+yG* zKKQ4&ou3r^OWe*wU;F@W=b;~dRC#~=ByP{|0Q`651M%~?J>Efh&ZSwO7Y5@6aa%tG zFNWLwOvOv7`l0v@YW!h%CFR5M>dMpbo7MOu@W!~^pOJVA+|K_fyqy|nG~OAv=Vc5Y zQuSl;ero)2_z+cp4?a?je=j~>jWZs;Ijk70bC@`?B&HO~F` z3RV9AzFPSt{7p5^gZM_=Ugsy{+i`myAHw&j@u%SXls}ArtNaoCsPd`!3EZxeY4~rr zT@Taozm-3V=UJBZar78o7`Nlkz^_pCkK?74KY^FS?flHdt16#`*T(JjVK#n?@+a{| zxIHg(@D^(Pr|^!-pT@i4cHW-BQ&jz2JXQI#_!u?LJUm_bbNEBJUFY-hN0mqL*~%B- z&*Jv=v&V;Z{V$! zuf^|Fz77xJb{)Qn_f!5Bo{HP+!+LxqZXZW)uKX)}GH%z~K75AqukmNpIN#t4l<&uv z;dVY__$uWG@U^&IKL_!5m4AzWfZP2)gzr}V9sUhoka_+dKc@UJ{yScX`XBH-%Vizf z^>73)hTHu=ikDLL$M6cO{zp7f)&GRoSM@*R&G5_E&tLG4YMkSE2)FZa0w03g`TP|h zqv}uMlT`gF{83eZ8lS7`&)|!3JDvQzl7WMa2dW%c_DnW8mBP+iSi=& ze%zkN%kiI8eNp@zZuh4cp68{k=e;;y47c-t1zrZX*Yhj!3Tm7Zcn#dHhpX`Vs{U%c zxvDRTw^#Mo;N4YyDZC$U_rEkgN{w?ZJ`uO){W|Is6kTkq9KdHO{?z}AL*Ph3QcwyY`zlWE? z?fx{vD=2S_*TC)kH^Cd@_Ii?xH&^2{#XI44Jv76+tNL5f7O8tNQl%Vcedt4){q`-w{8r z>O0~2R>?ZC$8`sOC2o)FPTW=Xo$)HFz6)L(x9jjOycuryzboEejej@ZL)CY~2jO=8 zbjL@k`W|>#)rathal0OR;&X6&J?Vu%ug33VwZ!8hUdyx)uO#O>p5 zJib@ePrwhW`up$`sy-e6OVx+*ysyf7u;*(cUL3dkb3cBqs(%2#3Ae{J39qfjc@S@; z>L=r^RsBPFXWXvCDR@8J?*GI12sQpAcv#g>#i!wR{Y=AWtNQ8q0#*Mg{vvMI!(;eb z++I&+;G5L=kK-RJe**tXjXx7Vg4_9@g`ZJA8_%&i>viBsya;aRa}Hig`BQiWHO|v` zP36zvjd6P(=i=>D{j+#?-0sgje4z5@@X@%P|M~bN++I&2_*C3}F0=rjsr-3-E^Z$e z3-QIu7vV1}UyQF)z69T-d@25s@@4qv%3r__D1Q+@rhGYmTKNk6Z{;uH`PRt#vGcGJ zFNWK7{xW{8@>O_6<*(p1l)s8M#O--pjW<)i25+VOHN2zp*YU2n{e1Whyr=TDct6}e z?$+TWaXSxh;_0|uZ*SobDPNC2ru=Puj`DZ#`M7<&Y`~Y}_IyS0*Kj+Z@8au~Z^Sp@ z_By!<-;Ue+eGmTvxAU+W|5o`H{Ab+m&sO}j@@@E^%HPLxye8|@j`IPYU-^gl<;u6? zS1JDpzfSoMygY8t@5gvm-igesq+2!E4bbN82+a61NbI2 z&O!VmRsSvines#Ue%!9Z@9^){_}}Bll^@3cP~-f7XM0`Nxm|BZ@O;XT;+Nxg9**H9 zal4;C;$@WogjZ1hGhR*kFL*87uJhygEy_>ejnz26;?0$x#M>%Ah2M$Wb#fZ-sr(E+ zNcnI0DCNK7>A0P@v-o7?f8f)VpTlP<{}Z2!+w*%KU#R>qd^v8<@89?uaWLtQhoz|T6tOgyz+8*uC>YW^=Xf*JYER5=jBHHYTTZe3V0di74eG7 zZ^9FmSHkNmuZ%ZRUIlNiyei&Kc{RL?@&vr6@x9hM8ex>qc{95Hr@$$I6-)49~AJ#xo-Ey3*h#;-3Px?c?w=ed0)ITZlBls;dNAff4qtE0eEZW1Mx0u{6TmMZeQ;W z#s}ecy$!+Bl&9k3a64~9@%xnz!>1}Aj?Yq_hR;(z0$-whB>pmP&-*C+4dtWp4a&#h zTa}N+KUO{t|6KV!_`?}WaSUxt#La)Q}9m8AI9&-?fyT4r{MN+Iu##= z+t2Z);S-ck#~)GtC_YE|WB4N6&d&^dC2l{jejHz~{0aO6bE`myy-;a4bs8ZV>#8N7<}xp-aW&*Dv$&%@g(e-7`ad_F!vc?2J& zd;vZYw|`IZJU&DDLVUjRMfghPi}AOWFTuAfUy6UFd>MXJ`3v}2kt!Qt*V`@lWaV4&naa1}5#{gWFDd^3e^dE~_*UiH@!iTl!Vf6l zf&Z-hWBi=*op|02$?@}O=V2Fqh4N4E>y>|sS5v+lzeV{Tyt(qv@H>=$j`vpn1wKsq zm-qzbd+|qIb++Kga!QWQCAAetY4Bw;t0DeIELHsA>-{NPLAHs7* zle0W;eurPK{Cm8#^22yVP1V8sCN6$K4tH8|A;@$CUq$|E~Njp6lJ@ERX9y@S@7k z;nyku6R)iNJYHA%UwAX+f8!mLJLZ>D`nQnsZ1@o6+3|an=fEFQo)e#?JQuz|d2W2A z@;vxk%Jbsel;^|uD9?`{R9*o8MR`H|Pvw{4`8FoU=g+>sD1;YPUKqayx9?wy;Mc4A z%kfIei{dqK`#z!=-avVA{5ITvZgvIUO8J#|d))443A~G{zY6cJ{A#?n8mA;a5V!k( z4L(wNDf~X=rSU1suf?BGejWZSZr}g9_#)hX?okGRQPp3Mzlz)WxdC6NyeuA7UJl=? zyga@Gx9jRg{Bz|M@R;(7_z~qd;lJYcd9xD!m-5PZ{!OyZZG9E|O667Y>v6mP)$mHn z6Yv_!6Y=`WlkjG^T|d?Fw#sYZcPX!l_fcL8PgPzUAFI3$e!ud%_%!A9@F#J*4sXVv zQ+^A+M0tIDrSb;&>$qK?4e_^?d-!|G8{r=+Z;XF}+x>5X?^T|RA5`8HKdQVL{wr?x z|5p4gZr9aqc=q?QUWc3G1(e^87gyc_FOA!E)e^r^c`H0od29S;uj>37??+4t%omJMqVGJ3pQArvtp^@c9>R~{c7J-}r_}hp@V{`oK6~T2Hp@D+-UlzJJOwYNyf0o- zc|W|2^8R=Q&ZJ>E%pg7OFPo0U(- zn<;+?Z>M|;ez)?6@qWr5!PAsa#V6o)Jxs$VDW8r{#qI0rNAVfBeLeXY{-mm(fzMU- zkK+qe{S){SRX-D7q3UPhuc-Rj_#3!g4^QG7l+VGp;&y(X!gnZt8sCH4`FRH4t9&lL zU-`56A?5S%Bg&t{e^x#pKdC%||E_!ieqQ5yt48a@Fe9g;&qfS#~a{we^%g4mA{0yRK61LfZOZ&%lO^OSK%qR zeO>ViK2-Uu_&D5NXIA5rl&`@b!|i;&hR?OUl>btChcruT%aO zz5%!MzaHPB{B8Ur-5Aia}x8voNe}q@U?KzEAnL__xXr;YV@1p1;G7EB_upqx>-br}7{0 z?C)oNK01QuQGOIJh}-=+h8I=!KjI~n|Ad#q?f)0=XWYf@>xy6S3d)b;3Cd64b#S|% zzv2yWyRJ^+O;!CVyajHr1E=w}xZTe)cxUCm;UU~UPyLP$RDKp8iQC`n^#?vl`8j-+ z@;~uK%Fp9#l>ddlr~Gexw{pk)PpJIcA?5M^*_!XClxL?t=LfRh>~ZD5i{tirHYe^X z&xKc3o*S>DJP)3%JTKl>c|QDZ+@7!ecwgMUekgzsS6&bwug19ypRDQ&;g2gXj6bW! zDS|IiemTBMjZ+kVOL;MTi}K?5F5I4%EAX$CUx^=4+FN@prQVOr8yfj`<`L%dc<=5eDmAiOX2fGn}UU>z4mGX-CJIZguw=1uN?^RwI|3P^b{EYIdc+Txv*F!bDi1Gxy zl=4Kpg7PH125#3$b-bbS8u;zXYvP@h*TO@%o&VZ+s`5Jcc;$8RN0isYpHhA^zC`&g z_!{N)@r}wG;5%`{QTc6n1Le)}7RqnOJ1cL2rzmfUrzvlRrz>xbPs8o}x51xO-WHE2Z->9Aygj}~ zc?bL*+`b;}h;PO1>!nWk4&`^?dvJSwyA%Ifd1w4PHBJ}&N8HZCUHBR0U2$iJtRGu{ zH=bX4H@rA*Ux#$Z%PQ}I*HGhx@CM3z;IdVmDj$NcSDuP*Q9cykiQD@fhJUGiIDSxh8h%WT zKLS6kd?fz2@=<)dYvXpE--|a=J|1tOd;;D{ z`F(f~-0pum-e1*+@igTV@$t&<$0y_VI{yIvxbjK(v&tXDmnxr(zlz)Wc?e&xda3%Bz>2k)c&DLhsA)A(5B&*1mtcK_$%)0IE_f3U zGyN}zil~@Kg)n6#glP&zGG!22bLL+)nP!feQ;IO!)`l=>ZEV&^$lo2w3Sne6*^M0x zLKqpuhJ)DHmf!0>=X3WxKF;jdb$zev_viZEUHjSh=Xss`xu5%f-+!LxIj3!fFID_D z;dd(jN8t|%ckRDj_!{BvK3FgO8O84qzFzU=!e12b?vHm0e@*cf!rxK+F5w?4ez)+? zgu8a$BYeAX_nx&V{p3O6If_3d{5avx z|33*oS@8zplTD8lfwV3>R&7T8O5IxzCpMf_os!oDE^G_R^e{mHVWUW__M;}imwyC zL-FT?n^%(a(9M%3;hh!#i|{>!yY{RXzK`P13*TSWvqAVFioYN{NAbT3KTh$#2|r2k zjlxeC?%MgH@Usa6Y{)X^}72hQMNyXn3{ujmH68?9^-xmI+a5sN83*RE#`TvgaPZfVx_*cT+-!pkn zc;MCK{B++Zw+ip5`1``U3wP^!i|}5Ge;~ZCaM#W@;Rh)Gq3}agJs$}luK35ok5=_; z6+T+=PlS&b?)HaIg`cVTKZF-4zD@Wn#Xl21Pq^#v=fbZL?tJ?~_##z4F1$|hFNH5v z{43%0!rk-3*TU~te7o>J3wQJC8{y9={;lv0ivLsi%Zl$1{+4jJj=mG#rug^5KUe%; z!gnaXQ+Ti?Id7ex{}$d^@gIbTg}eU#D12|lO~=I7|7L&11HuncJSaRz@sRN26weTT zlH!@dPglHy@F|LS6keowC*d;{?<~AV@h-yW3wPtyRrr;PcN1Qxcz5BqD&9l*3gK?u z?IyfI@v!iDc(!?r;7I${*B^$3OBDM=bNj4FX3Gk?<0Iq z#rGCIK=FNq4;AkG?<;(S;{Al@D&AlCDT?nayg<0~e?Q?7#j}K02zU330m3g)e1G9r zD}I3RTNEECe5K+C3V%%TLBiK7K3Mo`iVqRqCfxP+AmMSv4;H>txEtR?gm--Xr{g|U z_#TQMD!jkqhY24d-0fF~3qM@(Y~dq>yZiDm;iFXj!-bzL-2I+=gzyQ%-Tf#>c!6-& zo+E{yr^=5IULxG>pGOI=P~}Goj|q44`Do#nsq)7Nzf!ns&#}U<74EJ(O8CvH{Bgo> zQ{|5rez$P<|KD_i@W+JjF8{wgxx!x%?tbqWE&L7PZe8RF|46v&?-=26;ci}y75*>b zZhoF9yyF|m`R4dZ!g~sL^`9)fzvAPB4;JpmeZ26)6+cDzQHq}``~>07{|Um!DSn#p zNs3Ptey*zjbm7H{=L?^y_$1-gs{YBsFH!sq;R_Wn5Pq%VX9~Yrxbyie;q|Kg*~0Ht z<);XLM3p~B_*%u!75*2+&lCQV;!}mcA>92Q^ef?Q!d?5%7yh|$HxCPif2Ybvgoif$ zbl)oy-b1*nzgT!5;clLk2p=Ha?PI0F2P3gIP+&k{aUxbvY>c#UwkuB(J!uF6M+FH-eiDExZGtA*bz-1%H1 ze3{}g;mcJ$vxVO)-1#|2_`|~8xL+jvNyX<1|BK@Dg#TT*+dnTB{;n#2iSVt$-99{D z__wP3rNYgd$$9JAd71DoieE0gmvGnLTH*Z^ze4yx#TN)4s`#&k=LmQ0St$H?;ch@!t#2eCwzCO= zmhe+m{l^GDUGdq%&rtOY6n>WC1B9QW_z2-sRsExcM-;zEc&Xx-3!kCtzfAZAs{9GU zs}!Fnyhib^!Y@+wcM*QEDnC;AWs27bU!eG{07Aj5dJ$= z|Ng?4s`AGQU#9pR;q{7NAbf@5Rl-*a&yaO=hVTa!KU?@J#m^J|nBs-P*D78j{8`1P z3tunXt?OCB|El9*vGAdaPZORk+_nEW;YTRGpYRci*9t#c@gs$gQao4q35t&v zo+mt0*4M?t$0>e^@QK2mpSua4taw=XS&Hu^{9MKR2tQx(y@eMmzK`%}iuV;hQ}KSn zD;4iAyjt;nh0hW0=I!pnFHw9C;kAnQ6#g5#|U@x`4-_PD1NK(v5Ma%e7xcf z!Y3;Ji10HMUoCu!;*SddmEwOEUaa_I!lx^~MtFsAcYpbV@M^`E37@O@ZNe{8{ExyH zDt^20s}-*oUZ?mS!f#f5x$tF*-zj{#;wyx&RQzt?4=H|+@YRa16#j(b_X=-R{6699 z6~ABjM#Ucx{)*xc3g4voL&D!x{7=H$6n|Lwr;4u<9vANB|Kq~HQTz$v-z)wX;Xf+g zEIi}Aezohs-g}wS@iyVT6#q#0K8k-VJWKJd!Urk- ziSVI{e=2;q;{OmnQt@rVk5~LN;bRs5T=*%9e<3_y@h^p+rTACErwVuT|0>}{ieD{! zn&Q_8zd-TD!lQ~`D}1)%*9pH^@#}?Ou6UjBg~HwYd!F#${)7k37~xkdo}6XIT&wtr zQoc^{lZ4--_{qX=R(zcBTNEEJe3@|Pe+S`rDBe-{-HLY-e!t?Kg*ONfm=lB~WtH%d z=@zi$JNfj_ihnQs3B~^<{AtB^3STEYL+byx@aI+eAB6u+@gIf%U2&6Wtue1E9uWS9 z;z8kW3wP}a32zmiDecS<{*mID!ndh55uSK)gIckNG(rZIhlXP7PtYr;~#e+m!c@$SO+-&IeSKn8pd;X_imoohXX zAC|(qz;awE3Z-?J6yqj^(B(_Y2T|H;3dR%`? zRC(9m3l(?$y!ZGo_w^!oLvSA;AOYK;hpiK1le# z6(1}-OV;MZo&h?4;H?=@Z|j>V7d$6Q}G_c`zpSh@GRj$<4Pv| zJV1EJxROaecvpFM#Uwv?SNWgv!*-Q-JAAVIuwC5k@JXJtiyxN+^4~}8;%+BTesD}X z{J34*-4T-Ib9Zrf2TAfV!b7|62uXhOuJZ1VkmRTA;_i-+$_V1f~0z6Rk5YcSWBSnuD9W8pYs9X2CUGCVfXSb&9RB^fe z+#U}flWfl*3-~iaj`v9(n$dDB)6ASG$F81M`FC=>uN?ndj`x$}%oCG-x$?c_ zI7>bsD8~cj_#ipnUyhHF;{)V4PmTx5aezN2`JWJ}jpU!i=ZOzEmcsu*BF81$IahS4 z=;NX#K zawA305xqckk?0!HR?%>toF_U>^kUIE(MHj@Xg^sG+Df+%xb^SWy<6{YoxAnz*0o#D zZXLVz>(;GXuWp^X_3757TaRuXy7lMQom+2iUAgt-){$F3Ze6(b;MReg|8Cy9`R?Yq zo6l|@yZP(pt(&iI9lHJ0`PX_=a({2{ID6ReBXW)$an#78N9T_sycPX`=tUk!pWf4$KIDz)n!RX) z&C!pDk+uw4)W?`y@+ewEOdzjCpC$6io6*h06!KQ|vAvC%O5TV*N5pIyw1t>!%b;z< zeDXMY?mouUl1I?f`x&#CJRj|_pE1kG!|3%{#;hi##hRm2eTI&=+@P2Px(9)gGD`RMmVE_v=j#wEjHxHjLI-CX^8k4^x|wLQ<cPM(GSj@Ut7k8UP1&g5M5L!ujb9Q_v&CO1bK z)0OB&o`r@-;4c%^Y7Vi2JQuy>c=}0Riw+uXOe1+VdgoZ?(n#8g{(3xfU?M)Fg{R=d z$&4e~d@AKfGsnNO3FDR~|GCNYXKt>{e;<3D*l+G7>-dlLOcZzhJ4*Q3Lq#w*&Ei%x1ZrXr6ztrGdi zvewY8M4WcU(GAZUGjJ5`LAS4C9pSlo&X_0v#-2moh(7fq_1hf%_+{olc^s{Jg?^Do z(Qpf1kz4(K6Jttl-ZW+!F~pWZml7@H_2{zq7+0I4j}T$`UZz=<`IbEsu`>3Lj5ruA~~C&J|BTlO3xpS%|R@t@Rh`3_@_`xj$Mo{KKsNjdU*w1wD4ovr9j zqLtkIo3<09C=*7%CThpSf1r=Vj8kYc+WklNKzJA}HUZO*bED{m#C&)ydQ%`^mXOz@ zcMzK>(|~Rywv#ub`N4qML2mUzVhY!-MeipJc?0?|v6(WBXxs+5)jLB0Q)kPdS7!uF z?P>UfenyNUkE1g?1k76UD0(5W*w&9u??^kyqv#F9K=!eE^ps8k6K3zqM+bJHJo7vo zowi%REF+Jix9kxx3s0aty1W}74toYnC)QdR{S6VJd>y(o7az#Y z=zu9FhO$nh=$yQOX`*~By7yT6NS=khL5yRcY(@7xF<=(42D8vrLoioI;)Bm=EYVL?3trHKzv5SbHwolNd#rEOc8wZ6lAP z<0l170cG-0GdWF?r$7)5Tih!{&AMe{$VPI9YX6LI=zwg${WpRk{Bzsp9~6GQD7 zp$C3STN&SMbTl!N=b3zTDY28h9)12F^u?A(kNk|bQBN*9nrXMPiaFgdTgBWw&$WVi3iA|XwNU{J9!p5gIH-fdeZiQsi$rE=<;uG z@-UiB)Uu~pz3E?gg8%hsj~|$aBm5kb?BH5f)uAQqA5qH~FECB5MlB-`ogjJK;DdI9nTn(Tir?2k((2OrX$fpJz;bjF%}+0`{V^p6P{$DmlFB# zTJ$Ai2i`WLhmQ%G7_fSXe7cpoNM)>X|$O-Ytb`jFkY02pnoJ{g*~|$U0fYBGsx@Er8Pk_m44NuMKL^tN71}X7!Nyk=yYNV z{zTDbHjbb?x{g>v-i&@o>|igAqa)`tF7RCRpF}6-p}CZ`L$nRYXY?pyD|s%u`Ldvi zQ@#}qUyh%4ZlfcJ47(Q4rwBtmjp*7d2)owMe-W)CsDDAwyh7AbXDiz6*LX-CM)Qdk zcF#lu3xlSCJdFODSW8}qwh|l2tzPgOIL|y$^a>)Ew$-6ai8jjAqdSRBaC2qQWE1^p zr`5BFUUr_N+pnS=`qm{N2d^LX+s44>UP!@xv3ADu0*448`__!ItdZN}|3k@#EH#?Wm z5kx8e=c2b0L-3~_y^k15`3CekVgq?I`XliGxw$iFjv+RZ=c4mguugf_twmoZa_#dl znt2yK+vja`cVZEF7CL~)AoO`eS&L2R8&8_>~2oID?$L~J9Epe4k1@+i8`y^ICVv{`61(P*D< z(a^e}8OM8E7|nQrJ<8_jsFzt^l*vVx5Y6QE=*m}urk=b34ZccyY}@g>hj2fqiWOg1|CV|*r$pyRf( zZ`gCu1;jSW*P(+yp}+QAw3TSaf2+5B3Ma2eUnlC=pIgz+|6u-5PZ-T1Mv~{EQDTE_ z4|*X{L0*ggjfhaD8NFm1^O-qZi{AGI<*Bm)efvws!q$&2`igy-`+FVQ<7@mS52HCm z7G-kL7l{m2{8&Vxf{A?q}Z z&LHBP8%2wTgiHn3ilQGA_0%6n&p#++=95Rz8AOCUihgh~*W=z7N5>5fnHBcg3BCJ- zkm zqQ_39PP=!Z1yTCWctz0XE@Uk1*r6v^hs-j{=cBh0^C@4CE{ugtGxxGOtFuF96S>v> z=g_7jnXBjoqJTUfokmP0kD{}QQu12#H^dC`I`oo@LS`)ESc^VSskFNl%U8Ar!n7UDZ#+JH_c*4TXmZMhtuc`j;2 z_pD_c?Q<+zK-7~*(3^;r z^l74kHZ-CGej75`_P&o^PxK7hMxFtI2E8HAIswj}Bi_f546pGpMzErrS_Q|T}Dh`PpC&9AtLZb^tffLLGoO*`wG@3^DvB_Ks4JqiM~m! zCT~Tz5>4cBboaX$FY+vOEU|$+ADu!pl1I>Ih*rD*phw)z{!CwT(ff!+`Lr3Wy9b|{ z8&+2lG4e+A1EPUEj-I;`Pwf0b8;C}7tFI8t$Xn6SeXMKpFnTGmk-Qdt*mADbi0*Me z^NKwx3!VG`V{M-k(BXfk9d`djfBP79;#D2Gkyyi6H>3R@XFb~e1fBH+bJBW?4qwYX zg8t^BUq6LMR(aA(U^EQIc zB4Tz9qjwO?$Q#fXh;8J}=oX@pwGc(D&5S` zMD2j2>d#m3*;@JB>aJ_p>$$LX+UsTV?m9e>9Wbn+oD9ChPbnYn%zIh4?5>e6(a!mu z8ap&+v13#|6+VtNMp^LJc+T6@6k!4HW8`GN5O zeiYoFAKU3ah;Yh_3uXg zTrbA;O1WMR*JC_)jX|Q{QoYzswMrB);w4&iVM% zhEFZ{)Pzq3{W!lb=kph4a`xu@0VdF+qv^4rOLpf-n(^$MVLA`b%(inbVDP1-1NCHb zF7u+8)9ty%>RdxVx6{uy`q_f7O)0*v;~Y2NoVxko=1S_kOPx1{>y~o;9MoRhp6|}J zM|r|JhD^u2PWO)%&BXi(=M5&OR<|l)M@8vUYa@7DZ_Lco{=4jFpsV8P4v4o z#rM=}y1Ls_J&(I}G~J3*cN6KG_0N8`Kz*j$+==I*JnIhSyJVOytCH>oEMF(w&YM*- zZ?x~$oA%abk4~n?@WgzIcFdQ04eO_kdDOx@YGQpB;72UQkL4-tck>|CKkbVfn@*Xw zAJ*e&AfGx?J+*z#OBtvCG!Jz>)|26`?P=O(udnwi!&+&gj|KEGMjuP*V-9^x*SFL) z*)hX(oXlL01fsjvg6?m+<8`#5L(p_s#r$&X&h~kEN}uhx-I%goY(2%Cm(JUCzH47> zzwNaqyL$`$v-P=p|4(S1Tt8K9JDq3FoA%~wxD(%j?QK$b5q{BRzOvu8u-`W6{dPa= zR5I*ZTc_5VJ-3B>M-%ssf-rM|xnBy)VNbR940o<;U#jn`WWVT~X*%bz_9CHZVh?oZ zwATmwx&18Ny-Z)Hy>j}RcI+3VtS!U5F5sRJW1g2X&vQ6l$92=K_tg1i*JQEm<@VYO z((ILq=L5WI!>bm&YQight-$VbpX}MreUkg3{fnh7eK>zF&fk-^@_bgx!%|L98rqlr zA!V)EwyaCjmc+gMfOf8NFxNPUYYgEUgSo~au5lpO;MpdJXPdww$@@=r%KgV)bGWSU z)cwicyOyWUI!;f_JA7!thbDaZ$@2#Nw{0#?)8^E@Ej8DBV0&Yq@c$P)@1*WqZeF?d zW#?dOU-cYt_jB8ZEou6Y@IBo#ko84Hd;LhgeyR`leAiB=cJCa{-l@x__A%Y_l3Q!( z=CStMu9+6@1x?%w+;h(Y+G5wtWOa{p?Xi8!OXH8duHA3))P9q0{k7+h9kXKU(e3P- zX}T_F&bntPdw#n9rQ7dZo$a0TOV_rWPfkLed)g&ulCwyd2t$_Q=g68 zTuGhF`kv_8>-KS5Z@Tfb^%l#s)lce6c}`62r>@twrP|(i89y7T_1WiYH_z<+O01>c z?d)OP&)Rr@Xkou>V!te4zl^b8ma<>+J(A)5E%6LJIb{#CeOi~stHju{zqYZzwtLU( z{qy=?|`4T*R2Wb*JQajrmk1_xt`DMjd{BDW1o?@x464)z;JJCqE9jURLY*1 z!+ktJ9};amjtgC@qH zKwp3F|9Zx1uW#x0fnW06ojT{-+;a2Fy(8G;bbFQ^Km9D2x^C@xsmFF4t7RM$??iZA z${v}+9=V*dcFx=V$L`nLN^b?W=GogXP})^jhlzxuP(y{f%D-5hPNY$|vCNZr4zcfTZ3>v82>eNOH3 z;R3fxtfxU^za?r{^?SJWenHCjO71$T>aNw^9REq*?4HN_hy5X1F;_9jW`WZHuip-MZ4x%6823`?&4H@^pLVf78~~`O|J4>`TAo`zia5dSl{! zF!_C&>vyU@iSH)I|Kz*L#B=6?G;MFMY`S|xs+aBcBXvFM?}pOtH>u@qo$0QdZvFi1 z`xEy3>Xi3lyPvf2ZqtI=cX+oa+5N=LNv)~x5~;Wh7mZM^%n@b1^dyI%qCelgztO82MF18B@a|MjksZhZB=Xy?w2 z@_y(%vTENC^VIvH-LEFg_fm;Arh6CW+{9=9gJ%u9&L?-x?h@%7b>ArSzf}17cfzUP zbJ?|G&#O*%9`CZL-_@tyv$y;Y&P(;n<*DQ9=2Pmvp~qV9<@))-&DV5e={|F6=h}ia zbIr9QwQcSkr|!B=+pEicp4@X1-+b=cqwH$S!_W54wS0M+_9f;ud&YnFdq;cqCeF8e z0dwR(eSc%UPu*|+(|4w+&m`&Y!Rf{$-ESGrd#9-$txMyDe*Sa&xtm{B?U>z|@-CLj z>~)GM@8Sgp zC7*>&2KyI#SYU9n-gJAUyLRgOvGpyG@AK?E+ukqjcY({P%6XhRcG}N&=a8Ily|W&q zKDQ+1344gXzig4R!&5v=H!obf+Ixp{V`b-AwZ6wOr`x!83-`7r?rjC!+w}hBymr^o zs`s39ZM1cyo9Dme9nOtY>hEsJ=dZ*!$Z6l*QlDAun4}y3#P6*1IrVqI0^ZePDc@(U zOBpxoqy0U?)>oWnZT-^UZT0UKiRZJFF>ucpcKj1#y4TO&tJ_;EzjUv&?<0M> z{H9N6*Ur?~u{pCf6c6O@8ehFnySc3ANb26{=D*X_KI^%Zm(ow?S9@xGu-}(NIY)p0 zmF_;J-;G?`ZF^GNk$V5Ob12=upSr$M$HTVOt_NGE?r-Wlm+Moi7v%px{23MHJzW08 zF6(VF_zkk(h5yC2U*6la+21A8{MmR>lDCQO6b;W!@n(e0wHs~Hz3uhUO-xac_1vqYzfR*Tk( z)`>0?eMoej=tj}EMB79^7u_M+<&tDOdWr5Uda&pS(LB+KqUVdw6pe}2iY^viD!N>> zL3FL?deLUl&7y6h+eE(={Xw+T{A9bsqWg#r6dfu$LiBjiaiaO6Q$!=8GeoOJ=Zjt` zS|@s|=nBz?M4u3C5`9T@ljs)FZKB_b{vg`nQt6lIKB5Cf4-*|JnkPCz^eoYc=uFX= zXszgC(VIogKs$$I0>Z>p1CyU&l!w{$E?i-2-FG zD#~JIW2(zzyAR#|2%A6;5n zZ7*P6vE+a%4}vjhA3N5UUI>hs@at> zV+>_@ZLxx? zv&&1%#>^&9aQiu?l){((KBFr3FRB6=mi& zOUD#NW3#I%iN$kcW`$)Fs;VxS9d(5=^Qu`)MICYD)HQG+>W6;;eGGYc}? zt;F1!DHrA37&C%@PtTD=cln>Kn8Ly_g*DN#lJaTgC56e>FrK;a!iti@lB&|OXwmet z!fABhjInf9abd~q>cUw?bCb~ILrbe_%Brg?tN6!EIGSD-n^i=ktEbnPGdM11ux#jfo8dF%3%x)r^QNxrmPnkk#;mf9Q8ndjTta5s6 zM)`;w=4F!5{I|(w(P#b@MY5V$QOtfGC!bwW5#_r4uOkYl&x$ca`Ji7Q(R2oEmboHO zSW(5wlaI_b9M_bUU0^RTI9OO!nP||IpzT)j3RjZHs>@4e@!nLI$SV^Ej|2;)k`IH0 zb80H1)#a73Y5con!NQA*N)k)e92+XUXj)aYtkRrI#-gXim1M5P3qwW4Rn;+bL#QZL zRnEVK7@}#kk1sz%NoVd3O)IHj)cBwMho+TPQU6Lbxti|{O`BFRyJm(l_l2f0m?h@^ zghs1s%maz6#ylFDCJlRxY&K=qB(%mn8JcFd3A5HJ^*Hv_ z5?PehW-?%0kt8E3J?fa@TEH+AbZL%&6cfn?;MOFEAr*R$an{j<%Vt(wtzkSk>$b zb6Q5Ms-o&5_K%5Vv!nFhOv;#DnHWNIM#daBWM*4NVhz{@%Rko2J@0>0oO4t zV)$XD6?n?ONyv45{O|K%R?VD}>X>uij)39c`^`#U&zZ>teA@S~_xJmw z`FxVIFKe&8_S$Q$z4ki$>{MUX;mCG4969_ZlMcr!p7K+v{{H(vZB&mKw|a!*>AV+@ zUFGz@cAG$+%3UI_xwh;_mUaz1x<77CKeP7E4EQj zuW~r%-jU~c?_}Tgsor)uPR$ygmF0H)kdiw_I2^+qjt57PE))&G@Nw%#KfN zu>c=@g~9xh%2#==$N(YxZu{v_8n8!2Yr_wR0a^hkOE=T%%(1vUN7PvXB zt8OlP z3^b^I)$I1!aLW#b%V_rBBpm3fub-%m3oBk|<0>6`=%W%n>Z%&*bd+uEaX6_UdjZ*W z#+RAN&&<5+ayshUCs$t;)b!fv6}q#xeX=Nc;8JjG8RB#p1^51Pgd^&R#Dk|jE4a;u zeHAwNtT<`y4ghP)NeV`r%CXcAYaIH~U*I(pec#GY@M}YT6 zbIp5>bvVGWZgQ74u8ocyp36KlFT3LM8G8Fi_mX{9OifwbAETMy==og#gC3poh-$1= zMK)@YMU1&lkLHY@1fU)r`}Z6tkLKL6kNwf{=R7sS(LYiz@7BWm;O4U?2F8cruQU zv!y!+m;(7#W%1QA17#bNz2+!vGMt^Fv1}Cm;ZKY_TI3emj4X39YDe9#zD_31kKC~S z3Rn-aKMFF#_1SMnILxPy6+{;5;Hdr!!dn98gtj{a$11VVLvg3Jvas!d`?mKz#s*Jl zm$U7_aURXPq5oYVM`|mlI|YWcOMpHF?cJdDMu#$yfg@Hyonw!;_!_4cd6lH$8Wm&M zW6xr+-dL@(y7paP=eyZ{W4oC>&f)M!Cyb&-H+mx5ZmW#lm@M1oi~8Son7{arjHKDA z8=skPk@gw8bR*{-Uv%c%KzEwYNxiXE4|O^9^7X+@(_-Ee_vtvVx_(1ZwBQN;GIqZqY`agO0zv32_&!O)wV1!meRwTcqD6BgwGx{D6ThP&Y&w#3N4+-A3nwi5BJ^4Y#rz)N=6hcylO3WcC4&u83jQ7i4_@?N;Q#XP z;LVrE(h(xQBCf5B?`3*G+hP46m$EV?UWIRB?^5Mtz(HPW$yc6Ye{iR1Zc7Y!1D= zD^R5GeML9MRtrRE-6Tuuy7ZX8*qtn@eO$yhAjuMv#(MkNlPsDpRX~+^jCIMP?@8|T zKyis->Z=(PKj16dWqhNTb$g9IlKQc|dimDCINeyQ@7;nPZ!!Qeie8aNM$fDNeyw{; zJ=3PII^8C?e{+4uWiZ@$51u#c#tU$9`F$fWNLh-&GZ(=hJ$BhvEEgJ_Ec*Ph5vXvd zh(`E98ECAkPmf-<6}83|VY(+#VoIV!kGVXc5}r&}JQ2g5EP56UNW*tPEG@?VTwn~> z5HbC$@^Tz;nGOox6LS)EeSVbM}kr>>!gYdg~7(9IK@{ zMkQI)K$-dZ(KL-#jRx5trIT0{a_6cdnfL*0Oii#zTj)S`U<4*&*ecb#NW1xTKE8Z9 zJFv#5`U zloA}4vGtTBZf2TEpC;)AR{9A55;Ymq-?44yVExvO4Vf(IkbFv3Hg!)a@*SIT^qh35)coMIKv>zyBD>&|_;G0$zS z#pc6EWwbh9kIgK0dsZo5%GpWJibfQED;)9pNP#3eVN-@vZpIYi>#tBvMo@ktsLT6mQ%c^D@%*4ri^Kxo-&%zAwDc( zt{&RH&u8QmBQ(*OLrBid+2o}CVr=t3P}KXKuRMl#%vXsEfH$_`S$yZ4dMWuPaRwzayRm}1_b{`6 zqcv>%1Tz%9ESJ&;DD_9ZlSiAsrmCakGS3yB%f-nRA6IaySd>GGlp6jn=9s4m=B4p-u!x+%LdMu}n-}U&G@Ud@~c?GkFyIYB(v1<8v^tfti zBR_iSI+0{I#&H%!expw>WyRk&^tPWwSzq@J*X}wU+-wFS56i@!pCg?4nIvcAV(_%c zZqnGYe1GiLNALuPf!_C=pcd}=%XhY%o6t#lwUti4k*qe>`r0>1T~#<7=Tqimr$MA#%K%XhXeh#nrjD2LYPBh4TBoe6(*m?yN)jVn$c+R{JsmwayE z7yK>MB7Vs6YR_c!MQ8Q6wbGd&J*Y!*-pqUOhlJE0M_m`+t0w=>72?80$A1^MxNIA9 zb~fd@bE`M%5Eprb9-WR+(?w|5GK9L(t*(-D&MXA#md%MPXdKxRTnM|2p5Z^p)gs*@ zFf;OnfW(ueA+}PB{F2V~sME7b!Uk|hSIqD`H|Q|KOn#Y6Cccn{G8&%|_vh`RbD!pm zdsgL0(?Q_90=^z_MxupYg@?Y-M^2_>5u&RzJHFC?_&PtzzBo2_XD&RAX4_bd1CRxG z6WLDbb{Tj;5&TEu6OegvEbt4y07XyLBXsI8_Z|?-T2M)u*-tvdK+1X=bx!$-!x7h( z9?n!u!SuuzUgBy^CeI7)%Ug6d7Jrc-ODz~>Tb`A{n|B{Zp>n?OC9904RdF*F=1jW5 z4e=Urbh)H!3Oih!kmW!wynym4poj;yPZ=x4k^3nIt#HUZCxtdFrOMhZC7~*ly%{J4 z3$oDW(e6oilcH_UNQ<_>O_qQvG|kAcqEMkx%L?#VRfpM~f}bUe^3kf$f;xvr7LLRu zl@uZq<4Ia0Rx~fAIpicpq>B}Yn(gAf%!&oAI=j*??xUFXN$rk9AGyuX2sP^dyO6auGNBCHjKm{=r&nY_iOx;SyX4Z zM2r`S!=8_fX0b9Fo$cEJaJTP2|NINF5bHr<%i^yksbq2bAXz+SHv>3W7Kac9vt;r2 zG|Q01kFlxdhP}z;D!P&FhTC&ZN*M0}bm4a`N$gXS7@U-n!oSc?Aq@W%DB*UIErAMA z|6i2o1s=uDeE4H{48Ul3V|Ab>`}R!D!P1t|XMaQmVWi)bbk4Go2QHI#YiyZRh!a=R zBqf!TQg9at+zMMNEjU4)A%QMHLmQHbqtnGo0zYBRu;88P3MGTDQ6cajiVSA{q!uzZ z1O>fn8c%qT@kPfzB%;L1e;NUsE>(2qDLkUXlW+Lg`n-<7jzAy+d3qGXZ)}%ct_95oxV9dn|5jTC0>XG1R|!P84(mjyyH?{^Ijq3h3ld~8x`Y!I z2Fq;0X@b&d&P^7DiLo&ePAP~L9IeX7e!fDg&&NAhPqj4%f|619KRB>IkVTu`Uj*8C zLAtgf*$Nc&QkX0{L18a=Nbs?(J+W*{|8U*dB!nD;6Bu=t=>lDT|CiR?Cf z6XQ*pCG!X&n5p^{EN@9=kLyVu^3&sb+)gEn4hMCj1xYf4U!YP#mzt>zk6W+xROqo$ zu(ADY355oSm&NPbzdw3-7SV~W`i}bca>Auq{co@_lKqN;cXn#ect+vYI7e&G_=dpc zQWZMLH~caGh7xbIGN0g#ue^6rZnn-IZ1bYw;u-tPHw1TrXRv)yewdrxvDu5Lqr|z3 zzDM}y_+82GZ_Wk@n-bzkIj|-Jp>B_lS3vurJOcjEU>PmUkqf4ul$R^vDU(` z8*hmroCkhHW{3D-N?_4(>~3aO#aH~%qK7|KD@47g{p{+ie8$G$m40Kh`7$#@XVt#i zsTF=>qrY^s&$-s4Ju`Jwb)uu(dElwiIKcmBo8|JI!$xTL)~1l3zv7*!3R^ z{Tm_Zoa(EH;0CYq8*iGQ;-xZw7yD{2s_;ACjJ9{6F%(RJ9K?O*$dtIBk{0)wn;>Z# z;=U2-hNNkbw4r5`9$JgIZwc&4XJJ~y0;FguYbhBDZnS{A!x z(Yvzaf)epZSIIU3HtAPi-xUoPw~<3t&(&6D*Be7qmP;zjwjf8wNE>w7%;G6lFY=0_ zBGnID=3;mMk5XB?TL|%3;d>#@CgOTUMBqr(NB<*gIgx%=p+Cv~d(DfWwa0N1^jMz6 z9gyT%=2X>*g}`K3Gvc2ETgyt(%D=M&)x+3xWe<3+-*~~VdHa0EYks5KECsXCW1hqV zTMkJjcw@l2{jq}TJ7uf*Ayx~edciykV%T?v)>Ya&Q*5!d9$A}N+b69gDyXTJFQUsn z<0X31HLpoD!|dW62faNl4?IC$q5Oq0`J$K6Ig|bfnQHvkT5&{KS&r$yP}SY*3w3At zoa=M~9mZu2wk-=M8U#$?rO!zCjn9OY)unyrkCigtzR6eqkJfxyn0-AgC;V9ERR~w_ z1w7YvmBl^A9zAwV@ws%SxYJ)~cb4wR>LXDtFErkiKFrgs4qoqnf>!;HrruZC8+qO0 zwu;;+l;$Sfa|Zl^c6)Xyl z>_@BPPIigD(haO_t**Aoj^IZayiAqz%(T`s+C@F1{n462f+ah$S>7aqc?A0_zj1ue z`OLWzcf2MRq4Bw*i$*-qr$@`g=9a$CUgEYb=5sD7-vx!lwG1*4SiURxo#^?Xt}UdA zr@gNYRDs`y`o5;6asKH3`$HFvcB^VjVxt)nYRA`f73F$`J+d<}p1)avb1^}|YbDZ# zuf`u)FCS#Hr1T6DRiO%Xnw=B_JXLoR?374PN&jZ^X$qxHK14!mfzTQo#kf-l`yV$s z1c53Y0l5}o4_S`~2GM7SXKaZs5x-!A&|$o3hsu6W&SR{{YmLNj9%{4F+VYic@fr#9 zW&m(;arm@lKZ3E*8Kd{E6%K3Rcj((sfH-=7p~Oi_*X~)H9lUAJ+BPjLp+3Lyy4oX2 z$Ro6amyutR&}*fqz<2%8DNlaDs$qOGEml$JH9q!qe&Y(gH_jIwT3x$G?|g5_v}n$* zwp&Va9on)@H1w5z<#T>vi9c^mQsVEqzKaEPu0n+Zz3%DU@A5~Fg7WIxjiK%1^v>-= zF3Qe-q3vc684Xw%mSXLW*(6v@+9nV4Xe+Swai`z;k}T363dxabfiu47?+|i*rR(~a ziX0g`gdy{I?W(sYC62!6aJaEbQtdl(;Zx{9ZXkyy#lGl~)1sqx@A00Ln?s2Rdg(gI zPgH=oY>P+PXF+xh$b9ANf)5H4^;rI7*1OhGWm_OjTS5FM?$n)c;N%29+H?L1z){<7E<~3-tV*LFX$zbl>XYbUvF!KE1+?`TTQRK&>2xyq zo5_s#aPF(syUX#s>%jZY3%=lC4Jj6W^~25WW!ucFF+)D*dRB%qMaO_R$J6orlCo{a zOQuKA$BM4oiAM0^X4+TQ5>vp=-5IKQD;aP{bKWfP4t{EWfb0P|3CQTow{i?T8hOvw z6}#Z$(7uriPi_BXjY#A-BNiQI{uS6BbqdA?G9OhXLPx6Pr>cZKLaJn7$A~we6uiVd zKs9PSOovY;w4B_f_rzsh`gae2cO=A3$jB$hce88h=tz!VX+M8qKku}kx7p7|`+1%H zyx4xqUP;^_H)mVZ2b1~b^H08 z{d~fH{=|OXVLvaopBLEAv+U;y_VWn!RJwtUJcVgua~K=t(>r(M@TQ0vbzj}p!9F{W z<49?LK^C*6u00Wo)U1krSw6jMdxO}`*AT=HkOB|BOL=c#B&y<7fszu@3_>MrIfw2L z_wBvA*m%Z@3dyL~f^S=Sah0S+B+lZxmga1t?*O$3r;Q@R;H$pd2|gxozx`NA3cn1Lay%Y{9J2tY9q7!#z?Q>V>`eWze|RQx{LjY z#20_&jI%&=HPZETr{VhHjdTq1?>@z&FbQ0B#K2|)5 z#n%)1y3$7|B(|ow5Hs$LU6p+HELf@=Yl@WvSi6lV<0`il^@NMv$dvp%%l-pb%4;ky zE&&Vf>GysJGOg-s5W4*akh0vArgJ7-mWKc^Wx9mxBh=K5C$=zi7EYiWV9BJz*`ZWK#|AjwB%@e+|#z7;LrEe^lYT? zYlI1vt1j=kIXbL!@LSxU0%|p)=tUc|VD)C*Gd} zn0P9{ctSgKfjgO;6LY-HoA+khi%ympSs~Ekje9qD?#~Ww*JwR~BCoO06WUI}Pzoke z;EOG9Z-c8W(?hq(wl04|rt$b+tOjurEqo%xR~y|j&ct8ToG2sr{}(-06LF+)SJ_8~ zZBNBJ_(`ZWbbpgE6<0C>1q^eA?aWA4YNZv%!7rH_o7s+vbz1mb^65#n_X$BPYZ3ADHHyy%}d4%F&DmAemmSZ-n6)%xE0OKSnxWbmbLDNUHqBl zOmLnsS>J(X#HN15a;x7f+uGOz073kfS!x83o@3LQ#qhJe#x}2kqp-aA451k5LWVrZ z6r_2VJy3imrO1&jRY(z#X9;B9o1XTK4ve)pElQ$r&a{4Kz`^oz_}vc9$L?@pF2p-cvdxHA);y_-=CdlCo>WT(d!7m9@qG7}zS zqs8iInMCfcqF*9vD6jIs>&e6>uR(xc%7FYr={O*pq0(<@p0D~;)+{Y25Wv8K=F z?dYSgD>f{n1zZys!+}AUA8qAwHC{UXh|YAV7D7@7sCz1N1xoL!6bISSQ#o2?K|3p2 zsq3+vwy1Y$jDC8;E$2so`Cp_E&kjL0`RD5r*3LHY+0~Cp2yA@2*My3I+TP%NWz%(vb zLO|PIDj0>#3!Y5_J;@x*DgUpcqM_Y;I6hcif4|%7%!NcVHkl@j%tAnL6Q8|@CmA$i4h(FqlKqJPzVTS zMzS=N34**Eq)5a%=;L_uJSs$g%DV$+uj1e_5gvEo=v5-Rp>HY!g`sZ>S5fL%{SANE zOGj4}FBa?^6&r71mn_=i3>16MX($c^#)9z{0fEFUK*)-=(5aMSX-*C+Nr1yMwQwJ0 zzUVl0iN~+|?AG6X@rrTvCr`t(e ze+nO!Z>j>r(=}NRN^&S^Uv9(Z$T+2$9$Q}A2j+UM$wJM*cacZDOT(&0XNbBB#*A{F zK5D4P7)5v?PPlX5sNlPz-a?y~SrlykSXFTuC%#iHEh=R}5u8$P%9B=N6!;J*^cE*p z;yDtO{p_3-$_(FfO7K>7l1v6G6I)fD-=>A%9m9m)9oK%^iN0a{OE(aP49)8g>JSsBobFwT8^5LJn_lZ4Sd37|ky>&nt(F-5163Czie?x?8)2C{SRu54kv_QmUL?rEmFb`>7BhUuYf7`iS@k z0~eC`{$vfND;2JgFHmYZo3h~&e7h+dShch}zbXW*He5UzI@t@~icAr9kMr%*;SeHA zfZN<~9`201MSK8zOUb^rA2xLm={)idmqiBM=f%bhFo-IdAhU97`4y&G5cG4 zs2!sp^i%t~UCL=s95Fr`3nJXHF^V;aRg>b2XLm$pUBnDHk5`BrnHv>G#1S7yzz zi!Y88Tl7e`7O59{s^o~;R{Th1EVb~9;!?(37lOlU_a)JpC!nuvkEoz1EC3S#kgV7d zvg65mO5c(a%PzQ%wgF}V;MucI3k)~*h5A^D{)j+T?&&EE97!?DL<@OO`@3!MU5lJZ z#`(ELWWob29lqLavZVQ9_~!5;pm**Z;>Ya7p(wO`jCjd8KIfYvh-z(9s~Q=?WXp>; zfRx1!WsZ|F<3|lFaWmPHV0UEcVw_SP%gK|~wl6odV<-zQF%4tInBRcE?Y*2pq4+jh z_%{fcwa(h>BIgk~*Z2XhcIy2oF|_L1Z9d4HW`xJYX>Wu2h+@ei3j8yJ;Ab(i6^asH zY<_mXHkr*hR-TuDtzWp01)*>s|goJjEJNp5(nb0C(@}mVbt%bLc2yfHEIY>KntWdtTr)(|5tdMQs7LoCsP(0fcS*u0P1BtjZ;`O%g z7opL@e?m-TK(Xc=@o=0nvZ;(rI8zp%nwkS}P0#ijy@_ocCd59eyo|*uElEtz(s{?c z*wg-@Fk8o@b@22uH{$)JIH0Xu==2(|w7r~TJYbFd8b-cT6si47bexg@44aC3e73cX z(jq@3FGgWf1q1&YYAYDGC>tj!!f~Ez+_Fnq#q5dd76vq9*Iy+QH-}VYYgJvRS&VV_ zYLRn5CycUqAj^UlegQ5rgiY{a?`Fk-)UciGBMS32O|?ZuduD~&IWcBeJwy8n@e*Xx z`?3|q-;fo?5T1sWik*o+>{0v@7S}4~ro;xXOG!?sll4-GO&g%Ts1h$@7vhvFq)1(= ziF{MC^73Tj3Wc)`+8sXaxs*Jn<|+-In4@-A3Qk;aY&*()fwOHt9Q26@?XT3r1uB81 z$pe~$LL-ILP-m7U;wzMhqa85cM5m_qgvUI{Xi;R`Ni_mXN4ox%8YhQfq;2AGteoh# z>@DIRQM6>06duRg!VP*B$vPe50(sDRwIut#uGXH%zISE; zZnW=%5M90OcJ3l|eEU`@&{mtr`Hgl5!+veAQmTnfR#PA5lEMKe{i^CUIy_nRw^eFt%Yd7jK?+9oA zD7$~GZq?*V2{_LY?P1>07sY%z*s-0KC(#nGLI!GACytaND=)h?>=Sb=4HIAQ9#n(W zrfPOlBW6wps+Ozjn4SgNGE9@EMczfaIuGP{;veRCk6)oS{zAXFY{-0QxsvxB%;Bi? z_^OQ!1fLQ=9NZ;bN_E+6b(u%E%FJfV62n=-EM7~l2TXRYtht0TWY5*UBaTOxNq}xF z&xtGf{g(a<6C**drp{;0A=9U4RT-~TmA&9;-`N9xEmFX+?70Iod)2Qz@kF+VJ*$Me zym{;+yR@_?|!`El$ixMD)ZQ-g%CS?1Fg!o>o#M!o1@3a-bDCL#*G7n8k4 zy%S;4YN4pU!^SRgiIn$IPIFo1<@J-Sky#kTgx97|D&$3#R3xyPiIY`D2HvA75E31M zhY};C5BohGzVI-strmV#T7HK7bU=^9Pk24IV?d6raj?UbZMys<9{%*u*=WC|xY_cj zmr^UU$9(~g#P`XBEYB^MS(O2n#i^ZF2_jKaHP*xoz;N)^QCQALj9Pd%?quRxh{&{y zZ%d)B3d2BJs|rh*e07wVM7abrcyaTuPsqFNJp1zZBwuLfIh_8Qu@zLjS9VSF{@18B3&Bl-lKR3e`Wdn2KDesVGp zY*F6*9*lnf+|swav5S*f1@n$F*+JTV{|z*e4NT0n3OMt7)Y%xEJ*5X^_f)%u%~N8C zpnh7#)?~_Mb3Qv2dc)P6Cy_sPMZ6q;TE&$1tRr}G)yFX63ekXZZPYo&yBuF-6OW+E zL+Rd5Yb*9A;ryNasjlU+hc_{-IdV>ncklUPF)c47&Lo63WK$+yK&HbH&c9bm*pjQA z7mKe$&)Xn-7iG7?W2Ab(_4pm!wM9B7Ez-p0dxb*rP3{1|mc;v!YmDh$Px~g>35WwN z0+IL*MyQ&@AIO02@N{Qk0aon*?U%^_2gp~b9W^J^YWw^1Wt}83Ra=>JQmEfKb(#01 zY~c7pgDE3&v|IsON6^gsx1pJAqUFdzcV(74F$b*T!oiZnpK$ishN1vlp~aphHmBO^ z_m5?kv?XuLTV8UIpVA6N{N6hASn?z90(gY z2pke3M-J1~UksSD&*(F8DKH)XMry@{PgG$z9?f@fG&1rlhDdm#lKuX^dL;iqW#CxS zpR2SxP!u}ATLf1>S?&k;P##)UwyV$%xugw^h=Q1fmU ziQWJL<45uqH6eO#?4v!cL$o$Nt0x?zaPSri3$m_~k(#?tQRo(cjtfn`c#aYG4aI(O zyUOpLNAO~3N_2zh4V4DB@eBtEZ=f|Ji-b_#N%L%> ze63Kv6nF&-`F)Jdt`ymBpz2$#pPUNt+j%!vW-grEhwPAkMx{k|_7#$S zk}M+h1P{MfwZR^@Ui*S@c`;o1jQ}_kM4DJMEE_W3y>dCrRKlX`|CVMu)2dqO_f|*qAuCYP}6uf+r zidxP>T-5w!pt@ZTp{e0NP?HKlB1KR9Rk9BIZB^SXONd%7TdG?7i)V4c6SoU=IlG-F zTLXfSiUC4m7a}@hpa%$9QEL%$0fbaVFY${IiM}X`(&OUb+->6r`0yExEEZ@qQ%%yK zd)DIY49CJsu&qH}y@cP&5w@93&oMNtB3iplKJ~QmDMTvX7IQs7z4_NtF_aeljK$Je zco8Vh;KOfu^L7Xy?#O0^ab9c1B;SWA_$oJGGdOGjIo4UYvZSZuA#l9$~}5*kM1-* z?K|4&TZ??bUz=$@qf6Ph#2LIxPUB5X2cKx@3EGnJ@IsO&YD-Le=_}Df_o3i63h7NW zLZfqqON_;NcIS(oJ-A8YBi%62qDq;|kruI*dDVa)u&SF)x{sYXsfMocpLD{`iRnbc zBx0t8$3PKc!0ddi8S-wAm1Y*6?gu3IZbdr2oShz@_6&N0f+Tjbde{VqdXR;8N)JF4 zHS$5svTT}mJ5EkaWM^kXF$x)3Gb8&K_$)H#ooMm2IX$dW2~=32a3GI_V#N^Ng zv|UJik^ydYAgudYx`UzV7Ad|}9nwNbiltk;cEZ6Vt%Xx5k_HCx^7W}fJakBl$hWrm zO}fQRhqTbYwZ+Zp7Uvz(V)!8~WaQh^Eeh-w0}@k7i*DyB_E4}nz)t|4BeH+Qnbq&b z0!H)YT@y-UzBt}8JSmO$h^=v__z-hNq$g#q9|AH3m9`6seB`s+F~PU@?L>)$f$TXQ zn52?4sdGRenl(V``vbyl%Z&`~)9X?!pL9qIIr^rA^Gh57qonupGF>vr+(0DFD}REr8TID87=L0annh#nVfQ2Y8ye z3oN?$Ao7JpIIvT8VEOHdFJ%*8cYGNL1Al_q5aB1?|FAvGlr=e#Ld!Be&OlhOzUHGf zaeJb!Kd;0v?#Elf*^yO-o`6(K5j34fLofqprdp1ROa?#ELj_$dts6RXA( z`6V_vg*P}J?oPZK@}3p^4A0@K9mV^`iwdI`xw$tfxkL7SvfIz-qeC%6@Tc*-ErfBf zGW;eu_*6{`Uk1L=rb?Dhp*FL5eMc-uF)ehFJBN2ld28F>bFfw#GxD`?nc_Q~h{)+% z&z>a@@TiPU#U*Ekz{TY;8Kk7*NF!9Bbv7{!q1V{tFvA1SDxsS2ZaNha+y=o9JH|yv{fMCpYl3;gfJoBn@q<5Ek{=X4eMqJ%ub=(z z`O#4iFzXgyegY*azWh*8)y9xyocTNuhOlH2Kxg1aC50nI3O6b#yvUt6OEsx<=+6%W z>NtLN)Um&p_LAxEvEw`BZ;|{nc3yv8(5K-awAu@ZYTx0B-mUnuF&DPVaX(Yd8F7Zq z+H>ccFQRdBgyhK{z6?ca6Pr~vbVLhk7-%M65<96Y+n9JrOsVQN)lK3A#$w4k?R*Ef z`-8%1jlXiwdPMg=N)q*oWBD@P#CsGd!)Sf2$M>a7`DTPRi_bA;RE%FZo9oK>0ONpX z(dGWw*o9bKVj){DsU7v>YUf*?H>jI>JivDe) zhZVa6*DO4ZA}6RSJ`Z%$QXFPl7f@oZ8+%Y|o8J}p2S!!w3T~$5pE2wGciQFTpCGU9 zE)@La@0I+GaE5gBa?;mZ=_Qh$L0YN$QfgzAJi;9XV=t#kb#0$d^YSTH(KK?8WRan_ zvFAx9rSd?7u_ z9L71i4$(gK!I;$7OFgf-RK2=#*L-heCQt@Ofgc2pHFlUQ)8Og;()h##nfIgtGH^*U zz1q6@TFYm=s<-c#wdM8;`NsRUvp8ke{{$Z^u&&wXB6MEUlhKV&s=4)p3+S|qKi7@j zdg|_J1%qzQdMPj_>8T=3`fnTmun&NLvOdEm$$BE_GlRtP~{l;fY6Q4_0q0HIZ18hk7T8Y zwu{zlD~+G?@EBV<54b$MuH!vcJTX*!ho$>r6Jpiyu+(?*F;leKxs{KZYNt8E%ZbQ*Wz@Ir zSE2Z?Lh)P$hfLiJ#|hmQTJ5&;N_>ah#gfOzZWqOJ4&#axfC2z{ZoidmEdUlOj^Z8CS_d!wmw~*Nbu`??)w^d*-%Y*R|p{QEe_8g57pq z_g%95@Uh$?lC}g3yxD_Db4ICIiVfGZ1GOC;*7tzC=R^>=Ho+IYsl=Rzl3-fG8v}W< zOOwW~$nL=CvN+#YFXMo^?Y}ViHtFrYz5CUUKh_~xK5XQ#c424x0Z8PH_uYfqAkS8R zIEZpThrx-Z&&(gKMX7H@&nrJJF zZaxd}m}}}|GRU0X6sIf*>aVowk5l#ey@@ON8avgzW6<}5@JjA(o~3T+i%ls+sEs$1 zuP@6PC*LrOYC#fLAVjB(R51S7gpW>xniB@($!qM!RpYY8nb&ewNO2?F$v6ao@g_&= zjDLEJe|VB_7;hVIM&eu!$Gy9|LK||x-Uggko4PAmwDt;h)5u|=FNaafMd+aoS>cUd zt!fuvnkI{)R`s#kb2;Pau-rs+Srs|yF2)2Wa8sLb-*{a?-wJf>;@;5yJnfDjQZL?y zxRh0qJz7NkcLjAJP%QRGZK)?<;v6)9$az4w7hJ(m9a(M8_JW&8wK;)mFL+;)T*6au zs?-*?7aXIWs^|!*%V{rIBF{WWp@?M4yOygayF6_#Jt)-lAaM0nM&MfRfhNh2)P0yT zNyzVHSuTi%Y*Kfb_z8ARm&;FxT@$mDY>D~$aLXL?O*ilgB(%{fP}4J@{+NbJPk)De zPdtfhN>W&-hjtQVP9Y9`>C%?^h)$RR+Da~5NsfU`;#*_+NqtXTRrayz9wBcJ|K^>Ys6veOPi*SnW{MC5 zM`>Iveu6*RP&}EC+AczBZGmg#h5|4NV)LlKDf4};qzgd6Hv-CJ`%~8#NW~Xx6cD`G zZkllcTCadkRM#f#mg3D8NReNWH(SW#@)BFmeLZL?ujO|Pur71_^Xz(aOo1pPBM?T& zC@!%^akv^qY5;7z84jJ|HJr`y=48=mz--MbkXRvOyH2?n{`> z1h7KNa&{jcrj3eCZ>ORrS=2Mbo(7%BsxEV(8`&n*+S4)Hx(Pw9P#d23EgZ7^!@<_X zvcIs*$N7DUZkuDUyv?|hmzSl;7lr~#H`;uiwG1-X&gERFwQN@<@tUUfs_w+{IyL%)TeIR_89 zISnP4t)Gl|2%CTxjn~Yh*&tZr$M>d8ARp(n@ZhaL1rL^}v8P;$sqJ&tW7fEvA|RK_ zO!?z<%lyVeeV>HlfqEw9?Eca99mzLBlaB~`>IorLI0EHz7Zix_=unO%H(bR7Z;KjH zSYlSPK@sVe+b#5zp|$T>1ITn!A9^nn z3hvgG*)urj!2iPN69u=&p7sxQ&VWe=0ol|t``kD*M78RFLGeeWx$i8n#!rv8u|^2g zlWmiy1b0 z6$M2G6sWnxN}G3%8<1oRAO2zaDfAh09rkM;-{wCaW!3NgmDJ-u9tGl*I&@g;#Ssn_ zGC@8ETc3^&4kPk85mAOe|B^#pTY`u8AF1X^PAbZb^B+@&?8&(_EBJ}E()?fJtNr)* z0yaL&zp&<*%TBn)!Mu_HrMySyYN3ls>hk|oV)>_YQ-2cQ#ytCgi0)Ruv0DTfA({^m zTbVH^g-Fj;s<{ZKy39*C32An89CX<@C(gxtTa0tV*_~o$4E5lk6;FA`Rl;z!@CKFR zUp}yJgD1JNT@P!f@{UN zW*F4yhI2pnF9l!k<|_`~yo3Ppt6(8IYTusD{h?(W&HcPiQ>&Xb!XDRePLM6Rn3477 zKd7|I<>YL4|DOg}r&3ltsYIN?KRp9zY?hpV;y+u|g2em$@6H*mbWLzXQaJ4P{^+qR;&R{AQSjOvK{c;!u_Vf!;hq-V zI6QUJmxK}0Kcb%^!>5}6!;o#y=r|Fhsj@mjHAq~he8`OVW2-uPqufv{pT;GLlzk%f z!5xCe3vwA2?qU({0-m}ON#TWg%}Um`FLM@&hh<$d7rW>yb7E>(X`JE@C>J2KG5g^4 zy#oi=@~YC{_Wg0#UnKqBLbjUwu3A%+pPmmE;UDCg|(nzD49!%n^x-yB0zsP(P zyj?D`zt%kM7_mjl)+XNPNQ~9z|Goa-uk6W@{l^TlC*74v%#3YQKJ4mXsb@A$b#!VWeuAHSe9AXyOZPHEUSsR$9>R#jfK^hwYpkl(w7c+ZQd@qa}Lzr!Bt& zv9{z~AP++Ro_0qGrBz(TPX~lBMk1(guc7Dm|5ANNHjG*pufTX~wYLP<4yQ>uHYe^i zhS?>9szsg$-k(jTPJM-VOEE|9lo#Qb)t_4|_hV@JcW>U}Vp!oYhdwTHj@I9Cph z5>ImCEoEP0MQ;#yB35*qBe4i?&sMSagar0N`wv@G#2Wn1WWKDy{L7Toe&OKtRP2ko zK;FC?l9B0c_bIZnAZc1*bQ-k$Pq8+#G8cMIq52j$Xy|aY5TcsMK=o*4b}Rx8ivNf! zo_8#NIO z(e7UBalgi=Xy`4MP5Eoz>py28Ud1~#PxqrZq3INr2wC$f{@kCe^{skQfN0K3PYQ=Z8rSevn3vfT?yW8WL z6?yaXT+YxkY;C1>PY-dg*keHWoUaI}#-{{46bJ0@Eg^O@$D5P--o2r(hbfPn5$;y^ zFsAsg*LM4On^YCX54lz}J65!jxGHj5gaqJ?o14UC5WhSz#hTlx*2VUJlgO-1=l501 zDYyR=p}#`X-!?Ca`NTACd)HTbz*wKS#KLvH)5b8w!Y~C4YLur8<%CXn7cCS&)LRD& z^bWaUvWzP*5?@Iop7<>fTbnvmJj;#JhL07cJ&NsiQ0u>HV7|rc8?BC1;#a+iwgx{& zw}0{zr9|iB=Zu|3OH0KsvQ&JArQ$Oz6<53YOnfi&KbP(u`!@JK)5+#GWu>~cm5z!D z*1s{-?z#$5tT;&v%bSdflY=?jxy$n8`pPrH;ZgrJPdLvg_~TjSg3Zjz%G1ST_$=8g z+l0$$$eHsAIIcwx*%d{9p}9m8<Kq&#bA$?6YYJzN$yF zB`7hO)pHnTV4byY(d(IVOkLjNgOpTO@P6!3gNl}q$wY88D7ja{B9%t{Oafh9|cr*S;f5}ICr+dnE{wpGMXCu;Km z1hXFNMj|$9wD}8iEMyh@KZ(h*G`l@(#O=Y~vEBiAjrY}U&wesz#a6J{qY|5W17yo{VBk!aq>`~hZ2un!pC zbI#wN&o_nbHJ3mN5YlE#ur8sQ8CdKiWSUjSPrG{D%4C<#@Z%appzu(iNYs{gIK&kEA&lseVYt z?WFmNoV)wPY2OE>g>U2q4(1;xc{ZG72Xp3TqBfkjZ8;f37cOQ6OdPnm6G)v zbBp!ASp&g$F@o^ZfcgwpCpzei zrG9p3-+8wWamIyY;gmXXBt&SD$>37VIRf7sIk1_-8AKNau>QyrVf}t{-@~$+aE=ev zrg(^5ynS%-=ZcX1<|ey%sRg~mF8;G!Y~P*zvR(XuUEB-*z#X@XBX+SYG$|&ly`o6h zBMPX~+zL?UkbjP{9>m`|3GZjl`%DUC-W7kJM{iU7m33R!!iNp&Pedk6J) zs@$@E5?w^y{juAfiIZg+5>a{+4h&3=@ao)Ri&y6| z)PC+QUZKpKT(rv?#(zWm{142RY>FI}sPLnM8y|au)!0en%xUeWW5Y6R{wM}b7tYoW z0XSB4xN5WCyzC)MM1M?I6n~@UY`^&&#kw80Rjj{}W&{%|5&z8!)M6b`1a-->2qBk2 z(}LX^6Ex*(5Sgp^&<$%NuBNErVm)SkS}AbLD3f>5N_xb9;UAgGzcMClypMkzY3v@p zLQM`=QE5vZRq2KhwMbo51NJip@mSOLuU?_-(~%UH0>PpK*GopJMF)n2>v zp8%?6{Oi6G0E1L(6-e3ekravzub=_%-qP_L=;QVQTw9wyg~SWrrppot+c>asK$Pel z8VZwU;f6XPc?h2A(A(lETA#(limaK#tr2AmLTW5BjD(Qz?1PGg{;;g$srJ_Y>sfV} zHQ=j{7i67``F}{6&(lKod6ir$#s7lwbJv{S%6=3vL!9)`H{-OsUJ>)PM#&h;u%4WV z)-Le*%GYb5e~@6>Z{Y~*T_qN%lK)_ld=1$~t=Ud5V$S4V7v4@LU)RgSszwVRE^i4^ za5casoRkRty!b8c_m;lT|5Yj7!A`F9t~>gfFEI(!qYpyybI? z7xO8hNDlS7B61p*2o~SMAwR~&vcAGn8c`Tg9&4n3BU&dP^veHuPaH`Twa;L1x*vx` z6j=U)%ZIUP{D;!OSUcW_*E7@Q@GRrPIShhqO3Gy)VmI)WuJ@P1R5U;FIt%T9{K^O9 zZPGP#>1r0uV}FTapxrXOzffhH5_KQdVm0V-GL8q7ogm&ZCS?K=he?%}cyV!*btBgQPg9Y$I5jS1#$-@V z@g7nX1^(XuW4WvB7TpQw6JDqqG)!!pHPY|Wu{F}*%c)T&jtATl4@mnOuh!03vXW@z zb={zaLM;=CA4=4URX}W={CumMoFjKSrk0b$6)MnWjTi1$n!UW0NE{{j{}ZCDL5N0x z2><#fT(Q9`)QQJH2&1_E=jjznXiF4xi%Cjg)06i&;+8DB_f+-nsc-63-alMAa6bd@+lkg zhX+AkatNepL(V=3a{M8X^<%8w&pHV5OJd%GM>NXDnST)E=0hN_vT^RXfAH9UcL?OY z_B5?J2=dlLATPFY-gyw@3?Qw52JZY8m~MJuwUn5{alFjm0&mw3ypMAo{65a{E}%b1 zgQ^A+A4#7FWbMb9`<5e2-8*UNk(O3G1(482?yXbHi;AmAWVa1%wx}5RI|x6{&bQ;g zAl)(p|ImZ+yVFqr3w}JqZ^xhUK9Kz}cge~>^o$i;FPvPBS`5NRJx6!>cV!y@xlBNQ zIsgKFoUbo9b0Wp=f#Ng*bKBrT^M!-*e;u4pTy#rj_wveA{XBSYC4(9GNtF+j{5SP~ z!vS$#GJkpx;wv8TpdaCLW`XRak+=F(ZPwdRJpv)zqz=eO3hE^uExq2^lt%$Gm&2 z?m6=Vt&(bTH?_>aVSb~eTivZUH`Y#^IPuzH?!iA-PpEUxxj9g$n%wAa4b-#*PDvLu zyBF3q&TRsH{rrYHX*;0?wC)M>-8Hp=`3q}k=&lI{n%pJx8v}I>4fAiPYYddC-V}7u z-CDDt&Rx^$hO*O7Q)P49WoMmYH49_+PYZgkfyY??o}Rgl%Rw$?3}(=fmBhJ%{aw=^wqH#fD;4@eIcid*NZE}9uZ zLtSlp5Owu+EiH9(ZT`9EH?{^^g0PHc4Ao}WDejsDb5C*C-rO>O@hR^4a|5OJf`75s zH^VcdIz5*0t?t^U1Wasz&xh8`NZ^m1{+)IYMX9ooZl+K)2u{r_Jr}Z0wMSoG_};BR|rm1W1Z6T zMp4-`%3+QPj+QwJG}u@(rvYG0OLJYLTe?2mEy6f{(q!LRXUuXdJ!=-dnY4KPEKAQa zYJod#7QLR-Dvi>HXo6$OYsut;{JQMl$*&Kjhme+fsT;C&pj`6z5+(hc4LhCu!*>0{ zlu7<#QKHi(mYq3q(wPp)IA&sEF0KnKnm@PB?XlFnt|blft+g4(et-dDn9=IyU_dzF zsILjsG`P{MmH@g)6I z4s(cwY*C^FhWZ+1m{PTlMKvvrA_H_$d!xHu zv9rgYV)^{Wg*6TH=enm}>}6r7tDnEPP7&6qB(SBXajv@_y5_=t_uRVL22oQ?tmb!bb)C&Hdw~8+&cDbeOUMW|HZ;}VsB}JK0b>SQ!O>7RLCAz3wJl9>(4u5c6ZWUJ zrWFHH*C^}cLRNpKiT0`dp{)-sN#j%YOc11)A*Ogi9bzehp!&8LW!W*vs0lW}GG)({ zv4b6h+Q?AnFTl-cu4`$y8CvmL;K%}+&CeW>2v$Sg4K=klyIX_J&1g3L9SkI`?fw@b zWXMyBJXjoTq>1`Dlwbd`VGCU=?u~D$YqpUcqQ05BD;;IblDlb6Yf}S^ve=Jsq2x`? zGOglf;pg3eA9DWm%l>VYdw)KkGd6@lAQvjPVDxJz zPj>lr>d|tmx_fc%$+cVxg=oxJi`+G2P5;`N(TTp=6fdF}^{{eWHe{XXZINJf8fTq} zT77U`ehKY$C$0?+V29C<=;YLyQ!Z|j}PCWdiS;`w6 z!N|kRxejXUY$)_Z4^{!gm{r#GPmDSdI85|ofO~n2UWA1;*83=g31zr@vUjyyt~kpg zoN?+?F>GsDBw!G%t#N|Ic~H2!2R6ego=fHWAbUaz)!oG3)7`g7dbMYyFYD`B2ln=_G1-`CBY)M9+1AKxnbJP*1_aZPjmxqasZ!j`ZGS~ zlfnHW-21S97yDKC48>dF4q&BK&#(sQt7r9k)?3fU-LTC1yyK7AbFpOIJHyHZ`@%X7 z8SFXRdtqNj72W;WM4xx2ytB?ZXD_UulbyZpoNOQG+vjZLJSXEVV=Wu$@1Ce-etnl= zZHv|JY<3#y3+oa*J;OZ%rig6RJAT5**7?vXmPb7)>ABf+AjK7&^^U`x-7z`3u$)4#X~0UWXU&!LIS@hH3O`yt=9B%K87& z-TW;ZHhkdCc&Uy3QnW|7-?Scm|NrCuybCvM2zT2KObg?N(Es7y2iptxFfaW~yC3!c zEcRDoA42`Z-R8I9!|?WPDfSxn|DycTw{6(42lnl;&&U3^i#KfeIriJJzYF_~h`SW~ zI_zW}2KNWpzk+=Rj2B}cMLr!vE)T-?yk*1tpzITa@_z&WXV`DT{vPb%dB}VNY~V4B z$sOVLWV0DABH6zFdX4KM?j&cr2eBgQSdM8G*FLzTOFFY|>=XU7er9&Fe_szDMl9~+ z=fIZY6Kwb3V^hucTU(^D%sbnpcM1O(xG8%xeO2S{fS$Xt-;4d9*hjIf$a=Gp-fUeq zg1_#pJF90S^=zy^8yn4rvJw0ZWCOhZgd6Wh@z``2cLft`@evueK3lwd`BFR*81ucO zT``KtQADzPu;Z%hx{b$m^smb%2eBaa{W#m*>z-g{v$#n1V-=S9r6I2DSs&Jj;~Acb z^^InIYqLI+jMsiW5*)2uNOPQ zSbcU+j16TyJ&Vskf&NMOI@E{zx4x{Wz6$#U_L=UntOpq;d$A(|Ydqe>WxYK!SugZq z@6URNda>g<-q0X+W*J7r@ECVU<`IcFB0r8OIXpJoyLv#~r3Wlm?*T456FZi}J2o|l zl4Da)hnmpio+o9!dXMLz>A1a7vAz9zxbk;YFryIC+8pfiDk8(0RCeBuM z&JK6riB%6DTcH(r7|T}mK=!Jh`Xs!)tC7?@)IW5y#&N`-h&M+F!CH7=f%>F(rckB9`cx0fvDi=_nrW!7cZNsYoX{ES z#JTC9G@OA>=ZrXK4C01hovYmGZ~%M6HzVKNAa%r501wBgfJ^pOBlT`JC?3c0G;rK` z;KDXmjp4c02pp{E{SkV`T+{@B=-E{h^~q7F^^iL35iFST81mz0!X0`?xo958D-L*I)r(SVhcM~7 z<5)+wdT25mUYNpcZB-0hA}SN3(qw7J|4z-z=?Qt5tvozpK(W* zw?69<)**l)Fzhaw?l_BEngLt|+zlq~3^Ppa+=1h<&mCv7F+9Po*D(is&rFZ=Ox2yI zuaCh#Od&j?q;m$D8A0z%Ni>SMXdW@G@-TuUZVqvr?q}KQ0hbvwV*fb8&P7h=q8QwP zNgqFeuJvKWV`NPZB7RjTOkoU9a(a2BD9l1Yd3ONkVR&E??r`@kkFY!((Jo`FCVI#G zaS+Dlf`gNt^wh^C#*LscjtxY+5i&N|xe8~&Gsx8wtn@HWiisHR07Fwl5>3wx?x0=F z4Ajx%a}3d$9_U{O=W;_=KVv4y!qNF%>ckLJCtT`O4^E5G2_D#|1C!y&Yek?D>;jS#nv$7nqs``mHd9cQw-AKG=!C-v1R zv>JWD3Sftavx~#yoi(o$bgOqWc9VYWI(}MJe=q9fSy^Nb8Q_p&+vACGMnmKjJ*SUXAckDyR#`w zG#TEGOz?n9m77^+u-L-XG&8~4%uKL5W;qgPIq$n=&MY3fVKI+m#tuZ{7?)#xnDsa# zFfhU>H*(eGlb+$Rp?)96wCux^5}x$ok^XTX0guFJkr6F3G9-oI@pQ{;q^98W7b|D>}6ht@!~r7XdF(*q&ma?g!%cr2N_&E zbLiZNx9Yina&g1k(eQSnFY0U1j_z_gf)xZWPM8RB#LR;ymaurd<*w6Vw|R$G26h}n zgCj09I*qRr73RPI#g*I3=)^<43KF^P|>znTg{S&NN!BlVR`i1GkT@gP5^C8Nu}AgWF}s;FdfXo@%h@Re|0bZkUm>zZ)95`5GEWSnxU1>GY8sAa z!+Qo?@22q)0t{rh?&gpo2Da1rj3F@{hdCvWm_e+8ds!sB3W z0?;W2>-H(PZubCaavq3smsX5tVh~LSRr4apR@3%I>zu1NzagCt(&?ZO4HS{yPU%b` zjSdQM?qeDpMq&yShiR~hS+=D2Fu}zTNsn7MJCDX-q%dinmV(EZf=832)VkRjjd7*$ z={AO^+{)LjVJ7%22kqxwT=5u&O7CI}PxRs`mTMX;nFe#;u=C*tL*nT3aRa<6jE=GI za4Ew(R^BZ1j!o0yuyc25crwzBr%JGJ?+kUrh~eeq8SiM!Al9si!E0uGC9h$QD1&(LHe63aE8I@BLT^7_Cc zZlXVf*N;3Teq2?~n9>A)iD4F8KhBua6LKx+OJaE#Mk^i{nH=sfI9_K!9taB#Xu*+z z@H7K@npNFHbyP!Txu7b5-aG-&yj5~0kc~(s;v=OHpg@L%$2QbxHl6x?i{&lAR>}ix z8_nlhL<4LG%{8Y4Yp|>h{qX7?pF^-Rqhv$ z7)Tfrzc-LZKz+_Y8iCwL18D@r=M1Fb7oRf_&Fc)L5y*WskVZg!Y9L`yGdTm1fHRQX zuO7}IxnDeDAVEmH&Op@99udD7h=ja>Xuugr9-x6pz!`}6oq=d3XCQfi1|k795KRmF z*%^o=I0F&C7>I<#@ddrjxaR_HvT#k|Bi(}l7wHT{BKeGgk!m18NK(W=d;$U*?F~et zbGX061Ghg zofFkSd|rkmhc^%(?Pd^(R|D}WVjvRm2BHCHAU@y?#QRzMx{CG&A|>1mA}P6nNLtv> z-aveUHxTbv1MwjT@;8Um@=#|wze`jfv%1?utSH6jW*+y@N8{X$AyfTro%(!Pe{bmG z+|wcFbGM1=!(9=|;+oF8L+^Driq6|W$^)cnf7j?7oWb8cI)@?NB=88o+$Q+NmIN5@ z?%BWaQs7|>EH>4`k7mzDF!zO>bL~n;4+fU z&zlW~+%qpaE)5RT{Ee@7eVAGKP=-f$r|CR+?BSxt<(;Sxdv`S-fH8vi&))T6_b`nS zyzBL@Pw=st{QOMU9gLAx53Wm&%wKP2KkH* zcennz(6qmgcMhYch8zeELhiPlNBI41taE032(wNBIjre>V-`gO9_q)z< zh53ZYg>Vn&T}kD$eiy-q{qXqvWq5FF>yEes_s_?i!#sM=DLzJFa>B!8+(zZzVej=f zS1#7yUHJ@n10)_TJlsX@k3c_AV(5GXq`HG}*OH36 zYwz;GEuuJCC0vBQ}+}kndxJbSk zW5{RW+p_5~_h12$d|&1qmxb@mT*y(-uafBc2YLNyavtXQ&)-}}c&}?Y?{$^-UOsh| z%zTNa-bQ9V@z7YGnXgx-{nLIroI><@zxTKpc`h=o4@SI)Mx>8MFpIfoiQWZ89x8fQ z!Ym-~3#Rpj!89t#S&j~~p)GufCuZX@*13q*=aJ$;imx~U;?p=cqFtPu+5Pj%Y5(G3 znjb6X8!hL-w>I!jYpi#OkAlXB+*529SRDq2##e_aLBKa;SR9iJVNzZ~0?5-GK|&6J z_sxBM9ZUFRc{=x_V$Q#$qY+QP#&>os$@9~%@g1Fwc=|QIb4f=dKl~cMq_YuEzs93K zLP-(~QbS=#4YeT{%9CJFHWW#6pp%&csS*szhJulrYbHnAQ2eeG^Jp82U*mI;h|k-Q zWwi~(pXXO$%&%<-e=bSZtQ{1BDL z)35Q6l*iMr@z9XR)9>P0pCx?x1P$WXcxur2To3Z(dc?2!b3Np!9_CR!;@AAS9>l92 z-}xda53q#qVv&>w@)Q;2QW(fnRFaj-AW!akinEF+l3x!4Y34%HUwNDT5%ts^piT+H6E{a=wNUHG0XxTz^SEoJ{i3$8%2fu5-EQ zO4#Kvt>GBs z7m?nlx%eK^=jS_o@wo+{%jeeU^yN`L2DS4A;qm3*ae45$wYs~nah`F!e8qhRqQlz2IOXV#Xa!-u9+c!9DFgUCf9FkytZrP0b_z=_F zC&K6q`82;4U+vc7h(x*k1=FB=!Q^j4NyrmeG7s=fd0Wb6Wu;MA@Oh#k1zk?8>Vh#c&~d;qOnk- zu@oiI#7cC->pERx$MJEj9)6K|wg+ES9m!_#(mBIdKKWLXpU3QBW$?sI4qDN{rEgk>K-pv}8!es*q_AB)3bH4^aY zu-RIN}Yee0*_cvV))g9|nD-4C`6)>;_?= zLp`0&GlEn1J0CtRU0+HcW;4y_y)Gxb%+Z;x;rMjNK6e~<#~B<)T>J>e3;lS-?;Hs+ z8zOx^AAlb+kqt-W!V&Q}A|7ApL_Cg&#}V;3B7PKa+i^hbC>{{t;NsXhE}kBjMvqIU z2YKqN2UksEOo#`0d<^n7qj`8PIg^}6&LZb(4<9>d7*o@?>F z7wVDwpWZ5R89as(!}1ht+&S=6&v3AzqEGcQ$-^dcAW>V#nRbq*$Il z&%{&cDa-_ntRts*`N&!d(W@-y&*Ss6aoN(y(l{TVn&-rTj=b(}80U0euLLUd*oHoo zcPnq^^&i5V?!yYhKP&2=9dkvT3kqBeSGKhHT%7w%4Xp#cA#*xI=sOMho(n>aoYL!( z#!#c2^th(^{>CqvOpOf=J1foo(4l^}@{l}kb%F;E_*jTrpoo{bz1L+HFJk>zGpxA*SI+CT87>2l3@`6z1bt2l(*YDehspdKw~bNwNGoIm6ihdfO#2R>!xauAmz#Dn*b(ireb z0r;fC@ToR>8|kW!u?>>?@)r+y3#(=Lc`(<+h|8JqHqvt@VjCp&xPB%h3VSm_n1Bs!btE&}uq8a*=W+ z#qWxbj;zAZwRnBvXFS%~JQtk7&fLSoE=HH+?i2VDC#42Ec{=2p)N+$<0J#_~H|Z{H zK9`i6)N-!4yF|FtIUn=54{9>Xc^JdTLd!Z=yXt!Xkoafa%)r++E+3{GaeWvo!%p4< zan8v-tR*9Oez?O!q%b_Q^ovhpz^B zV(~H;7p2Z7oyR94CQl-PNh5it5jWfWIL$WV9t5~0@if1~gm^sj@gMW^9$fvLhgU@J zVNCB>$5L9a_h^jE!z5lak<@vBC~oRImG#Abt;rKIU>hm(BYahx;LZ zo7CadAH=)d67RTmeCAaYikG>)*JT#3#)?wLidOH<^Lo8b1V73?Ek2a@K4ui3k8_qF zIlaFTuZtlRV3Mwe8bPu-zaYv}{fej&oLknfi6k{la%&~NOp{fO^ZI2By|Qj` zUKfj-|1}d+co^s$g!uh$|1A)H8K!rL-@(Lvz%ahA)jQ;V)oE-}z7vkGD-Vz2<`*L$ zKO^P7CIWZ)QdeSR)!+dBshs=nCBDYxzhFA$zZ*K!GlHMx!5|x0)j4)R_bUFV8^Rp5 z8^r_>CLKYSh+(eg6(l{jO)&kaX>FHT)_HlO^shZ%JJFs4US{7A+( z=zI~G6cFaf<2UQ12t2+BJWT2v!#i2Vcn|s=z8UvHIq@*cebSrqoQJ1y9+q<+e-eBJ zU~qDrp@4=56U<3t^eGokTRTu0+v9gUN9G|tx9I9q4qY@Lm>bvDk{**IHg<7}OcvvoGkhR@}z zhR(*>mNd?`q;WQwq2^uEINOrO*_JfUwxn^kC5^K!X`F3I<7`VCXIt7h+tS9_mNw3| zv~jkjjk7InoNa02Y)czwTiQ6=vc}n#HO{uIakgcRvn^|!ZCT@NctN7=u&i;mWsS2f zYn*L)<7~?tXItJl+wvv&(j1;|p2cyB-&etFo}moiR_|GjC#`(kxtIs{c(jwgB^iE8 zp@+X#o`C7$unY%AF@_Ng<9A0U_Q!qz_7(hPHN0Kw zTa9n0;cqDG!ymwX0AqI^=j&u}2@gwoScU_m7{dsLmt)@_`vKTj@Q2&*+_oQ8;;%sT zLpFYqA?wF!`Weq3cY_!66n=35-%wt&I9t<^t-+(&CE1##*_vh9n&sJ={j=fW#n?Nr z+)XL>z$d0SK--AtV(fUjjh`f_;}i!F#>G z)5R=tM|{~9smt7PxjVX&n5Y=Pf=8Dfa}>P}fSHMY2f%zpzXNnSK&Jy>?qR$GxQv)~ z5P=y7M_0xbaV1;G)5R=t$EEJL z%pI4z-s&RB>ToG5o6>#}i zWUoC9zb}UUc7 zWuxYX@AKuh5cfaA>-ugnZ*Ji%J6V2*)&D3p{^gtebUuC*d$=3Fqw0U5cF)6(J9g!f zFWM{1j+5VmuDKgCO+M}=hoAU@V~#szuk3jI_XMn!YD4&@1%D`upFPCyviEl5M`UVy z9)HYnC!GXJmc4kCKNnt{>&1C4w7L7*r&E| zV6R#YzZX4;whGu z`z`RPiT>yM-^X9s*T=UM_}ShXe(@JS&s!VBucP1>R{d|%;wRu=GB`0g)jf2=RR6?U zR~U8SFE20TkL}~unZG%Xb)Qf~exuy+cw-EfmUO=s?S9)DKlz3qe5=*8hsWx8_&ACt z%YX2eFPleuNAY9X@(&{x_U-Fcw=RbzKKd0u?;GS-U2ofJ!v?#5PU7}`;)V_MKZJeX zG5%zEmi^z>8#dT|rziQi_rRt95bVmgF8^H}{%7k56~ov`y?qHT?x|GJF- z&6EFP?1|X%pK6`UIEGnors03|^%1ncJha@*Rb>79^jwK;kW<1e%6Ee*JG#V^Td5MT-N1$ z>`Z?Rc5*JpPMd$Pgs+B6y&u5N^L+?A^L-jS^?e&V(|?Se={uoO*go9s|JGvMFn%=; zw`b5diQgu~U5=~48TkD)7|0p*taeowv*p`j6TZRxKd-CKpF3~aaJDU5Hr%?xK=$&l z%q>4@!f!I+ub6Pxr{fHL* zZaGquoO|EtN6!gwV|d4#^ZnEC|7OB}HsPyG|E*to?40vmWx`o~ZhFmx&otqyO!$i? ze4hztlXLl9CcNH+zi7hunQ(2&@J#qj6JBq^+4S7<>rFVDnVWvq`?}_|-xpssH$6LV zZuq|U&&_|;`E%3fz!2EX%@Uloux-JqjkCr!9O7eF8) z?&;#5A#RVjec}#?dzQFE;*N+rF7BkbGvcll_m$$FEAAFGe|{$t2Yd!cz0TdH)-`|r zd>psff>VCB#WppB=VX}^m?t4=F&APSi`Y2EJE+U$|8=U33)3Z=E5m$yY6M-;R5NkR z7j6vOIG%%XHSGB&yzu;5E{s$Eo_RrdP?mXl{nU+N?%QhwTscKyoMvO5n!BRRZ9g@@ zuuWBqmZh7gYXQVj2e*b57sn~D7L--d${>dt8P3loVa6!~-mJ!h*=h*8e9{Kk;rR4J$=U^uZWAMn^FZVTeH zY@UV;uI-pHXscX{iE}6um)F^y%t>)f2|9;)Y(AcYaW(Au2DaeyDC)CusxPdERugNe z^?Bhg@7uK?PV>7QMH7<5)jYxzq%}}esvkA_1J>}-H?ItHXq|`z8oNB zU3(~0;#?4inuMJraIVdD%g-ksI(eLCqAMLar~Pc_y8QF4Jh6+-3bf1xxO(V`}Md&>dT#|QA87&V%uC0T@EaT2y5LXN0cwXk4!vHZd>HARaxz z`XHfk0++qUBzK?(TTOyp4EXK5n(yoIeDi|1uFP$7c!W_er}eQxU#H$Mm3W}~=TK^z2Zln*S|`^cY{fPbSnq#{}lUGzDBP29XJ!mg`a zLKjnAzK!A#tyY(ptrf(vd>0Sgy4*2a4@c}Fk7J6BW7x*k3gX^c5O-BU9HOLu;OSzh zvDN79nrj0Z7v587T%(H{ZMqo{y4C3E;=ym{!Reyc9q94r>Y~RT=*hD6^ES?x6~wLI ztRP=O91XvVV0WO$cTyKU?m$nLy&8KLJ?=n{zm#;*;|}ydA9}ru9(SMzTS44tz8hu?n_-*}q33f>YoOuOt>rvcgaR+2_+s1M0v&{d?~^62=0fY;QM3C18i8AvJNmZt!y%9J z8Rq8O)n}hmR`PA;l7#28Nmomp_omnp1h9zHqA4e9hd8p4wa=In)=!d$aKLd`0^FMMiV9b}td0YET|^k)v*FN+b1B z;psY7d13o)v@U8C-^h2l@E#{A%A+oF)ZM6HlZbZ-kDry{7V<(n^r`KSBb)pF)i$?0 z>Wi^w<>{G29{Wh!QPbPGFA;k#(pSa)l&9wn_3<3B`c4ylTo-V&yjc5Fp0z)$YURAJ8F76cdgj7_Mzpe9k%0Wy7Dv}@_3F|eXkOIx*oE;So>3+wLi6& zSbgVPuD}r ztGXTF{noz2=WgrQ5QMt>iOEa-xZ!--;@{X<2Wh1{ZM#1K9omYRjzM85}sb)LSATxW%V7p-Q4w+ zQT#`Z1i`!kvU?DaCVKjtgD zohbcV#8dk#%VNG$g{O0p_Am9R{l)Ok6rR0)sC~z_VYBuNd8)mP&Svcw@^tPl!?W$j z?_9Bt%8Q-vxBkm9?zDW5%uRX9QP-!oKPr!X$?a*_sZTkolWAqP&&v4F_sAiy%Jt|A z!qfM@{M=EBz5%g6y}ntV*1JqynMZkgeG7S2>O0axA9>UlV}Hsk(#JlJ?cXWUr`O-G zzT{D#+7g0oH|6Q|cNdgM>EBnH_Ora${#Bl~U&yP{zvs8mSEYZISER2>|GvTWZ&=?d z{i{6f-)EqIVIt9XtcLU(xnAn$EJ9w4-6`*n=KkZENJyEV|0+D4UzDeIr>>sAovS?U zU*+kzB`;<^c(jGSD)y(mR{CQ4WrOI``9RUr8)-lu6?LysGy6;}-g= z*z-?H=!>!EUkFd_S?gQXo_{GkwP)p3wdXCxUbOu~UKM-Zwgs<>J@0Jnd3PAtJhAC^ zwpNt>6}jK%=is=7yqJ03m(H>~g~#{4+(I7PFLwL3@c0~zTgZ#CJ6}4>zArreEgteV z!_I!@Mt{t<%23Qy-3wLj{cUqRomgoom83wc{q;QdB;dVdu1!ryb!^R;tZ z)wf;QqVzwAK0CkY{9II~RouhEv-69tpIenJO8dL;?EFGrmHFl0!qfR>kD`-C#GNDW zd$h zqX`w=3#I*bmhyX7}4-m@7n&*^+qgjKjGQ-)AdFyZ<+9H zeXD-HXIg zj?M?6{gvTpo|VG0*Q3z>G;bOA2;tf5ht31BZP={+LSD@EyjlB&JZ;-D^|kG{s7#?2 zc`lRjrdjq?Pepfsu|J((_N&OzV$Tzv&M%8Kp`yD|cv`#z9@>cZN9^_dSg}8T?uDE3 zl%uXsZGU``@c20kZpsVw#n|72@_e#LA34+)!~3=HTIq|i=RdU2M-KJH@cvjrU(EXS zufo&k#o8a#Rb_qpH{q#0FF_rFa`qRa3q{=aFX8b$H@BtOmDk0H$n6ZVzpbU*vdHo_ z`{gpfsJ$$=86v}12(KpP_Kz%YvtMm^2iOde;cJAa{ktNvyv=^C@HGCp>Z#~nCp?{> z53I=1Vn>j|7V@gJ-^+xj^UERH@fF?Mr2Tf4@?8}T7gw{4Zdi#qj*y=ePsedkr=4HocdBg&gMKdu#v^m(4=C>N(FwT&2kFF+~w zZ!AYoRxjYC)YtNk5Ph`2nw~Vmy~o%~$cw<_SuO8{NYU|8%X5|Y+-vlOyz-PrPRl#8 zkyOcdztMM8B}${vtg)A)k(6S8=Lm11oPxZR@$qWIJ0?-z>k4=&`rc%Ce4CWgeis+; zQuMvu@c7^DQuMvMfS020D#JT2QQtKMycB&OF}&jw^<7`UOVM|e;hm7E@0J2yioVYq z-ie9&zFfdd(f4)3J4y6aU0*He@b8m#{Sxx3tgp6g!mGMIxJ&9A>Pur3tU9{rz6*tM*5IDed=X!#f4M zlx?A@?@Lo)D7%;N^m9`DzrrcoBBSqRDKM0M#I)aOh|~3R+?|mZ(qZ(4yejs$tO>8` z{pG)!)VHcVZz$k-d-m-Sdw*G^FJ*kp-+S)$=;hMCRqMND0WYP#mUnuh{T*cNCFE7H zzm-jRRqgLdrv0cdrTvO{DeL>~n(C|ed}AlWdqtxC?NY!?X+O(51Nu_7BgI~xEs!%) zU?{trsc$#pQu_DV1-ulA$C~lclc;YW(YL3FA}?h-LG&rF7qFD;+sUTBA+O3K%2N%m zFHzs=EqGP*bsJuPqQ3qXyej$z4R2MVzTp3RrFmeyuHBT7V`WG(8rfOUe|(GrM@>B-YA5m*x${j z{X$-q_PfRK#uD}2)`C|>-|dDso~ZAR7Q8C`duIz?4O(NjyPEK--v2H)^WQ|QAd~-x zMqeH2YR@KXso*`rdyeFuOyu2b^i7pg(LB@rhBw_jYpIk64R5AYspgp;GQ8R5Sxcq- z(eT!mD%CvG!-lu6dDc=Xj~L$BD5dsSWxjv31+U6{@K_UG)#onnn1!Sf}BgrwJ9^1)X!B7rz=Doe!!Yk2m_xPvpH!czS(%O(O3Mqwj)5-k{N^Jbs_9 z%6e@?cza9ZzgFC;&X%TsUsn|*<+e7w*C+C}6`sB?yD*WrgVFbfMBdJZ_eSti#>Xy( z_ohVNamJo6O04g$M&Fwgc?*T7_WYJa-d@5}dwFXjZ;|0$oXG1i?e{kD)LyErua>po zRasxHXu_+yK6tUQze|GpR%yyp&3t-kBJUMO-(>->N`I_0?HBT@^vB^Xc(n=*cw`e^ z)&A`@?f3Se{VK@IR-67+Ue)X6u<&$#c}JkHO8=f<+Ari)>EDx^@T%U=Oql+lzLfQN z5s&j#RePCfs?YaEEcca$_fF~GSPqK0?YshBO8Z&fAq23N@QVLLC$Wv}CPwge-vHfE8ozp@edDIuvFUl*@$Nq@bcfRO*f;3QAU-GCg zrk|A;j*rcSLwi?7{&whKkyV#!E-&3I+T%UguU-{IkAd1^1Q`gZrYmb@5!MZD1d z%IdpJ>f2eM&+^LH;k$(wjyLTOmREa@)fd`xGhU3oB3?K?%IdpX>bs<%{VcDHz7MtG z>3ECPS2W(JFXYAO3whKMJ1(TTvQJ8VLwmNoGUGydx3u7~er4NDd0!A-XfLWyd1cy7 zd3Utnu|HzQ4FfWdGwORj#Jk~dsca8AWo<9Z#*QYvu;f>m^6&@Mf zLSBsB`O;Z-o$$7k2<271|M;8q?^Xr8n0ZC@{aD6F5wA*p?-ib|d&2s1{Kjq%2ybgC zcwH>Obk7i;j^9sJ(9XLgt&B78AIG?C`%C7K z$MI2>r@zDa88BFPa;j{P%KW1By#)|oU;lZU1@qn-b^rE|jNcU^Cgl0~K92V%;py)> zhCH@ktiCOzKMoA^iMNvTXQS`4l_-ruw~PI0%&qFF=-web9lxKe$kAeV3QyN-w`oE} z_byZ4&x4aP|NU3&S?7ZLM?uUt00lAF=v&7Ja(j4eP7=V*0s=$F_9Ww^(r~x2yDT*dHmpX9>@aU+Sy! z|Hk$f9@~l=+fVgX`F~@Jg{SjX$gA@I##+_a364B06Mc4m;r&sJ9qVbID?B^DkQZZj z$~#1Oc77qR%KUPe@N|Cp5>5nE^f*&}&y?}@Jc$T-RoZW13tpA>+q(&`YX5e$;8oGL zzu|pZ8@8g`WA10Z0uHAseI60JE{J zyZZd<>j0&+Uytb1{tbCm+HXL3+P`;Jt*DecPR6f3KlnyseNPsiuGd0dmHM96f>*^} zx`n6f-EX44?3>tmUYai(lK$9PBEAJT#a;$XeM4TA_8V@&tI~dT(|&iMzA5cDZrbnL ziM(myy+HaS_y9xN0##V{5i&ME)bqx-->vg zx5{pB5T0H?ig+>WwYLaQ=ldT+NJ{%%YTA#yl=i#av|kY~rv2V)+OLQg(|+$a?e~+! z_WQ7DKk`!A?>f_dMZB2y`-Ew~B3?}UecH6&J)5}w$lH|dSHw$czam~r`~5Vr{p|Q9 zFQxtL_$}haw4WWnMZB2yv*Y(?QeVBE$F6(V%KA^A=UAR{ahg(_^7MI55ih3wl&8;2 zLLND>^*vYWyHaXnd9n3XUNe2<#niVIk9HDU-wUL^&o8Jid9n3XURMiVOnuAnV#bH% z{Tw3Zm1)RpU@*m|Of+de1PH@)8qc`@tA zc0BD5%~#g7`hHQiV3T}TNc$Zq>A!4}uWa<~(tant$MF%%`>ybGyeUuLZ^iO{Dm)z@%2STEqv~(x{;5g( zDNoz69Y@puw@LejyqNj)p(gF8JZ(oke>?a8nzWyOUipbpSGO#CQ0{-VPTC*(dk?X^ zzly#h9^+zp{}i5nzarG<=Vv`ryO#6mj|uMyl3jVKOWUy=Ez2H~_B*ZxFJ?a2OrDRo z;>FbX@xnX4g}#{U`4ff5|7*of+fV10^I(55`ra?|{fQnoheutpylaJblHn;wbxLwu z=lUl4LS9V!-P}Z<>N*df8i;AX&o$9Uo^QW6-mOjasV>#ow&5hhmzwAcc`@yGdlP+n z-Jm{RkIQaP6MNP+5A9jksWH5#3s29lyii}veDF1?Z;?K7Sl<}l*M-+gpPozev~uqf z-p2E@UvI?P%eRGR*BfE`#n{XDg=gn`>LN$oR&@;1ejq%%ej$f;qB_Get^9v%di`zO zC&k#G^7Nc)f7C}iiPcwYF+Qr;pYn?I(e7gPEfjs5%KnsR?N99_R^M|(-=?xZXAP}}=4DXj>e)R#v{8FnA{ovLIk@Y>o@cy@~kS6(FalG=K4 zoYeThW5UytzlFz*51CJO+-Z6{_a9;}%Os=a>AI~QN7I$3?HBTBDzrc9ExSD?`daZ~ z=Bv$j@t?0N;?bUC^=&CU?ccDz%8SwWWW#$1nzVnF$962c9V*vz)%QCTR33H3+RF~2 zPwmC>V(mqF+8-gWioHC|^luR_rayLV!PEYTvFB%-{tfjhFGk-Y!}~q@6hkc9j#0#I z^OpGWq2Z7hqf5)bQ0z~`Auq;`wfwQdQ+o+{Y`@s;L^D4A5DPH*PZ8b=CH{{lJvR7q z;Trs^{f=(ItI~ca2v4sce-7#!Gw*48tugi&@~X7oDWXs9FXUBezte@M z_80QD(Mm+Py~0!bdl+TeZpx3nUXDroZ7v#=ryO<5N*p)#th`WPOur0DeT(#wLwzy4 zvxKMhDbg3y&!fUq4a%b~a@5uHwR6XWr`IFph3yw(H&eoUoSayB)J2ZE?R07SwD5HN zhP==YHGezzfbISIK-=8%s4r$-P@bMQfdwp*nQ&*fmTOjN4jqTb0o=hz7HBHBde=i-&yRfM}Z{g;vSl*kP z*q`2)$MVjW`OjXDLi=Mom)&}$e~Wl(e`Q(Bcb4$%^@#e^{$hCJ!n4;8wQsgxOdB?9 zzmTWe%jj&@ej!h7y$sK`-(RGDT1OpsWmwF!rHnWIy{{r(OnomAdv3*xsqZ_5r_Wzh zpZ@M&Y<-Ve?62qAK1IBk`fhEW9~ALo>btG*^!oN!6NK=M8VOMBW{S zw>fwz+b(8))^%0Y`Q;*Ge|rB{mA9+B&pS;j`MAXP`<7|H$0zc>Z+KfI@_uS~TPE`E zH@qh#@_uW0TP5=TWOz?BJY5Htwef>@^Xr$FOM$HoPv4`LILiBJXO$+a-~At>Hbx@M7oZ_nP_nnT8iTKmXlaKWd4* zOU(LZ*F@gshPPWH??%%fyC?FlH2U^PXS%FZ#Wku9tQ-_X{B}@==6CE)<^reptxk^Um09 zFX8F?1?B1U-B{ig@_bFpg}f^DeV_1bef9aSo~Nw)A>rBj&f9GJsQ0RRz8~G_#~W>g zo7Q*UW_wiPUGv^%yge)NmR;G5cUUFfBC!{Jp4h1G3oG$D3~z63NZ*{%$7RBMij>?Z zk+(v4YJZCoc?TJN`zG>M3QrqqzeL{QroM|e5l_ckM!h~-$7Fud=PyeWc{du~vc&p6#njjG*p@Nd&cfSG3N266S2Ox7FIL~PjlTU8_3dl) zSzfHZWk%ltiTa*r^jTi4zC(?^6^Z(eGWskpR^JIm-*Xf7z0~NlyjXo_7<~sO>RV;> zSzfHZVWaPPiTWmuKFf>Mcec@YP@=w98+`{S@-8&ILlSv!HN37w-Zkcab!8&&9Y){t z6M647yh9Ut*BIVmiM)>)-rv82(z2E-!(kr{g!QFL|-`owu)l-`I>7Ti;JheU*1|;`lw!j5o`Rt?vbGc(L_; zoV1_XbEvP%_}xl)I({uLw!Yi6;lv zD&zN=qOWLtR2jc}wBg0p_f9i@UxM+AKll3#Ro0W=5nhiN^eKcTY!}M-?G?sL6L}X2 zPruK8Y9jAq;XPgSy)2Qpm-KI+@J>tQeNgo65b%hkomANl6@C3u_~nWEJ|g;53wbH} zUMTvG7U1cL`fU4=m!i+M-zyUJU1s{1yiKX^j6{8xoBky)Mc=-rf6q+RXWNgw6n#s~ z_~=g5cZIay|A;-4m!j_g(YH!?J&F3RHvLOpioSzP|Mn*8v+YM-iay(ZeTn+6k@nk3 z`h&a_eb1Nn8xUT9qP}ZIpRQlXOVM|P=vyuNRwe4Q?MGgUKHGi+fbm*c^?Af~W_(y) z?0WacHoVyN-!al3dOs8Dt8zbcg7Bn!Gs}yu?@QY7V(a@ub3YU6t8zbcn&{K}8Ow{U z@0o3QvGx6#xt|I3Rk@$(7kxS(SYB*>&uYVqt?&Kjer9#z_`TVTH_MBy?=5Y3vGpC5 z_S5kj>Z>w-Cxxfu*YaZPyS5E4w!XhH<2Te-W&FNM^y&Duyx97l--Z`k-#?o18|tev zeqS&8bo^RgY<(|k!;7u&U(NVEOUAGMza4&Vw5G;c!hM%~zhY4Gt^p5!?(?U$66I}{ zw@H1KH$+&%cALxxX9;6CQQtd^zL7+I2g~<+w2EViyywgBd8`rOIC!*?s_Uye&3tNk zvG#md8(yqEe?j^~=jTvgmHGKA!qfh+yx98Q*@hQe->shE-!Bx^x61tdZPBOmb68*U zV(a_;HoVySZY%XI(pP1E{)y<*`8lj_mFLCxw&BIrcSotO>YI@9tDomzAYrx7cJ8l4 z-{z80dCF0@9Y@n25T1sW7wY4f_i@ zZY)pphdlOCtiIofJs0V#Vt>jj(#Lbe>idJ})8C5>>s!VClxOWv?Il*G-Jjdy)TcYR}bvFEZQDuZOJtHP*W^wav2qWd5_)qtO0hh>uGD z7V*^nVtCo3$GGhFdPIF{e=)qr3(sCZ)V^cwxmo*#Jk?%CXS4PTd1~urc((oOXt$K@ zhvt4}GLg4H>{;jMsYKorgs1cAbRzG`!qYaJN#q?U<4ymc^(=TqYX9na%DUT&z9A{F z7BJdyV?KznzAU@l^snW`-XGo3h8H{D-Xrtr?gjPr*UPy2UM)Or@36ik#n$(OZFsTu zebhXk4E6c>G_JlM6@5D1EHAdcH?-l!)^~$>J{jus^L<=>Zx($zA6Q;&eLvfV7hB&2 z=KfeKG5Vr;EOk zg7zba`ZfhG)E6_)tQ33E`=e(4Th^|Xr}KgGLVdnp%6-oLh!*<7{w=Fdd9C#MekrH# zSkb5JXRWXHYr~D>>HKmw?1N*g>h<>?bG@{@vh613o88-n7dv0=Eb9%u{)YPeJQX)T zKf|oAEHAdcySL%R*7qc_m!kUmc`B~Hdx}1_=divp<4pT^Q5#-teNUD87U}czUR-@U zMPJeQh#9w9-~HS0V(WW`)K~Sr65}`J`n$WizA2CM3R_NH>MXN0=PO8OP(IPp`jP-^O*<_itH!%G2?C4#pY&^7V6>F&5@|p3E;p68Wk`-W#O8 zMZCC~)C+3H(|IMVOBw%66Mf{-UShX%gs1kR?Wg@4%ezo`+P~+ra}&0e=K8Tdk#~~( ze~nSmbbg|}yvOuM$g5&6&3IMqo z+|LS6=L6-1?Z@?G+3gF$)AxDGqrUKdp)BuZ@XZ%Cq*z=ZWkO+F;E5cYxea>*qmKA9?JLSl%JR({>7ZtZyvu1;W$MgD9`+=RqEk z>-om^TQ1_7{Q6j+Oo`;;H?` z@LnuDdp)8)wZ9nNX~MJD54G=Ddv4Z#Ay2iJ(b=s1LY~@s8J=ywi_mVYBY8FK`n?Ev zOKq?H_c1QtpyYlFc=*eCr65735wU0Gy_K+ptu8#BPcKg7{jk$t&&Ng6+Y)(?%6z52 zA8|<{?=j&`h`vh`d3Q^F>%zMXJhc}_#jaoG$^Ea|tn!qjuAHu|qdd*1JRKk8#f-OE zv6mu!OrJgwYwM4zsQw7%3uj=HTFVVd%EJ*2#_{W!0d-CiyFbUmaz>Z-CH zQl5_AkQdrvS$zvy*dO~>>s^-jx)%1r{)pwhsYU;?{bG3+H|>utqStC{lP#OJU$yns z+ncsuwe{7zo3>xI_0?5P+OO*R>Y66?t-8LtTh?njhv@hqk8vC$G24%YXXlry>#KW( zXXgX8W9p01*sT3RUd(*oto=fswr!bqwC(qH^h3(FwT!n(fsn`c((91gP1$oiApNm> z0gv@myD7_is0EMnmD){N-k%Kb9f|dQqy?`^egEBpSEau5p6S<<+8>uE+RF}NFUorl zctol_m+c45_Ys+|^m%s3iy3F_cxum@udHkJU6EMd>rH(_UX}Vb<5jJ%<-Ir2UPfho zukC$hBJX7RKK60}UM2kzJFlpo?PPrPNW|5N`gWG_(JQ?7fyen&#|Qf*=6bZV=$ke? z<)|ykZJnnIZ+pWF^~KoXtK|7ckv?)_?eJXTwbB=Jy}Y1>K60ophWFYM`Z!OQ-QFZT zeLkf2LS5vjTb6f`@brG>17dG{-dUwTb`g8l^M^d&e(R&!Z&%^z{b0zeQs0Hb+qk~| zzFh0A`rEmCHLb6&CwVdUvZ!f&wSWD6LpxoX-qEzaURSKXWx~_nt8etj+<8mS-_E^B zu5X)5M$4l;$IO2>3s27*@@UUGZ)tivcW;^hiu6?(ANvST&l~Eaoy6+v5FWK~v%J{( zs#ACyk2i0BvHJEGp3YaHzAEGQ0O8s3tGZ(C<(5rsf1hn)f1y6@E8kgrsoklo=WFL4COm6@p}v^w<&nbMRQ7k2@YMdU!Tgl6ePj=R zzom>1ZeretWd01>FJ?adycr+L({ZM*>TljlZB^sQXX}YqpqH>o%<5u>G)7ys4r%GoF+USAIhVyD)aNpg{R{q z1w?)EQ&X%2R&GV;^ZdYI-~O%VN((`l{HU^7Oo+KAt01-`7Q- zK0md*So>3+wLi6&SbcYiK7Ae=>Z@XZ%Cq)2U*-eaN{qc+BKJr7c@@=19{VGf_b%aS zJB2*fH=W6d$e%{3X*uPcU zuUqCndp!#6kL_G``>^zH5l`)}EQ|TB7oNQyQJ>mh4DVCIv)2!`@7OkM)_x&RwU^P^ zto=fs+IktDZNED)(Xfu3|EgR+Zj<&~D<`)+<(ARLJj&D0Z-hM7Q|n!p_mvj<$cw#x zD6dE#?Jri}H$|UbKf?M}xqc{5uOHul2VLv>IO>BN(!k#ned{C~^5(}FvXs9^csmyG zwy40nuLW?d!~0kw?-u#Kkhb4- z1-zK{yWQ|UUcifKzdH@@`T|~zzPklGizHJTfGX=aDeLEZ8Ed{(7 zeY+aoXA5{S`t~xsTMKwG`Z^5nbKr5UZ?7L^*U^v2^;hlXwgMjYmF4}%@IIed-#421 z{tK1|aa^~R-7Xg1E2Y2}l_#CR>u(J29fo(i^7ML+a7_Qs|JN~2**T)Gh!>-8bK$*8 zcwbU|qD$>YlG{348GV))yUuFGbL(+w$F{;G!xKc`xe^Zbkr%7a^1iI?7uZW#ZOnIt z*von;^cCevf6)FUsg&~+(;p#^^^N6iYufJ))u;9hx2u#gpXvQ({C>577c)MtHN3BZ z#|C4+#&EO>*Bjo~3-onq<`VABhIeNHFGlCBhWCvEUW~rm4ey%;ycm67GrVsV@M84c z)r6<_MX~eM_YLnZqmOnIGoRkmgr}TXeZMrkZySBFJge_JhNn79n6k^Vwb7?M<;3cH z(D1%%^u_Y5zPptNmv$V>`@PW@@~T{qc9Qw@JZbRni9WVpR|S0!8-3r``UdlJ%=rCB z6CTG~mG*ng@P1IBkM%CQZC>;5^K^ZxysGoTmWKDkM14;-ydM?tV)|nT!~1aoud8h1 zA>Y#s?U+B3 z{cj?#*YF-p{Uwoil+pLsMBb4`-`^5>CkRjN?~z2_@xoL4`+FkqrKbJ+c(+z+=MW{Ux_p-jwj(=!<9nHTveqEUv(Kh1j3+HYD=;4UdiI*5lw( zn%1|hZ4U|WO;TU}evIQuJ+&Rn^6G7P{M-~jCb6k_`gxkFyvH5+}629#>ZP*@M7LCd_Z^?3vWBC zPx_^;Fv)ONYr;t z6JAw)A2q!HQGL>>vGu)Cc-kKiprOM4h~<5H6Z39s!qagPt512Ch(Xx;Dz~h?XnmXU zI8I{b(_3WxUTX9yC$_#{G`tXd>@thR4=QX}|jo?_Y`feq(q$sl8NO-~Ul~mq8b|oF{e?YcGE_`u+`O zO8Y%(c#kFWHW=Q26L|}E_3IZM9~%;RTN&QGMEl#;@HR{2?Pz%U^PGzIvWwy6&vPpB zb~n7oCDwN@!`mW}x1ZrXK9RS~@U~3k9cXx4CGu7p-V+jeM;IO_7x(-CTuy;{{pFlf zX8W34f8Q>d^XGM9e|#Pm^L*{wZFstVDXXsxFGb%o6Z_*>(;xZszl!7cB*V*}|5fCj zYIynczlyvw3@?BFSCQ9mcpE+c6K)w>W}Y>|)BA<|`CmnS<3`^eiS{yMcncGG=NR73 z7+4%zRi8iqP{yxb&vRbI_B-F`>rAZgg@%_ukFBWhEr$10G@hGJg%>-Y{@l!emKQt! zDes*!0G^hp?*XIF@?!NVPxU=LQQz;3KFf>Mr##iS3-sYH`Z_7ipFJ%4E|-Y?6Ycpj zV}F)Mtufm_jlN}x`rd8ySzfHZ4MyMcM15BqeU=xi?{V_~E3|)CB2;liTZ9a`YbP2-(E)F zfr~4u8HmUOv5`VQQtzt+bvPw-iEh(BCkVu`hIJVMBe^J z-@-)RL5BCNMBbo$zC`EyXD9N;g{SSeXCiN{(YIG3?>wXLIf=XrjlR7Tc^4af`y}!% zH~JPO@~$@e_D$qnYxM1x$h*<#Tb#(d#pvruKWkdTt``WWzg9dHOzH)`3NJD~dbK@Sdl!0@v4lsQDZNmzAEF* z@?NOzSFwNJVfy39MBWv`)A|0WMBe+2zM~U)*BX7tB=W8|`i@QH-E8!|sDRg1G|@GQ zyH$9)zEYm9BV(^0w;SGZqL1UO%J}$N6Q1f)Zj)(Kre(g;&nrKO7KX%pok6=Hx9s+y(WgA+XgikW{oe3S)bGP`>7w}^GWAokp^Jkr(PcGoawBMG(Q++Q1FXjI79I-#0uTDwS z_hh5*r3Jj0_S->ts_)bSUQGKv&FFhs0WU`1u14Q!iM(eU-pdPkG4)+!c&8`wmKfeE z5_u~O?~Fv=A;P-?a}BpM6M2UlUUwqzXv6DC&A8y?piUF@im zTd(1*GCaM`mBeL(!h5e27%1R%m4zYSsPL|oGOH7LQ-(JPUdr}o`F)?O1aej)?-9dW zlgRs*@U9kpL*QYl7X6$=if3m_`zdcYQQromZzPd7U;h8J>KjeuZ7IB~qyfefc~3ID zaqv?5<2=(J6N$Xn8D1ScR+-=TbI%jSReNaXULfnC_esW($8`a}ZxFLSc#ZJhFT6>L zOW3wE_A-^o+sX9rbRusT!ZCysIF)&5O1ieb9cYdP2UmJZnucE#`8hx)x)b}@|FXvU%_iv-`f<%3r z{l||t9ltrRqP{JKr{njviTbuN`f^@HeLEU`uS?YT45KgSRn)i8=zD#lzI}|ooL5ob z5~J_JM19XS`f^@HeJhQ=HzewNq0yJ~D(XAV=zC+LzLyw%Ij^F=(~Z72L0|ZM96`6K z+wQ8lrCiTHEE&mTS$&V9Zaa>qUn1*!r zH~QWzJl-d8Js!)uQh3+O3EvX%xMYjvT_e1Y2=A?0U)*%D9eF=Ux9rv@_A)L7LLT+S z-mk7{!DIWy-mgvw??BOaG3p!Iv%WV&wCi`t*3{Wq?B%19<86t&T@CM&CcFjP@RvE- zZ)>H#s*gO@P3=VM+n(feSl*?H`qmqLdSFlR^JL!-^)>uWmOmF!7l7&x7Qhac^6tD=v;q{H@;NEUqXU2!}Xm_E`R9@Bbw$_Zdt008+tvVmP+SK>zfETVe z%GURdMjsn3r9Un+`jp512-j_8^)=&F?T<@MecuNm)Kb-+-*4>s{n~!A9%sF|m96i4 zMc;M4SY~;&8)eaLw_VYOr|%h**^X!ReE3u{{3_TFQ)x=HTC^W z0WYS$dz$**QoxJRx1Z7X*#cgd*m@afx$yM$_X&w8 z;>C>L@e;h4@wT=FkNpr^-}8j`$%6VSFJ}B+Xn0>L=-)1!t8D*XZ0h^vMBe3w_mxE6 z)rNORBJWzm`zm<&tGs?bTILtE=dURb_X)IP+DnW*pD4VWP?lTBqaBkMW6!4w?`B7v z%d294XA19A!uvWKFJU`qssBEN{y(%kwf&@$`u~N>p5jL7-%m?{ZzS?=F}!aoPx@8w z`^)OPU3j070wIr8CNHLc?`*+i|B@Fozuet~r}gB#A7jt=wBWIxdL4nc)OLRh9_vY7 zOno0Ryl-j$R(#($Amif}sm)!9yb;6ub|P=e@V=ACd!^xhH<5R~;oS{h%6jc#>0j-S z?-^d~bCWlSzRybkl83*_*N=-0@B4}R-dVs)(RZcc{UA}_2Mc&9`mQs)A13O%seqTF z?^eV65nw62FB#sCO?~x!1<%2~-S()AkI2cq#37LIE$O z{Z2K!e156ee%%GUl=d4e;H9+RcmXe^{ni>@KL2(35xzj&`E+q_({4LYc(+N$eE#e5 z5oI}go(l~xpI?L*tMB3ho@>8~`Yt!TeEe3_cXa_TMc=iCmyeH%`fe=XrRclG@O}cA z8y|B28+(5=@4x=~tLsVfoW6?p(_0kqWc<3(5W7BoaskijtGNFAAH%yRvHf-_;H9+R z9tFIV_S?IFm(qTnhWFDJ?I)L%tkt%nfM?sU3`ft=Wq3bpp|8wyyCVvCR$m#8>U)vl z{k(;~E-lo;J-L8q^_Ai1DPCT{OR>M+0-n=Xar~ZTc=sl@-*^EprTu0Lcq#37ZUHZ) z{a$N$zesGqiwbxt?RRMbFQxt7UBF9ezxNs5FB9AE+5%om``u8$OKHDP7w}Tr@AHOt zUt;^+QNT-Szi$=rQrhqP1-z8@`>EmGpV)r)7w}Tr@3#fKl=k~m0WYQf{%&}`0&G4m ze!6Z}x9oG-+hskj>u2&@ea-rrnz^^z?kwOreNCSKwd3Ahzzh3BpA)y^sP20V?*SA{ zX}|jmcq#4oPysKc{T?phrL^CphWEd1+E49K+uyqLZkl`lMqW|-wc{vv%K~1j_FEu! zspYM^Z2_;S{n~MqyR+dvnAm>17VuKqZ?6JgO8a#b@KV}uh2i}g?T5d7{^REcV(w=i z`+w}6d%PXf`Tut~2XPOIpiEFi-QphCiMoYQK~=O>QB+i0=|vlDbw}Nzt%@q5N}{Sl ztBtCPstSs@2US5;v_;%1D1!1^Yu0)uYd-U=HEY(h|M>p#+plD=bN1Qu-tXu0JTrUt zKIbHGJS};4F52??KB&&~bL8jn+PofI26)diyqtzBVqFP%^A*pX7uwJ0`J)MWgZ=#g zdj8Nn^{4DdEQcOv7Q=Jrh4wQ#?$dU@^=^h&_}PBMa)|#h@Lmw+_awuU zh9}AIE#SQ<%&&89b$`=5Nqz$vo+Q7O7@j1*HG%h1kMq;KUglT&+5N5U{)_pQeu?`p z=J&ENzxAOXnkUI`Q-&v*zik;_;g^`-uE2Yx$N6bqFY_z?66X)|EB$(u-+zSp?G63V zJV}0|8J=YR4r6$QUt)fr1Kz7W&QJ4tnP2IbIDeR5>DQzD76|h@9{QnqlKj5T@Feqh zGQ%tU67xF)c(3(1Kh5i9ex+aH{9%5jUyt&8U6|iF&=1X%slHp16+Yxy0 z_BcPy>t%kWU*h~>ex+aH{9%6Y3G>?>`k{G}{PtsblKDG?;T3*~`F$36|Lbvnn%B$x zO25SU!~9CW9_9DGFu!A=ADSo0Z#=`3%-=~2ukcIE?|Z=epvU=XUN7@2{SxO7^DF&& zl%M|QWzpZnpCA7L^h3iW`Td09N#^eohFAC{=J!kB4G`w{TZSjeZzjW&ljL^~ z@D}TFewx?I{7S#X{TK5q{SxO7^IKe)-y_fu&6DK!cZR2s68ynBUS2PcnZi18<2Q=cjqS z%&+w8QGTUg;{0KL|NrN&;{Kfn-_KtyDV)ExV4gKkGJhXocnX>P{IMCslkC6S0dFZ` zemTRF*-|rcoB)^*(o+Q6Jfw!zMzXutfB)_=~Pm znBN-=Pm>CT%M0^co#9FH8^Z7;`EAVbB>8OxycLA`?ZogT z`R&2*B>C;n@Fe+t5_l^L^E-m!N%9-V@Fe+th2cr^`xfv93G+LZ;YsrQA;Xj8cRs_D z_Ca-!j1akTAbh7@j1*4>LSTej6}6Nq(CHZ&f8%{C=(H`zq&p2L-Vvt zTMqe+V0do5ZNGoC55p_`65oG52zaXt^ZPWzljL_a!;|FqC59)-?;F4yEX=RV@Fe+7 zVtA7L&SiL#{C*0&HF}(%=Jhha($91Jqy65uVt%Dx;{J>Ittrg!a_EQVN%H$O!&AuQ z?|)p+@Fes1XW*^X^7}8tQ^@4`d!OM+=5NUhs;?Ka z9_Ocdz09xlOPoKewzsMdmj3sd6N7VFg%4!p1*e(o@D+Ozp(oL!KOXVPxE@2U+I@Pf0$qCmpFfz z-)6%6mW6(3o+Q5yF+7D#p1-vjo@D+u1m5Pt{I+0tlKh4`Xatu$B->M8xlHWSO%Z2%E z#PB5f4P$tc{B~e?lKegfyb;3uMln1|exG1?lKc*5c#`}+54_!k`JKS7EXc#`~1 zVR(}Kz7M>Q3G+LT;YsrQ8N-w0cLl?fP_O%Yr!oIe>& zp2Y9pz}vgWewx=yzmY<}SD;?allZ*_ynTA?r+K~f+gIq<`Dyk1S@R@*1A#ZH$9|gE zOTYbuek(z}nkVsF6L|ag*iZ9%>GyG=-}+Fm=1KfE1>ONY_S3vx`i&O)Z432kp2Tlg z;2qdwKh5i<-$6pZy`f&sllYAW-oZWg)4X2#eM0DW7}TqI62H#@?+~Hi@eEJm_jTZX zvd4a!*Gs=cg?=YPy_zTSI|F!QdhDlpz4SXw=ywj(t9cT?DZu+wkNq^SmwulX`dtR~ zYM#XJYT$iF=yx5%llc7!c!&4cPxE@|_gSIe9Z;|4N&FrF-Vr_a)4X2#jTQPm2K8#5 z#BUz(j_k3Y=JnF=|N8q^pA+Wy0`x=kB>BA#yrYDE?=d`yU;o9`_alxL`Yq4!Bz~&_ z?--$9#_%M5LxJ~sq2HDaPvW;D@QxMw?auHde)|D$oY3zOh9~j+EbxvK`W?&gB!1(8 z_XVNfNeoZo_dVbpFZBBX!;|>^1bAN*`dz~CB!0gH-j{@azh!t5znQ@Mve55Vh9~j6 z2Y4q4{T^X>62HF#Z@kd&S%xR^`w#HGqWpZ{|JC1j)Q_eA`YsdU`=Oer{#5?`-53t> zCjsxPz-#;c)wiKu&6DIe;AhqItFHxRMM5tHuB!1roUbn}7n%7Iei9)|Kp362k??I?n^CW(Afj6ngewx=yzq5pX&p^GJC-Hj`c;6TLy}|G#e*XjB z4|?pUdA;=eq0n!MORBH;HBaKV0`Si6v7hGk((gw?zty2$&6D^I0p2-1_S3vx`u$&j z|7x-@zm1_EnkUI`E8v|g^xKKyN&NNz-j9WT`!hU=-zR~0p3v_Ih9~hG2fUvM{l3ER zB!1rl-uXhmQyHGb?}xy zPvZAi;QdtS_Y}jE_&o=_i-mr#GCYajLg4*O=(pIV)$>!$llUzIyi0_Bt1vu?--m&B zsnBl&h9~jc9C%ZepXB?ili~ZJny3CGe}8of@TMu4q~5_FROjz9hPM=bb2nnmfcJBT z*XH+OH}vu7-%nJ(r<_N4(OotJ-sOy68{RfP9{H)YOAj8g?gYGFfFFJTJOWkR0p692Uz_907kxbPYgzBtfH$4|26Q_5II8n&$2lZ;6B)=OOo+Q6nOugvWCcnFY_iJB% zYCn!SFM7c8ZnO>3yoz5Whx+>{@U9`AonyV<#&{9$?*SeiU)u2gWqG&Q2lx&7DKC8! z9bfF18-ZFp;e-|v*4 z`cv)~w133*c|GvcJUqVSHj9{LV}@7w*?FP;gZ|y6Cgw1PSNJ8)-}b<}PMF`W3{R5Z zo(xZt-+l~FlHb9=`+Xq4nEmck3=i{*;m{l%3B2nAelh#qIEIIQF&y$c0eF8Y_|jDOEQVM3!SSVu zL;1}H-b@A4Jn91-|6+M_fOjMD?DHiZ?_+s$f%iwtBMz zPv=Lu(Hi^waT>!b{Gh+|_)Y5%fOnHHzaKL^Nq!eGJV}1j7@j1*D}nbXVSc}1c#{0C zXLyqQ{>1Pk`P~k@n}zw^!|){eJ;d-N`ORf`lKh?q-k+5m`}|>FC+Wx1e|?vEa6HvK zw_ZAqHgSkQA9%NrAH4q6Tz%fr#9hGf3O~z><&fV(;LTDn?Lf!-wy&q3gMQpfJbQfB zye>U>#QF;GO1~cQZc~2xjR@`4=Dd&8{|kP%Q@zk%x_{I99`OF6c%(erO?UzYapXimtF)~0#~SsuOrLVn~!ezZ36R<}HQzvK>Ke(ONJB`-0*4LrQm z{5B2nx_WNFvnju=fp@1TKROOJ@pfc*?(rp-Lyxl?!z=a=s5AC_awNkm{46h)Lw*MU z?=E3}pJaHF{0?V$lKhTlc#`~%2j1*JelhPOe3jv0elZ;C?@7SBJKz`dd@_;YpjLi~^i!|9+8hstTHbB;fr+R4t2u4=k1aer;^?~D_-$u- zx1yir5Vt8e`uZ-wdsvv?9+pSn|1Eim^E?W8k1&2Y6%(-@6LXxN!th+b zSPuD3_3(((w%%U??{Q(h*DyRuy}$SHQtQ15cu#ohjm;73)jYS}SPu0U>wVJWNA=To zzV$Y!SMyxISPt>;_V9?)w%$3w`@67SJRWGCq+UE85HGdf$DrP)$S?7H?H`tRi*1n0 z)2}Pr_JeqIzUK0Z^IiKqNAu9MKHKD%$Rodh2=jXx{9Im2e#GHbaY z4h&CH?+At`sdsM=kLqlj-^YRXterpN(Ce4c*JbE5#yT4uK;Sq`k9v;<6bvM;XU%$h{BMx!t z{!QzBz$?p2{ixzgbpEG#>QBjwBC?@Fe-Y&+sJq z_4id@f4maNFXsKfWf>mk7sH{sSs8f$3HZf453j-S&@YBVenWuwYQQh2jRNaN3=jQc zIP?&kGd#)sZOiZ^^S3kb76|j(o#9FH+n3=<@;i{>N%9*5yw{YRq~0Td_qvexdEmVv zV_cw+o@p}q*{}cNCo8d|P zUIO0xLciA;p2Y7R;C&$U8_-`pf7U#S-%`NSFIE*Y`T1=Hh9~h`6?g-bpXBxQAb9<& zd2YS*dR05?zfG6Hz*`J>ZO;!r4E1WBB)|26x46*nqYO{twq5c_V?hw2(I%c*_WRV}Q3T@MuoxxJtSE)=$7ZYo5-&ErR=hpzm8YacC|l0dF-WSMcEHSz~#VE$UntI|b@>c`5Z0kLq=K#n12BpL>k0cUq7Ah=+ch0dH+#KQ;v3I>LH4V|bE!w*g)z^xKKyN&G$rydgrreHfm^Z#3}MRetJE z`MgHQ1A4yGkEQ?mE;H@%g^pL6=bjJ6a)>{R;cE^~Zyv+r{B&PpxJ`bs9G~Au0{Q9l-=_UzzODBb`v97U`NeR^ zZvn&eeqRLM zMnb=@F+7Riw}3ZP=ywXkllV;n-o`?|a~Ph)?*ia`ROojJ!;|>^0(hGU{eH#pB!0gG z-ljso8yTL&Zx--26Z+l7@Fac@0B>`l-=hpq;`evpZ6Wmg7sHeIy$HNvLciA-p2Tk< z@U|5Cb(XBY|Dt&kza@dUmC$c_h9~j+5b(C9dhK}-op;drMAN#K<=tZM=<@XWZ7Ppm zPj5qh_We5j{+d2ti@mG|^=`}Xv}f#PW8iJa@YGGwmtnx$p5e8rcYELsXLxPu-4%E{ zFuXQ?djfAqA#Xq6?Zoif)O#@Sc4m0$rs&J3fVT_7Ym?uRz}uDKwW)U;@N$ON#_t5+ zjZi%I^&lM&V&5nK2E&sa|4s(pZbHA)7@oxM2f+K7(C^0#PvUnG@OBsaO=EZxzbk>a zhtTgg3{T>BJ@EDv`u&OFN&IdH-d;k#dl;U??;+srE%ckq@Fadu18=0z?>UAi@p}b$ z`w0F1%kU(A?*VUL@T2Dq{TTXh(`6yNA3I9O8*u%o;vwn$bUz_)An^7FUfbu(#h0qS zp3yu>Kb8jG$Ax}_7@ov$b>JN!^jnAFN&Ged-e`}XehmG$=`slBMe|(0SPnhTVBj4n z^c%wPBz{AIcaX=Ajtf+mZ`~C7p?R)fEQk18Gd%8mH?}Xsn0j5mSPuCO2j0QL{C0$T zHP7{Ho8N8>PmtZGIzx_X%NsBcWc+bN$-pcL2kaBFyiT zP_O2>er@wRoZ(6G8_U$|`nAn(9PmCV%`F~a;NLcN;j`nApPOok`PZ!%M_>(@5FDZo2S znBR|}Ud?m;+U9pY!;|DUjj7l5Yn$J6;C)J1@6Vv#k_W$UK<7_Q>*c`vw6MQdGdwrH zw*9>pc%Kpa&185IzgvKJxX|xTh9~j6A9$Y?`u&yRN&KD!-Vs8-e=iapL6Z$R3@Fae#0PiTF-rgp@Faex0`GXC-}f1w#P3|-eNp*IcvF15#PjE=!241lznGtE_$9-`dSf_r-hU17 zzAVh|_dZ@?em4Q{1Yv%+F+53rcLQ%c_|fYb{TTXh(`5#{9xQo~Uo3AX@V+ASo8{vr z`ppL3SCyaoQ~q3?`~5-vb2?3R&tZ7(>wVpi7!LJmF7Un<@YDNUlixgshkh{}@|zF5 zuLu0{2)_jk5B*{|nQbBy^p z#g`c#_9KQv`Mv?XlLCG*=N<1dJoJmfNE=kEHv>t^lKgI9c#{1747}5Y`Q5?rB>COP@Fe*?!tf;dJpsHkg!w(g@Fe-o zXLyqQUS)Wa{N4iInZo?uXLyqQ`j@GmkC%S-c-7zXxV0?9ljOHD@FofKTZ7?A@*BeN zB=ffs!;|E`AIHUuUDOy?+bY|fcFE%lk{WzOU?UDGi{MS6!Jy@?`$D&AK?8+ z$U6vl=O|t=f6nhG=PC=Gss7t^8D`%fqWmTU&wYO*Z-S|>f7<%d@26;uFW`rE`I{%GKp`-goKLhZlBMSWkdlha0l z_35s8KL3loPq}}z6B@EBB8?ze5?G#P3MpmHS7c z-|-Aj;&&qO%KgLR*EHAf!#tP!2lTgz)3KK&r&fmd>l9%X*`CTORI}rL&@)G^V0Pm+lzaxCS zM8D4i?_!}J=2!9({V>0u3H>m?l9%X*`CTIP`x5k{m?l9%X*`CTUTI}7?z@)G?f1MlZTzYBf5M88Xcce&6H^DB9Yewg1c zgnpP`$xHOZ{H_rCT>%&+7n`eA<4g?^Y{$xHOZ z{H_xE-3t9Ed5M0rfp@jg??E3g(eH1-`<2iS^DB9Yewg2{g?^Y{$xHOZ{H_uDJq7(J zd5M1i2HtOkelPiWiGHsG@3%rf%&+7n`eA-EgnpP`$xHOZ{H_)Hy#xIyd5L}lmNh@0 zL+|JOPUyFkkC*7T0`RUA`eA-0FVPS4`@PT)^DB9Yewg3&Lcdj^A0;o*@58|RgV1k% zA1~4GqrkgC=!f~0yhK0DZ>G=>^DB9Yewg2lLccAcA0;o*Z#eM&DD=yHyhOjffOnJ7 z5A!Q|iGG;hpM-vxU&%}K!~AX*`t1+>D0zu~p8(#Ug?^v*@e=($2fSN^ewbg$OZ3D1 zW(oZ;zmk{ehxy$q^g9mvQSuV~#slv*q2D)syhOk60`GRAALdu`68$j0zX<&>zmk{e zhxy$h^gA8;QSuV~eh9ofg?{Jxc!_>L1>RjkKg_S>CHi50vxR<`U&%}K!~E_R`dtS7 zD0zu~(}8!7(C@cCUZUS0fOoIZ5A!Q|iGG;heL_FXujD2AVSe`u{ceVSl)Oa0zX0z6 zq2IkeUZUT_zlyp+ z3yiVZ)GJWy3AZ@nE)v3>NY> z0p1!y-Z0C{tlyeK-V-)I;;kj*%>&+tg}mp0x3-Y?GVsqsjpUX?}n+ARxDnI?aM&}u{mgh6} zJjsqjZJBO)_u8*$p8M}3#c~KdgW(l^_PmPDulm&IU9}N?PTS);li?M9mKVz*?ktAK z<%c=a_PEYwcy4~N9OBMlcwByz8`V$S<2sk&x%tI%h&vB>8}-ZPZ$86w^J_bQ3m6`k zALT~%Q+>EDWO#0Vu^i$KxWW8;eYC&%@{66Dfeg>hFP1}ogBTu{ALT~%)AqOyW_WIX zu^i$K0p8HS{ORK>)lb{wI+WqL`RVzK;ShHi!z=Q$$6@lJmH4zhuEQCg>le!*?g-#* z9LP^UZxWxj$8{vbbNzIEF&yHKW_V5ch0YVkFg(|f>LX9`@U3Hk_t8Lpxq=Yi#~a7+ zTtDpT{{l3d2hUex-`BRQQ4&6SP;c@x(L;bWp zu2UGEn_n!4xYK~QiE#d=Gdwpx%8ha)58pb2;c@x(sri6*$GCViGSPt%&q8^iG2{9-x89}B$Ah4VL#;ko%yZj>W=_}1|Z zkIRp8qxyZk2@KE8FP206i43psOPs$+4A0Gva-$r{!?#XmcwByz8`baQO<{O$ez6?l zPXpc-!ugxd@Z9_;H_DMbeCrH`$K^-4QT;yNOor#?7t103EQVM3CC=Y$hUex-xlxYf z;alf0JT5=Vjq3OD<}y4tzgQ0O=K*h6VE$s>H<{1y-28NIF&y$+!0?*-tNFgmLWbx1 zx%~}sh(F-Q>iOT6f&60LHyOzATtA&(42S#%F}$YyLhru}W_Yfjn_q}SenWt_RUp4y zZA5(99@n7^&-J7IwuwXBVGOUxFY*1C;S8_vgZCe3KPC^~I)dRf^*8sy)a@e~o|_-# zMmYvh#g|4iJT5<~x9RvdhT*yS#d64dEbz7#&fhqO=jKPbQI6!{TgNjzEi6*` zFg!QESPt>9+w~GM)mu6Qy89`Uo40C(}1^4VE$sB zH>Wc^H$R4KO7t103Sl|us_kaH*=6Q1*!*lb~xy5kEZ#=_m>Tl?Ia{|M2{oMYBIOI1G zcsm60i+SFh#PD1{onH)x{3bKJru;(Bn^PE`>*wYd;*j4o;O(gL(?8qja&o$J#Jaux zc})6wB+V;+p4A=?A`q3k?8@*8zsTo{3QT>nC&MfJED!JB^!a|k+ew(;!3d}?bqak z>vT9CXr6m~iRBP?2E!}-?Ecmd`!Rh^+v7Tu;T3)@ImDgC@VNXaH>#hu$8|QtbMuSk z5O)s4li^ zJc-|co2swhb`$yyWOx$4LBRW%&~GrqllTn*-tI!bp$t#rHw<`t2>pgLJc-{3;O!~& z8_Dn_exrf6m(Xtv!;|=p1>WAuuQcd*cJYlbKB+Yxx55c=)L@FadCfp>_|?*N7;@%tq3KB@e;*XMMeMX#@Y z=UL<6d`qz@y7%2P@&%hh9~ix2)r>uzex;F;x`$1hY9_rFg%IhG~j(o=r^6= zN&IF2@6$rRnG8?jHw$>55&F$$coM%kz&l*%H<#f_{N@4gvqHc53{T>>0C-0T{T4Dj ziQj-fRo`D5EA$)4@FaeNfOn+OZ!p7?_zeNx=RAJ&d`Zv4^!$kHP=@FF#d3%{jNwVn z4~8>5*N^HWPxA1sBY=05%1^>O9L|R{&wals){A_PW_Ye2@u+Uv&bJ=V@La!G4)MRr z@LWIQ#eP3vB-0PqFP1}oqk(s{u)ilky_)CxQ9tPMo7Ra8&&`i`lw%X`Oor$B#d7Fz ze#G!xKjOvqWen2~*Dsbseq(`mjIh7wL%o{k`cXgV@tfA4F+4Xv;!%!GyvrG$>le$R z$GMu}xqifp?aMf(AFf|4hy2C^@AJa`UJLbVp6f^bpvP}oXEHoDKjKl2O}twep6eIO zp~tzC;kkaqi|xwZGOK5-iu1Ecz?+LyeR&>qkb&?*LRs@ z&nNG*chJ0|UikUbCJyl@1Mf8jE9wOv-M?wQ#@0)IuM2s<2i_Y(-c7*!ui~jcjjp0f1yBm0K3jO9VJc-|9z{y_^k-McZGhdF+7Ri+Q55H==TwZC-K_^c>fdnZN=~;emel~eWBk7 zh9~jc8+acG{XWj{Bz}hgPoHck#pLI=&oDfR-%-FDp#0Pyub+M_{nvMy0_QK9=hoY& z&SSc2<0cOArvYy<;PtmWFZu%1t9g?Az5=|(g?L_ zcoM&hfwzS6Q-8esN57p%nqOR}!#ryqw|_Koh&uy#ODdlF7=)bj1_}MpZ)u*yZ&~22DfC;J z;Ys|~0Nz?czab1y;VFreH(Zi3H`pu@Fad`0dJ_#Z!*J^_+1FRjfH-f zGCYaj6~Ozb(C^m_PvUnS@HP?p{gL5G{B8x_rb55j3{T?sAn-O5`u&aJN&KDy-sVET ze=|IZ-%G&TLg@E8!;|>E1H55EzX2;(&!06<;=0e(9Q zd7lQ}PQYuM-{%^5ZSzCk&WvB1c|H#Okk{4^dAopL+y0IRzg>aXwjbYY;I*w6c{%vC zt@pd&x0m9%-w)`g2!uCd4BsL@OBgWoyYJbem@1?2%+C)3{T=W9e5uT z`u&#SN&Nl*yxoO zg??``Jc-}`fVYp(uWyy=>o?7l_$>pxeZh~u@2ej}|82U=hVLhj67uE%Z$BY#F7WmT zUVqEy%atHM&6D(FFz`Mu^vf8Y#BW339U%1EjNwWAwgKK~kDq=F{kQ2d59USlT)$Wj zJeW2gFP1}oA7gmj`DAR}3z&LczgQ0WEd<`d!u$ z{o2mo7a5);zadP$u3y{yh63-C!u-Al^=h8$*EYXzF+53r!x#sF`OFu!x4Ud?m;+U9ow z!;|DUmZ{hEYn$IV;2kE+?-Hn2^IX5S`Tc_7N%9-d)a&}S&2IwmKJCjd^8LhLLA{#i z`qAr4n*XNtcfk9M(C} z-dLgEYYb1~w-9(o3jI1Cs=nW(c@n=Rf%iF~-|`Gk;`bro9VPTzi{VN9)&t(rLcfg} zp2Tk$@QxAsZO`x|e!Bwi^FqHp8J@&%Kj0lJ^gEd0N&G$qym3OmBN?8=ZyfNB6Z)ON z@FafU0NxjbekU_LiQj3!J6`Db1BNH@`!VpIQ76wXPk(>E+jJ7?eElNeJ*!{^&;EZv zZNI<&zxS)}*Off`eTBBXz7MLr=g2RSw+!%3=&$FOJNYzyI1Ta}uXt)?%Kwj)>ZR97 zI$QnMcbN#UKQym+eFXnMQxk{ylNes%NBP;6UWYVsCo??v^;;~5{H6f!E2>`YK)LC8 z4&_B0TCaqDAdk3o|EAT;v$?hP`;E_!`eFOr5r$oo2zUz?w2eF*%J*ET;d&&jWi z-&~(xVt&XwQRU|zPx~#mPp#dEo%m_+)4bw%+LA*L^&IfN0eh#%Ch*$U z`wIAJo}}LY0&fENwXJtL)O(WR>Ej*MNoy>32E%jbC6+_|m7l^A+-o?e8q$ zecM;B{ki!j?rervsW*~C_09p_cWk|MT%lDzujjN;V0{nfMe~aJv(MwP9D0bwSFOI^ zRQl2J#jcv$rHumX(hRTgYssO97zDhNh54<{@Fe-I!|>dBp?QwYZv%!W$!}BOQGaPp zX#QxW+)C(l_}>IQp5bXf$}N^dkMmXFb%lN> zF+7RiMBtVA!ST6Iecq*_0_&L!ukf?HSPnhJkAPR^m*{ss!;|>^40scT{k@#wN&0&= z!{eSmV*7F}!;|DU6L_Zx^Sg!NN%FfBc;6HH-OunOet!jCnP1}m@g&2O^!J~@EAvbA zdx7Ce{1yQ3ROs)rovir%RXYCDamlyNh4b;#guHpcEB$PKrJw!W=S8>A2VUt{@^Vve zByR!mPG{=X@8`tkw-9(|2zdkkJgO+2e%`k9bLuVpBI_Lpyt-d*e$PAdJZli}&J@-= z7tkxlW!o*x>;3!f#x5^~iM$^Q{gzq3>gV$M5(*w!uS>iSTi%2AhOkmRQZqANjdF*Guza{Fbx4CO^IJ#mwUvdpvlA zsn_+3<&Cwxzgph8DnGp~3Esy+uEc9C!{9Im&-%#*7 zPw2OW<b1A6|T=aZ)6{#46*)ZWqMxqh+FzrVD+zggbTz>mDhv&ruo@N;?E zkGwQbf8KQYJ@{QB^t%cCTwaRbZQysQ(C=>Wb9pI#bHHyZ_)%Z=IgS3?bQx#QhiLv> zp7x`@#`4Bn9?jo0j~~rpliy>IpUZRoXbzir|A7216Z$<1el9P??`81&xzO(o@N;=7 ze(!?c<;suFpY`iiJuhuuw=TB2dHwO2ZJf)~uMcRRoBB#$9~j`d_0s*D))g&puD#J$eDP55AbwfVlP`+zo+a5R|)Ig5$Z)= z+j@yd^>Vy6_3i-mUM;M5H>ekRZR;f-)ywhP)H?#|{T0;PZ}*efc^PW=51MD>>7NT} zb7|tW_1oOzM_y9iuOUC;#@4(s9A7lAc)b9}tJt~O#`6AQ1wy=-xgp-umUoS=IMG%o;vvJ=gnB|j!-Yh({;AxJ*~FUmm1IZCAJ?Un*1DIOh1VCbYa)&{D$Vw ze!r;g&-?6U{pMNTZ-u=5fHyT)KbLdIRuoWAba`_h%1J z=U1Eub(@T;U%$h{qdH^HTZnp}kC&L=Bfz_z$uH(Si2R=L@N|B~d0&_A8Mi*;;ko&> z@tg1Csr*v>UIpG?nEcwjzxI}gr}NVssyi;dPUn3Ok2r1TuYa(4|BucO%6e6PDf`E= zz`FzTBhT1+R|ejlLf#s{yGzI$0=(Hm-bTQ?Tk(q5t6h^AcfaDf&y%saQLg&}?*Sq2K;S(nx-2CZG_1~t;MEm_H zI=(zCd1nFdX(4Yi@a7457Xt4YA@5S){Zq)h z0(k!t@_r4xe+zln0qV4Es&OBMJ zqi)Oe0nT1#+2h}H_H)hCUvA>i_Ulw=oz85ASNLUSi+;QIskLivs$8Sr9EMl;sqOW} z$1z{+bkJ`u!z=u9vqisM`}8`%+~!_uzayOd=2_nJ_D*Gfxw*l|v3FN~F0Ip<54^eR zv0C@n@m>J+YF?3F!<;Pg%N$y#vykDn?yo}}aLcITp=ka}zswj!^w*(vIs+MA>;5{# zL6%4TE&X!qr&s6x=GH~ms=t-54hG)if&SVSErO|!^!(+{EkhU{_Lt)jVx0=D(-{i9 zCjx%@^*UbAZy3WvKaN9O^cxPmH`Vd9cwfU7iN`JdSo$wrisOsZk#(n5=TGz8{f&;J z$XUdz?jIjzc!ghPw!q^ba?x*VhUe~Yw0|JS=eIM%EBtcnXIDCIAs7Ajv^?5B%KREQ z=Fy7dv(t@E=i|V8E2Y0$+FlNYdNr?Qe;rz3nDvw`;y^;m_U=lqH|wBq@}9H>|Giu~gHTd|+Z@LKoRA2Z^QXe)AJ@izYUmG zJ%28FnQ>_Qd^ym^%Pr5YzUL+M8)SKO{<1KoUMIo9;8*f8>t|Qr+~EE(#K*IBMm?W9 zenX+&cT~NVc~<+K-SvzxTx&n~GR*Sm{Ho;T=3e^sQ5)WH%cFUI7yOo0Sc^6f0N3a@ z0`e<)7SfhC67qYG{2X2voZL^*Z#2~VKjLL(tG0e)ERXt8^71s^SnzwF{2X4_pxJAz zcO2yR0rBjRw4ImnP;bf0j80qL1RpO?<4uJ8I!jddx3>MAWO?*{Sjn?~ZF!R|kB)x> z$j{+*P3i14_IC=@yBP5@vw2&;X_iOxT=McX-gNL=octVK*Pz*Jtak?F=lp*O#rC@1 zHpjo2mPh?9dAZSP%bV5UN6+VmUcbhAXE*q@<;?-V^8c@}q3L>;s%w?Epx<2ZD|wmO zq%CirkC&(M<~P*aHopZvKU;5G-a;SG*4vgh;MP$^P;`8GL7i+A=eynF=EnD7R#11# z^a+Z+JUG$tX#c43GIPg1wRX*im22cZ-o(qz=6!l~&ZEq&osQ;Bb^QKic~tM}s@T@` zI*;=T_|wY->#rdo8GE+>j9}W-aug1$QPp?ky=GNx<>rbiIc^sU-8ZR>@!FnAY z&R>m}Tb^E>?aZys^S4Bx-jw-UGQdljzn4_+CG(frd8XrEjhC6Eg8gvjZ{sFjZh3n3 z^~2$94g1>~f&JH_%>&r$;`r=5&Mx3r<7H;UV7(4+?}sofzQ7%-=DaP0nMo?x4`*IZYU1UV zr&nJ;9Nww0zpWL>&!Wu(*lV1>v%#;%%glzsdL8czn|Qh9>DAfJ+*+T%%b?zU0`-o8%>XZE{;mh!%RQdI8ZR?R1^eO53(jASms_4*ef@BFIDcyf^0R330QS0R{%X9; zY#6N9@y7Y9@p8-4tFxWCwR!$V2I@_jzi$M1Df9QLaQ<$A{kO);Oj5yqIP-FM6EC+s zz54p$@E(EvZS6pQ7HuBDUgP{d1%5SNW;P7g>v%uk#LF#Dug-Sn*82Rt2K9~#)EhH@ z?*Z?m054|#miS)v_4$8#JbyJ_W|9i_!!$gu z@iMbvuwKU-=dZ@gEl;n`cIMXR`P(;8Z_4~l2=G$o?=|84t!U?&UjNp3nMo?x4`*K1 zXyWCTr&nJ;9Nzk{zh!~^EZRJPy~g?54E$=m%xoB}*YV!IiI-cRUY+gCt@Zia4eH%L zP;boqjRM}c1H72|I|O(OdOUwMUS^UC_QRPMoWB|`w>-W2`r+_!{?-ZPXVK;X>~+)p z)p(iNFj%kSjq_LI<(8*cXFGFi^Ze}>s5fQ)z7^o5%-g$KY`x@+T>jv_(X!8K}8t3n1@T>7Mvth7a$NS7CUT%4Mb+$9N*5~hBsP}+C zy)pB5G4M_f@M7lg3gEro}Se4~K{IHzbgsMVkk(*G=m}Tb^E>?aZys^Y`&Uy(#neod7Ro{@xVM-)~|6t?@FGRIne;yxiEt z%Pmi@zJ55o+hKoOKaihAn+LGhIDhwpUyYZU4TJSM-j6l$a?8`Jvz@uMK7Y?Zy$1&B zjhVlffY%N1V&?Bn;QhD9^H<|#CaGXQoO!|dtMPKn)2pu^4iD#Vy+D2zZ63g0H_cy- zmzfQN^*Y`-e>Glid3trWGq*O+-{?TSDf9Q;054_!-WJYZ=hW)Yztnh{Nh;V6XI_?W z;^mg7S6@FI-YS;&yxFX?K_EYk#0$>f+Td5?Wrh%}*YVz{iI-cRUY+gCt@Zia66!rT zP;boq?F7720=$^{+Y@+i^?3ejyv!sO?1wWiIDa)>Zh3n3^~2%e{Cy;lpGBJou-8rV zSL0=7!(hFRH_l&;ms_4*o$bu6&GUCqpx%`En;77w%-=%c{2c)MZ;h9kq=Nl$=H;*^ zUT%4M_4UKy9R>T_hJpMn+B|^0#`*ga_|eY=Xdpj}HVxaYZJFWWt?vDoYvuN`G z_8RAJdCQ~kH`aKW*)UkI+`oR)H^0nZ_NB{0=zQZd<%p?`;hchoYe>Glid3yEr!{OolZ5+tYqRj)?>!$gu@iMbvuwKU-=dZ@gEl;n` zcIMXR`8zaFZ_50g9^j?S-v`3^%VGbm@iLQCupiF6?9;@{El;n$emJ~?VSn2+ke@}H z2e8*Te}{u#jhC4XgY`Pz$2ReD%hRi~ow>C>e_w%mKNYAqX8yhnyh#CG%>11Wy!U%N ze>Glak_z_2nHQYD8ZWmzz54p$@NoV%3FK$d<^k+=)BM$Vnb|N{uj7sLSL5ZDr&nh? zb8GYb9TuoJW&X|#@KWYa|MHRg)9LS;is<(_>EE%VI%zHX;q><$*nexh%xoF#hr_$5 ziI-cRUVZ&=c$dTewpmKO&f{DIel=cZ{nXkuA6Bk$o^NR4xVOcZ$Q0Uq}1y? z&imk3<7L)QtzGkB!6+ebY-P;boqtp&Uv1b8v?w*l}5 z1bDV|TZvhk=C8)f%yy~sSL5ZDr&nh#%&qo#5SYKsQ|fgd2j{QG%Zy2|UWbSCSL5ZD zr&nh?b8G$hhx7NDK)osR_x%7bW&ZjCJY6zgaQ?P{{kO);3?bMLXI^$_;^mg7S6@FI z-tMr!ZJAQ9^Ems1UyYYpKecwvhm~tQ{vF!H%gyGo$G;oXG^c==kyonug1%4eroNS4=dL=&p3ZIUT!uI_QUbR`5Tr}Z(#mvyv+KkwQD}C zTsO^MjhCCvgY`OoIDelF)SEJYKMe3v=5L7r&z4@#&*^U$_TL&Wv-zpDYd)-8_PJeO!YP`(mr`E3duyWlre>GliHV^j0@x%GsDy3ehzc_z2 zUS|E&+BF|muAAns#>>s-!FnA(oWHSwdQ;}_M*&{S{LNRrQpiq!*VNhe{g($}|E=*d z!;L-vd%TI4Tb^E>+|8}^*B}3a{cW{Cej14voR?R?ug1#^Ay}{D{dN;Cw>-T%+nHPI zuRj($qx${EJp%Q{%-^!W`)Ys}Gk>cBZ^-~pmy8!YUS*a?-w&7M>!;SP`LJ@0^SpNxFE^XV9{&!6dOsJaH)j4m4ZO(# zUd;R*1H7dIJX?A_Kc~MZKz=n|X7f{P*L+yH#(6%eiI=dqTD#`M$~Dg4g-yKNY#yxF@w*J_Jt|Od%>4Zdc;^OqG4ppl@CF8Ww)A>_PJeHK z{A#?+=BL)K`LJ@0^LKX>FE^V9`{DRK0`+c}Qm@nBr@*hq%dDSTyXM2nHO}AjO}yM} z9<0~#dkyM6I#6%S{JjUf9|w3b^S8vA)$@a;13X)LJwK`8x!7%LI6~^m=|ye~*CtYP`(mr`E3duyT#_cU%)MH=76h;rM+G>K&d^ zuhZX?!LP>4te;xD=EKT0&fl3$yxeRatk>~77wY|dpx&7IyBK&s3Gia(?+V~88{pZ} z>-jnT{Vn8I<7GBKwRX*im1~^88=H8!**w?}$M1HicZZaEo&Merel=cZ{nXkuA6Bk$ z{vK=My^h~AQ17vUdSmAACE%SO;Kj_}o4{Kxz_X>-^K<&!nNKODbREbn>ys5_?A>-2YR@T>7M>!;SP`LJ@0^S4nGFE^V9>vjCL zgnGvX>W!Jdoq%^ifEP1=djfCy0MC|Q&(G=a0gzvfm)ZQ(+BF|mu5tbjYvSc*^I$(5 zzoVeuol@#``uipDtMM}Hr`E3duyT#__su3=ZZ;3r>-e1l^&S_fH)j5R0K5wWyqNhr zA9yPSc((L<7L)Q ztzGkB2D7C)p(iBPpw_^VdWafJS^UZ=l@gI|r8SwFRQ&4-n1oWEn6c)8g;Sg+&v6{z=%fqG-+@7uup zX@D0qf2RX)r2x;CUeC|z?>UfPjhET{)Y>&4R<3dWE^6ZCX7gY_9KXw<-aMsVr@z;L zUyYYpKecwvhm~ubzZ;r(x!F8euj6+s)cd7Cy)pB5FYqo7@M7lgQQ)l{;Mvma`8oZ4 z8uF|0GMk@TyXM2nHO}7)O}yM}9_)wX_XgBEBBfrZzwd)zjh9(JwRX*im1~^8rM_Q% z|DeXp&E~;+9lw<Zk+QiE(Pp{5)=GOYpzZ?nm zo)D-vX8w)`-X#HE%>11QyblFxaWT59<9` zO1;kGTmpVIUS|E&+BF|muJQPHWfLzqo5vpiu7!HX2kMQPzng$}X@D0qe|G?HRmJO5 zCH8kso%r*Ax|L2li~nEJ{r@k|o?3nWsPQtxrTJ^(UC_kKEl;m%E;ye1|6fkEJbFIb zJ*8e}{-%Rpjh9(JwRY8qoL}bfu5IGw3ZgDFe;jYB!}}xD`;|bwdj2?GS3jV=+zz~{ z0iK?}Cf@7#_D@_;`bWx6~5GZ&|fLuKtqeqV206 z>Enxg8EkpNLsyp^)?!D_DBX3B6r}u~cyv}fMLEcbLy;LWyF2ns8|G(p59zUv+ zR+r&^jJ)AKUT(H(suy`9px%MP{*DAcm)BK_P4!|wMhAE){T<_}m-9`Hl7X zQJu8bN#+*hjq~wxbN{ye9S`;XoH-tZjxXzU+@o`+GXeZcUS|A!|4xDVYNvy|i9TL# zc^Mwzh-B7vI!8E1`%Y&P)O$HoZ(c=IK109B;8*f8vl%^)S0K(O$eZHh<(8+{N=4>& zy2g5^LA}3dU$1_;DKFE(ug1%o`jJ(5GkiS7(HD9iH=ot7RlOD7OsMw?VZF1!ug1&T z)jQkAQyhJ1TkjmGcWHZkrsGt^{#MCvuI0@)I-Qc2nHwVJxx$<0p8*YG@7c=Ijq z1+#f)8DYH(ERW7NYP_sne;4|AilZ-W`#a#a>iOET!g>c<9`(26Wrbd+ZGQ*(c)8{2 zwMBmiTORdy<^Fc(yZC%L#PX=WB`>pn>d8$j`Yy;D>f_~x(41el@=(Jpk6v&6vi3o!LQ_H#vtPOSFs=Cp8 zxLxxhd%aF)YK1oz>Rm<6vnsiKT|~!eeUPgh=qw%Q?@@UDTjOPB!&u%wd_2pc^GQFi zYaY;EKM${0$xpu?)O~HL7til~^_H(MGxNYcKjiu9)x56y+f?rg(0#0TIp+A>W}e5{ zd7p8*Gfg^cDlyn)nv<~0qC#qy}XB`-4uZTmaT$IC5Gal7V2_8RM* zZh6$-6`6W-mSk>J{jD6vW`JMG%gp^F`di`6^zm}b(`&fD72YhUcaX5&+2B{>WljC4 z<~PU3QyhKi%hgqjdgnsD)9LwFG4%U>dj3N5jAu*pERXgNm!~;xdGmpHmGa}BFMVA7 ze3`4ibXfqrm8ido^)3wXQtBOWd-eSOYG1w9m+D%y=8Ha59}R55^N z!y6IcrTC2m-ft*B+sugPx61K(wB^zHL5-JH`&S8HeS*(NV|+Zt(U<1q>C}qfSg3au z>PKR|<1CNP4@zEE=tZ2bWfi~iK3;BldR4RSyQtSQ72X8Pqw|9g3G1C`dDPz;FKgG| zNj{$9=u6xFPPV+~&E}m|h4oIcJnC=B%gh6`Js+Cpp8*B1SqZh6$--?ra>D~~qA z@~FQhFSCAX?V1nSYka*h)5pur<`Mm^_|39B>hEeyf9=ap)S~e_3F8 z)Zf8Oy>0rt(DJCiB`-4u5zlWG`vHG3=YKU`Zh4B^H6OCqSnoi~qyEmI{Z~DzJ}>Z{ zH!p&B7k#Kc8f1BtpUcy^wdD;4-Wt@8M86>cUW(sP;9bk)r*rgQx|J^t3-HLV4R1K` z)@1T)!y6IcrTC2m-dg0RVd~N}FL?YLZFzKjDS26eD|os2kiACU7$46jpuJ|5Mp*Gfg^ap)S~ADRI5uHC-g%K79(%cJ98$;*sE zM7Bp)xgJiUhNt?(vW9vx5D5!O2e{A#?c>3Cl~zn|vgDUQDMvZNayuvRtTVQ{QLo52tV|az1<mkB%>8e!1Cz=EQDZTh#NLL+f-F0`EE{SNPeTzo{=pe$MfB zz#V4)p#ExJk)LxuWL0Z!`UX6I8OZPozszhN)nCVN5W_3{EH9$J4z1G}%0v3RBzk3BluOUCI_ZW{~*^dT4toO?vzmnJBhrDls-^P@m^=j$|);rPiXr76e+TXK) z_fhgo?C*~)kM`dhuOUCI_hOG<*^id}{e{P`wZCry z??!t4q0X|G>MVL+!gqXDcd1-H2=MgC(CcX_PuJTEzs*%Y`W!Fv^S#fe=P%Rp_OjGv zql%B{c%^yn`HPQ3+vEEsgBV`nmzgc-e1l%6V~*&z2E!}-EYHXB`K`zB3cuX?*|krv zYKAz!sZM^ISRT!DnO_4((TfZIyvjDf+ajgE&MVAapkB>u*FmYuTKCr>9>DNg z_Sd0xI%61K>;5{#BQ1~mTjrOW{`uy_d{w`nGu5GWI$r?Zut0zH@rIkfF2U9MHHL@% z&hXHW)(=>nJxP5 zO2--E(2Be%K3;CNpz~dt8{*Kac}FT{fzIgnq;%gn}6 z{cz@Gu8)^no?V0eaCq~e-iuP|b^1FW{7PPC{p=dt-yGfoAJ5hqwZA#Mg;4K51NFwt z-+(*K`4v5XJQLu>%-=xZT^iuo2u!f{8s~42<R;SGm+p9|C*Gk+t1_iTU{Gk+t2_wxYHM$mCD zIDexdzmk`kt)lwj%-zKQm@mGiQrfA+SKdtCi!@6>UDUNq24P}>UH`t1^h~0n|dAIG#{@`y$)|W)O&SG zy-t2Jz^~-Bsn_An^zqu%>+ohly;r5w>*O~Z{7PP%dL7;zAFoZl4sR~h`R;VpoAuSu!b$!{U}mAp3fI=lgQRo`DLd2Q--cmpku&L>|C)Ejet zFbH@r1b8v$2ZMq4y8zEd&~Yz#elP^`D|wmOs^6}`=Syc^hWdE9<=Hj%{9qW=du>X+ zPJf4kU&*s|M%C-^M)-Jb>UDS{q2B)l>W!Jd(ZG8pz>Ar`F~IvnfM+Aj{eM-Gfei**e>vpH6~$Uk}t9 zGk=qT_ga7#Gk;Tn_s0OwMqq-q*EoOEAit8AnGO2w8tjKNf75-u-16)iJAX5v-WyZu zb>?Lz_?0|cXH>loZUHuP z41OiAO}!3ph>zE%UWYdn>b*0iUMIg{;8*h6)a&qu`*>~Yb$BD7-aAt2b@CetekHF> zy$)}*kJqMNhc^c5eJfCJ%=y7s;Jq2(#hf3E1KvFWo{ga6Uhw>2JmgpMGP6~`U1QG= zCir-{<=Hj%{9q!~dv{8`PJbtXU&*s|M%C-^Ci{48>UDTipx$=_^~TKKG~m4x;Kj_} zbl^P@;MoW|?gi&>2IN=rGP6}wKb+&$Odl_|JiEru-z=#2{*-#1{>}!!l9yROy9W0+ zhd0N^vvsz8eKZ&9{UA_p%>2y*-unSw%>2y<-opW&jlcwJuW|ksKz=1JGaK~VHP{bl z{ucUpx#ih4cK!z3UH$&=Ln-w-^D@x#==-%L&(;}LufrSUR;SGj*7w`A~d``^# z4FTR_0bb1f4F%rcQu^V{%P`2VFHwEflCNM8C^EVB6O9yx{^EVxMTP~A4YoR`BbkB%=TFEbr%nrq~J-p9*{*A4C`$UDLEXn#9{sW+4(@+N>^o!9R8 za*B^v<`e8PTOZo4Nay)YnbNwXbr+LNx z*1#c#uGhW%o8cAt<>p@H``IcyeN&U)D@?tGpXD|0Z{~67`Yqt?P5D_~>6h_yi1l_Z zH|Njv`cm^MejX0_Aa5Y>Mv|Z6=u6xFu4H-i`dsrQ{auscN&34!Q*R|d&zzVv%7R(xw%){{%&h|bbh6I6~Bz16Z2?wzg>a1FZn5szO?P{-j+w_rF;4oy_Ni0_V;tZ8%6o$MSSJ|hvs|U#Qp7f%cK2Q^D2H>yZ(M1c>9r`;^<4;{+?`k zwEt?Jq`zk{JV}4gVd|~q*RsD;fVV&8mlyH1?(b!mNBghlRs6Dc{kyBacc+56Jl8L$jht2QADMnqwwDEPey@4@%S{~G z9?y3dGQ7esGh3AVhx)v0ZmL|P-++6n?_ZUEYI}X5*YpKn4-N+2T}rO-W9Ba}2-T}1Kj-m=K)ssR zvcC>Z{d=Vhukg!^M^t|u;xL9+_*q^=e;u0o_evRF;g?%KyZZW4^w%MdusrH-nO_6P zJX+CTht}zg1m0{VSNJjgwKox}ShZi*xn(rN!~Sv{LabAvsefMucy|Z<^l=L>=r@+( zp&!Q~F8YlF-aP@ooFL9x>>padUdCG%dMYXgZqa=oNRftf0X$(aLl9CkAG8ucW+96ojqq>vX0wyw?47h%*>o%l=zh!>${dH)a&TQb_7w9i{ z+`{9_9EOMe^uaS1%o(kwc#& zZ;+3dn=R;klD5Ycd4oOmE~_@o)!(Li@%t%5Jbs$j)x1ny1un=N8sO=^Hr0!~VNmab z!g(GJekCt6MYf&i5k6jSd3tRz&m$Y^ZR#)1%V?ipX8fA^i@Y&Do~~0}n)-{pv7UNU z=XspRFLj>B2Y4y-JOS#RgY&FrC3L(uDKEO7=;6`-chod5i%909Nx*v;{nT+a{Crs@ zPKNwSUS{ssc7L1Vp8*B1NRG^qFE>ir?f^W}8#D|wmqQ)}0J$X?_AF~i5p&E~%I zaDpRmrl(#y&uy9)S@^&TMX?_BUJd6`L^>NcO%uhDOw zkC$7XUR%ubd{4cp{axVkqdMF6ccG7G>ume{G2p&YMNstmW3;fp11*pKf3T956%P~f zexkV_T@Ui{a?8_ei~bI_yqC=89r8=T7X6*zsW-L16Fq)ZXWRZx^6_k)ZTmYJ>OEN4-zkTOJ*s$uG6PGdzA&XWRbH^zn4PYL46XcNWz9 zn0mdS{*>=S(D@{-CRP9SY|EqLpXRye+#dC4@0kOh&Pwvxqh)6;?48$ zh|{*-`M`TzSnmRcC#iR#hnHIKfcr-kQPR9T;i)$^$AJvbtv8lK{T&3nCp~^tKW*n* z2Qxg^FP206As!xa+SWT1cz+kxJB;B;>K*RkrPezFcu%W(wV&qY>TlcpMp_=7pSrxR z=4I-t#btDW7jwMFhZ+O*K4a^pI;n2l&iDCP@GE(l*+TQW=EJD#aXwydHrKq+`I@=c zqU-Tc?>~k8odA9=ud5!mZGR^Qcq#pz1oi$)Snp);b9pKCP6_Z*>YWDlJ_Pfu-$#u( zFQAE;?%@%K_7l2)(>lY$BaS|=Y~wf6!y^uHo4n}jvw-(+$WQNYAwN7HpY7ohr^ye$ ze>8{TDaG=*OgvhtE?UuVF2i%5k9-^-Zyv*w_|0c{62Aq&dlvdjuWP72Trt0emPgNT zB`-5u((4-J(C5e-@W80zOEq3@wrKnMZJ_1R`Q&rLdIy1D$;+&tTD#^$_8RLQ?BnHT z^S1R4fqI{Zdi8#{6l-Q~M8BaP9&wuX58Qu;F+9osF`VH^_Ky(^PvSR{;Ys{P18+X` zx9$Er#`0)?D|wljhqn9gSRXI9JiWGfe{Ebty-o9n^E}??ml?mN^EKp6@bPq=>e8PV zi}wn76Fv3n{Y|5q>c#zSlE+W;x|)}%tH1?$lLNe%^EKp6fqGvM&hs?zD|wkIvh6%i z_wjPe(`$=)p3zWmQ-5(@X8QaxP?;JIUc{%d7c~KrOfj@ zsP`o`&)oBe?>Mddk?AK0dzlY@n&&=$_&BsZ{=D)6hFADyW(%4Z-+qFA3mIPFXL&x3 z&u_qkqlz!l^HG^!ZnmKL^PLxIzayOd23j7S|CRY!o{wW5P5->IOY3w70q^CM{yN8t z!BDT}wd}7$>vV=Nyw?47h(j4(%l53N2@zyHDTu)iFq*jQbyQ=xS_qk;FIfFF0BkA7nq9{O<{pWj&Ey&CY# z3F54Hd>LnX^!t*UhkhJ~ka+wX&+rtoJP&Gn{F}h=3ct)4v_1Y!WO#*NZg?^KN2Uer zWs>F5@57e)<>n5}$3K_W=}ZRRf|UL`d)ySLSMyr-*P(Sf(->as{yN0z46kK>9a^U| zgWqXL)q~Qt~qM0L}GQdGmd|-178VF)+8&HU2)+0?VW4 z%TFxPdVh0{F6#F`z^~+G#vr2J3U9!i>iJ*E%Pmi@;d(2)ftE-0zTUdO=5gtIkmb=l zm%Pl}qq$xpnRT#_ms_4*gY}yG(e)6^qj`Q))vNxL?;FtTOW*5;;`!HkyrJNydByS1 zp0xNlpe0uPw52x0wK_4%Dn^{=bDZ*}_-|C;_J zefo5Fef#|CR8?2^+&i;1!Ykr4Qevk2ZxG+M2(O3_yzYEd``h*iuZYhgKG>%FCfDB% z@WOl)@pW+IYJUD#jc+IMzV3o6;zK@W$*;1#-9>smFD<_zEz5RCctw0h&YLB_A#qQH zmzLj zxFWuU{3_eqW2D#f(()V9-25-XE8;V9-YoeIi6FXpBFqYEx#enz5k2wQu7-Uw?uep z`3-6A{a=Jv#D{#Oj?de`)A@Z_e>3N|8sB!}eWy=;eFb6JL3%weF~0%Lz5k2wlJgr7 zcSU$bd`1M!FnpWyzlnN?|FKb?E_E8 zE6*$H5959J^HE64vi%WWYJNlFfe0@xzah=d|02B9{D#Cs;OY2W)}NKLn#Or$@cs8N z@xC`Ozeh-~=MBm4(Fkuyevd_XL-Kn(!W)v`6X0on%lhk?-;>1q{=od6BE6nBB)_L4 zydn8L6X6ZX@7V}%NPf?Or}-`GuV;SOz3UH%53v^1CU* z8Vd_A9!wvk@X8Z*^IO&*c&Yc_-Nakx`kVXL`2N|~h5xS$*WW+j_n&J2 z^}MjX==_Q~O}u}L@QV11l$e9n{4$s0`%r`zwwESOQ+%f*ydpk}_+T|JUGaS$Jk4)e ze;pjTTK)O=tHgWYMb&)F^8Pt|;@X4uqR+pc=QVY4&c_$h-22@KFU$w$S2=2ZenaBE z2(O6GND0lamS@ZF@ApS|sr@&M?*MrEd{ow-MSR}2KOa?&9wgp_2Ilt=>GixJ`8^!r z4ax732yaM!k4AVy@_P(C&2L$MJ@b27lY;*Zh9tEb(>?%v=`}&HR4D z1Ztg>_g`9suH$_fpAkhfjn4sbLxfkv2VQD^H%53v^1BH<&2L$MR`jm-HX*;8iMQTO z4vP4C&Y!n{r}Hb%OUtk5(Dl{`FSY+F%iC=cURr)bn)`fbgqND%khlXponMvpXXUK! z{Dw65ewTQ21M|C!^m^Wq{O*qMhU9logf}F=dn3Fd`P~Pe=C`cBp84HRyodA{pTib& zfb^C;BWKOQHjRV)Jae##XTgJQYS+v=M0y|ELvJ|WJq(`SKS~~S&Z0Nu9ckhv=nZ*C z!PD{nVSV)a4uItt#aHr-oG_E#fOou!XTgJQ%Wrr`KS6pQ-b1fkS=J}P)B91$Gje;Z6VHMN+om_~9LXA>q<{2rTT7Mgw>M!7>)ZZ+; zl=_>6mr{R?Jln7SHlqG&{WsvH)ZZ+;l=_>6mr{SsdpeC*m$+(7iEk6?Pw&4a&qzK} zd7GPf$VVz~3wWQCaI!K!9beii&z0f+yR|7kBNx#3l(<~YFmGEE&-UYO@6zkW)0F(~ zXo}AuzC_;6CZ6g|1cn3)DGa}D`tc=&cc_U6y{Wvz;OTf( z#)qJ^T}y4&*R1zQQ+!6srt*$9@oYcdu`a!CJV?pM@uv7xZzAtR6HoOf@=lW8r%`+M z^ZS(f#wqZ0{#^2)H6H(yp;CW$U{E- z{60nRxhA~wSy^-cJHtKJ~KBcyj@54~Z)N5RwnTjLqT=WH&Ul{L5L zV_iHe#oP3T7dQ@{_TSq5GV%Vq`f{0XsNNdSAUvZv~6mQiV#AitF=%Qis$yRd3XQgd{({hC%wPeLvJ`9d>lL-uWCGl_?*pUv$8JwuX~52%jddyR?ckG8^-q) z@N~R-Odq|$c<>#Huf{Wo&)HlyE9*jUz`N*IWqzRbSL0bJ-l{j?&4Z_UAKOE381VJM z)A6dtGlF6?ZDIV>Tx~vhVA7?!P9)ycn0w~o6BZp&F%T_ zT|6tr+w_L1#aH7Q#OG`-o0T=U=TR5WO7T{`L41!Vy^rsqHw^gc z;AwlV@eJZ~HkZxHn%nd9x_DNKx9JTp@KW%!JwIWf-d9n4HJ(9y&gQaNS+m~X>Ec-_ zKC9k8CcU-yO^Nf36^gIMGlwSy^*?zC#z!O7S+mVSGOhp62(-ee?$H<)w&xnpAUwQHR&r0!G_5KFwT^g9*F~wKo8N}yoE}NA#>wQBP z&r0!G_5K;@-P=QNI3BzcJRPrUJcIb0&1JK)F8Xh9|NX}7aR@U5}f4GZhrFfg(FuvP> zr|tO}ee?$H#OG`- zo0T=U=SOt$tQ2q48(!dX;Awk))Fky)P!c&mO3E znc}PQ4B~S(m(9wW_5M~D&r0!G_5LC0-Pc2JI3BzOJRPrUJcIb0&1JK)F8Xh9|NYA@ zo|WQldc*kM4W5oy&*`H#7!UrL;;Zot;&V2a&C0sa8}R<4i)W>HtKNV&CB47YLvI-H z=fTtQs>U;j&)HlyD{F4gU+dyoDc+_xyukOs)A8z;d*}_@%f-twKhXAE;~B)~Y%ZIX zHMi$$bn&bdZ_^vbcSG>BJwLaP-k`nQoZ_qT4B~S(m(9wW+w(#f&r0!Dy+M3;CB4t< zp*IZpp5SSFuJH`wb2gXF%9`8r&vx;w6mQcTUf{vtX?uSDK)t^}@zr<+@j08zW@XKK zpV-B-QhZju&m_J1K)pG|SK}GP=WH&Ul{M>qSr^Yr@mcl$I_cftLvJ`9{2q8ZUe$O8 z@j08zW@TOU-{AiHCtW-%#oP3T@%<@yI$ph?kKSNB_-l%<#xsb|*<3a&>q2k9`-d)` zmEx^>1Kuj>ePIv1VZa{-Psgho&mcZ$bJ?t{xjlcni)W>Ho8IsOUjk3Zt6%A%H*7E8 z1W(&@jb{*_v$!SY#_g{YhT;o|O-ljKW(9>0IC@vIbY)f@2m{qxIv=nVtr_s=z+L43~UvRPSkd*=7gHJ+8?ZF<8C z@cZXi^w1l&7k>X-;~B)~Y%ZIXHMeJe|6Jo)Dc+_xjE~w zSy^*?=J(Gvo|WRQdV~1*{qwK&&>IHK@1JWtgZP}yWwWy8_RQ~}YdkB(+w_JP;P=n3 z9H^JyKi7B$@j08zW@XKK`TcW^XQlY8dinkH@<6@(`KubwAU6Re^uid#OG`-o0T=UXa4+Ejc28J zo8IsO{Q0Y2@1ZwrFZ}td8qXj;XLH%Cthqh&=dWr!E5+ONhVk*|uU^wfZ_r-&^H(*V zL43~UvRPSkd*;ty)p%Blx9SbzQgh`$sjNmEx^>10H|>=(l_54Fl%yAJupU@j08zW@XLo znZJKj<5?-*rZ>C*fB)!rdgu+?3xEHp#xsb|*<3a&Yi`f{{i7PsO7S+mVSN1kqu=eL zH)t>X{i7PsAU0R#-bGdNz z_X+Cnzw%8ZXdW5I_Z|BCRyCdxuKxb3F5cW9$4Ltq%!r>lz z!|~v{;OWoHYCMDZoXy>4EWVIux_H(>+@ksI;%xy>e_r+nef0W^V7UXuSK}Euu`RzQ z;Qd$^&w}S|Lw-ZvJxTBDdgzra%KE}wn49)A?rtir|tO< zd*}_@-{Zj3_FUr`xo(@@khiysXTkHfL2t-=4tUz0|EQ1Np#8m&;;Zot;&V24o6-Ij z@Ltiyvku~x_13ML^ai}wklsJ;q1Rtem)`?V+jEU)s#E99&GChIw=CNN-j`9J;1%g<{a{CTbtf6zLVf-dwFXgy}^ijisCDIDS89m=_X!^-hg+8 z^se;L8;l2MDZY}IqBr23YvQHo4S4H5B=bMb@6kSbgZkS5p0?+bm!db|ZEWJD=nZ(A zNbjHa(3=IzX7KcRy5uG34RG0(CZ3hEX6e5nZ!38EJbkV8)%lCgPkj{y)l?$*?@zxU z&#Ri>l4qodj#IPpKGwvu;CbuX>#V%bf~W1dj4xrnW`c^?hWZQj`opu&*Fu_`??!m3 z^R1B5J4(D~Q+~U2^Yi5~((8GN z^;c<~$0NMt`U{9BB6<_+FQ8@FN#gCJ`de?ZEO$xp*YN*&;e6bX`bWvLQd09fEAM91 zKT4hv-c0!o0zXCh@H~IGiz8R_@5fC*%d*oEUUGf|;+aT3iukNVp!KKmu;uv967Ovn zRp+N&^DKToKL?(^KPY)dBI&9}=B+y=_um@Nf(P5An|T|+)At8|)g^imH6|WU4@P*! z{mn>;)bajMgjd7|UembJ6yM^;Bc`a4RzzoL9x z;)>ey#cNy4I|iQKk4m1AqMnz_W^~QG<4rs(#XT=Y?+NhqepJRs&(lJ$uQ|Rhz1sfj zB-z8fF1^}+XXUZpcMQz$NyJWiQEW67SJXJgdAsiT5P%bbj!%h+asS z3(%VNK9k}rc}C+iSqks@O+2eSo5Xu5={*q9>-%xj!g>!j<5tLhTe1A>PZ>c}8J%i^X{d{rBGjhfC&gQZiUAy=9ZlpNBoNeM+Ij8%5M3r|A zyfs|nZ_@Sp6qU=m4@-VkZ^<)q$_#odybVn}3!b-?8j}6G=AVCT1W)z8)9J0WXW!Y} z(v)Za{=ftgZUXPCMX4++c}8~3!8Yk;-sUEr1rN3<&&=Bb-q)mf_O5|?w^Dp1&mcb7 zS@mvf;#u%uXVtr%^xnb^BB}Y6E6aKZc>2EB^L+YsoN8((%Ha1+J0rXzJ|iV&X)nt5 zc2|T~#AoEJraZ{e`uBTwM|eeiR!ZpmlD2#(+uJ?h>3Cn(pOv$kIC8We-(KR~d|-a} zkzUUmlHdIi-jMtri13Ew_h5uKB)^Bi)BKk8*E7F|iFeC^`8`5Uk4AVy@_Q`8 z82Jke$o|l+ke|ouWjPR248xS`| zc!~K9Xj!&7!b{F?K->aen2#bpD^=2c|1|+E%eE44OOO6rCc|xP15f8yo>#=zF%MS; z&#$&ec&YhSwzoSXydpj$XQj@sc1C!q`IRfndKY*)K9}`p5udlM&qs2eu6Gmf)&ujq zhxB^hko@kA@P_1fUxYU#zxyM+A^AN3p60i#Kc82(boXC5PuB;DciSHM4M+S#;OY46 zd1?6#Y3}pI5ngJ3L*kJLFD<_zEz6EZc&YgfiO0ax@wu!&D;ev~Z%E6s`%f6HXJjdS4X{nzt~`s;cBUH4I$|AoBN{D$#ui13Q|jGUEv|J@kjrRFz` zZxeVrK9}`p5udjS_utLLyWPP2ZXvy%HzdDXBfKH`-4@{u$?x_EZ%BT3fT#H_>#t{i zcM@-*M}ET*e;0Uq|Mk4I{D!nF+a2Mh<~JnniSW|$8`83DZ-kec-;lTuJRP6Q`kOhw zAuY@H6Yt#v@4p8~ujeJ^*PmW42P3@X{078B5nf_`1Dc!vMR>{i4Twj;)BKk8XQfI~ z@4rWhcl#dww@ilHI0l~HFFmiQzn=Hs;}KqJe#7`qM0jcW4QcNCWf5L#ena9Z@N|4G z>(9zr-T4h^ZvIEStpoFWhV**gko=yF@P_2~T!c3yzw16$o&S~fhkVR+gv zfv4khS${LA1W_dvYA9eDrUL3%weF~9!wa@iT-CFeIF?uzgd^Bd6I{4c^w&Tl~6 z1D@u$tUoJN(mg(#fad0Z#JfX}{#z!)ZR`V2@4uc`)L+m0@BRocHNRne2O_*8J|kzP zKK~w!@KW;|#&-xj9iPkkvxv{zgy-MG#QQt#Z@KXF{grs#>m#JM#xvcF@QkBfJR6?f zy?u=I{{29`$H6;;OV@a&JEriA6J0zTp548D5}THTE}l)}odHkBKaKAahq>7O?`qHddGE6g@p+!F!a3tsEerF`weYOt=zOgS$-H$R zzqB}2^}c6dem8)p`K|FxQ)IHA^SiN$2Tqq>=51=wTjm4px+zMozs(Ktd7gFuQ}er} zg_nDthqf#n-&WH5kDTAU1r|B94LrU7mOLXT&*hOqExWci@vIa|L} zepKU`^Vg1T@%`gi7th8h=l3!1ICy&h)%g7V!#&z0&o@pq#OHa%{KdG9mWA&hCtG;M z{KdAw+#%+jBEA1QFu$iMz8cT8$H)0N)5HU(>;B8UvkiKEK8pHFoNt_Kh|lw^`=2`B zSoeubU8yY7{-O2fdAa-FrI+)&0X%Kb|28nc8!5gT&$u947S6|}E}m_HxkJp`+@ROj zU(w$Z^Sh-XKF=%Ki*Xw*3+H2N3(q=EYJRto-qnHm-A?hY+*nbZ+#OHa| z{ZAdA54P}f&-2ihg~x+Kr1#$k=JzngSL2zM;M^h3$B{0cP2(MH(ChQjXMT08AwJLR zGrv0C!Yju64!xY;6QuWj1M_>5;;ZqD6W+3Leor;=j6k~DGxJV2=xBs4P z;pI+pmtM~AInw+7f%#oGy|k$K%cT0V8qeTBgW-H^=;GN15Oy{&d25!o^`0y{B9w=9~hY5t>EeVjT)~*FXv-h6Azp&z0BJV-sP^Y{G#!d z`AE#~j)wR=&$|Dq_uri@yxj9Vv}NJ;vWxWoh`R}0!IjtdIR5*|{yx&QaQ*EDPy27l zGeYpZwkl-ao+h3>&%>tdpf&UMf~WoWE)l){KHRi0Zy&{1@{ABt>u-M(&z|R{)ZYQp zd*_JW6y8DbwEvd8Krcd-fN9P3cc_U6Nb1k04}+)u_pSr=9sy6=bICIzEcN^QN1J#( z^&SIH+w+eO)O(!bD|tQjo@nCr)O(WjZj0zm8Lv)Jd?hc?o6g_1@zr=H7S;KE9N)Pvo;_bSw#B@4r!Or|)Ap?K`TM2MtKOGlEWeNMZyUhV z{u}aqUgwN2)x0ooV++qZOzQo26Y2fn!2E8e_-Z`Utkoakd~9jrfzzdzd0QLw`urC8 zXzOh59L~qKhWI?sy8o&9-QL2>JHW~a{O+XqYCO{toIAw%*ww|eX}sMH zdVN0JP@UX=_cX*;jt8baKF-J97GBZ*Y#MJL={+?tzxye^8m~hy=l4Jp51g*{%)EmQ zdi(a@Lk;ou?Z1axc)3e$mtJl!M@a972j=%E#aH7c=J!|^&pOd93+MNEgWj^gC63Q0 z8saP4i)jhY9pZePY~fjVerkSCk=~CC%itXs7#++H?-cR9*@RP&q5j;{G6Uuq-8 zSK}Ej(e7{R;@S4{d~`GE{g~=SUc2;id)Y$q)p&*@sQS#?+Qb8=E5FR!)}Yt7m*Re& z*q*mH#OHa|{ZDPrJ6d?T=Xq$$!tHq{>HTpxsk(wIuX#;<-?R(7%Me4!GqNM~eckRR zo;}aQrtF|K=XVcy`aJj(5xs6#UedkiD%FAuqiue&GDTky+7^r z7T=FTrwzyH7}xWRAJDO!q4+$H$9ti5gS_|8RmMSMnr=^hV4n)|BP zr!FlDYX2?k&k9fPm+QSB`Cb^;-v;oszm@d|UK2;I=HHi82{=Wz>HNPS8ScI3B-;m~h z|6hccn%|Ik0zAF{mi0GtenXo3{V&A(xO=}*#Mg6vbqYNF{*mV;=GUKIE~g{BxRQDyyEsgmyduL)>wO804*|0(aDJ^F8%47afXJe^;8 zUQvH&FR9Oi8za2b{D$#uitvi~jGWaye-3GG{ukk;<~Jm60Z+&0vi>aM^ENUMm!tKc zH*O`~CkFQ4ZQ$wOd-uGw{8roF_6RREzaeo)gqN1zkd|dTBfQl7hQwXq>EE|6>(A%a zEvfx?H}QU|NB<4u+XJ57e?4zVe)mRrL-M;X!W)v`{Sn@f{2l;L@4sdJ*&@Bk`8`Oy zX`lWZj2DMUujeJ^H=w!S{}`4ECI6zAWERjzh*{5?J$pFOXrKg_S1I11$Vr`L<{ z!u)DJnz$U_<_NEd&qxGKoTm7072$>XU2k1US3^x)j_;1(X@1N4^BlJ{apY)ye)Z$T z`&4><{UyugUZmIa{0aIVJ2k$ajqnolTZ!*M5nd6W5ecdBjUv3n{8r-I1D@u$tUuc? zzNZrJ)0AJ$i}qu=%K3Hiemv;G=V-k0yrTYQem<&>2kSl~&u=;&l<^sfVGdUN@%hMP zi{sl6;f48a;wYE<+r|hl%PhxWe+w0F0#EZ>)}Jr$mL`rIEq=aGxyokZ zeWp)-gBG}j^m<-megm3&e;?t6{dcDP2E=U8k!-$0nPpX&Im6#zX5Rvc$(j` z{w(72wvs{FuWQ%-0-Ae%Bi?5zzuIqop-Mpjxjp|9jaQ!M%jr1K#5o_IZi)Ss2rta9 z=A((r@%?IqSHx%JdQBXSisuKv5#fdTU2k1Umyaec$M^f-X@1N4^BlJ{apY+I{`)7y zyDUAw{*vW#l=OO@KcR1a|0=>u%x@*Wzm4#U_>4&K+m!;cyIgaA|2e`-%x~p#9{^AD zTh^bI5K`m&IPpG5`PIB=KQ4u0gYR#aM^ES{Ud(W>qzWu~I(eM1DbpP65%E1Hy|DXPxD*WpGAD$w&ypXx%V%`+u`0P7V*va z^CP+H`SmgI^ydqnSJdB(^XKy<**YHKrR0}+CnCHeJ|ky#<(GLUBfOOSGVc_4`tyad z{w(72wk5xE*7@~m;(Z?d?UKy&`u^Z$bU!-Jv%P-5%332Y7oOMKvhe4D&(Zzp3xQtW z1ob}Bgk;_o{-pZ+R^yo_lI&;RRT_C#KA&yVc-I0?$AilQy%#%Fs@@w>eCK({FZyv) zl&tsWjXdPnG?8RK^KMUizZmH4liweu_|Ef?kHq-4H}djc`Mo#ky?5gH%=5`JG+udL z%J|H@vk_j(_{_X>5njsp%)E72WddwN`5siwci6z?;mCT*?#d|>4?mSl=lG2Z`ZiW(939 zY>IDhgjd8j`}pjur(EXIUUYmePxD*W zpGAD$M%sxSEk4f>(A?+si1($7()+Kny*&k<&aXVLs6QI-!!qGEkAJ5lywv=L{4)_= z5ucH>y7L>--1jviywv=L#B<>3e5kBHi}<{4&99uN>vfk^=T|>JaDKG`Jk77?4ax7u z2rru78RsvXBD_j|8#r2D-2OI4c+vbeaGAFSJk4)ee^w$$o&Rl(@QV1Tzxg`w|9Ro~ zehT;Vru;T>l*_!Ii}1qyYJY3uGVj3=o-eES@g`1Fe7hsOFu!`gY~pf!j|ZU(HKXyJp^w2(O6GNF+@hjgxshBfK!b z<@{>K{<{l2z5kZ=XZyvsJHjjCqkJ^A8=kNIGTKX1ew#Q=_4lF(FU)Uu{|#sNS@vrY zUYOt1_+A^~h57C7zt#B0;5FqpHNGRn`|`l~)gEfko>$Z#wHM7NTkaowBfK!bsr`3f zgcs&Fwg2vq@WTA2_TK~GX@1N4vr<#3@g0otiufoWP3^|@Uw^1v{*>Bt86S8}90hQG z-x1-3`JJKvR^t1+2+yCO?Ibn6e~IwI{LavSEAjmYcuo0Djqel0+dr57d=!o_hp0V! zUQvJ4UNoOr6Gyom-_Zy!%x~F$ts_L9YkYeS z>+cwNn%}bie0jHMdl9d`=J<{iZ>`7p9QNQ7q}THj^XpG9my;1*a()BisR%DIzX8pC zpDw~n&Tl|G1D@u$tUoJNGDCg?ntMJc-q{}cEtBCk&Vi@TN1j*I-^~3tq`4;lIe9)0 zd8zpgi5nukB0eK$b@$(pmSr0wywv=L#7*Go^HEuU7V&u-83*KO{qy{riTA+u>EpAq zz1>23J#R>Uw?=r;{JQpI!$7dj_w#KLUM0T`97Qv4dxRIwZv&TkJHXTYmh}g5sq?Fy z5nd4=^*3J!{y#4q-{){Y*Zx+<2VN6Lxy(Bo;f49t{?^20-nSw=UsmtqO`N9quK0%P z_)_){D$d!Ykr45=j$B<7D362yaOL-3OlDf6Mx_{o>mn;idK8aQ2sFKZN$ul;70$cZ&!w z%x`!9t;V+y;f484jc;3o7v{IS|5oF>J9tg`O^xq9#JeB$Uv1A_Ty5X?2T#Xm&nxP0 z#_?G>Y9AiqrQ}yRY9ABf74aE4V^*EYdrE|tl3(SheKvSHK9}`p<&4z$_7m?Rl;5tO z%ky}3fW|A&3-hb(MfI>{-oXej%!!aK+@YR{fm)E~7MtuMB<_b(A% znBTJhn%O>|b0Wek;&bKwqU}Yz`kLcA8R3QbE&H!^tjKe#Z!cl}odQquTh^a1?-p$@ z;?>t2-)Z8#uup!27I=pAdR}6F1DbpP65%E1Hz1yi@QV11)YT064QMW9XXN=v$E&jb ztng;aZ$R7tp60i#Kk#PAZ$NYJUx@dWi_-hAD3SFh@N|CVc}4xr+-?%3-@4CVS`<{?s7HR~ z%Cg=7p5A{wuc*JCa;yrv|eov5I&l{58lM&vK{GN*NhUE8jgf}F=XTa0^mi5;&zh{Z}Rrfy8 zrKJ46F8_Sc*M`g~OKjFgyz)p=?c@B2+W3m&Y_JGyumzft1T z`Q+F7=nX1hBY3K}T-$R6<{aj222b1bH~Q!e+RGM-uf{Wo&)HlyE9)Y@fVZ`aXQg;zBS^SOa~cTs#bo-Dc-6#i0=^T{Z0?PVZevM)BaoI8N}yoE}NA#x91~WJS)Z9 z^oAEW3ZC}gN3S3D^WS3>pXd4N?YfU^O#FWQc!W1({(K_BE8;T}LDRgTDZY~t-jMn8 zDe%I46!BTa=WS%3AxG;!|2<8-$Mnc=I3AnK;yu1ce#8665%BbW z< zET>4X=OyMhpt+y#M|jEk4TxtVydpj$0#fh4XCu7i{08xz15fi?)}KXu-X`3C*L_ju zf6Cj_BfoNGS#JPO@4uc`)L+m0@5Tr(HNRnenGXF}|J^cdd^}NLV2DB`DLWGx`-+=h^2rn_e0WHg( z8{sAAHz2+kJk4)ef3xQ|pk>)BiMOsLzrG8`+F!1X$JyVE@HoFQjv{WHg*5l~42gGz zmiR7qkgoXN5aDrrF-}u_ZzJ9nU3@+U9{037TYlekh{pSpXQZT#FU(P&d54>L7Cdh& zEkgF|nt4ZPykDQLw{o?k6ko|R62T05E4*V(JPV$;l@hXF*G_Nc=yB3J=k$i{CCoE! zQHm-o|2*YHgvaeA#!)EqP7?2;miTS#!)WwP807++Fq=b(EFN}XUq4a zGvIv@CtjS+tK|1A@iw&7Uo08!Y>uxwUQL^L)Jb2+~CZ<79|^DEEe_+p%<_^wL4t4DY?64!a2 z@gbMXb-=p}drF>>9jX1}#!Wm6p0^483S>eZ!5)D@{C+y2E7&DU7L6o zJa60eR(SUyy&Ik0A^qdh2#?!eO8k=WV4$$bMaOd|SZN{&B5zy_KtNrT9vo zkqBncTj6bM;#u&#t(1`cy5{-wcG7!or#EabVV-eIQB+}l`wN#H5gxaf7)Ke*+ey6Z zw8ZDzH80HD72$DwF^+PXx0`s^)%Ieggx=4!JX@YW?*UKelh;eCD9@WbULB6`ivDY)6;pPwY&jau>>8@GJ>!=;NRbS}c<{Khy%VYj+*h30P6 zUzXikt(Iqxc`u;(t_k$|dP~*&a*FRf&t?VBa70y~O;p zR`UAQ-#-!W<|VIR{k@NPw+MKB>hGh(yJf)ZQ-7Z!-WJF6<5l1BBxVLULJ z$++eGexs3>_ZnZaH&@5|TLpUij4vC&Q@!VT7+*S)%zCfU$iw)OSbsMly|;FHi}x?! z@ch*0-v8I7n4boB^qW$Ao)^xCbe_wc^E?yKvh21IUJ;*_5_7ORuVgOA_ahO#;e4ox z(-hxN67M#B>My9!pCP@Tmso!R&3(Qp!b`5dfcTJz-o*L~Xj%3s;@!4S{RJ)NiKN%_ z66-IZW!W<#yyW@|h|i1YO{~9wmSry?-tGF-UyzYy((8GN^%v0G@0*M8lIt%Z{y{`< zV*LfQEPEsIp5cNk;={PC^U0>4!xiI8K>Rb(>v=_d;5BiA@g<;T+22HXMSMm|%)vH| zs~q1yM0i8;`)?6m5uZhTuubDC$M+%dJ}1Sqvi>?aINd$JnM(bgCf+k$a7BD6`3-v9 z=Si>UCFVDvW!YCFydpj$isoQj^BWMq6X7N1H=w!askg{{=rUArS$`Js!M5f%AYKhT z&2L$M9UQq@@%}2HW!ZI!_bgX=z5#H*)$(k)y==nswCXK+MoMZPn4>=PHaGDsc-~eN z$$nk)`>-way#MTUy_KtNrT9vokqBncTj6bM;#u&#t(1`cx^{XiN4JySeNJ!K-@-h{ zrqX_Vu?lx~M})`iCB{(%zaQF3yyvvU7kmEV_;y8j9AAvn6yI**{c=luRw04q@p%t; z+CMyx6;KmQ=!^IGy78@G6TIT7J;eq)^T?GHk*<0SE(-x6PJ+~W97 zMR*)vjMEg~Y2v*g(w^J&R)4yhWoL-@!U(S|KIWYz-mkROU$y2%F^_-ez|-;B^SJ(E zob&Z({ORSgZml~1E8{bA${g&h{#(|cl?b}W z=aA;UKS;b6^~rBAB5WbOo|l;4faZRGM1(hFeBKt}CFZvh-}VSEIllpM2Y8y_vi@ez zZ$NYJ*NFGxKKTuL+%D4Vd5QTAXzu%i5nghB1LB?tuZYi}e>j`VW^`Sf|3!Go`3>UR z2cG7)tUoK^r1sza#Cu7f{01%N0O|F-qW*9b()UBr%5yti{ROlvI~d_5=Qki8itrNi z8_?YRFTzXCZ$LZ(p60i#zuEH}(A@lwcrWdf-=O^+15ZDH?|F&&4QOuu7vUx6Hz1yf z@QV11w791GxE!tDe@{ku$@vZ9I|ZJ8e!Q%|+4CFF+~;42cc4#xgBEj!^m<-Ve?9x} z*$6K=zd?NGBD}=>1~m7o=B&*Bv^|&ghkVTP{2Pu~8^F{2mi0G#ek<{9B;M_>q%F0d zz4yX>i-Ipj@r8lBpCjH@$MXW_-0I>UA)eeM@qHa-LtguHO#EW2;Hln_HzdCQ#O3Y) zy_du<-?{e*Hx<1v!I^g)$lFW2J2~EvN;k&yQE0=i6UuKlvcq^S7Zld9ry(G}->3cmu4OCqeitWN$Mbo0Kj$fWh1yxU+rax?z#9_Z z_6V>R%&Ik|nSDX_5yv#=8=Xpc=+nxvy z?M23e#QwH7!W+`x_CHIg``aU_{RQ<`G>O#y_P7WS^;hubjI^{_``g|KZ%BW8 zPJ~y)XC;|j_`{35;=OEt4DYkUy4(>ziBzOetZs>{pi1X ze+%lbI8FOoSSH+N-hl`&>>u3ULYCiV-oXeD^;Zt^3NQ#R2UfT7Q~XwX^az zfT!*Grw8VDBgGf;au-yWUe52P7G9tHZf?-4c~v`W{cUN8Pj#xDmAAEtXN8cO-)*G# zX9nhXJH;3Bau;HkUe5217G9tH?rhMjc~vX5SzmL1+tm=C>Qq}N$sXqIZsJ)vKQ+I5 zNbe4p-}MfqI@RjD$j?Rme_c4f*I@pvm$5y zzShKPif<*tE8??=4_40%sre0wUj|R}Th`yq`3-4V_D$m5r%!%^4!!QJ)%k(v zCFVDvW!aS@yyW}_#A`-)iTMp^S$4w+FFC&f@n+y@e#`osJ--1h%Wg-!ODP{bKKniz zE<8T(rTd5H`3rV&l*zn(5nh;&IU^-?Tvd)*=IxL0iugJ>O}qmUUJ;*_5_7ORJ}XBp z$9E7s&2L$M9h@fKA>!S)M}ET*;V|j-ytMp=v@AOk;icv`Bp!|M(()V9vg}xdmzv*@ zcpN;_1^BWLPM|eeiMg%mC1FDaI zK656*OU`c)-&yc9zh(Vd#OG}=-;urN*BswD;{BY)cbE3-;M|`Y%iK$U*$oymk1tD?-${v-hWHD+juB=n%}bitemCe{H*akns|#n z@*9o_Pa?gZmzLju>h_2DB_& zCEoogA6@fa90% z74caqF$b&Ts&dqFe4D}3{Fe3C!D-@cA>PmT$Zt3zY$d&(mzLj;yrTYS z{w&ef*RK8on)`i55nghB1LENbFEPIX%{`w-c**$0%fE*qUVY8= zcZ_%s9GKtZq}TI?Q(JDdRKJ7iJirgWi^98zQ_R`P~Sf=C_QmXMQ&k@4*A}yP5QQ-jMum ziSUNxcWZ<nH=fCgamy%}+H|y>na-Obt zHSsKX-d1{)?AJ9vf9wYDB9wW^K)rh?zLIAof>gbGn|KyHZxi(HBfSqDsCPejS3(RW z&mcZ$bJ>ipIUfg_cvgxxJy$B6c?ZF}81X%9px#3iU&%9w&)Hlyqic@ua1+l;@l?G> zNbkd)-eP>oh1d07fd9NqlV+QixOuWZBo)7gB_aBd}N%Fsl?+080y^k9h-`fzM^7ahm9V6c3 zp||h%L$8DH2WWgx2zY(!??&KV74`STfY;~ymp7&Oo)qx<#CL0o@5$ixZ7=Vld_2YR zhAe+iyrqG>_Y!Zf6W=y!FV6ta>s*g|Y@1KIQ!2{_=)D^HN67PfeO^*{8(Vl@Zz^vScvnY!&m5?C zGkEh6ULU<%T6lf*ZUt{6;`^`q{{A(w?~d?>JawNjz{Khzn=KgUs!fVQJjLY#Ii|{zVF-}u_ z$BFmLn%~@&aAS1W`0Tmi_yUSfc+Yiu z{cx8$uTs3leDb;&GoLq*_tV6CzUHI2%ej1z)i|2$&w_V7#Fr1`JpjB-;O!sCdl>Ov zFp&2s;=OPn@A1U@6~`<38}d-Jo2JT-?B5IC^-+H>8pwM#@m}nBLzd@*cLT)t62zxE zwf)U{jTcjVFLgYRPUYzJPNV;7dh_tFh9K^^oBhDJd?VdY2jhYn}qx_ zcsD|PFB_=$>l9ze>!bJEExbN@*WFBh|Ay*)`9Qr_0#EZB^7`n#Y74KA-fNQHR}9p< ziQ)@+ee~YAh1W;#%}DRB4%B;ViZA5#(Yv*U*GKPNNbj!=)cX?@U&!mD_Z}_0K6-bM z-d7IP`*Rdu$m^r`0WG{fdLK%9mj~+IP4R`iK6)S9!t0~=Nu>ASK)p|+_(EPEz57~t zee^z`^uB7K-WO4PA+L|#m$&fx=sie!Up-LoYbm~v*GKQ~w($DseI4oj^?`biP<$b; zkKVVo@cQU|JL!GRK)vsv_(EPEy~kU4ee}ME^!~;`z5hb-g}gp`-`B$HqxTf)eeFQK zpP=|cULU=mY2o$J`vubbn*;TprT9W#AHCmb;q}q`UDA7Kpx!IqT%Nb|`6%S|(Yv9A z*GKQw!PDo#-x{d*+7w^N>!bGuExbN@Hsg$D87)_NAKUX@cQWeThjZ71NEMu_(EPE zz5mw2>!bGrr1y^o>ir1C7xMb(J>A0VqxUk>`^N+Iev#q}d42SLwT0J5?>W-@`hj}C zPw|DkK6>YFQGMPDd42R=1w4H|`jdfrH&T2duaDmAw($Dsy%Fg>GEnbLD87)_NAH#v zULU=;C%tbNsQ1nkU&!mD_s3dzee`Z8y>A?-_opeokk?1=eOq{a^!_~QebYd_yC}Yp z*GKOoTX=o+{vzpp^FX~%p!h;wAH929czyIfi}b!_px)hn>^>!bHd;OX!bIfExbN@caz?C4AlEriZA5#(fgzpULUpYT@-AUR>-E>@c=oe$Jw1OOetCWP<@M=!PRA$kmA4AN zygnVzevYmWzq~&D^7?c*Awn+64zq~#j&*}ICetCWPjn}91 zvz>H(_~rHKcuvPB@XPDNZ@fO8pWTnH55K%V9nb0b1b%sa_>I@6^Ru6?UVol^L;eE! zmi$HXN8~S&pOe2#{+Rp~@+ai4l0PMXjr{EXqF?LFkZ;K!k)M-4CVxWyl>F=gbbazI z`6Kdk^2g*)$e)s*J&>+XzJ;&j!y+9Ix^}P49K1P{p1|J#-#kd-)AnuQ>+vxiUxBaj zPU!e59iP(iHS)6uSFb-$z9D~sd`tc!`6Kd|$j`}NCVx!+3i%WASIM8k*WZgg+9i5# z*^tfgL*)4NaD4Po@wNZt@HIbE_~q{wd6=B9zYk>uU-Om2*YR&c$ES4MJY0Cnx9~Nd z5gpIz_!z#%n>|8!dVNcNPX2`a?2%NS{G9v=e2sTXel`-G_76^r#c|a?B0q<({b!l{ zG5IU-HJ(*EKBeQ?Zi!F%^YFF&0v)$>d_>2W==d@nAJg#(9bcv6YjiyO1&LSVGw?P3 z1@bNVi{y{UUm`yzf0_I-e2r&9{*?UeQ4~Mrtq%~fBa~@-6uzDxbqw{S)}AKYy%T zuRIRFJpQ<<{$=vV@HM^_IzEA~<7vJ}cw10E)5nXy5q|yz@oxZs^hEKm1wVUI_53k> zjd%29Iera2|0&{Yel7Vqe68;>{Ib2mSADDSwLMJf_!=G0mgM@%H{@IRI{xMG^?J+X zkKya}SLpbJj%zijUF|ro=c%0%e~tWXFV!#n>nh->a$NPylW)jhAm5U|Nd5@E)<+Is z+t0$?wil7)uo{-yRqQuEDd#Q0PGIM)>>t5uIkhXgf4iKg`_(RD{}^@+*4|ytUxuB+ zYB{y$o>lG={0Z#*y{gAofAsEJw6N1#R{iBGi$8^3xQh5W>?*9eMD{PiPGBo==gePK z&Ktq<@fF>FH92n)b_}})Yp*WHxqLof-M=uv*S+tDbK@vZFYp-*-48p$@pbT*$j`}NCVvcH#}~q96FQ%duTuFnKK~OE|MgLD3SY;cY%0gq zH}G}*8Nt7T>LWiVe+*xF6FNSHe?#ylr{(&ZkNlJ3-vr0UpQ`$kPm8}vkAJ3Ge)L)K zm2WQ-U;DrLocO9|fqYB;BKf#%Z!;p^68SlNosUo8Ykf}P>;21|5k1;obNH%nnfx() zZLcfjPsm>-e@gxu`Pt_s9_7!&*LVzkeIL2_{p$H6_~w@$sdzHCEr|&%9B4Pe@ec&HkBuT3}5^Alzej?DX-&^g|GQr zq~lBEFVp#B@+a{1`q_2mdg@#9bNJf+$8>y3zPVnNH-fL_bNH%fnfx*NE96heUnPG^ z{u=q&CW%k4KTp0Pe}Q}pU;Ec0`6KvRpJVu%&k1~;-)GmCc(lD+@^kVh@HPHb@~7ml z!Pj`R8&vaS$>;u>rNKKT~D=5LYw5&28x=j1PwKPG>L{0aH1W|=;*N3myUnYMHU-?t`H&y=62w%$^_G+8JCGvCfm&qTKze4_m{8jR&@XPUsj%SyWUh)n33*=k! z7s(%yzeIjc{xbPv@>j^8kUxd5?Q!+}+l!uUJ|K4C<6?8zRoL+tWd9nhyEJ6`Mit6gu;LvVRrUJV*Q`*a__FOHuwk zVi#c-u6~cAK6BVr*rj>dKY^X!DEZl&95c?!Zq$CT(zs>ufi_eMxHx! z*p=JC-zs+g@nT1?E3gYs!g;W(uy(KPUxr@J4*dbQD0hq^6F~&wcChqZ!30bDtXlNr?0B=mu?{Et=$Oaen{*x z>=bt4#{t@g7Z1%&le-U;Jy9S%zRF1Em6l?!o>@w^WcHw=p zKf9~6-$hu}sdnLAa^5QJ{FUVV71$j6%|y-{VSjcpxPK%2*I>;>vfo}!>=ah7$99Zz zt8;R``Fr6lT}AxWzZ2iU=klY!mg5;XIXKI>?h1}CV1KRrd!_seZ1&IMFT$GVO1oNu zoxsjNPxg;sS75W}%l<{!G3*+w&E@zq>=brkzwFOpS7FTyWd9QE1a|&~vVR1-0-ODc z>|cZ(!>+;F7s>Hu*eUG7i)DWfy9#SwBKwzMC$RG`mHi{w71->6>|cZ(!>+;Fm&x&E z*eUG7%VmEKy9zshTKeY*b_F*3r0idW9m7sPCHogXE!KQS>=Nt**1STlw*)(Zo&QzY zKZ0F>&3;YxFT##t*I?}{<@hq}6n0@*_UEvxu;!rbUxJ;$&c90bk6>3|vscUhMObae z6O3PL&~KrC88$~ftisNJR_bE}y8@eCCi@p*$GFZKto?Pl{xa+ocHuR$KZjj~HNPSI zmtZHb^RJctBiI$#>^EiqBJ3D;4b~o#)R3T*bfvVReF47&zve@~7t!%krreqZ+Iu&c0UEc=&WC$RH}W&a3v1vdKw*}n*@ zdf1L}d=1vVPRcFAPGJ}RQ1<7rtFY#eWd9QE1a|(9W&a3v1vY!V>|cZ(!>+;FKau0h zuv6HDBeFk-U4>nIg6to|E;4>=bt4 zZL&XyU4=D&Ci|CQC$RHxm;EEy71-?0W&a}V7+hV7f|CZHXz1@bNVe3?axXGH!I`8oN^#@H==TFFAC4Wjj^HTja=6y%#D z-;lpRz9paIS)}75@|VcZ$zLXaO#TY_6Y^KdpOU{uKF5E-zfc1gYT$oS4SctHznUlC zkpI6(`2{H#YT!Z*{D5m<0pp9#w=DUKiszN`l;tnZzS&l7Jf+V z^m_0&iOpeGVa@er{}Sx@hT^ZmPOyLe2C{zyy8@fxyhYd?*Ik7*HwGVe0y}SHzeT*u zYHuO?r?5*m6@LP|dK2*t{P{bHuk|##j`%CE*>%NVgdM}K!LHoCT0UE-`ita`$zLPi zZmpJIx?|PPZ&~%nH?R5@x>e6I@uuW2+@V@NCx4ZEL-8#AXtn&(?W+ES{1MgHJoyW^ zt(MQpH^f_|;}eQ+@zzzIxwiOAuoKvMEG&4exe$0{^M1Dm3%|zFOjcYwc|SrZ}~^Wj`4HkHCX#&)$3_FwQDGE zQGN=$jB-=h1&UM4nhk$4oj)y+pOe2#{+Rp~@+ai4!q@xT zP~B7TuBf1S(WAbBuh&~3UyJ>qtfhEI@XLJs4~zE)RZst0ubWf8m&qTK&-F0Dah-qi z@eBU{@EV}+o6VDN$X_7;f4I5};a#YK3pH?|1}@aV|I!+;9rvR}IzA%*e`&Qe%3AtA zuD`Kj{*NA5;rEH;FXH`4Sv}gs$@v-HGmdfo8mzqyj^hH0^gePK$EUC(<>CB!^4F-m#;w-8^Pa`#66^$a z{#~+v1gqz>&F@l;cY%CE?=x5F_%glEGk1~qKzf~(J68SqyH&5Z_-uM#ME>**cP~&2 zZxoxuuELr($^Io+y{_5|$4$Nd%FU(x+FQh0a2LTH6JN`zUB&n9mhkd&M6Dn9Q$LV2T~OTU@unj&ut_`LW6J};ibDv#{~^cj2( ze+hQ&ic+5zpTp;J>RaT08K0Yq*{MVvp@az7%+CtndehClyR z@fYEb;Ll%I_GcdvyK+OZYg3$$_GeGyJowA-M<_o=`T0A`dHGqfEAUt0kKh}`H@Ob3 zqt{1Vs(T6NsXzHH?(g3hyZ9ecehfSRVe$2RwxjP!Ir~95ZwjmDjqyFvh0El44!a6# zJ}3K^U?;Fz-rQb}j~2w*JBVF5BX;=pfhCimC&n>)E$}i&k;bYhlK2MP0 zdn9^2w&p=nev0ptFW~#+D=5F%QGN;Km761;l}j+*U9~#y%|96NV*i+qD@W}-+Rq}| zUxs$K2D|zp;Z0779Z`E+LHT90y9J!D{0Zir^KV9Z*cI3d$E9BWx7N=h?z>~y|7-sI zT_wNTA6B+Se1sj$l_{vnR>^MOeCg zHpc!nSo>r-e;IZPyYLj*&*d-p7i!=_4P2;!3pH?|1}@aVg&Md}0~c!GLJj=isR6rC z{e1C%xAMgw@byPO;OqZ)*Y}0%U8sSu23D?B{XR@~?W(^>epvRx_Jta_Py-ig;6e>t zsDTSLaG?e+)WC%rxKIQCw`w5gzi0E`EPwe2eEsnc`1&h9;OkF*z}H{>0bl>Wxw-$3 zyWA@N-i8Kdu33G5utffZ{CRr+Fk+uRpJ8rQ{T#!DK7XZgl=hMGxr;^EG3*+w9m(-! z*s>fp?9=dh3fL*^!qa7c4!a7=<;^qXyd~HP?EEuj{|I&kmdlSmg81-vTSkwSatnVY zb{U^5o#1n}^Zx)Y><@w*bKjqV-a>0zwg7`LC#x(oxslP_cQSO$=6`* z6XpEXcS!x2zZSa$JAs}58`(dC<@#TKx*VUv^6`ad$nhL@71lfx*MptFa`_egyDRv+ zLyNF_-onGchh2p=4+kH10;}cJuAu#7AC>bLVfFYLeETsuz6`6!=dXzT!>+(Cu9y88 z>{xv*2s?eBa2MV$Hiw>t6dz)sQs7j`2~*b#Uuu-QZ8_#*5Wb`4hJQoC?J@L*SA&CkpJCD;k9{kZg# zW!NdK^4QMbUpOP!71-|cVNz|MbD_K#p!V6$_we-U;Jy9R5&CC8Ux zr?5-!m;Do1tv9v#zsm7dSo3em5&-E{TQT#<5pZ}8h(~pW>_?XxweBWgJ z8S(QEi8ZHi9Cqcy;;*d2ej4Z9N$hk@>=OKiv*M3%{s`wUTwnH2J}%a75^LZu!(W0w zLHnD0O3uqse*P2UFaL|!|Hs~ahTCqGXCEK1F&#uF36P<8Q0Scjj47sw-eKq+M90*j zcM!e9P)$el9)?b+qJ^3;kc0#hK=cmp_4@wLzOMDy$0yFQjqS5O{d_-DB#pGR_t9E= zIg&e$Kk#=9BY&q*$(8;y{oR)|-f{e%^%&ZE{6X#hk8&}8-xHY6^Lpwps(yj>SjZE( zV?8?7BVR!Mryt1Sj52Y4R`Sx$7wa*y9_0$^?|vy)^Y;PEg;b9}l+y+2|0CJcp2;i6 z9oV1g?CR&)-oScQ+E;$>OJ8CBi^!Slt#CcKpQ>JIAIKS3oX?rdt3F`H72CYca2xfXu+^KDdLPv< z;e!6Qs*l*lHRs!@y=8ZMp{lQd}{YPZM_)%r|F|_lN z=gS=a{?8xM_<`-OII;bn?Jqd8{f_O=Z9jIg{q9qn`xnVGE~nevKYx1V5#3uh+xNCS z@cVDPs@5?dAWQqbi0jqgNA-AL+E2y0okp&=m;D{7KVF6>$eEwB>+5Ofd}g-4Vz|8K zpRnT0{yFw%t?4HZiR}8;a{|PJhzfs+e zPt=!PwEN#`+=vCc->DvP#zW2jWA$6m|AhH4eUo$$aF;XJGx zw(;GGR9|?`HNQ~Vy+{t2amB!SpRmnmJ)-k%$8WB{Uwi$=JL|gY?jplM=K7;OKUnn@ z+fj74S3Tm4?hdLC*!o)&zb`K6ub}I4#CU$?8QlfAZZY0exy?I%ZFB$Kx|s)Z#?`ck zpKbP^$QApaZ?@;ZZ0405oc3$NwtoXZH(So+6~p~E=krfD$44&MJ!7-oJ!~@%U@k>kzwHc+)(D5 z;a#L3Y3BmXL3z58Ojnk1e>q%Lh67}OJ?XD6yBo-r?bRD8FE^Ic&1JfU9B)beuGH^F z{qC~6k97ByE4J5@b-cRz&DW5_HRW`m?5`!qYs>CBa=5PajE{_Wj1P>j=ow$oF}{3D z*MIkIS-&BBe%^;aC@+7M`3rhqam9)Diaq@j`afyhh~bO8FNqcVMRmJA>%%p^)kpTX z<&NWCIqrq^npvm9`efP@?UDBU>CO3_$*ak2yUp@hjqg4uBhJ`yeJ@;>nRSm`caH1Z zaeb$I>%6x49oP4YmFv9ldYQS-GuQdV>nCxYk6h;i*LUFh?zz5KwqLo<7q0V_{i$5% z%iXkJBd@>6bw2Fo`i>mGXMb0Yf9CiHwm-1F#T@^@aR-jOXB|6^+i~10R*rw+_zTCM zIsS>`PaJ>XxO@#o8#|!9-DBwsIHTWv-$m?X03Do3Yi|M z{$t`gdlciJDASYVg7GQJ?x}LX`ZW4IU5?L?agzC&a>e=zW&bKU;`|o+y;X);_HU!# z+hxJ}2--Q0@EGNl{R-^Y_(Ii}moolkvU|CVIHSv|514Vq!2VB|U!(rvwQ|CAu=0Zb zb;=_aoL{f{@CKQ2#qdVe`!~si3(oIQeR;R^?~x-G?B1(-#2I()2j)L2>)Ah6;}S0D zAIEkuaNSH;p2PN@E8X*C#_)XQ&%$-oy-4*L*B3LM>ngsQc63}H13J#@_-6IX@02UH16;VSeNubD zp4a2d>#^r`m(cV2n|b{?UUvibuhe`A7j(St2F#dv{VnKu{Uz3C!NB?Rti#IjR$dPs z*LlQ=>$;+6JqmW*4;Pvo7(S-o<{Wll^Y(J@0=c96qh_{XsfT_rA^f@?AG`_b}ywe$)Gv*L^j9*-s89 zmhl-fPh`f===gm+GvA7Vc`NoG&~_4r6KK8(EBX_vK4QVl{;U{IqJA^`=h(jiR}9Zo zzqWqyE@nL*y4mi`dd;SNHshmdUml|QmrrbNr)@vqLG=~G9hE1n*xyO@gbVsRtL`5v zM=a<+NgWGzUs65djPA>-514Vq@D;UBSb4v^zm(Q3VLQIP-T0Wz|6gY!xBq{3A@9pV zRr2xL!aY{wTmN8kBDe9GyfePdvzI!v9{aTQHS1@W#XoNIeA#xJ1O3~24<_6G+q`$L zKssxVb-j_u2mIAAL0EBb)r! z-^1-5Y*%2r0(_!$p*L+WqFb z^iMyaH65b=8`cF2wod)Y)IZ^Z{^Y8USg?(2jwe#Tg58OgBhKhfqIw(GT(7F*2?xjt zEB04YJz*Qy9L}fX%eZ1Vzv>fKY~z~qU)tvyw10z>8CML)+r|C|_Ww%kKUVCo%>HBB zZgYMS^S+qvV{7l9t$M-*!z)yuuwon6?9Z%qNVuRs3)ck}Y~z~Yv>X>!>`%vW;eu^k zb9kTjGvkWk{p>$hY~z~Ylx!a>_8r^D1>3mh_&RN;VE20E{!KFBf^A%LeV+P-=gSGl zmnj$QUas86HHW`ZJ>!bY->L4;Bu5<1LVsLw@$^3{{c$)u{c*+Rob*2z{c$)C{c*+R zeDps*{c*S;{c*+R!u0RykHbaik1H-0qyNR}kHaPDk1H;hrvGK=kHh8Yk1H-$p#K%= zkHeMdk1H-$q5uB$$Ke3_3V zD=s&o|4r$S!_DcBD=xRB|E=hc!)@q~D=xRC|Ly3H!yV|4D=v4U|DEZN!(Hi*D=v4Z z|2^oB!@cN_D=s7b??Zna?ni%Iad`m!A4q>39!!5+ad`;+A4-259!`H;ad{;D6a8^` zH2rbK<+1dC9Q|>40{wBtr|0J*t{Be1&qu6i$M5YqzjX8Y zY$5O07UpGYKR&r5xA!AFx%H1GXES~_&BY1r!`nT7AG1=wK=V!s>WO6aty<+ov_a+B&+kP^+nCxC@_Q&L8axvMx z%8Vzs*KagAnVik|YO;Uz=KRs*Y;rZ(zs8IwxBGW8?SfhSiG)+%?JAcvSY;rZZ&9f{08?^m){DIuIx2tj6`gR4jE3jRG#QkEI z?;pKY_m}qhC{J$pyFfm++;5WE-(s?xb-e9(g2~C`LT{{C&7^GB02`DAUP zw{P|jCMS~%xsCVl*c=~C&g9nLy>qjFFgclA$nAQlCcAf;`AkkG7joMl|L)E4(d2A$ zCAaZy8JpofoAV`;i^=Z2oBe~y$>g@3X0h$>GxM38OfDw7_nYx1x9v8^OY1pn!R|83 ztv!<9(q4 zGq!Qfk@p1)cIVacMx4>{zEB(2T>hl@fBc{2hy^>|ABsEg6Sa}DyCVCKGdkWE8ZhJL zXy>};YF#4E*!qt!U`8|CO$X{YEB4o7J#azK`Lp9k&U?Y`zt|s~(Q)0`@hkfks>V%Nv1fe} z+VSqp+TZCS(zZ`$;rOusd*#u~g56mUdwhPf_G`uP6y>&^;bqDhR}3%bc(7vsR@D(9LD|1qj##jbYu4wh zU;hG`Fuq)QMwgY_xMn(7^#%Rwl*1e4gcaMk9r^skfEm+EnHT-bly}DQ9|QNVx{Lc) z;(oQD=YAErU(M~lbvDj}*+4v_wmYNa^BMJTRqy$nM#6Yz`lI9X8TIe!&*wA}#tP2&!`urKcCY` z7%xG8beB}Fm!dzP(?}REOMi5HKBHcq{(Md&VGQ&~$LBNZmFdstG!n+E(jOh4&!|_U zKcCY`7_UixbO$QeYtjGOGGV+f{n7FHjCwu#^Er)#@rLwAcO&I`WBT7jCX6?uKf0UK z{}%M;a~cWbt?7^MHuR75=W`kfj?ZV*JJO%eX(Wtyp+CC2D%ZQw|L!tjyeIw9 z@%fB;Z~F5&jfC;O^hd|%GwS{6{{WdVK8XJ49;{psqW?qakMUvjNB400KZ5>`q(8<- z(H|Y3&!~@~KcCY`7#~l6bWc#OPo)2oWWx9q`lH*;=QF~-`Z+RT#r_1UcYo4-E8>jp zHa4DC|IRDeosNJ1;*5^ZeYA1Su4p?EXLS5tHDJazuGzhf@i?R7_kaO2wsFmwpS$io znrFa_D+YcZw{gwo##$eL6MlYT!S1H4AGUGLayQob?i>fs=7uEbNTl>#z ze8L6&7gQgypdH_Rk^RCM-NJrhMms*8UHumH=U}^7usf&fcKmvK9bdSEoUmelN7WNf zcU7*~-;H)$(BED4@s_e+cPr(HGrC)=Zuf7Xo^i!+8}*;Cq8*=3%le={9qWSyyVD=` z`Yar`zmv8%V!`gt91qUu?xOmD8CMLf-^e-@?C!yQIHS9#>h}1CH*3E$t{C2;`h*qj z_&%#&!Ug>+R3EY6%D)@JtC=4w_WXMy;lO@pTru2B$1`C?yMN*KYzHg$cVNG9K|9{x zk>kLE-JMjAIHMguy_TN`*dMIi`YjjIarg_%5nKECPufnw?lWu`XLO%cy^U)Q)HALa zKBxW@R&3*%`K;= zj4OtltGyjpbE00czlHiGT+nm>Y2%vt)Y`8V!)e%mtk`q^Xycmwe{)>8p#LA$M=aR= zSoMfAx}T^%V8-z!su%2D%6Od7@!X~DS95$C<8emEbA>jp**%;7IHP-x>H}tM zbIc3xAKSuyLNrGf#^?4e=OLYO!bH}n&HkrhVfXido1H|Mmv7_nELsTGY=N* zKEXU_$FKa{4qsBg2`lzrRz0B|Keu^5seS`yTrqq~?RNY`y<-1qwucLP?oW1ncLTki zBF^Y;$mio3N=h@@yOuIMP_TT313LM@F^hfjc6U_DolOwr(K58Vl`_*Ln zXOm}>i^+$#7RSZ5%JJ{V!THZ^-v5v8V-9S;-QNb2Bf0HwHtoCH-fv z&FLw69#ye_>gIE-m30cU_GjgI1JC0p>J|I9so(f^_8+@P1~E!Av-<~GVwW(j?a5ce9oie^BfbOD3|IzEpv@i~l+&s$7aX8xat3hYHI@IBohx6cpvqH}&E9%}mjU-#$hk$5P_ z$*C5e2aOlg^PYn3U_H6xIbdwh1L=^@tZ^%bvnaRmhF!MdtZmxgDA3f91|(p8u75ka_-B?nCDJ zUwI&z=YQp)WS;+(MCSQlc^sMNf91(!^Zd_0NA(d4w)2yJuKVwPt#AabdpQ0GZqE5% zZ0>I~Ih(w@`K#&ge`)47Ig{Jxa|*eApN{{P#ak=)j6 z7t6j=PW0c|p2@}JYO?$N=6ZRP1G%05WZE;itxqMl>nHqSbG;I|wO7;b|G2pxiQMKd zrrrN(v;WS*@E?ixo$=&${Z-TM|GYV0GP#;;w|7Ky_={N|ay$Rov{%#a+<}K|vK?PA zIhkBccE>a0P2Sz{B-6i;Ps~7ne9hmECy?9v?{5A*ZI5iPU2nx?zt86JN0YP3d%8bI z_V{Y{&+n__X~&z$?fNLD-R_S+fmsiev&og*?muonjc?hLclL+eu8&G?`{z$+wr_Ga z+3x@Da^1u6c7A^%v)(3Glf#KO``h{QZra^R%=(hs`bCqo$<<`LeVhGB&G|4nn_S5| zukVv>jt}J49!+~T?ZvdalWV><-jjEZ-{fp^HQ64o&Hfad`yWltCRcLXKX=N_@qygh zqiN5ky_j~_Z63ef-y@nk=4-Fl-sDJb>zhrkCi_!u?q49c@yWDj(_T%xJGEIqa$CP6 zdc3xOH1pf`OndwNr<&|fvw6IBd~ezVx&1thrahTk zH2Z}M)(5HHKbUr0&>y7why}Zcs2*`f$M?_;=zhd`#f&S4|5p2i75o2DJ)K_bvYx2cnGpgR!t+}33_0ZwzjUtNya=F8VqeZ_E~ za%(U2@2;VG#MVBy%=iIYdv|rt3(nZu`vW-7xL|AdSL1wR!PdTBL+#<3a>CYL$^C(B z2V1*i{D2vE+RcB=U)4PBYjVK!b>#*9H|S@^XZo)g{#pGdtk^S;8Sc_;*be%rJYvDF z-9OC)<*_=C-Qzf)*t!+IucPC8m}C1sW;zUfFKfmX!=U*ltk~vl_WSDd)(IE%Cs2LF zg57?qN1V}}Q1t;bt{6_F_6aMNTWGzyTgr%S|LVw)TbWnPG7CG+EgzEgd~g59Z9k2s^_dt3(ef6I6* z*!>;jaYnm;k?)0?(Vao#2F$o(IHTGptl0mJ>IoNgcV<4!xMH{q^I^sQuFQuE`n#z< zVsN_NC#={XkJkq-Xpi3?U;Re3?db&C-hzHVwvPq76RK{qmsy<-G z6~l+rK4HcAVAb907>^lO46kQAR_x!Pdcp-gzppOOQ@ek@9I;^c0@WkV=w7J$fEiZ| zFH-yZ3mJYXC#=~2O7(5zl00=+o(RG9bc$-QT-y$=x(d}fOdSQzGAqY`cGJ~zrE^qe4@Uf zzk~XXSg^a}VULg0=hl8F^&2qbigx??L3;hJ7#__104w$fscy%Q{9awKJB@zN9v-It z8CMJsXMU_`=WRJM-`wUst>(|@aBaB_#BwFAM|WizaYlC))(bPP81`5DgcbX%s_w49 zc+9wBxFX}RVjombxS(f$NA#oCYs7-xeN>M)qd9!nokHssaYo0#y9Uf?$M^Tvb`mb= z?yLHM8SQv~ppJ9Ig59-Lk2s?p@2;(W17=(?Tu1E_R_w2z9gnrc1UpfC+aQVLK{@-XvyMNtx)gE!i`aRWq z=1FMByQ+QzW?V5a&xCgT%5@R$r+Fr9{rn?UAF*I-uk`QluYL&^^bcS>7VI9Vdc+wW z_qhSPL_eI-JxcWfGp-mOt@a7q{#q0F%?15KG_HSyOt_#OANhC6jP9oz*Zo39oY9US z=$~;#|8tEWv7j9vR`r{(V*fMM6E0}S=X>b)hZVy;l_#v&^ZkEzeD@*lUpS-tM}E#= z#udYd)jnaxzNntC{z}Ku|C-~$1^sVSAF*KfTh$}Z=zgdAfa&Sl-h%!a$|Dx+CeuR5{V*d@*6E5h!&3u?~#lXM6Cv?B0KW1Dpu-+4f zJ9GcUiaXcApP3Ict{DEJ_6c{!@gJ3X@Ay3y7xc$deMCFn{hsy5j4OsesC_~^KK@zl zGrGSpA7)(9jxS$R|L&h<#2MY!nGfyw`hB(c|0WYI=>J{y5$*W!1+`CDvHv3T;evL& zUzi_ld;GTAXLR3D9x&sIc6|63^`FqTr~gv>g8qlfBNps_q`Dm+sn5G;cdNz?m~qAM zGqq1>=daZJpC9)2-Q#q94w!Mp@ObX0c&PcQ_fO#Z#|8Zpx&G0P?@!F{F}R>V3BSi+ zK|6jrx%yS?Pr-b+pg*PRc6{c#UNL-w^~8$(HxGOL3fFb_A8L;{qx*sC1KRDEMeW^} z7>_f$FEbwP_)LA>MSJDC?f+HtBwWycSM?F?{Dpc~)z7xO|7QO%taFwE%px!cJ2Pt z24d#ASTX#k#!pzW=l)`byYLnIW5xcfswZ5~j`!UEN3`vc^FFup|2@q+V8#{g_`uJH z32l4gyf5f~qWMQG*!@&>J3dmMchT;C#r|T(6~nL9KB1kzQty9r*xUEt)b9r)7VN&I zdc+wIH9tSs`#)-a|0g+OcT(NAA`T~0&X^dtU}@v{ePCvsqyLJ5`{npSZLeVW8(seq zXLP?+eZbuE@!21=$G1`s`>5Z975(K@AF*I}dDSD%Xyd_P zJD(YE^6qv!nf}FOcYe)(lpX)>c5p9m_pJYZd-*!-t%o1C=YMZK_1oj#uE2H$wkxn* zf$a($XIG%Vk)F#WT+rWG^$`o&g;@A}w!aqrv0!&?)g#*R({F(~KtD6V!o2?SY9Fy+$NaHv$BZAZtZ@aqt0+gD z(XlROxSQCoiv5)|KH-9%`R(}e8*CrDZz_jx%Lyym@sa*Bx^HRRfEib`<8!b6D~5ki z9xo~jb{A8&337+$BZk6o2h-mopJm}y@1;L z3(ABG`U|N(q8&e6TK}1N$GQ(_$9I=z9M0%2qxygu?fCwZ z>X&dqe<{^RENI71Tn`odi!dK9=($ep_?7D+a2_U%Tu*bmu2@$)K5{+G?YiJ|lC9tL zKs{%#*gr@);e!6bs<&~?`To=&AP3C2VqpF@ZtHdhwkxn*f$a(${tD#F>ivWE{o=F9 zhd+ATy1Nx9tmiTH{h7-CZQsAx-I?6B9~CR$FSmLB=}kT=ws}mNGnnHYOg<*<>vmtZ zE3jRG?Ft;5R-oK<^SQ!kGtV6gb_Z?tU+$~y? zTKf6ezRztm*=)`w+S~U@R`Sm8pVvNOpBM6`e=s?cclOU@yMMdOiSb9)@1uqJPS7@d z9UXuBemPHW``?q>dPVYy7@tk9 z?TOs>w{5psXm8thH`M$s2XdRgjoVv|tVdhVY;q;rFS$pTC)M+uuk&%kCyRhPKC>>v-DztdMusdpG-C&G>K&&DX|9a=ZSsY2VHC$NJ`C zj^Eu<>vK$b{d@MOou5eFxgJcryVd6Pa;!f=+XL9Hz;*?;D{vfLfyn*3-QTmx$I-*y z9@cgR{#PrI_@3GY;}7-un;DnmA8^P#ejhnv!ERsGBhKhfp!$FrR}A~9ed2qOEB1U3 zbKCjC_x5yr&vIFS64*MJ#YbN5HJN1U;>Pk&Z>#g*}a+})19gT)!$?NuKz zW1F{``JR&%!|ye2!iufGb@_w(`#;JN3-+`p96qge&A6hSx8-mG_6IBW`?1{93OjLbV@$M}dV*A% z|8$NI3wF;?J>rb{xvH-io~Jxv#s2xK`rb{)vB);UZXr=#s0Ob`!~rE z3wCc-J>rb{9jdPw-l;rc#r|EY`wz$w3w9q=J>rb{qpGhMKBhcj#s1@}`_IS`3wEDX zJ>rb{ORBFJzN|c9#r`X*4^NR9R}4>O99CSOrMiE%9I;^c9MvNZFH+99VtBFY6INVa zp}K#i9I;^cD%B$nuUF2vVt9k<6INVi)&1M#hy}a1s~&N9uX4r}!~0a9u;TJz)qRm8 z7VJKvdc@&V${AM-pH_Xsipv*N_g|DF7VH+)BNo1ws5?IQd7QDFO#Qo)%l5k8aUXtu zV8#_kzIUZy*XenC#2MYGR39+o@@38MzamF0*nO4##-07*Kg#jh|9v=aoYC#8`ha$P zroQf?-JO{6m~q8=61Ddyl?fM|xDQwCKcV|=!QRCXNd;&b)3N_wNA{_v@wIw_m_$|M+I{KuUq#H+A(pzUfO;8-OT@f=EnuyhZv6;XI{7NqqJlCxblMj6UzNR z$%G5K&oLe|&b)3N_wNDISC}9DSC!+F<&5qr$}8tHJX3kXiaq!7gd^v(VE01i#~B^> z@0IfzGV^1_p8I&hk@H!wdmZ!RjPCWSubj{DR_4cw{j7Szk@H!wdk^#DjE?*F%J~fc z$oyEb|1k68$oVYTeUkZcM#ueo<$Q+EGe1`Bzrg%Bay|=oUt`?6bU&!rznl99F6iH* zy1l=x+-Jk7b^o2PVt*Rd6E5gatNQwh{STQkd{RzWvHz6n2^aLAR(-^R-9M=waYpwU z)d$SDV)(4uC#=|iPW6Nf`p>IAV!`eUsz;pBeNpv8t=~`d^C$dNPFS&DRZqB}|C#C| z7VLhmdc+ysFH|2eWB4bX*9j~3pW!;d1^s7LAF*KfIn^W1=svIdfEm~3Z?#|HcXGmt z{qI#zXxDF{?*E{EBNj}2@6v+)x9mR_?0%=Zoj+2achR2sp5+Do0lKb7EZAL5^+U~1 zeQxbnSHA%>t{ASN_6aNY*Hk^>f`#u9?yjfyh%>tDvpux?m#ME9Zou}jVt+%nj|=)6 zsXk)Cj_)&`FQs;OX*poV6~krdXLc}LT=fYn_LopS;euxPZezWx-ft?8k@;YmK8RnE z{`)csqn_OUo-~;DXmT<+oAH0`lI}mWWrtTT6v%Pb?=uEXAJLAeZq?Ud+C39Ipc5z<&3V$4h$Dl`-&OE z#Z~XGDihA{Qf~V{oqRKgA7Ay5rU~=^D6g1)p}b)ErE>Qx`u#zMKg#}3GGY0Va`)eI z{=IaJ>#nT*i8!OXit7DaWWwQK<&52H8ISEacf7$>4*AakGp?9!r1k~EG;?EB61O zoG_e;{#da;v+BzQq`#mXv0&mj7mTaUZ~htQo4k_4&pH2`pvh$SYqbwpey7}V-Hhka zesr@e&u4vK!205h?uDukm~qAMBDGIgv464Z2^aJ)QGLXM-Ah%EIHP-+>H}t6F}z&u z6ISfA>IoP0uTXu&g54`sk2s@ymFfd#Trs>_?Gsk)U!!`$1^sJPAF*I}u<8+Kbgxr= zz>F(~*QIoP0 z?^k`qg53vHk2s_Ipy~r=Trqq|?Gsk)|55dX3;GYMK4QVHs2*`f_Yu_x%(!CssM;s2 z*ndp*gbVtQt3G1E?h~pu%lU@(d5>znRe6O`ZXuB z-r3~VZ>v^dHtSnVw(GQ*_G&?z*b7%T{@{#rW3Cy=I8;)jsc7JS6W_&ie zm|RVE&olQAlY_~T-0mmIv}cox$<<`{e6xL%gUQk4WO6pSm|RVEFEHCTIhY(xP9|rQ z3%RY=Lf(fHxtezOLhaAV+Vx;^A$PQg7j5o;G&z}Uub(~5+00)|uH<(7E4dy2o^Jox zKE8Xg&R<&}Z*os=_nTnyo*w^Twiiv_)A_gKw=1wGE0DMzclG{Ge1%>=`>~NsZm*|8 zZa-i5WM7VovDNP1D>v`w-sE6%G&z}^$?g78OnWuiy~=FgLW`9f$CP$N#$(g)!J(%`t zvg7Zm+Uv)g988WTCzI{*F4xp^fbl@-vEa)4CxQ2MCT#O0-iKMx^M1~V?%kSqz>F)7 zms5Me?()iQ{_dj6Ge&g0Z!_($_KMNGUlUHgIbUq=qoCt`ngJ`%(|g{p@w{I%;=ubZ z87JPispxsXX2jUuuW1KlTzG%XUrGBpV!?^$G<6rxYs&TXoTt0Kj5uSsq3RP>?0LUt zz8>pyeK}x8_W|mdam93?=3mfXOL@fg+8Q6OBPXmFJJn}&r(%1UaYeIyF7iIcjP7lW zZ(dkAnqhBUd4Pf@4w(gy<(=mV*hH5OBmj!@e}$R zseQz0RC~p82eo&1lIoP0k^46m>~5=i#2MY~R39+oisANZpRi(o2h|fU= zi`plw*xyz4gbVt+sXk)C?(V8boYCDw^#L=k81AX|2`l#ZQa#~<{@$vOSg;#ak2s^d zkLm+vTru2N?Gsk)@27gg1^xY1AF*Kf0M#ST=pLy0fEiZ|4^sPt75fLPo^U~bkm@5A z>>i?e#2MW~RUa_pis4~upRi*8aMcqo=pUi_hy}YxsvdDhmsB4xUbk9(Iz>F(~N$nF>?4PN6!Ug@aR3EWm_iWW8&gh<_ z`hXc%49`{jgcbYesh)5_|9sU)bPv$aodGkh7#^th33q-j@E_AX)LzlHcW>n98qVn6 zq`Te(2@A>^VB#oc2 zd#c7q47Z{k=Lf6Z9YnudsC~xefvWol(eIXOA8@2zFg;A|3l2}zxQvzU_P1spwwp0g zUvQ-!9-?_BelM(;`Mqz&<++;I^ZRP$_uQV}NBwQoKH|i@71QI{e;l8y?Uv>f)ZTIa zJI;T^dIq)kXOsyS9Im2z#ueN3vA$I8;bqdjQQIGIqFymmU(r2M;|5%wtnvOSvOZbu z{Zr)h0_x~*uKI`**L}r8z2o}mxjqtxhcYjAPtg1kNB-SZF!ArErOCeoJpaC_{GQ+Q z@0X5$pG5Th`(wm`e?Mf5{JUhv{3Pw)+T?W`IR1E$+GkuI$ND{9Cf04i{)N=B@Oj5} zKCR=6HGjdxze^VEUZVDh{`H!F#F@I|Iw{nlr0J!7OkW4;N;kKO$=E@HT;+9#Z; zJMM#(de8lFpq|kl@7|X4d-VKv9}c{jT*>YIiX*x{>mH6jqT4&p^?&c?^L2ZCp7wTr zdXsJcZQicH;jKV0*Uw;bH2Lu6`rovTX1-+dWO6onHo2I*m|RW%-|XXYsn5#sxBGqf zKHXp1{o}ZFtpER5Jjd7GPwdI<_>XJHyFH%m3T#*4$XkKP{o>X~-jv&!_M#PtA3SdV zd_A_G%Ju4ceh{v~a|CS1RmnY{14`K12gYZducmn%Ii5~=Mt6GU0ps7&j)CWK6OM0H zd%=~zOAfDN+-s$yp0A_l&MS7;Q+veBc31R&qxKQgJCqk3FQQz~pN0N7Ur5F(~->H4Viv90ZPq?7}gX$v|?Ea{F z#2MY6R39+ois8>{pRi*87u6Fk=$+2*hy}ajsUC4gcYM_c%(!CMN9_|>BVa5K$swZ5~pG5T$3w9?}J>rb+WU3FCam9AsH|xpO zzdwa+^{rZg^tsLFo7v<-KCb@z_n3YiRMvmrUG3=SH-CTXOy1S7ZGF1}hqVI!Xuf`W zv%O&QV6xrkXxc}UlgX3GcD}tW=VSSL6!yQ}AFIiG+xa}wkM|4a=Zncl`u4UHZdc$K zv;v;%{kZyk)ARq=YWL4$(9$0#b|oCc*Eh0%`y3}$`-mUJa#cMS@CV2d+f0SrT}|x~ zTl;uP)eE+I)1Q`kv0%sZ&cbuWj^~^8)au`#MlNrWp68p6=avJGgW3zGHV*6CnUCj{ z%Rew5&nwfJl^5)IUKyJ_kL+Ho&y}^~YNoR>9{t&sM|9^@9x&sIg}-ZYKhyl(%IDt5 z>C1XIoP0-%x$Tg55V&k2s_Img)m$ zTrqrG?Gsk)zoUA>1^vIMK4QV{UsaDdqx-Jv17=(?RJBi7vHzax2^aL=SAE2S-M^_G zaYpy=st=fP#qb|$pRi*81Jx5Q=>Jpo5es(zrFz5}-49hCFyo5hM{1w2V*lT&CtT3~ zkLn{9?0&3z#2MXBR39+oih<|z6Smh?Gx0h31^xBdKKfJgdc%TUr+PZKT+p9Kxy`?I zy8_!4*sj1aWd+jrHlH^fQ}*lFx*rqk**@QQY(0+ces5P`y8_!4*sj2K1-2`&U4f%( z1+w{lw2<5P6&`9ozJK_?zjnK6Kh%6jaUmXbjYGE3KTL*)%C=emB|VQDvDKU5t7@Mx zeqDJ+_YI!sVH?*B-()-%w$puCb^mj%=e`UGCP$N#$=T#$ay8lgVsm@m(9>9nf~77KyK?FP5VgR)xR&2=|7pAO}6_toAyH9hmO@` z_p8n0@5rrxZ`$qlY!39_IewFqnJ=66V%isztI4a$?$_pc$UDbl@?iQ$)1FNGWO63A z<1HpvlihF3>&4_?ax^)aoJ}q!SMsi|H+%jLm4B=KJrNCo+>SSzb~`@PzN_ueyJ@%c z9n*6$>r+j3ztei|YCU#$eBB<7-`)J%_B~qx&-rPuk6`ki&3@b;9a*n-zp+Q0chg?& zdjHEHG*n_Nxyf7sl9Ah+?!v}e;^O}qP}xgV3;^=9|?$j;GhKbu@l z_J1{~q1b`Sx_Yf9n2+ zOfllZ_i}muKC-*F+9QsS(sP4?Gj%trU-xLWM;xeUoT{b32iebheT zz_^T+dVgQ_Td9Y~YW_rh!HIgsna^Ljr)zxVb67JD)HAx5Xx;%=>fsq0pIaUM6I35@ zd5*?=z8}xum3A!H-A(myXE|ZT{w}KfcQPIecJETXoI=~{PATgLWdA|Ayoh=Del>eN zm0RfZFx@TX_zsOL7^!#fRDCA5dHNe_{(Nt>C-O>O$f12-`lHo<;`<%D$0*nKeUH!3 zJZ=6+d!oLW_L+7+G48RNZzPviXTpK@?wRTzp3MGW&-qL3Jl=u%aNv8bbNhbl{nhSS zueRSi-bC#KF89%P{e5M3UbROY&ZnGlrtZiqhV#>pG_WXTo-T{o^%XrM|vj{Q}ovzLVNlT=-sl&;2DnLhUp5d_QBt%=b2~IP$%X zrG0-R-|N{wih1~6PsjI&Ch7|g)N_;j(uyPBYgn*8RP*+Hf9K5iHafn)(?4A8Bd*lL zle7+nddKli)GN9tY5dUS`xi5=+*jLrTm7fBoe>LmpH@BMjP9RQAFzHxx&Ne0xM2L4 z>NC2JGafUp7?^LundjqezpHsZKE7A;73|)p9C1d+bv0nd$bG5JzdmI1`TP1V%@^J+ zC#=}NNA-jYdiE#&quOV5A66bPQg{pZwPFn(UyeSvY* zJL)qIv}ew9_>B5jOrKR=X`iU~)R*Qz>-zLx=Q_uN-8WQ^IHUWf>dSvH{s)Z5g57^I z9%pp_rTXwinQ_Iis6JuE{!6MS9RA37TrvDf_2FM>#}&hORiCh8UsX@oIjv*F8Qt+z zAAZdIxMKJT^JB&Sr_7JbKAOkxD@QE2{8Ih>ujGgYyI-pwaYpwW)u$6`-irN+loJk| z$BZk6Z!sP#_TN@L;lO#!xMKJrARhf%BYk#c+JBr~1Ho z%(!Cst;SDSvHzXw2^Y?@Ke6T;vEaga^xx6A5es(zqI$#`9j~K>^XUJZ@mR3?AI9U1 zj@QY+dCa(C_?pH|Sh44Rm2lxa`@gV#EI4o;Gp-o^o%yk1&;2an#CfjR^LkAInzVbH)_|uh)h1=zq`gVZrVXsz;pBaUbkX!u5qSx|6D2FT?xWmz4<@ ztU>>7Xg`0g@d|36Fy-tbG?eA>Yynm2Q_TT0?8OHA@&$u(s_CK~Ouw8-e3LL{$AfNT{ zpC8P-X+MS?&R>0Z%67f}>gQm)1KSnYuE2H$wkxn*f$a($w^v}{_pSDPp_;s!{MTNM z#XMh_%;z5m^L!zFOV1M)tlw1b$(heFtnKp*7uo!MzBAdA_ua)p1lrqr4kkyF?KGol zPbN<$XOj!L?O!$7U3ByBS-i=1e~xGl%(o8%qshtSOm6SL&g8a!#k3#M{aMU>yBlBW z-@Z@7Urg)O_9u|r--qpPzGGW^GRHfaoK2oh-qYhPX1;~ou8%#Pe|O_6+iR~Mck#{h z@5wvuX2L-GX-&PwYUXS8|FxGeuV0gc$^Ywlk0Tu;$KPI`+2m@nzogc)^^fFsy^SU( zlP8n+bQv@Awf(6k`%7(}|6pF+ON z&M&#Wev`?2y8qkp+ZEWZz;*?WsVk7p{jQjNOx^FJYQHMS-+ta7RomIld+b<&#NTx}6x$_u)?D-YPeUOD0PI^~Mv8>UoKOn9R3S`-ZZY};*Cw$q<`b3b<4AEJ$A|av+xvslDUxYe#b1zxems&Ww)r8nB#2?Okhc z197;v+B3R)YkLFEA6C07a=?r$hL5Oy!ixPzRZqB}|Cs6{7VJK*dc+ysCsZFWosD*?(C{ZoY9?w^~L=6 z$}0x1JYmKDtg0tm(4SlN5es(bQ9a^}?!2lGnAwjN!#UMHVa5JjswZ4 z_7`VLV8HE~0wG86DdhFkVvqW^|WQ9?)Nc`LSR}e}7rpv0!&O)g#X6F3ZQH&$LT&^}?j zx!Pwe%-fM2;|44@RR8WqGUAN&DysMU%Y+O1tExU?!R`Rn!!6~675iJM?rtFm%(!B? zwc5Me$an`iV~)xzrrRkm7}<{*%Qe;B9Vp$^JygfNqmcLVBpum5)ck69~_xxU)-xY^`l^6vJ2G5xE_ zyBlxY*F79>=Q~s$&Hc_~Z}OqWn?i5;2a`?r-Ns=L$M0?f(ab-ZoJ`)`eB1V8_6p>$ z=()g(^{dML*LYrl3;KUneZ>3?#$*3o#^Hj#s(z@|V7mhr=Iy?&{`qvwkKy#n6UHkk z&*-kKJfIKCBNpuFA9#K=VP@QliRVBIdY<=;=x@*bSg_;yPvp7Kj4rZ&7;dXPVa5J- zs=K?i>_u_wci-I{$yq8W^Og!vKQjS+r#0>cUoBak>kdNH;1dkX~(&~@A2jl z;gqoD$M#T3DVS9MQIQyrBm278RI4yblrhY}XyUl)XH$2ZXPYcJ#-yZ%S$H)KA z9XF5vf4?99@9CJ9`r7sT|E~X1e>nqR&cK&5@Z}7AIRjtLz?U=dMjt?RO!4?RdeTFyty`Di&GE$5@Umh;ha zK3dL4%lT+IA1&vj<$Qx-IUgS z)vL=Y)61~bc3Hi;Ec7L{=u0g0B^EO8-jz8PGRH#Zjk_|(LgrY=91EFaA#<&^D@#+C zHK@yK?CL#g_wY7Q8_VOZ$H+ZiS{^Sgk5{!ChibblkC#4=mzKv%%j2bm%)5^(v^-wb zs`skxvOHe;JYHHJFD;K(wO#oCs#arDZI|W!n_7%5wXwW^>GODT zrJwQA@_1=^ysFhGRoi8Gy!3gzv^-u~9xpAAmzKw?T8&b*U6#j7pT|qfCs#c>^ zZI|WorWT`2Z7h$MK93i7N*OOLkC&Fmt6GgxwOy9SOP|L}%j2cx@zU~mX?eV=)hJcl zWqG{xdAzhdURoZnYBfsLc3B>8YB9>x#`1XS^LTNml=0H?cxidOs?{h}+huvY^m)9r zJYHHJFD;LkmdC4FjZ(E;md8t<$4krOrRDLeR-;sHm*w%M7NbmUERVN)rSsix4Lffz zW?*GLjR7#`(ijLsRb56CJkPRf_}IjZfT0)~_myVes`sr-p)nT5eWhCSz_3R#m0C=t z7DJC>=uu3m#gtkMJ&K`6F?F?=x>^i9ilIj_-D)x2YBBUEh91Rquf=q)#n7V|dK6P% zi>a^0(4!c76w{*?)1wwck7DRi%sRE0b!sv6D25)z^sL47ti{ly7 z=uu4XT1@X+3_XgWM=^bBF@0(=^eBcN#jIP4S+^ELk7DRi%zCw$^=dKnD25)ztY3>+ zzZOG}V(3v!LoKGE7DJC>=uu2#EvB&+LyuzUQB1#DOut$TJ&K`6G5u>X{cADwD25)z z45-BnsKwBu7Z2QG4v?UhP9Xt zYccdFh91QXs>KYd#n7V|dK5Fb7BjdOLyuzUQOuB9%#d0PJ&K`6F&oulHmb$YqZoP= zGqe^nv=&2;V(3xK#j>@Ju2P&l~dayde+I67ujY zArH?9^6;D>56=Md@C+aik9T=^yvxI*TOJJ_*pY|Fjyyb4!*wVR zSDidub@FhH$-^}!4_A~tTv76H{m8@hvqf$F!0`H!hwDckt{-{0e&pf$k%#L?9>qj20A9=Wb>qj20A9=Wb>qj20A9=Wb>qnkp72cWY!`c|7=IL8AFhAXz{n7Ij8vJB89;_&P zu%aA;`#5`WA7>Bd*&gPp*7Cq`9(kBY9_EpUdE{Xpd6-8YeD>ha!u#Xn;%0u-j86~z zi8MX>K$@OWs2WEP4aMLdyqi2UWlSqW95W|IQ!RK<&1jmPR)e~XTB|`% zr4_cdQ*B!|u&sEyjA><;+O}+9TaLlDY+zgQbQ!f)*p^#0&nz1tkDhq!uW7;l+Fz4^ zU0@Fld9a)8p&<{JggrFm!IH3thCEmj_Rx^0ab`Kd+k)XdHBYf;GM~Ww7*&(`0LBJ3 zY6IJ{flb&zW*f+StXd%tjkS~8;QG~A8ci}jo7^_2=0Omu;Hj7K`Q)}|EQ{&b4j16}IIVY{DKIwQac-w&hkBV6*bjP)zfT(jX5F zd8#!J4S7b@JT&CN6T&^vDvus%;CQzO^E}K|H3Rc(4_2lPtV|o&J2sGT_gX?5NN58I zH?AeLfrK`Y&;}CPK*Chjn(KoC_E66mY3O4D8v0ZuReN9)T0iv|ppG3INN5Ay=&mZP z9~d^R)5=T6u+ERXe_5_-KOR zURxsSkRcPfZw1R=Rw#UnGj2&-nFtBwU1ta7^z7g`EtM<^K zrxksEoG~)sxw#ed^OIlHj8=TLsudGu4-I)RWA@OH2Yb*S8uDQ3?4cnKX4M`V@^D+1 z)V4Lgwk>(MEqS;Jd1%PPO~^w-9&SP&8uD-x^3Z_C`{L#?IoHAPtitfD+Q6(j2D54p z=I)kSD;RDC!>wF}R<1%T7?U}Nr;X)Gz$k2>^EO7zh_PwS*rH}^QZqKI8C%-$PPw8s zQ5V-HN*+#>Je(hSXvl+8!5LSw6^%)3g;Rk&G~~glz#ba%U{=pi9vaGnS+$3TJeXB` zXw{jdr^|y)*h51eY{DKI@^ArMRvXtvwQ$tq9`^8;wH~(BdMFQjC=WX(4-I)Z;g{BCenM^L<-xYj zkO!M^3=MfW;mSipc{t(n(2$1{E)R{`woaFao%}a8`xG?)i|9}5Hk)dT%QivgJ63QY!3~^U|aUkkOv#JhlV`Zx;-@H!8vLl zZwrR=)I2yS>Ct)q`!cX~8`!7~Y|92VVFQ_I=sMxRTIK_5ne9PldX%|WEwc?|wt>t& zRfWtpkeP-u_o-#>BM%bxmWKvBK5yKr69~>5Fnk?l4}$E$6%h=dZMtG+PK?I}&Nffh zJTP)Sc5y9624iX-7~cAA+9p-JP7`Gt<}G4 zt?WT7dk}074Y$IX->v)>po<)PaJ6%qw^fV56_GtynWw824aH!>?V%wL=Gh(^-d4?n zuG)i+IfjO}Rr8>SX*Hw#q}IcqCAyIBl75o@iSd*4gY)Ye8pf7K!=d3l z;qSvK;Z@%>j7v32DC0s9ju(G;{`FG7Za5}v37f+`!}Y^nVb8En*c)tLg!9R}V=EnDC%JlTMTDRIIWqA_ghz)* zfu8S+!%3C)g>K&wc82o5JEkH(C_l*j%dy|4;^`WBOI!2wvSeK4W)bJPwrVs^`B@G%KgyxzCppx7G*8VZ^VEFQO3f#&&=}VkYBIVdx<$HLtU>6h z=>H(xhI0S%!4}8EXBSh*wCA$}=HsIS=HD}V&uBhLU_Boa+=qGjZpQyzjla39pZfJt z&+Qx;9uXcL9wiptd9z=<1D}d~yxpcI*}opj2d18P*i%c+U4CfKTUqXh$CbC}W|#YQgmhyx$n7AG=dY<{M7W8__Piq!aYH2H%3Z`|I?1~j z5jQa;@4Lik-WyT#)<|)QGel$sZyoF`u4Fdr{)xL&P6>EY3!^vGxsn&*$N(~o?7PR_j6 zeB4gWr|s-ty`DgGzwt>lzveaiL!9Trxr?L2Dc`P?e!mz|ney$vA@n8DAlKpXS%=5x zIJB-W){W)(gD$}K!Exs!z9|}%F6FqiKQ8U9>x*?`IWFywOMB}kv}3+fPE7j~)xNQu znD`S@e?sa{Nc{<^KOyyprvA`u-@3k7H(NuF6E@OKPm04>x*?`IVtT=N_*=jwDa~)P5V>TzOkH|_)}AV zO6pHZ{VAzGCH3c|{+w*zy1rO9mU9w+PPT8|RIE!mJMGU-d+YjQ-B`{}`?J&Dx(V&v z|8vv+-1P6<#Gjk`pQrxkssDNEf1djDQ-6N8Z(U!k8_W5LKR?^IZYtKLoR{|JrM-21 zv2HBqrTuwnZ{37;?*D~pe_{G}Vd5`L{ROGNAoUld{sPvIt(03?PqKb&_h?YMZ@HE6 zV?o6ahz8UCX`Y|Z{%M}SK;Cpw^PY>Ew{FzDbEAGU`pxLKqu-8xC;FY}x1!&QekS^v z=-;RRzgK@N`$`?x38`_`M}r&}-p5Kijd-2MkB!#;wXRX0`;q*-?XPuB`mm3*E~zinpZ&G2KK1oo^;fA~ zDOaZ+T5-_I@A^j8E5GZTsHfunyzkf%U|+Lax3XIO?Qi1x?pMzu4&&Zd{!+FR8@pKZ zZ*se55jqOU4)Yz^xNsaAFlhnw+fAa57jl9w%HS$W6)W|DM zQX{W4NsYYHBy=0{|7aYDd?NCQC9Ds7iTJD-AKc?Z+O}RHKKL9gT_ZmHr^Y9m^5b(% z6Cdx>UuKsdkjNthu<||Jilr{;&JANB%Wr9 zc$g`cY4L~nLIeG+c;NgMvSPMD{}P|(@MCik+YuY5#UEmO@?(195?ryi2Wq?pYHe#!XY8{ALoVZLd53?en7Zk zhYjAIej&8`6=EK>Uonp&=23+I=j;dkBK#uyeK!5*w}^g=h!+trB3`V^ zxO#-WL(G@*VZKDnmx%dQJIt?$`4tf_B3?wihWA+KXr}qW#@zFQWaw(q2S+5$#2^7tvls z`-jtBMEl>Ty@>WA+KXr}qP>Xre@J@~?e9r@5$#2^7tvlsdlBvLO?wgTA4z)=?M1W~ z(OyJ*5$zvMdl28}n~obKo=-xwmqvRL?M1W)aXy)e4^%z>B(EnA&-w9ip1+VsnxsZP zX_6Y}MQM^6=S69f8s|l6k{ahlX_6Y}MQM^6+dnkhKa?8Vl_sgNU1^dU+m$A%v0Z7B z8rzj7sj*#Yk{a8UCNXcV_}$*|=_71KiMO@d3h_^pPymTe)x`#c( zO4@Y~dxnTtJH(5K7jayi!v264aQpq+OF!xj!XaUqQBI}5KI|33e<9n!FTyXP--^dL zMf6*QU-j^d@QeLZzd<-8gkSaWi|~tesqYc?4&hfl{385fztj&52Z!*h9)1yiv0Lib z3HyZbs~&z4eh}+qTIt7iMRLDm-4E0{137Qd8z^qJ{S}aY(Ee%hgK4jPXs7)F_D_3n zXSV%l4?p(bjPh#sgNXe=w!yyzw$q0FBf?K|9d5~Z><1D1LBu){u}(y+6A|0jIsvs# zaJ_Ru#`PTYV7>RH1{>MW{?kfdj-S+VF|9Q2X^r~Ht=LZ*KlYP|{UpM#@xm{{FXH%7 zeo*=AlAqLZmi*AlkMSuU;}bDH5yzS8ah!=b&T8@Y&xk+7e5f7fL&SWD*w2c`aVFw8 z6A^EJhX1rhHHBKk9o zer#XFc17eFnmi)%fVc2|??m>Wq((kzk{WrXNowRdn(-tx`Xx z=ChOWBsJz$nxw}3N|V&+|C{O0o7CusG)awqNRx?wEAek7UK;Vzh?6E0za;TX5-*K- zX~apBiC>!drHPkDyfosZ$;5w__|FnAjd*FqNt3L{JT7KDNsW1wCaE!x(q!V7Cw_V2 zr4cWUIBAmgn0INC8uKnqQe)nw$;4}Wh}ZTICru_^8u8NDUn?@+6|BcNrAcaxQ<|hk z{ELZyG4axfmqwg4iF&?I{Fv8i^ev9a@h<@6ib~x`UAI`fV-iIF7 z{drq`*ek^IFy3Fc;rWz^=V2nQM-Gxd#Qmu>;_VL+U-O@rJR>Ydd&95#blh6M8PwRv-2X(f@PPPZ9kDwZDGK z>tpO65&K2N{GUZX)}4s?CwUz{ip2bjn17P{{Y(;hMC1|S=l-EzgkMB{?kDCKkze}_ z`FDh$`9nV-*RnMXt(5c_v#xs=x%c%C3)e~B2c{UOFHjd>RFTtdV=+n;*Or~M)N z`MBmSL_ej`PZ9kT(N9q8`Esm(uItOG>p^Ogx>q!*`sw9sss~jcjqOMy59g8XMYI#M zfB1f({qq0VKR?U-iRhPzcoFd;;zf)@?J*7!@glBcv>hBzB912!@$0d_B>RhY(j+z7 zOOw>t?z)-}kQ&>UCaKX6X_6Xw1~Q(cMjmN0?WNIP8ttUXwEtS#e=Y5$(Ow$!d4A?o z#C(eA=LPbI$R~|)UYPk5kw-+lh<=EO7ZI;^=)Z_~=gD?3pV}VgQ^Y)LeUR#ZG~%QY zr+Sj>5bOOHT8|;tyEN9dh;=PuU5n`F*Ry^_^ixDXMf6idKS3Se_h-B!{37E29=`~` zh~u(5=bL1E9G}u8^{8kPn#b`P#EaC3lP0MVCrz?F;&)B{U8xZ#O;RIHnxw{fcVj$B zjr}7{Qe*tmBsIn*O;Te%q)BRwQ<{Wkzu!*(-=;=Cq)BS@Lz+zdvcxY-yfosa5hqQe zp8eh<{ojKc{gx)F(Qj#z8vT|gsnKs~k{bP%CaKZ?-I<@HMn9xUYV<>zO#JA?k50Ta z;-wKMO|l;S-zojyi5mTuCaKYHX_6ZKmL{puZ)uVm{gx)7IsdDWU!+Dqq)BS@Lz+zd zqQoysyfosa5hqQep8ek?{ojQe{gx)F(Qj#z8vT|gsnKs~k{bP%CaKZ?otdAcMn9xU zYV<>zz6 zL_D7xF~5j-5q|7{`9=6eTnCA`4ia%4RP(DH{384!;x!KVMfhvu+BW?ZkzcI)x7j1? z9il%wBwj?kh;i8;VqEr5E88btM7)T3vp>YV**~o`CtgInhNyoh)aWDadSOX!%<-~`YV4pDr`nO`NL5mK8LN+kI!L6d=4ujev`zDh!?Tlk@APw zt~AyIo`-0Cis-+H@!B6^y!KDi^DVA(KIdvfyom9NJwlAvems9mei88^_Lu!3_Lu$B zN>k!R#EZype~A3{Ps5+!y8j~LMfBhP5dF6w&!-YEB3?v(`$OcH#&M_f3XVGw$6f6_ zvrY1d$Ri?;{UP#5WB$LI`4=(&BKG^X@`u>((%6sNWIu}7k0SQ_4)kNci`efX;+lAKod2^m`ael`6MdxQ}oS&s}UX~_VkMnY$oS*wpzWP9YD!2Xcb$SX}!Bd;{c_K5p{`AKTTNt4uwlP0M# z&NmoOQe&LbBsIn$0qilq()w8k{WrXNowSkCaIBEnxsZv zX_6Xw2PFRhYUGtBsgYNjq()w8k{WrXNowSkCZV~%KIHt6)YwnbBsKPvG|BdetFS*L zHR7a6YQ#yCY+vS<_n4ogu8$_EdqtDfjdRQUj3=p^qDksO(IhnI=bP*gNsW1tCaEzm z(j+zJMVh3>yhxMOm=|eM@px{}{J5X$r}${xPf6oGO7$e_Tbt*WciDfEx*APVkBTO# zF)u3_Pf}xEq)BSbi!@1%d66cmF)z|2HReT{gyy{LmHF9=8uKDeQe$4ENovfCG)awl zktV4zFVdvq@wq_er&00Im>+4(i|R?#b6#G^{JcPod66cmF)z|2HRfer=4T!?=0%#M z#=Jp~j3=ovFVZA6=0%!>=KOqv{U@n0FVZA6=0%#M#=JUK(-IWa2+b{3nT*M!YoQq)F8Cx!k6D&J*?u zF~6J1A7VbGF^?kVPsF_0pLSRm%7^tJ)`dMne2!>;+Vu$W{Waym_rOGa4@|`O!0b;u zd_Ju9_Juc&w#(1SMPHB?$7}p7mC#kV+q)BRwQ<|j4cu!_LNsVz!lhhc$ zG)ayA9H0IiPmO*^lho*kG@1A#5`RSEr4cWUIBAmg==V|S|54QFw=_wOeoK?o==VwK z|4G#7w=_wOeoK?o=>L)F&ym#Vhcrozen^wl=+8Up&pXuUhcrozen^wl=#Ml>jebaz z)aZva$?I3deV0VN2)~H!ir9{b{2o|4ibaNxU@Tr7`}kR1dNq^B_%9 zqd(H5+DD^*(&(S+N!FvE(j+zJYwK)(YqgKY_M!3pgz5N|4G`NCu^kbgM~nCzTEyqi zpg#ZJ2l@CpxHLZZmL^$`e21`}q()w8k{bD?Nos6Inxw||q)BRQSDK{8cBM&bY*(7p zcxIOWBJurhQ2pWcD*MChRrW`kq((oaNow>%nxsZQq)BS@Lz<*UUS6+?)W|DMQX{W4 zNsYYHBsKC%lhnv7O;RKOfysX$HS$W6)W|DMQX{W4NsYYHBsKC%lVdBh_;;Fk-<=)K zpMzf-xaVU1{ipsu3V&y*zn3EMcNqM8OKT7s&34w`RiR#gXGJE?y2-zF!S|uL7>9^{ z@bevMlDbzkiT%gp`e@#V<8v;tSBTHK><{rdmo(P7h|dE=d>&wb>hU?3{UP!nmHZ;| zi^y+(i2TyXFCxE){Pw3F`Rx~R+|9smd-%HQG>#ANo6;mT-an;DY8=m}Ykv6C8_+nO zrAcZW&(b6{)`c`ljrAZ+Qe!`XNnHBmcPMA4iS6(j+zVN|TA-C-M6vUK;Vzh?6E0zi;CAO}sSX zr4c7hCVs!f@0WOK#7iSin$-H7!N04)`V6sdrLo^d%&Um`6fxcd6dxjwH0DdhJc*be z5c4ymT$$@O5&6YFbN&5g@Gq?IHrL-@2JfVXAN>?Dz78JOYsUERvB6pV9SR=r;hb<5 z|2~`ka88K)__Zs}3(0=rd;QWRHNM|3O;XoIlhnBWQ$0zI>p*ET@%u7A;`dFwG~%TZ zCrz>*{lN8}`XOSw;MBTq(ydy7iB!Nf*krz4gB1c|yccuNgx`uz@M?Z{CgU*NT1n30#Gc*@9RXPm* z2n`f}oaUi1`Yjs*UINa)*-5}jzCtWYS(G{58p`rY zJAPiI4qY;+x>*7LXfID<3jWanG*|x73EW*-jbx|b*Hi#}DUp-h>Ioq*Ap|C*)f3X% zOlNB=+9CCcXa^i^9BZsKJ~!Sp-ZGXLOO4Nr#l~{ur^Z>vnZ_~3kBuK0YmAqTXAL|U zW0&3o>KcB6p9P|NU+Rpgcco5`TIopaBSzxBAMH+$n&-MU*UgtYBdWuZQ8>QX9Jj3m z?k)-3G!hF8+~QH;&W*qg4T1X<0=E+c?h*)G{1doFC*B#Wy)wajg}`1RuvaE{uT1b> znSfEO6G(lrQ(x@V7o)qSVL=Plr_pK51IBN!I)HV+d}G1s|0%C; z@82>S=$|seh;U)E1&%)e*S!QTkGY`n?y|bBVJ3cbrxU!V)fjJFBs^*0x`-k86*fg0 zPfpMdSmFKfqLMvzubcZ7RMNYBko;vFrc%p zfvJI7>JJd&UueRB_=nN>VIu<0Gw`!m0GBYpRZgeDwM(aQ#so)VnbK+0mM|Wg!1)+9 ztKV?KztRM91`R4st3icnr2^P_%r2U9cIRV!XO9ui!Ju(M+6Z+9)le&dYGW&as#pP3 zICZfdK!tM_6+l&Q1yJ>{0;txp0;sxM0aSgg0IG@=K-JRQ1!L~+OY>7#xgay zz@XT(CS!ns$)a;hqpvZ_7-Q^e>}KFw3~aEwG1}P4*u~h{7;ZEhBaBUqkw(?n#`vnS zt+Ac4y|II_xzS>5VC?A8PW5O3juv1)arP#b8d&pGIBgR+iQiY(%5os+$9-E6x0K?kNOS)e4{*ZUs<{v;wHM zv;wHMumY%>OS^NnQ&p`1s!gl_s?Dqbx7*+C_IEp}Dz6jS7b$>hq!r+H2e{n!-pd5i_qH`OmJ@==Gi@rs%iyL4YvZQMp^+>TUr5BTUY^9 z&G=Omt-AB5s#XBiCRPB|W>$dPo$q$%yPZ@OKjETwQkz(9#;?^)L37kiMb6d4X2$Sx zPa9No`3UW>3h-d)KCA+vl>gdON+^6t#5$pruegpt^TXYj!`&CDD*wuh^CAUMjkE%& zwzLAMwy*-In)%0CJQ@$Bs#*b5!>s_SkyZfJmR11O7FGZU-OLZP3H-ek7p7FzYPi*K ztC3bCtqT9(hCf7xcUb;T*agmlzqXlL8eP}ux=r{I8fRB%<{w&dd-%H~ZcnOeHNt9y z)uvXPQgM9!ICg+zXy(^BITHh&41c7=5IF%lhx0F&7^!xEBk?s1)(OqLNoFU6;l@a# znSY?fIs&Ir96;>#mUarmtws`@TUr5BTUY^9 z&HQT{?vC$MRjmN3;Z^|ENGky2!?bQ>3^g`(vZI~sXsZ*gPP97K3U@?&tJ@NaaNSzh zt+o2h>NBg)tv;@d6;w!~_w)l#d)R(yv=2;X)Is})u&tX{Nw z(dwsGKeam3>P)M%tj>bMz(zq4t~PJ>Tw!(cJ+wJIfxa8m&Y&|M~s@@84 z-MX$@*L70${EjuV6lcK&BvqXiE+DD8S>XbbyAju5bk^I6>qx2|R=AF&TE`04k({hG zP=xEcyAD^CjNH{~S4ZM|vW&#-0PA*h-EOYqg$wGIxo&sY?QXS))gD%(twy`uDz{tZ zx}99Nlj|0_ZjtMDcHPcayIAdlL1VMed+fM?AgTpmUFEv zt?;2UBNtdLv|4C|2WYH2&I%u2QXOw~g4GFDCtICtg%2(nd4v@{Hl#Yz3LjEZ9c6Wr z)k#+GSmB`s-@x`GMiM+3t^<%7=cVrz#Ipu~3>DS&FE72tLQ+-`u|Nmcnl5!*=tZYMR;s+phpaCaQ& zc2ZTV;jRPRPIV)tFrw>yStvAGH5rA!E5fs|&}cLng})iXI-${MG75hWgmprr(PR|< z_6O^PMx)6n{GAWh35`aRQTR-pbwZ=jWE4IpXPwY!G#Q1z#lbqE(P%OXe`kYrLZi`S z6#k|L>x4$5$te8&4Au#aMw3zaTN$hq8jU8S@OLm+Co~#OM&WN!i9DsY;pP zx(SYKvud+?%<3_#8CEl_rdv(7nqxJ`3hy1<>^!UaR`abotU9c4CCA9cR?k^IXZ5_* z^HwvhW?DUI^`sTv)tKc4s~4?aw8DEF>sGc@{t8@$lLyfP^etE6Y(tDy-LG8tE7$$X zb#SuXHLknHb=SBKPS#!Rx~pAxwd>$y-Sw`!-gP)VaeHvG?nc+$=sKJdSO+KTZgSmC zuEU~b9h|JY!F4yd4ojbPaI)^#uKTs?e(gFqS$D1Lu5}$wYitK6>#lR%b*{sygmrMT z?l-Rcjq85nIyiYHu#us=i7Nk+pKnsSn*gj%L<2ZaghGQYp$OOM-lEFCh-bUCj$CW? znU(G)s{G@2X3^b5m4CWU)#=DLt#mh0<)59iPInW23J0~skxN~tyNN3Qz?zX*gWURZ zE8R_0`Nz|&Tj4t0O;q`p(Tx15>wao=rq!8NXIY&Eg<+0@B3!4tiE7c^M3sLg%Pr_` zqRKzArPAF*)prwsv*@m%iXYxoPTdt$OP!VO3aX`>m2L;B_-S)R>UN-7bURS>?Ev69 z-2hbiw|^Yb8gG4#>vnaocXgd^2dcgusQPvQaNRPu)9pZ&f1t+E>UN;YKX0Sb?Ld`( zj7Bxu?N+&+ZU?ITLo(LwjQ2 zUv(e2?gOhgtlqHt(CS0C)9pZ&U;O6Qd!ml8>Sd+dfvRr@0B6zdK-IScReoQbeR-40awMQ7IOb^x%_?Ld`Z3TB;d2LP*&y@ijhKC$}5>Qk#vt^Q;6 zAFJ1_bOTW3_fpwU-2hbity8K6j$CN9(CRoV-2hbi{Y6IV2B6AsOH%0upvvz;Qt1Yu z%5N@G9pNmx0jT;0pvrG4vhFC?=?0+6uOM=?x&Z*ZG`1k>^(Yr_$!A*$g@4=6I-&5X zJC#uQz=jIoWz5&GJ;G|B)j+CJE~5fmCsl9N=sJLPO;&*0U4chlXmyYLx3`zu?d3=*{{F9We#3R&plalIxTg?~l&ZIC zavi|B3RmlWb$yAyLVbj{9w=Z6-ht|_(EE{4Ddlo00+H`u3iK5aSsW=q{lbw1)Gw_F zC(70YAuI95*{cJOViy=OTRvmtWnRVUx z6V8O{`ns;K>-xK{zw2~iHnmh-S8<)Lx|sUwPA&Acsu1^Kd{|N(pD@7aPO#neZYSuf zi(8Pwjf3k1T|Kc5iaEc-oCA#R29~!sBn+_XZr~tsoiMgpU@1 zS#aVb`q>6QZ=A~`pzwQ!JQ}6ytpG2Ed+;ef8%)#(w;TKZ0q8*U51ksAinaT#@jxNC z>JH&*?ZyvzsDxrv2!0>wI|To^88)x`)-<55d`I7Wz~gIt8;ND7$}%3m5&lqVW7%Gc zYFT#5F5}0mmSuZsRxQg;*=0O_pB!yb;%g8+XI1bG36$-14Y%Rn1yYI6;bG4!H*T~m zzA?eFLnS;zH>79KhV(Sko-pZQ*evmt43zjr#-u^;v`%VQx#w%MRJ_Xw<7T>Qxx^JbZeM z?~k)0s<)hjnY-|@cY9COo%LnC$jat~)n;%W!+_LOsiTGjTITnyu@t>@ptz3M|$qN{nJ3jcc6BeN`T+5^v(DJpjEb)A0qA4waoM;lUSF z;6Vuw?Yf4qjc4R|`BB1;5}sChP{M-}9(>0IZBfF55*~ap1|F2~@ZXMW$3LaSQLyY( zS;pfx{?TWY+&dq0?0?c~M~ShcL>~ORama%bc~BzeZpENP3`%$^nlY3Z9ZL97!e1`p zC{V(Kl98?Spkz!ddo@bEV%aIXjGw4pp~S@FOM2Kj<9S4UgsvAR&=qfEs2RV$on;en0PHr5+zQNr_mmHWwq z5+1Bf)S`rq6$=|BY&<$fiE}?ZC}HDqF3KjA15_TU5|H=C2n|7;zkGM0+kC@;)Vtu z+{mEB4Gc=$xS+%h3(6x^9;NammG7v;ipBh+M9cvy_g9H^i@orQX84DSfsGifVU!1} z#HxmkTI_vzkOw7NxfbgjwP*zoVqjynBL*dGtaI2XVPl=cMhP3M9VJ#fO008~1LeVL zhuu#$);!{|!ck&{!w(y!ZLD+nQNr_ml~~X4po9l288%ATSkEY%R1Q#ipvrc|phWF? zvQff5U$)EDve6%m4n0KazCC#{XCvh#`eCE(If{4bqZQ@U(!Kl)Wd&usB0E*D+p zOyYSGB|VcW%epoEd6vp{l?zm^Q283m+o!2i%EdNo8N8mw~2 zm_6tgS@Gn-@H4IXJP{M(AZHiHU2B|+N*-HIE$r$x#kotp? zo{5T4e+H>PDA`K=LCF~PXR!K%5+0O@8La-Gq(}W3tp1>+NBtSB{-C5s{TZzOprl9r z8La-Gq(}W3tp1>+NBtSB{-C5s{TZVEpo9k{`ZGlRK}nDLGerGCNssz7MEyZYkNPu2 z{Xt2O`ZGlRK}nDLGerGCNssz7MEyZYkNSf(iM@;x9+c?MM(Phrdeond)E|`es6QL2 zKPc%@e>PHoP|~CRY^466q(}YPNc}-ckNUHb`h$`l^=GL1gAyK;=+98~2PHk~&rtOT zB|YlTQ1u5TJ?hU;^#>(A>d#R12PHk~&rtOTB|YlTQ1u5TJ?hWK>JLhIP@+G)QB+Bf z`m?e6gOVQgXJhpTB|YlT#_A7Bdeond)gP4fs6QL4KPc%@e>PTsP|~CR4Aa(8!h;h1 z8K$kHq(@sHrmdr-M_V7Jt)rwzTOX#aqohY$AEvFNq(@sHrmdr-XA-XTa3R^wkIy<- zbh2nKO}r#+YKCmW%~`21q#Hv}bh2nK^$e+JNIgSvv(wIRm~^n{WYJ!#45>1t$}j)p z{ken1yz&~q?~kH`#e5d?$`=?J3*38Rq%7dW$XP(PAx?6qF_0)aS+w(~$vRkcvS=^6 zag)1ole^uGPxbH*h?O=JOFPP+D@!|Bw4Xccl^al zSxC8reOaJ_9a;wKg|ZZbUW#tKP!>*NA&E_vrI2;Yk!nfL*Vqi!f?g<=Q7(~GMK8!@ zluK1GWHBoivtl`|<+PU4T1snS&sivX&Eni+EwaGe<2WcEVfnIv#NsV4^R5g9cGP(6 zvNEYMi_ZaOv-qUE!6yRvLhM>kN+W-*7wQ{@HvP|RjAhs9H61$`)HvzWsI zStj6`qs(IQDK>N&mokd^EIMsn!5*OKVA08Xi&P*Q z!Xp3{LU=;nkTZ@;*bWw*EZWOZ&iGKy_|Us~HoKQ+GZgJ8utd3WKDa0yT=(<2?qMM_ zj|EuBJdts&+{w$Zjm^1@Ex8R8oh;hR*4)O{+{V^-BlzbW)_LRE0*_6~L@rhooh%^P z76l~R-odtau9AHst+WE6*9V|Low3i*&b_cfI z;qJ=E3r^ddn`~#%!D1ruJ6l%4U~1zo)!J-q=P zy&k$prHmd^DZAp`rQ8mED_*`L8Y*o$E=ro9lpg=mLEUNz7kGULKhEe&kayW9uqVNu1RHG{*00npMegO;_9FCS8D5K!cNt!b zkZT!Ui_mr%UW?Ff8D5JKvz)Jq@U_B+<-hPF_|axLUW?IYIbVofj{3!TEyZgQ#^g?w9}A1h|zD!g9D>rK4g!s`vZ-bUY%X9>2q4D+zC9k2KC z`WUY@c)f?$TI6K=&oC!1fuG~`AG|(AUi57#=4)vOZ1is_UW+jgOF5V5*Alc__Bw3z zVF~)Q>;<$#j-}vY^kq3-OYvHS*TR?anvK^7cwrtFVqQPQct1qjmv{)ih5h~(_InHV zJ6`2v_)e~rXRx*!dg8rkE_`#bM&`ml7ru4ys)z4x_;@zO@pE$(|7h;WO8Mp3O3x|$ zG~iFD`xEN^gzcce>tbEL!t?DrsN?HY*r!$&ZAe`?HLf%{Ox&zxh5-~?2 z=1ADTgZ(?$c;R#N4!q{$Ro8GcUXxLO1nQ4K{SmN#3;VaQe_JW-n8SH^wPWt)@hx#% zytc#ZtEiuW*Br#oz-tapu`|%$If%tRo`+XE_T4<}yN18OM*rvG)s8uvhu20te(r(B z{LSM@YBXLKAkUr1aVPTLSt(mJ!nZwMJ58{5!$ILD;b!5M;Wpv+;plMJuqE6p z{7$$}ctH5W@QCn7;fdjC;aTCiVQY9vcvW~^_=j+EI3=7KJ{mqAJ{5L^&xgyx7sEHg zcf$|EwPD?C&ttE!Asi464x7Wx!mY#Y!=1x1;a=f)!~Mg9!^6WLg(rnS3C{`758J{^ z!YjjT!{3E}4DSr@3m*s{3a5v&!nxtI;gax$@U`%r@T2hau>L8}W1p~JxM4Uv+$`KW z+&lfuixUx&X9Zwv1Xr-b*14~H|tIpN%} zGh7rd4_^vj4c`b?hik%5!_UL+_`WUw>lHSH1HwV!#^I*n*5MA}&S6WqSNPpvheEgH{p%pAHqL|cZCmz4~H|t+2P!SvW!$16!!5(Fgrmbf!?EH2g!_jFhew1z4o?by5}qAi5Kas) z4}Ts0HvD7wm+wuR(NjM8cqr?4X+HZ39k=-AKn`NIlL>J65b#FBYZfV z5zY?hhR=pe!WY7q!&Twi;rrpo;b&p@_N>!z{cwYDqi}dQGTc1;uW*3zv_rt@(58qjp1$K zUE%%VBjK!YUbrA!7QPa`8NL^O9DW|w<1dH!-@4&|a7egGxK+4)xN|rr{ARd!xNmq+ zcv$%3@Rab(@VszBcxiZbcwP91aB_HG_+a>GI6G_)7ltdsSHri$HR0N@9)Cl{|JDx& zg~P*9;Wpt;;h69{;ep{%;mP6IVQY9vct!Z@@TTzA@Q!dw_+a=*_+&UYd@fuXz8J0w z-wQtuzX*GGdi?#u!C`YaD%>XAG2A2kX1I5FKzK-aOn6dwM)>n^e0XViZTQ>p*6@z- z-tfWj(eTM|Zuoq-JbW#DH~cj0_N>RhZrBuV9BvkF8}1hVclhmazwnUoN8u^q&%*KH zFT!7iH-&!;?+zabr-e_2o#C?ZrEpcaI{YwP8`j}30r_9Auy43QI6T}e+&bJY93Acv z?iKDG?ic|OYzr?9e-+*k-W>ipygR%cBy5{?PShU3EThlhkmg(rlkhi8Z5!%5*4;kDt-;T_?W@WJqr z@QH9vI6qt*z8Jn9z8iiL)-CXS^a=ZhP2sR`^YE+TPT`*6cf$R`ABIPT$A_nd=Z0%!lMe+usk{}%o;oF2{!JHkcbi{YE$n(*^*orRuSy5gl~nPh4qU(-o|iHSPi!h zcMrc2emC4NJUBciJS99cJTJT`ye#}p`1^2j_}B2!@ab@I_-eR1TpQLe&UnJX;pXA? z;h69{;X&b1;i=&{;l%LD@TPEb_}B2!aCW#Ld?|c4{4DIT#Qp6T4hctv+lMXTcf*6j zW5b_@t>NY24dLzK-@?bjx#8mQ)o@L?Hte}H^BN8fHx0K9cL~209uOWCo)n%FP6)3G zZwzk_r-c6sXNU8{72&GzldyhS<~7_n+$`KK+%^1mctCh$cyf4dcuDx1@Ye92@Sow6 zVQ2VaxH?=L_FV3M4h)Beqrz>&-NSE&`-O*uCxmB(6T-{G8^b?__k|CIPlg@g(r{Jy zL0DF}zkR~N;ilns;U3}GaR2bo@Wk+}ur0hI{B3wg_&_)#oEt6KWo?qEQR9;%yLR40-Y#}OZSGEw9Uigg&{x>kJ zhTDd_hu;nl3J(vD4Nncv2`7Y?hu4L-gm;GbhmVG{!};OT@YV3W@UyVzOYVRFaB$ch zZXSLm+#%d092@Qz{xCc`JTW{YyfFMlcvW~^cyoAH_+a>0I6G_)pAVOXFNbf2?}wj; zbuW9oy~DoYz;IZ&S@@N3$8e8uY&b4FC_FMeK0G}){9CXJL<5J?@5Z!>~ErBHS+AHQXy47yd9jIy^BvBRn^p z5MCPoI=nfY98L-U5l#u`r~x9}U`-r<4a zk>QEqnc;=uFT!iW--Uk;?+YIap9trM3&NG*s_?z=)3Dp?9$%lZZ@6JNJls6|YPfT_ zXZY=K-|*n@sPOpkwD4!)1>wZ-vhbSl#_*PKa(Hj}K=^R@MEFejT(~@36|M;@t33X7 z!wtd_;nv|!;U3{$;ojl*!^6Yl!qdZ_hZDj}!)wBu!rQ_-!@q_93TK2*g&pC7a7Fl9 z_-^=V*!>NUcl~g~a6~vN+$P*9{Cc=gcvyI1cy`zpUKRd6yes@?_(a$dE)8D~*M#NG z9Dm`Uuo`|f+%5c8ctChect+S3ULD>X-Wxs=J`*kp-v~bqd%fj;HHFRL*5OX!H^P0w zL&M|4GsD*K^6-Xma`<34Gki9DDSSVyd)xhL42Oqb33m_o4i65G4SyQ8hF63)g_Fbk z!^gt8;gaz6@WZg%JMLHCaA>$ixMTSBaG&t7@Wk-!aAJ6M_`C3q@cwXm_)NGkd^vnK z{4DIXI{P(j4z~_>3cnHV6CN5KAD$VuhL?vogntVE8a^669WD%C3EvMZ@4A2Mg@eP* z!tKK`;s1m`437)X4BNsh!{3H?gb#!>!uD`!_)7Rr_+j`(*z-O2w_mtX*c@&eZXIqL z?ilVKjt%z>4+(!9o)(@RUJza!ULO8ByeYgjyfgfJ_;5HgoEI(&SA`#jUxYp1_jnt_ z!Qsg8zrxYsp5b@H?}tZ(CxkxFMi@bK`Y@SJdbcu9CwcwKmFcyIVnI5X@B z7lto{uZQo3pM>2%%zg_8ht+VKaF=keaG&s?@bK`M@PzQx@XYY%;rMW3cxiY|cvE<5 zct?0o__uIs_;C1G_+xTWpLE-Rlvv8Ymr|`eS zy~BgTqr+3fGsAPk)^JjId3a5DV|YtAIlMQ#KYS>h9zGd96V4A8hReg3!#Bd!;hON% z@QbkL$DXgoaB#RuxK+4AxO@1`a9sF<@Tl;_@F(Fp;rMV;cvW~qcx!k^I3;{Ad?b84 zd@5`Yp9>d5fCX}l1VZl!AUYsCfwDO0$!k+ zsjA(5mya!j{Blr|< z#U0p;`|tn;zDgc<2ke49@pL=~hvOKWfLCKBPQ!V4J1)i5xB<7}o45yC@E~R%OdfAX z?2dhK01m|>yc#1o3va@^a5=8V^|%RNz&CI={uK{k#=j?z^C&zXPsOuwB#y@toQiS0 z9&f_i@#nY0c+$r!5|h$73Hn0|(A|LJ1u!$N8+*A3;W_AEX2_`9-r^Pr)?$nT|;9qe+evR2dt|NBE z9(XDa#36VA7U5(p#~Pf0^RN+@;7WWHH{x@+1K-7u@N;w-$>Yz#PS_oL;{Ytgv3NCB z;~ZRw_uzxL9yjB5d>cQ&Pw^lIGC5An#bYrad*kUi2n%r(j>E|q!l`&I&ccOwFRsET zaWlS*Z{wfwQ~U}8S;_Nhiyg5W_QJk+CJw=oI2I>i2&ZBkufrR$5f|e!T!rg#6TXOV z;BMT9pW|2P|9J`jlZCmMhxynW3vdt)!3%IaUWsKm6{9!}ufzFx8!pECaV>7ZZMXy9 z!M)gm2hg=io@X{5h28OF9Ed}36pq6yu>zww3+LgjcsDM?hjBeVgD>G9aSwiiUt&g1 z@;q|!SUeH?;b6P~$Kh32iFJ5A-i&wRFY(v-I5y$)_&UCa`|t})Z<{>s_Lzq~urHpC z!*MK5#xO>4HZH)Q;1c{5uEnQtEB*oB!4L5>{5SjxGyP{p$yVAZhyNU*4Y|rON}ke1 z>8c#7bW@H~x+_O2M=2eZPRh|rXQh{NqH>zjS2XrRMarehP-U1hTp6K^R4!0PDWjEulCPYp zv{SBEa+EpB_mpboTIDk32g+4SNC_)d${^(&Ww3I#a-MRQGDJC7i6~KJf-*_DQYlf& zl}aV1)GO1KxH40zQ)VdBl&MOMGESMOOjfQ|N|g#FUFo3oR5Fw_rM+^35>yU<{041n zt6Zn_P_9vGmGR2u$`wknQl?B%zONjwG$;d=LgjpAmNHwpS-C}7s4P-`tlX;HrZg%) zQEpf6Q0`QIs@$dgOu1WGtlXolP}V4qDvv3TE9;csDC?D%V z{mK{00p)FFr?N|VM|oFiR^C%~D}PeFT}Ap0e^s3VF<%mh1Ga1*5gc^ zgE!z@oR2r-B5cGvaWVb^@5hz+Fs{XQ_#|$`O}GWO;Y;``zJ_n&PHe_KxEJ?f3;qqi zz_0M{nASdd9|SQAbFe+;Vn^(ZUGO+O0efK|JPrHdKs+12k3;bS9D_x88BWGxEW=8y z#u!e++1P;d@n*ag@4&lp3Eqbf;3`~=YjGVuiBI9v_$)q$FXAis8vYS?;d}T#eu$so z=Xd}Q;@23^KU(X5GBF1`;8EBayJC0z9-fG&U;z%qbMQPIj-&As9ETHeGG2|PSb4;wShyeu?e~t_QZoTs#`P z;_=uM`(R%jfahQ#j>IuI4kzK&SdLS%7VB{~{t$1(ALAXk7=MW?a22k>b+`ea#x3|f zZpYW~EqoXE;78bk`|%*A>t8ALKiSv;J7HJM$6j~}_QOH=eH@0PaV%bjS6~P$FoH3h zj&tybxBwSo|GxbO_AMBgIG6AGpQT$06PuUgN_+^{;N$oNK7~)?v-ljoggfvpd>7xx zkMM7J5L3sRk(QnK9W|W|ejU^tXtmDPJgC(=S99#pTK~+L=ANzA{`qINTKne@ZngH$ zpMGfFc<6UzzbPZFG4cNStseK!Kd05&Kfj)JTF^h5{CkQwBR4zE>wmBHKN(_iX=@mY$bb``@|!Pg;7<#JVA|^6TD-b?SgJ7?S0m%>-90~)b;w3wZ8`bC+n%g zgc*td)!zwOXR_|eI*auH*2$yR-=$c$;qeiyb68)>x-IKc*6mnNVcnkfb*wwE{weDt zSU<$tUt|CCTh>P=m+ocON3q_`x+ClTtUIv|Y%EMn-B=&V`e@cCuBunozLT& zS)aiAIo97}{TAyUtar0ceV*BDSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8 zHDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZ zSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!# zfHhzZSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU)_^r& z4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU z)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~w zU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=` z1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8 zHDC=`1J-~wU=3IU)_^r&4Oj!#fHhzZSOeC8HDC=`1J-~wU=3IU)_^r&4Oj#Jy$$3# zm!`O-9bB&Lc%*Yd&H1uQX{R|Vr*?9#lb_}7N^i|e$y%huc^*B|3to}c9h zN^if94COgjpgAh*l);)Cr^{7o0<#%OMm&nV@7AGt%R^!vy?N+m%<%J>P+J*2rocI@HY2F>|$p|aWUBQtyI z{WRyw8y;MG4RVq4ncqk5P!4ErmbE9UL(Nh7k&?Ya$1IOM$+=w3 z`SNBZPjjPOujFfPlIQnUhnkDzmr8-=!amL|JK4FjG_R3)r#LrUbH40ys&fbc9bkG#FqxyLjwm8+)cm^H7FWmP&J%~82X>3N^}l#eLwG&jj+rITiF+Eg8f=3LpL zoT}N|C8FckJ)bWx@v~mDNJf18>&sorPVLhydspikXfBY$l=b>d70D^e2F+2~uGYD& z{<9_vl@`61w?f&gIVx8vn>DYIEy^5!Jo3J%u94p^dt9sY)m$JOl%<-zKT$^M7?#R| z$_C9Yrc0?f9kX|$azOi+$R8`snj7V#%A1;-WO|)G*LrTQ9HHE)xkxrBxq2P%14_2$ zHF9y>xk-BNQu&K|_2Xw*J5A@J=SJn*O0&+rS$3VS`&QfYWtmc>{iE_nN|W|!l)q9o zYhELtQI>1}?eZ(-Ce3b!KC{Y7|2py_Ws&A0xlSq9+$2Apsn5CJf0lEDlrfqMvYfSb(-bE>-A@#UZ+uhs8niui|lxV{_OCtBd01Q+8&jI=IZsef1!L_ ziEDe4ynMdiUUP~3RGFb;b_<+4PFbn#`SO#SbPSqXqT_Bwi!+THf3?E_dkRdue;? z*K}F>z-Q`%o1qU>&^dpuSpk9b>yJ*RHg6 zORZkRKQ{NU$8s`UPHE!#YSbTFz-15h?P|^mx}3F{O~LKy&57-s*xn}S+N{ke@T&{Z0`fHS${qgqK@%n4_UFYMw8+urGsq^u# zlei}qfBT;B*K+P**D^EUGKZ!Yq?PD-nHlbztM?tplju+Pg+Kn*&vUw8%GK)t={s$G zE`H_r_uE?EOReX2nXX;`#Q7wzZ~H9QzO+q2c1cz=dBu6Ye~naHKR>lCWva)Nhu>GJ z{aT+xYTwq|Qu}%Ry*=)mcG7Y(GICzc45-bLv?4wJkDl+hFXOm7w{e|s%5=FiGF;or zpv&A%@2%g*pI0f@$iL_9t==;)XMSGb&>hi~wLPOb(2`bk=)DjB{AH%Q%>Mcuw#jg9 zhUzm?5{M=~$5}y_)jx6M(X`aPma_G+wEnXpb$eo>u!+f3IsmQ|2hk`YaO zPCI0~4zZkqHYM57tRg54GlDc>Q(Vu1h&w~E^Spx>s=hnId&Gz&Ew}HV;-~5hK@InVS;h7Gu+tc4{oAhD_H(>KO>()(0wj{UD!zH)| zx8P3Phwk^u=N*MTaR^?5Q}KGd3m?KQxD#72XKV8HyW?OSj+3wg=i;51I>+U#H{h$d z7x!c4bDR(6V*w7vORy9pI1A_Dt#~*78Xv=rxD8*&-M9}AU~pUV_;Rs3o{R%<2wsTe z@JcMl8k~j=cnjW%OYi|)jq7kDZo%#NCho?4xF6l~$@9s<&X|uU;{Y6jqi`Hvi4_>b zIk*5D@g7``tMN%p-8c5RNM0ZNTqJw2&qeZ+(LQZ>I1-MBhsCPmRb`>b_;6XgsOTx_o=v=yG>ltF03%W8qM_Ho8*3bxf!( zJ|Y&Y)pt&_{QBbB^7=@4RH&vr629EIwSJp_@$<{eWBv`?tA5M)cqkUHkB+XXs6F5P zC9!2@T|8Vpp{hE3e%;8bNZ3yL*L*9w3_yU_qv_2f0Srm>{ z)W)hqHD%$%+lFIqNpM^|qB9s-Uz4bGLZ~zncK7C$tBJTbS-c-+x>yFTOFR3kw)7AGp zuDEzuaa}ZAR#j0|R-8NLwv^{xp;e@;wq{!5ap$hq zI$Bj*r5nSAG}ndW#i3}lI6gBP);EpGE%kbz>QKB=@8-W8Ee@4cmq%*cOik5wQ;Neg zs&tkMU2$1*x4Uvb41y2~Qrnkn(hsxt@ZzD#b>;lHh^TIZ~9`8CzW zLvjCjx3t6|>cUjJg=xi+x^Va!|HPBhi)(8VZ!{_0A8zuQ3pB@LRb|!s`%7bDu1PH3 zPcNQUR}+m@)x<0Gjaho}^iWyigXhi-6i=_HjfQL7WKH@A>-}pqrQUyDAXHi#i@To& z^wEygmg(!@K=S+^2vn3s)V;oO4OE0{^|~u%@-z8hprRsDUstL7FHoUN60NOsj|P(O z^LU_w1Nn`n`goc9ZJ@$`xZMV?UT;&N!k?yl#+!KV=0HU}tS`{F1}Zql*8){_p-8kc zTcliIITr^_bB_qb1 z(Z6rG|F0DKZyb7G%eOnIuA5dCi>F#j{bu;jYyOdi-+6GkxykL@kN)n*TaHO?Z^G|< O5!+}DSOfo*4g3dMHQQ?d literal 0 HcmV?d00001 From 00597127dda818ae29a30ee501bc720cf9a15f99 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Nov 2021 16:39:29 +0000 Subject: [PATCH 0052/1258] Add missing field `skip_missing` --- vendor/stb/truetype/stb_truetype.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/stb/truetype/stb_truetype.odin b/vendor/stb/truetype/stb_truetype.odin index 169e04a95..3abb187c2 100644 --- a/vendor/stb/truetype/stb_truetype.odin +++ b/vendor/stb/truetype/stb_truetype.odin @@ -98,6 +98,7 @@ pack_range :: struct { pack_context :: struct { user_allocator_context, pack_info: rawptr, width, height, stride_in_bytes, padding: c.int, + skip_missing: b32, h_oversample, v_oversample: u32, pixels: [^]byte, nodes: rawptr, From 50057b0696d1e89346e1a50ddbc8c237c73cca0c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Nov 2021 16:56:42 +0000 Subject: [PATCH 0053/1258] Add basic support for `foreign import "foo.asm"` on Windows with `nasm.exe` --- src/main.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 99a55b2b6..ec20cdc80 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -175,6 +175,9 @@ i32 linker_stage(lbGenerator *gen) { } timings_start_section(timings, section_name); + gbString nasm_str = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(nasm_str)); + gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); char lib_str_buf[1024] = {0}; @@ -212,26 +215,47 @@ i32 linker_stage(lbGenerator *gen) { add_path(find_result.windows_sdk_ucrt_library_path); add_path(find_result.vs_library_path); } + + + StringSet libs = {}; + string_set_init(&libs, heap_allocator(), 64); + defer (string_set_destroy(&libs)); + + StringSet asm_files = {}; + string_set_init(&asm_files, heap_allocator(), 64); + defer (string_set_destroy(&asm_files)); for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; for_array(i, m->foreign_library_paths) { String lib = m->foreign_library_paths[i]; - GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1); - gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), - " \"%.*s\"", LIT(lib)); - lib_str = gb_string_appendc(lib_str, lib_str_buf); + if (string_ends_with(lib, str_lit(".asm"))) { + string_set_add(&asm_files, lib); + } else { + string_set_add(&libs, lib); + } } } for_array(i, gen->default_module.foreign_library_paths) { String lib = gen->default_module.foreign_library_paths[i]; - GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1); - gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), - " \"%.*s\"", LIT(lib)); - lib_str = gb_string_appendc(lib_str, lib_str_buf); + if (string_ends_with(lib, str_lit(".asm"))) { + string_set_add(&asm_files, lib); + } else { + string_set_add(&libs, lib); + } + } + + for_array(i, libs.entries) { + String lib = libs.entries[i].value; + lib_str = gb_string_append_fmt(lib_str, " \"%.*s\"", LIT(lib)); + } + + + for_array(i, asm_files.entries) { + String lib = asm_files.entries[i].value; + nasm_str = gb_string_append_fmt(nasm_str, " \"%.*s\"", LIT(lib)); } - if (build_context.build_mode == BuildMode_DynamicLibrary) { @@ -254,6 +278,24 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.ODIN_DEBUG) { link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); } + + if (asm_files.entries.count > 0) { + String obj_file = str_lit("__odin__nasm.obj"); + + result = system_exec_command_line_app("nasm", + "\"%.*s\\bin\\nasm\\nasm.exe\" %s " + "-f win64 " + "-o %.*s " + "", + LIT(build_context.ODIN_ROOT), nasm_str, + LIT(obj_file) + ); + + if (result) { + return result; + } + array_add(&gen->output_object_paths, obj_file); + } gbString object_files = gb_string_make(heap_allocator(), ""); defer (gb_string_free(object_files)); @@ -325,10 +367,10 @@ i32 linker_stage(lbGenerator *gen) { LIT(build_context.extra_linker_flags), lib_str ); - - if (result) { + + if (result) { return result; - } + } } #else timings_start_section(timings, str_lit("ld-link")); From 994ee5a559819d982083dd88eaaa5fd8e3bbee3d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Nov 2021 17:57:31 +0000 Subject: [PATCH 0054/1258] Allow for multiple .asm files --- src/main.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ec20cdc80..16b776173 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -175,9 +175,6 @@ i32 linker_stage(lbGenerator *gen) { } timings_start_section(timings, section_name); - gbString nasm_str = gb_string_make(heap_allocator(), ""); - defer (gb_string_free(nasm_str)); - gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); char lib_str_buf[1024] = {0}; @@ -252,12 +249,6 @@ i32 linker_stage(lbGenerator *gen) { } - for_array(i, asm_files.entries) { - String lib = asm_files.entries[i].value; - nasm_str = gb_string_append_fmt(nasm_str, " \"%.*s\"", LIT(lib)); - } - - if (build_context.build_mode == BuildMode_DynamicLibrary) { output_ext = "dll"; link_settings = gb_string_append_fmt(link_settings, " /DLL"); @@ -279,15 +270,16 @@ i32 linker_stage(lbGenerator *gen) { link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); } - if (asm_files.entries.count > 0) { - String obj_file = str_lit("__odin__nasm.obj"); - + for_array(i, asm_files.entries) { + String asm_file = asm_files.entries[i].value; + String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj")); + result = system_exec_command_line_app("nasm", - "\"%.*s\\bin\\nasm\\nasm.exe\" %s " + "\"%.*s\\bin\\nasm\\nasm.exe\" \"%.*s\" " "-f win64 " - "-o %.*s " + "-o \"%.*s\" " "", - LIT(build_context.ODIN_ROOT), nasm_str, + LIT(build_context.ODIN_ROOT), LIT(asm_file), LIT(obj_file) ); From 07ec93bfeb628f19d545d7bc8758ffd8163e431b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Nov 2021 18:32:27 +0000 Subject: [PATCH 0055/1258] Add `procs_windows_amd64.asm` for use with `-no-crt` --- core/runtime/procs_windows_amd64.asm | 13 +++++++++++++ core/runtime/procs_windows_amd64.odin | 11 ++--------- 2 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 core/runtime/procs_windows_amd64.asm diff --git a/core/runtime/procs_windows_amd64.asm b/core/runtime/procs_windows_amd64.asm new file mode 100644 index 000000000..660f8982a --- /dev/null +++ b/core/runtime/procs_windows_amd64.asm @@ -0,0 +1,13 @@ +global __chkstk +global _tls_index +global _fltused + +section .data + _tls_index: dd 0 + _fltused: dd 0x9875 + + +section .text +__chkstk: ; proc "c" (rawptr) + ; TODO implement correctly + ret \ No newline at end of file diff --git a/core/runtime/procs_windows_amd64.odin b/core/runtime/procs_windows_amd64.odin index 394df14e6..273bb57b2 100644 --- a/core/runtime/procs_windows_amd64.odin +++ b/core/runtime/procs_windows_amd64.odin @@ -20,13 +20,6 @@ windows_trap_type_assertion :: proc "contextless" () -> ! { } when ODIN_NO_CRT { - @(private, export, link_name="_tls_index") - _tls_index: u32 - - @(private, export, link_name="_fltused") - _fltused: i32 = 0x9875 - - @(private, export, link_name="__chkstk") - __chkstk :: proc "c" (rawptr) { - } + @(require) + foreign import crt_lib "procs_windows_amd64.asm" } \ No newline at end of file From cf390bf8b9f0652679a4ddc2ad66674e3793e3e7 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 24 Nov 2021 21:20:46 +0100 Subject: [PATCH 0056/1258] Recover from closing brace not found in field list --- core/odin/parser/parser.odin | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 7660005e0..b4efc1460 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -416,7 +416,16 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token { str := tokenizer.token_to_string(token) error(p, end_of_line_pos(p, p.prev_tok), "expected a comma, got %s", str) } - return expect_token(p, .Close_Brace) + expect_brace := expect_token(p, .Close_Brace) + + if expect_brace.kind != .Close_Brace { + for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { + advance_token(p) + } + return p.curr_tok + } + + return expect_brace } From c34a33169670568526fb0f34c252ca5bf641d8ec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Nov 2021 22:20:18 +0000 Subject: [PATCH 0057/1258] Add `-extra-assembler-flags` --- src/build_settings.cpp | 1 + src/main.cpp | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 4fa07c808..1012fc1c0 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -196,6 +196,7 @@ struct BuildContext { bool has_resource; String link_flags; String extra_linker_flags; + String extra_assembler_flags; String microarch; BuildModeKind build_mode; bool generate_docs; diff --git a/src/main.cpp b/src/main.cpp index 16b776173..d35a01f10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -177,7 +177,6 @@ i32 linker_stage(lbGenerator *gen) { gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); - char lib_str_buf[1024] = {0}; char const *output_ext = "exe"; gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); @@ -278,9 +277,11 @@ i32 linker_stage(lbGenerator *gen) { "\"%.*s\\bin\\nasm\\nasm.exe\" \"%.*s\" " "-f win64 " "-o \"%.*s\" " + "%.*s " "", LIT(build_context.ODIN_ROOT), LIT(asm_file), - LIT(obj_file) + LIT(obj_file), + LIT(build_context.extra_assembler_flags) ); if (result) { @@ -651,6 +652,7 @@ enum BuildFlagKind { BuildFlag_UseLLVMApi, BuildFlag_IgnoreUnknownAttributes, BuildFlag_ExtraLinkerFlags, + BuildFlag_ExtraAssemblerFlags, BuildFlag_Microarch, BuildFlag_TestName, @@ -802,7 +804,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_VetExtra, str_lit("vet-extra"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test); @@ -1348,11 +1351,14 @@ bool parse_build_flags(Array args) { case BuildFlag_IgnoreUnknownAttributes: build_context.ignore_unknown_attributes = true; break; - case BuildFlag_ExtraLinkerFlags: { + case BuildFlag_ExtraLinkerFlags: GB_ASSERT(value.kind == ExactValue_String); build_context.extra_linker_flags = value.value_string; break; - } + case BuildFlag_ExtraAssemblerFlags: + GB_ASSERT(value.kind == ExactValue_String); + build_context.extra_assembler_flags = value.value_string; + break; case BuildFlag_Microarch: { GB_ASSERT(value.kind == ExactValue_String); build_context.microarch = value.value_string; @@ -2065,6 +2071,11 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-extra-linker-flags:"); print_usage_line(2, "Adds extra linker specific flags in a string"); print_usage_line(0, ""); + + print_usage_line(1, "-extra-assembler-flags:"); + print_usage_line(2, "Adds extra assembler specific flags in a string"); + print_usage_line(0, ""); + print_usage_line(1, "-microarch:"); print_usage_line(2, "Specifies the specific micro-architecture for the build in a string"); From 825548120484826f7de85fe2e8d346b22bf9d63c Mon Sep 17 00:00:00 2001 From: Joakim Hentula Date: Thu, 25 Nov 2021 11:20:40 +0000 Subject: [PATCH 0058/1258] Allow enums to pass #any_int checks --- src/check_type.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index b7feb562d..b4f30d2f0 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1564,7 +1564,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is p->flags &= ~FieldFlag_const; } if (p->flags&FieldFlag_any_int) { - error(name, "'#const' can only be applied to variable fields"); + error(name, "'#any_int' can only be applied to variable fields"); p->flags &= ~FieldFlag_any_int; } @@ -1614,7 +1614,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is ok = false; } } else if (p->flags&FieldFlag_any_int) { - if (!is_type_integer(op.type) || !is_type_integer(type)) { + if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) { ok = false; } else if (!check_is_castable_to(ctx, &op, type)) { ok = false; @@ -1684,7 +1684,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is param->flags |= EntityFlag_AutoCast; } if (p->flags&FieldFlag_any_int) { - if (!is_type_integer(param->type)) { + if (!is_type_integer(param->type) && !is_type_enum(param->type)) { gbString str = type_to_string(param->type); error(name, "A parameter with '#any_int' must be an integer, got %s", str); gb_string_free(str); From a4ba91a55435febb0b5daeadcff2450f52680044 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 25 Nov 2021 18:47:58 +0100 Subject: [PATCH 0059/1258] Check for non inserted semicolon in *expect_closing_brace_of_field_list* --- core/odin/parser/parser.odin | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index b4efc1460..1d27b4a79 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -419,7 +419,7 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token { expect_brace := expect_token(p, .Close_Brace) if expect_brace.kind != .Close_Brace { - for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { + for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF && !is_non_inserted_semicolon(p.curr_tok) { advance_token(p) } return p.curr_tok @@ -428,6 +428,9 @@ expect_closing_brace_of_field_list :: proc(p: ^Parser) -> tokenizer.Token { return expect_brace } +is_non_inserted_semicolon :: proc(tok: tokenizer.Token) -> bool { + return tok.kind == .Semicolon && tok.text != "\n" +} is_blank_ident :: proc{ is_blank_ident_string, From ffd7ca57f14efe63469b45cc0757d847c17c5556 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Nov 2021 14:40:39 +0000 Subject: [PATCH 0060/1258] Move nasm.exe to windows/nasm.exe, etc --- bin/nasm/{ => windows}/LICENSE | 0 bin/nasm/{ => windows}/nasm.exe | Bin bin/nasm/{ => windows}/ndisasm.exe | Bin src/main.cpp | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename bin/nasm/{ => windows}/LICENSE (100%) rename bin/nasm/{ => windows}/nasm.exe (100%) rename bin/nasm/{ => windows}/ndisasm.exe (100%) diff --git a/bin/nasm/LICENSE b/bin/nasm/windows/LICENSE similarity index 100% rename from bin/nasm/LICENSE rename to bin/nasm/windows/LICENSE diff --git a/bin/nasm/nasm.exe b/bin/nasm/windows/nasm.exe similarity index 100% rename from bin/nasm/nasm.exe rename to bin/nasm/windows/nasm.exe diff --git a/bin/nasm/ndisasm.exe b/bin/nasm/windows/ndisasm.exe similarity index 100% rename from bin/nasm/ndisasm.exe rename to bin/nasm/windows/ndisasm.exe diff --git a/src/main.cpp b/src/main.cpp index d35a01f10..1abe0f42d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -274,7 +274,7 @@ i32 linker_stage(lbGenerator *gen) { String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj")); result = system_exec_command_line_app("nasm", - "\"%.*s\\bin\\nasm\\nasm.exe\" \"%.*s\" " + "\"%.*s\\bin\\nasm\\windows\\nasm.exe\" \"%.*s\" " "-f win64 " "-o \"%.*s\" " "%.*s " From 33dc12a61aa2040d5cd82c8a20e3d9ed82a8c9a3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Nov 2021 14:46:03 +0000 Subject: [PATCH 0061/1258] Add supported check for `.asm` files --- src/checker.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/checker.cpp b/src/checker.cpp index c0a15905b..3301e2bf4 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4120,6 +4120,15 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { mpmc_enqueue(&ctx->info->required_foreign_imports_through_force_queue, e); add_entity_use(ctx, nullptr, e); } + + String ext = path_extension(fullpath); + if (ext == ".asm") { + if (build_context.metrics.arch != TargetArch_amd64 || + build_context.metrics.os != TargetOs_windows) { + error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s", + LIT(target_os_names[build_context.metrics.os]), LIT(target_arch_names[build_context.metrics.arch])); + } + } } // Returns true if a new package is present From 27106dd9aec67ebf9e3c53572513051e8bc973c6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Nov 2021 22:25:07 +0000 Subject: [PATCH 0062/1258] Allow `.asm`, `.s`, and `.S` as valid assembly file extensions --- src/build_settings.cpp | 12 ++++++++++++ src/checker.cpp | 3 +-- src/main.cpp | 4 ++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 1012fc1c0..29abd441c 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -822,6 +822,18 @@ bool show_error_line(void) { return build_context.show_error_line; } +bool has_asm_extension(String const &path) { + String ext = path_extension(path); + if (ext == ".asm") { + return true; + } else if (ext == ".s") { + return true; + } else if (ext == ".S") { + return true; + } + return false; +} + void init_build_context(TargetMetrics *cross_target) { BuildContext *bc = &build_context; diff --git a/src/checker.cpp b/src/checker.cpp index 3301e2bf4..e32adedde 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4121,8 +4121,7 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { add_entity_use(ctx, nullptr, e); } - String ext = path_extension(fullpath); - if (ext == ".asm") { + if (has_asm_extension(fullpath)) { if (build_context.metrics.arch != TargetArch_amd64 || build_context.metrics.os != TargetOs_windows) { error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s", diff --git a/src/main.cpp b/src/main.cpp index 1abe0f42d..7b4bc92ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -225,7 +225,7 @@ i32 linker_stage(lbGenerator *gen) { lbModule *m = gen->modules.entries[j].value; for_array(i, m->foreign_library_paths) { String lib = m->foreign_library_paths[i]; - if (string_ends_with(lib, str_lit(".asm"))) { + if (has_asm_extension(lib)) { string_set_add(&asm_files, lib); } else { string_set_add(&libs, lib); @@ -235,7 +235,7 @@ i32 linker_stage(lbGenerator *gen) { for_array(i, gen->default_module.foreign_library_paths) { String lib = gen->default_module.foreign_library_paths[i]; - if (string_ends_with(lib, str_lit(".asm"))) { + if (has_asm_extension(lib)) { string_set_add(&asm_files, lib); } else { string_set_add(&libs, lib); From 7876660d8c78143c71d7ba2b42d52ea67219a628 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Nov 2021 14:57:20 +0000 Subject: [PATCH 0063/1258] Add new utf16 procedures: `decode`, `decode_to_utf8` --- core/unicode/utf16/utf16.odin | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/core/unicode/utf16/utf16.odin b/core/unicode/utf16/utf16.odin index 380381f9a..2e349640e 100644 --- a/core/unicode/utf16/utf16.odin +++ b/core/unicode/utf16/utf16.odin @@ -1,5 +1,7 @@ package utf16 +import "core:unicode/utf8" + REPLACEMENT_CHAR :: '\ufffd' MAX_RUNE :: '\U0010ffff' @@ -80,3 +82,49 @@ encode_string :: proc(d: []u16, s: string) -> int { } return n } + +decode :: proc(d: []rune, s: []u16) -> (n: int) { + for i := 0; i < len(s); i += 1 { + if n >= len(d) { + return + } + + r := rune(REPLACEMENT_CHAR) + + switch c := s[i]; { + case c < _surr1, _surr3 <= c: + r = rune(c) + case _surr1 <= c && c < _surr2 && i+1 < len(s) && + _surr2 <= s[i+1] && s[i+1] < _surr3: + r = decode_surrogate_pair(rune(c), rune(s[i+1])) + i += 1 + } + d[n] = r + + n += 1 + } + return +} + + +decode_to_utf8 :: proc(d: []byte, s: []u16) -> (n: int) { + for i := 0; i < len(s); i += 1 { + if n >= len(d) { + return + } + r := rune(REPLACEMENT_CHAR) + + switch c := s[i]; { + case c < _surr1, _surr3 <= c: + r = rune(c) + case _surr1 <= r && r < _surr2 && i+1 < len(s) && + _surr2 <= s[i+1] && s[i+1] < _surr3: + r = decode_surrogate_pair(rune(r), rune(s[i+1])) + i += 1 + } + + b, w := utf8.encode_rune(rune(r)) + n += copy(d[n:], b[:w]) + } + return +} \ No newline at end of file From c9c197ba08d5c4d9697eaead3d3ec545e8e7e195 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Nov 2021 14:57:49 +0000 Subject: [PATCH 0064/1258] Add `os.read_at_least` and `os_read_full` utility procedures. --- core/os/os.odin | 55 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/core/os/os.odin b/core/os/os.odin index be1f5ad4e..83158be80 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -55,6 +55,25 @@ write_encoded_rune :: proc(fd: Handle, r: rune) { write_byte(fd, '\'') } +read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Errno) { + if len(buf) < min { + return 0, -1 + } + for n < min && err == 0 { + nn: int + nn, err = read(fd, buf[n:]) + n += nn + } + if n >= min { + err = 0 + } + return +} + +read_full :: proc(fd: Handle, buf: []byte) -> (n: int, err: Errno) { + return read_at_least(fd, buf, len(buf)) +} + file_size_from_path :: proc(path: string) -> i64 { fd, err := open(path, O_RDONLY, 0) @@ -85,27 +104,27 @@ read_entire_file_from_filename :: proc(name: string, allocator := context.alloca read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator) -> (data: []byte, success: bool) { context.allocator = allocator - length: i64 - err: Errno - if length, err = file_size(fd); err != 0 { - return nil, false - } + length: i64 + err: Errno + if length, err = file_size(fd); err != 0 { + return nil, false + } - if length <= 0 { - return nil, true - } + if length <= 0 { + return nil, true + } - data = make([]byte, int(length), allocator) - if data == nil { - return nil, false - } + data = make([]byte, int(length), allocator) + if data == nil { + return nil, false + } - bytes_read, read_err := read(fd, data) - if read_err != ERROR_NONE { - delete(data) - return nil, false - } - return data[:bytes_read], true + bytes_read, read_err := read_full(fd, data) + if read_err != ERROR_NONE { + delete(data) + return nil, false + } + return data[:bytes_read], true } read_entire_file :: proc { From 6616882708f9ad526d215cbe97b1a3f12dfd6bf8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Nov 2021 14:59:35 +0000 Subject: [PATCH 0065/1258] Correct reading from a console on Windows e.g. `os.read(os.stdin, buf[:])` --- core/os/file_windows.odin | 73 ++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 4d740db7c..419f8bbc2 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -2,6 +2,7 @@ package os import win32 "core:sys/windows" import "core:intrinsics" +import "core:unicode/utf16" is_path_separator :: proc(c: byte) -> bool { return c == '/' || c == '\\' @@ -96,26 +97,78 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { return int(total_write), ERROR_NONE } +@(private="file") +read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { + if len(b) == 0 { + return 0, 0 + } + + BUF_SIZE :: 386 + buf16: [BUF_SIZE]u16 + buf8: [4*BUF_SIZE]u8 + + for n < len(b) && err == 0 { + max_read := u32(min(BUF_SIZE, len(b)/4)) + + single_read_length: u32 + ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil) + if !ok { + err = Errno(win32.GetLastError()) + } + + buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length]) + src := buf8[:buf8_len] + + ctrl_z := false + for i := 0; i < len(src) && n+i < len(b); i += 1 { + x := src[i] + if x == 0x1a { // ctrl-z + ctrl_z = true + break + } + b[n] = x + n += 1 + } + if ctrl_z || single_read_length < len(buf16) { + break + } + } + + return +} + read :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { return 0, ERROR_NONE } + + handle := win32.HANDLE(fd) + + m: u32 + is_console := win32.GetConsoleMode(handle, &m) single_read_length: win32.DWORD - total_read: i64 - length := i64(len(data)) + total_read: int + length := len(data) - for total_read < length { - remaining := length - total_read - to_read := min(win32.DWORD(remaining), MAX_RW) + to_read := min(win32.DWORD(length), MAX_RW) - e := win32.ReadFile(win32.HANDLE(fd), &data[total_read], to_read, &single_read_length, nil) - if single_read_length <= 0 || !e { - err := Errno(win32.GetLastError()) + e: win32.BOOL + if is_console { + n, err := read_console(handle, data[total_read:][:to_read]) + total_read += n + if err != 0 { return int(total_read), err } - total_read += i64(single_read_length) + } else { + e = win32.ReadFile(handle, &data[total_read], to_read, &single_read_length, nil) } + if single_read_length <= 0 || !e { + err := Errno(win32.GetLastError()) + return int(total_read), err + } + total_read += int(single_read_length) + return int(total_read), ERROR_NONE } @@ -172,6 +225,8 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { Offset = u32(offset), } + // TODO(bill): Determine the correct behaviour for consoles + h := win32.HANDLE(fd) done: win32.DWORD if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { From 2b07afaf701a7a67f86ec907ea232a0b47ce082a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Nov 2021 16:03:03 +0000 Subject: [PATCH 0066/1258] Add lb_build_addr on `or_return` and `or_else` for sanity's sake --- src/llvm_backend_expr.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5187279fa..edda3a267 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4611,6 +4611,16 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { return lb_addr(res); case_end; + + case_ast_node(oe, OrElseExpr, expr); + lbValue ptr = lb_address_from_load_or_generate_local(p, lb_build_expr(p, expr)); + return lb_addr(ptr); + case_end; + + case_ast_node(oe, OrReturnExpr, expr); + lbValue ptr = lb_address_from_load_or_generate_local(p, lb_build_expr(p, expr)); + return lb_addr(ptr); + case_end; } TokenPos token_pos = ast_token(expr).pos; From 517c8ff1dd069591e225c6dd047a7d866948131b Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 28 Nov 2021 02:14:25 +0100 Subject: [PATCH 0067/1258] Include Matrix_Type to the `is_literal_type` switch statement. --- core/odin/parser/parser.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 7660005e0..b151d0188 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2825,6 +2825,7 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool { ast.Dynamic_Array_Type, ast.Map_Type, ast.Bit_Set_Type, + ast.Matrix_Type, ast.Call_Expr: return true } From f1a126e162b22d3de74e73c148426ef3399c39ba Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 2 Dec 2021 22:44:47 +0100 Subject: [PATCH 0068/1258] Do not save the comment when peeking. --- core/odin/parser/parser.odin | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index b151d0188..52d4b5e5a 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -47,6 +47,8 @@ Parser :: struct { fix_count: int, fix_prev_pos: tokenizer.Pos, + + peeking: bool, } MAX_FIX_COUNT :: 10 @@ -209,7 +211,12 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool { peek_token_kind :: proc(p: ^Parser, kind: tokenizer.Token_Kind, lookahead := 0) -> (ok: bool) { prev_parser := p^ - defer p^ = prev_parser + p.peeking = true + + defer { + p^ = prev_parser + p.peeking = false + } p.tok.err = nil for i := 0; i <= lookahead; i += 1 { @@ -222,7 +229,12 @@ peek_token_kind :: proc(p: ^Parser, kind: tokenizer.Token_Kind, lookahead := 0) peek_token :: proc(p: ^Parser, lookahead := 0) -> (tok: tokenizer.Token) { prev_parser := p^ - defer p^ = prev_parser + p.peeking = true + + defer { + p^ = prev_parser + p.peeking = false + } p.tok.err = nil for i := 0; i <= lookahead; i += 1 { @@ -305,7 +317,7 @@ consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Gro append(&list, comment) } - if len(list) > 0 { + if len(list) > 0 && !p.peeking { comments = ast.new(ast.Comment_Group, list[0].pos, end_pos(list[len(list)-1])) comments.list = list[:] append(&p.file.comments, comments) From 6ce5608003e630bc0de1c591fd4cbea3fe59e1d3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 3 Dec 2021 11:46:54 +0000 Subject: [PATCH 0069/1258] Correct `odin doc` default parameter value `init_string` generation --- src/checker.cpp | 1 + src/docs_writer.cpp | 7 +++++-- src/entity.cpp | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index 559b0ff86..667146eda 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2050,6 +2050,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { // WASM Specific str_lit("__ashlti3"), + str_lit("__multi3"), }; for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { force_add_dependency_entity(c, c->info.runtime_package->scope, required_runtime_entities[i]); diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 430e26782..e8e8892ec 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -826,6 +826,9 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { } if (e->flags & EntityFlag_Static) { flags |= OdinDocEntityFlag_Var_Static; } link_name = e->Variable.link_name; + if (init_expr == nullptr) { + init_expr = e->Variable.init_expr; + } break; case Entity_Procedure: if (e->Procedure.is_foreign) { flags |= OdinDocEntityFlag_Foreign; } @@ -856,8 +859,8 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) { init_string = odin_doc_write_string(w, make_string_c(exact_value_to_string(e->Constant.value))); } } else if (e->kind == Entity_Variable) { - if (e->Variable.param_expr) { - init_string = odin_doc_expr_string(w, e->Variable.param_expr); + if (e->Variable.param_value.original_ast_expr) { + init_string = odin_doc_expr_string(w, e->Variable.param_value.original_ast_expr); } } } diff --git a/src/entity.cpp b/src/entity.cpp index ef4f7e0fa..b39ffc63a 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -166,7 +166,6 @@ struct Entity { i32 field_index; ParameterValue param_value; - Ast * param_expr; String thread_local_model; Entity * foreign_library; From b5c828fe4ee3f0942b2eda1dc5753e4ad6d38ea9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 30 Nov 2021 23:01:22 +0100 Subject: [PATCH 0070/1258] [xml] Initial implementation of `core:encoding/xml`. A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). Features: - Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage. - Simple to understand and use. Small. Caveats: - We do NOT support HTML in this package, as that may or may not be valid XML. If it works, great. If it doesn't, that's not considered a bug. - We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences. - <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options. TODO: - Optional CDATA unboxing. - Optional `>`, ` `, ` ` and other escape substitution in tag bodies. - Test suite MAYBE: - XML writer? - Serialize/deserialize Odin types? --- core/encoding/xml/debug_print.odin | 73 ++ core/encoding/xml/example/xml_example.odin | 55 ++ core/encoding/xml/tokenizer.odin | 339 +++++++++ core/encoding/xml/xml_reader.odin | 651 ++++++++++++++++++ tests/core/Makefile | 17 +- tests/core/assets/xml/nl_NL-qt-ts.ts | 35 + tests/core/assets/xml/nl_NL-xliff-1.0.xliff | 38 + tests/core/assets/xml/nl_NL-xliff-2.0.xliff | 52 ++ tests/core/assets/xml/utf8.xml | 8 + tests/core/build.bat | 15 +- .../encoding/{ => json}/test_core_json.odin | 36 +- tests/core/encoding/xml/test_core_xml.odin | 264 +++++++ 12 files changed, 1553 insertions(+), 30 deletions(-) create mode 100644 core/encoding/xml/debug_print.odin create mode 100644 core/encoding/xml/example/xml_example.odin create mode 100644 core/encoding/xml/tokenizer.odin create mode 100644 core/encoding/xml/xml_reader.odin create mode 100644 tests/core/assets/xml/nl_NL-qt-ts.ts create mode 100644 tests/core/assets/xml/nl_NL-xliff-1.0.xliff create mode 100644 tests/core/assets/xml/nl_NL-xliff-2.0.xliff create mode 100644 tests/core/assets/xml/utf8.xml rename tests/core/encoding/{ => json}/test_core_json.odin (63%) create mode 100644 tests/core/encoding/xml/test_core_xml.odin diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin new file mode 100644 index 000000000..0b7ffa822 --- /dev/null +++ b/core/encoding/xml/debug_print.odin @@ -0,0 +1,73 @@ +package xml +/* + An XML 1.0 / 1.1 parser + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ +import "core:fmt" + +/* + Just for debug purposes. +*/ +print :: proc(doc: ^Document) { + assert(doc != nil) + + using fmt + println("[XML Prolog]") + + for attr in doc.prolog { + printf("\t%v: %v\n", attr.key, attr.val) + } + + printf("[Encoding] %v\n", doc.encoding) + printf("[DOCTYPE] %v\n", doc.doctype.ident) + + if len(doc.doctype.rest) > 0 { + printf("\t%v\n", doc.doctype.rest) + } + + if doc.root != nil { + println(" --- ") + print_element(0, doc.root) + println(" --- ") + } +} + +print_element :: proc(indent: int, element: ^Element) { + if element == nil { return } + using fmt + + tab :: proc(indent: int) { + tabs := "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" + + i := max(0, min(indent, len(tabs))) + printf("%v", tabs[:i]) + } + + tab(indent) + + if element.kind == .Element { + printf("<%v>\n", element.ident) + if len(element.value) > 0 { + tab(indent + 1) + printf("[Value] %v\n", element.value) + } + + for attr in element.attribs { + tab(indent + 1) + printf("[Attr] %v: %v\n", attr.key, attr.val) + } + + for child in element.children { + print_element(indent + 1, child) + } + } else if element.kind == .Comment { + printf("[COMMENT] %v\n", element.value) + } +} \ No newline at end of file diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin new file mode 100644 index 000000000..24a277de6 --- /dev/null +++ b/core/encoding/xml/example/xml_example.odin @@ -0,0 +1,55 @@ +package xml_example + +import "core:encoding/xml" +import "core:mem" +import "core:fmt" + +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) { + +} + +FILENAME :: "../../../../tests/core/assets/xml/nl_NL-xliff-1.0.xliff" +DOC :: #load(FILENAME) + +OPTIONS :: xml.Options{ + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "", +} + +_main :: proc() { + using fmt + + println("--- DOCUMENT TO PARSE ---") + println(string(DOC)) + println("--- /DOCUMENT TO PARSE ---\n") + + doc, err := xml.parse(DOC, OPTIONS, FILENAME, Error_Handler) + defer xml.destroy(doc) + + xml.print(doc) + + if err != .None { + printf("Parse error: %v\n", err) + } else { + println("DONE!") + } +} + +main :: proc() { + using fmt + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + _main() + + if len(track.allocation_map) > 0 { + println() + for _, v in track.allocation_map { + printf("%v Leaked %v bytes.\n", v.location, v.size) + } + } +} \ No newline at end of file diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin new file mode 100644 index 000000000..a63dca5bd --- /dev/null +++ b/core/encoding/xml/tokenizer.odin @@ -0,0 +1,339 @@ +package xml + +import "core:fmt" +import "core:unicode" +import "core:unicode/utf8" + +Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any) + +Token :: struct { + kind: Token_Kind, + text: string, + pos: Pos, +} + +Pos :: struct { + file: string, + offset: int, // starting at 0 + line: int, // starting at 1 + column: int, // starting at 1 +} + +Token_Kind :: enum { + Invalid, + + Ident, + Literal, + Rune, + String, + + Double_Quote, // " + Single_Quote, // ' + Colon, // : + + Eq, // = + Lt, // < + Gt, // > + Exclaim, // ! + Question, // ? + Hash, // # + Slash, // / + Dash, // - + + Open_Bracket, // [ + Close_Bracket, // ] + + EOF, +} + +CDATA_START :: "" + +Tokenizer :: struct { + // Immutable data + path: string, + src: string, + err: Error_Handler, + + // Tokenizing state + ch: rune, + offset: int, + read_offset: int, + line_offset: int, + line_count: int, + + // Mutable data + error_count: int, +} + +init :: proc(t: ^Tokenizer, src: string, path: string, err: Error_Handler = default_error_handler) { + t.src = src + t.err = err + t.ch = ' ' + t.offset = 0 + t.read_offset = 0 + t.line_offset = 0 + t.line_count = len(src) > 0 ? 1 : 0 + t.error_count = 0 + t.path = path + + advance_rune(t) + if t.ch == utf8.RUNE_BOM { + advance_rune(t) + } +} + +@(private) +offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos { + line := t.line_count + column := offset - t.line_offset + 1 + + return Pos { + file = t.path, + offset = offset, + line = line, + column = column, + } +} + +default_error_handler :: proc(pos: Pos, msg: string, args: ..any) { + fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column) + fmt.eprintf(msg, ..args) + fmt.eprintf("\n") +} + +error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { + pos := offset_to_pos(t, offset) + if t.err != nil { + t.err(pos, msg, ..args) + } + t.error_count += 1 +} + +advance_rune :: proc(using t: ^Tokenizer) { + if read_offset < len(src) { + offset = read_offset + if ch == '\n' { + line_offset = offset + line_count += 1 + } + r, w := rune(src[read_offset]), 1 + switch { + case r == 0: + error(t, t.offset, "illegal character NUL") + case r >= utf8.RUNE_SELF: + r, w = utf8.decode_rune_in_string(src[read_offset:]) + if r == utf8.RUNE_ERROR && w == 1 { + error(t, t.offset, "illegal UTF-8 encoding") + } else if r == utf8.RUNE_BOM && offset > 0 { + error(t, t.offset, "illegal byte order mark") + } + } + read_offset += w + ch = r + } else { + offset = len(src) + if ch == '\n' { + line_offset = offset + line_count += 1 + } + ch = -1 + } +} + +peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte { + if t.read_offset+offset < len(t.src) { + return t.src[t.read_offset+offset] + } + return 0 +} + +skip_whitespace :: proc(t: ^Tokenizer) { + for { + switch t.ch { + case ' ', '\t', '\r', '\n': + advance_rune(t) + case: + return + } + } +} + +is_letter :: proc(r: rune) -> bool { + if r < utf8.RUNE_SELF { + switch r { + case '_': + return true + case 'A'..='Z', 'a'..='z': + return true + } + } + return unicode.is_letter(r) +} + +is_valid_identifier_rune :: proc(r: rune) -> bool { + if r < utf8.RUNE_SELF { + switch r { + case '_', '-', ':': return true + case 'A'..='Z', 'a'..='z': return true + case '0'..'9': return true + } + } + + if unicode.is_digit(r) || unicode.is_letter(r) { + return true + } + return false +} + +scan_identifier :: proc(t: ^Tokenizer) -> string { + offset := t.offset + namespaced := false + + for is_valid_identifier_rune(t.ch) { + advance_rune(t) + if t.ch == ':' { + /* + A namespaced attr can have at most two parts, `namespace:ident`. + */ + if namespaced { + break + } + namespaced = true + } + } + return string(t.src[offset : t.offset]) +} + +scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false) -> (value: string, err: Error) { + err = .None + in_cdata := false + + loop: for { + ch := t.ch + + switch ch { + case -1: + error(t, t.offset, "[scan_string] Premature end of file.\n") + return "", .Premature_EOF + + case '<': + /* + Might be the start of a CDATA tag. + */ + if t.read_offset + len(CDATA_START) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { + in_cdata = true + } + } + + case ']': + /* + Might be the end of a CDATA tag. + */ + if t.read_offset + len(CDATA_END) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { + in_cdata = false + } + } + + case '\n': + if !in_cdata { + error(t, offset, string(t.src[offset : t.offset])) + error(t, offset, "[scan_string] Not terminated\n") + err = .Invalid_Tag_Value + break loop + } + } + + if ch == close && !in_cdata { + /* + If it's not a CDATA tag, it's the end of this body. + */ + break loop + } + + advance_rune(t) + } + + lit := string(t.src[offset : t.offset]) + if consume_close { + advance_rune(t) + } + + /* + TODO: Handle decoding escape characters and unboxing CDATA. + */ + + return lit, err +} + +peek :: proc(t: ^Tokenizer) -> (token: Token) { + old := t^ + token = scan(t) + t^ = old + return token +} + +scan :: proc(t: ^Tokenizer) -> Token { + skip_whitespace(t) + + offset := t.offset + + kind: Token_Kind + err: Error + lit: string + pos := offset_to_pos(t, offset) + + switch ch := t.ch; true { + case is_letter(ch): + lit = scan_identifier(t) + kind = .Ident + + case: + advance_rune(t) + switch ch { + case -1: + kind = .EOF + + case '<': kind = .Lt + case '>': kind = .Gt + case '!': kind = .Exclaim + case '?': kind = .Question + case '=': kind = .Eq + case '#': kind = .Hash + case '/': kind = .Slash + case '-': kind = .Dash + case ':': kind = .Colon + + case '"', '\'': + lit, err = scan_string(t, t.offset, ch, true) + if err == .None { + kind = .String + } else { + kind = .Invalid + } + + case '\n': + lit = "\n" + + case '\\': + token := scan(t) + if token.pos.line == pos.line { + error(t, token.pos.offset, "expected a newline after \\") + } + return token + + case: + if ch != utf8.RUNE_BOM { + // error(t, t.offset, "illegal character '%r': %d", ch, ch) + } + kind = .Invalid + } + } + + if lit == "" { + lit = string(t.src[offset : t.offset]) + } + return Token{kind, lit, pos} +} \ No newline at end of file diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin new file mode 100644 index 000000000..526be5856 --- /dev/null +++ b/core/encoding/xml/xml_reader.odin @@ -0,0 +1,651 @@ +package xml +/* + An XML 1.0 / 1.1 parser + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + A from-scratch XML implementation, loosely modelled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816). + + Features: + - Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage. + - Simple to understand and use. Small. + + Caveats: + - We do NOT support HTML in this package, as that may or may not be valid XML. + If it works, great. If it doesn't, that's not considered a bug. + + - We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences. + - <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options. + + TODO: + - Optional CDATA unboxing. + - Optional `>`, ` `, ` ` and other escape substitution in tag bodies. + + MAYBE: + - XML writer? + - Serialize/deserialize Odin types? + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ + +import "core:strings" +import "core:mem" +import "core:os" + +DEFAULT_Options :: Options{ + flags = { + .Ignore_Unsupported, + }, + expected_doctype = "", +} + +Option_Flag :: enum { + /* + Document MUST start with ` (doc: ^Document, err: Error) { + context.allocator = allocator + + opts := validate_options(options) or_return + + t := &Tokenizer{} + init(t, string(data), path, error_handler) + + doc = new(Document) + doc.allocator = allocator + doc.tokenizer = t + + strings.intern_init(&doc.intern, allocator, allocator) + + err = .Unexpected_Token + element, parent: ^Element + + /* + If a DOCTYPE is present, the root tag has to match. + If an expected DOCTYPE is given in options (i.e. it's non-empty), the DOCTYPE (if present) and root tag have to match. + */ + expected_doctype := options.expected_doctype + + loop: for { + tok := scan(t) + #partial switch tok.kind { + + case .Lt: + open := scan(t) + #partial switch open.kind { + + case .Question: + /* + 0 { + /* + We've already seen a prolog. + */ + return doc, .Too_Many_Prologs + } else { + error(t, t.offset, "Expected \" 0 { + return doc, .Too_Many_DocTypes + } + if doc.root != nil { + return doc, .DocType_Must_Proceed_Elements + } + parse_doctype(doc) or_return + + if len(expected_doctype) > 0 && expected_doctype != doc.doctype.ident { + error(t, t.offset, "Invalid DOCTYPE. Expected: %v, got: %v\n", expected_doctype, doc.doctype.ident) + return doc, .Invalid_DocType + } + expected_doctype = doc.doctype.ident + + case: + if .Error_on_Unsupported in opts.flags { + error(t, t.offset, "Unhandled: . + The grammar does not allow a comment to end in ---> + */ + if doc.root == nil { + return doc, .Comment_Before_Root_Element + } + + expect(t, .Dash) + offset := t.offset + + for { + advance_rune(t) + ch := t.ch + + /* + A comment ends when we see -->, preceded by a character that's not a dash. + "For compatibility, the string "--" (double-hyphen) must not occur within comments." + + See: https://www.w3.org/TR/2006/REC-xml11-20060816/#dt-comment + + Thanks to the length (4) of the comment start, we also have enough lookback, + and the peek at the next byte asserts that there's at least one more character + that's a `>`. + */ + if ch < 0 { + error(t, offset, "[parse] Comment was not terminated\n") + return doc, .Unclosed_Comment + } + + if string(t.src[t.offset - 1:][:2]) == "--" { + if peek_byte(t) == '>' { + break + } else { + error(t, t.offset - 1, "Invalid -- sequence in comment.\n") + return doc, .Invalid_Sequence_In_Comment + } + } + } + + if .Intern_Comments in opts.flags { + el := new(Element) + + el.parent = element + el.kind = .Comment + el.value = strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) + append(&element.children, el) + } + + expect(t, .Dash) + expect(t, .Gt) + + case: + error(t, t.offset, "Invalid Token after 0 && expected_doctype != open.text { + error(t, t.offset, "Root Tag doesn't match DOCTYPE. Expected: %v, got: %v\n", expected_doctype, open.text) + return doc, .Invalid_DocType + } + } + + /* + One of these should follow: + - `>`, which means we've just opened this tag and expect a later element to close it. + - `/>`, which means this is an 'empty' or self-closing tag. + */ + end_token := scan(t) + + #partial switch end_token.kind { + case .Gt: + /* + We're now the new parent. + */ + parent = element + + case .Slash: + /* + Empty tag? + */ + expect(t, .Gt) or_return + + case: + error(t, t.offset, "Expected close tag, got: %#v\n", end_token) + return + } + + case .Slash: + /* + Close tag. + */ + ident := expect(t, .Ident) or_return + _ = expect(t, .Gt) or_return + + if element.ident != ident.text { + error(t, t.offset, "Mismatched Closing Tag: %v\n", ident.text) + return doc, .Mismatched_Closing_Tag + } + parent = element.parent + element = parent + + case: + error(t, t.offset, "Invalid Token after <: %#v\n", open) + return + } + + case .EOF: + break loop + + case: + /* + This should be a tag's body text. + */ + element.value = scan_string(t, tok.pos.offset) or_return + } + } + + if .Must_Have_Prolog in opts.flags && len(doc.prolog) == 0 { + return doc, .No_Prolog + } + + if .Must_Have_DocType in opts.flags && len(doc.doctype.ident) == 0 { + return doc, .No_DocType + } + + return doc, .None +} + +parse_from_file :: proc(filename: string, options := DEFAULT_Options, error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) { + context.allocator = allocator + + data, data_ok := os.read_entire_file(filename) + defer delete(data) + + if !data_ok { return {}, .File_Error } + + return parse_from_slice(data, options, filename, error_handler, allocator) +} + +parse :: proc { parse_from_file, parse_from_slice } + +free_element :: proc(element: ^Element) { + if element == nil { return } + + for child in element.children { + /* + NOTE: Recursive. + + Could be rewritten so it adds them to a list of pointers to free. + */ + free_element(child) + } + delete(element.attribs) + delete(element.children) + free(element) +} + +destroy :: proc(doc: ^Document) { + if doc == nil { return } + + free_element(doc.root) + strings.intern_destroy(&doc.intern) + + delete(doc.prolog) + free(doc) +} + +/* + Helpers. +*/ + +validate_options :: proc(options: Options) -> (validated: Options, err: Error) { + validated = options + + if .Error_on_Unsupported in validated.flags && .Ignore_Unsupported in validated.flags { + return options, .Conflicting_Options + } + + if .Unbox_CDATA in validated.flags { + return options, .Unhandled_CDATA_Unboxing + } + + if .Decode_SGML_Entities in validated.flags { + return options, .Unhandled_SGML_Entity_Decoding + } + + return validated, .None +} + +expect :: proc(t: ^Tokenizer, kind: Token_Kind) -> (tok: Token, err: Error) { + tok = scan(t) + if tok.kind == kind { return tok, .None } + + error(t, t.offset, "Expected \"%v\", got \"%v\".", kind, tok.kind) + return tok, .Unexpected_Token +} + +parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) { + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + key := expect(t, .Ident) or_return + offset = t.offset - len(key.text) + + _ = expect(t, .Eq) or_return + value := expect(t, .String) or_return + + attr.key = strings.intern_get(&doc.intern, key.text) + attr.val = strings.intern_get(&doc.intern, value.text) + + err = .None + return +} + +check_duplicate_attributes :: proc(t: ^Tokenizer, attribs: Attributes, attr: Attr, offset: int) -> (err: Error) { + for a in attribs { + if attr.key == a.key { + error(t, offset, "Duplicate attribute: %v\n", attr.key) + return .Duplicate_Attribute + } + } + return .None +} + +parse_attributes :: proc(doc: ^Document, attribs: ^Attributes) -> (err: Error) { + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + for peek(t).kind == .Ident { + attr, offset := parse_attribute(doc) or_return + check_duplicate_attributes(t, attribs^, attr, offset) or_return + append(attribs, attr) + } + skip_whitespace(t) + return .None +} + +parse_prolog :: proc(doc: ^Document) -> (err: Error) { + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + offset := t.offset + parse_attributes(doc, &doc.prolog) or_return + + for attr in doc.prolog { + switch attr.key { + case "version": + switch attr.val { + case "1.0", "1.1": + case: + error(t, offset, "[parse_prolog] Warning: Unhandled XML version: %v\n", attr.val) + } + + case "encoding": + switch strings.to_lower(attr.val, context.temp_allocator) { + case "utf-8", "utf8": + doc.encoding = .UTF_8 + + case "latin-1", "latin1", "iso-8859-1": + doc.encoding = .LATIN_1 + + case: + /* + Unrecognized encoding, assume UTF-8. + */ + error(t, offset, "[parse_prolog] Warning: Unrecognized encoding: %v\n", attr.val) + } + + case: + // Ignored. + } + } + + _ = expect(t, .Question) or_return + _ = expect(t, .Gt) or_return + + return .None +} + +skip_element :: proc(t: ^Tokenizer) -> (err: Error) { + close := 1 + + loop: for { + tok := scan(t) + #partial switch tok.kind { + case .EOF: + error(t, t.offset, "[skip_element] Premature EOF\n") + return .Premature_EOF + + case .Lt: + close += 1 + + case .Gt: + close -= 1 + if close == 0 { + break loop + } + + case: + + } + } + return .None +} + +parse_doctype :: proc(doc: ^Document) -> (err: Error) { + /* + + + + ]> + */ + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + tok := expect(t, .Ident) or_return + doc.doctype.ident = strings.intern_get(&doc.intern, tok.text) + + skip_whitespace(t) + offset := t.offset + skip_element(t) or_return + + /* + -1 because the current offset is that of the closing tag, so the rest of the DOCTYPE tag ends just before it. + */ + doc.doctype.rest = strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) + return .None +} \ No newline at end of file diff --git a/tests/core/Makefile b/tests/core/Makefile index 0f0ffe4d6..e17dede90 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,22 +1,29 @@ ODIN=../../odin PYTHON=$(shell which python3) -all: download_test_assets image_test compress_test strings_test hash_test crypto_test +all: download_test_assets image_test compress_test strings_test hash_test crypto_test encoding_test download_test_assets: $(PYTHON) download_assets.py image_test: - $(ODIN) run image/test_core_image.odin + $(ODIN) run image/test_core_image.odin -out=test_image -o:speed -no-bounds-check compress_test: - $(ODIN) run compress/test_core_compress.odin + $(ODIN) run compress/test_core_compress.odin -out=test_compress -o:speed -no-bounds-check strings_test: - $(ODIN) run strings/test_core_strings.odin + $(ODIN) run strings/test_core_strings.odin -out=test_strings -o:speed -no-bounds-check + +odin_test: + $(ODIN) run odin -out=test_odin -o:speed -no-bounds-check hash_test: $(ODIN) run hash -out=test_hash -o:speed -no-bounds-check crypto_test: - $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check \ No newline at end of file + $(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check + +encoding_test: + $(ODIN) run encoding/json -out=test_encoding_json -o:speed -no-bounds-check + $(ODIN) run encoding/xml -out=test_encoding_xml -o:speed -no-bounds-check diff --git a/tests/core/assets/xml/nl_NL-qt-ts.ts b/tests/core/assets/xml/nl_NL-qt-ts.ts new file mode 100644 index 000000000..6ec3f2f47 --- /dev/null +++ b/tests/core/assets/xml/nl_NL-qt-ts.ts @@ -0,0 +1,35 @@ + + + + + Page + + Text for translation + commenting + Tekst om te vertalen + + + Also text to translate + some text + Ook tekst om te vertalen + + + + installscript + + 99 bottles of beer on the wall + some new comments here + 99 flessen bier op de muur + + + + apple_count + + %d apple(s) + + %d appel + %d appels + + + + diff --git a/tests/core/assets/xml/nl_NL-xliff-1.0.xliff b/tests/core/assets/xml/nl_NL-xliff-1.0.xliff new file mode 100644 index 000000000..7a1abcd66 --- /dev/null +++ b/tests/core/assets/xml/nl_NL-xliff-1.0.xliff @@ -0,0 +1,38 @@ + + + + + + text + tekst + Context + + + text 1 + tekst 1 + Context 1 + + + text 2 + + Context of the segment 2 + + + text 3 + translation 3 + Context 3 + + + Plurals + + %d month + %d maand + + + %d months + %d maanden + + + + + diff --git a/tests/core/assets/xml/nl_NL-xliff-2.0.xliff b/tests/core/assets/xml/nl_NL-xliff-2.0.xliff new file mode 100644 index 000000000..611ac80c4 --- /dev/null +++ b/tests/core/assets/xml/nl_NL-xliff-2.0.xliff @@ -0,0 +1,52 @@ + + + + + Note for file + + + + Note for unit + + + text + + + + + + Note for unit 2 + + + text 2 + translation 2 + + + + + Note for unit 3 + + + text 3 + approved translation 3 + + + + + + Plurals + + + %d month + %d maand + + + + + %d months + %d maanden + + + + + \ No newline at end of file diff --git a/tests/core/assets/xml/utf8.xml b/tests/core/assets/xml/utf8.xml new file mode 100644 index 000000000..c9ed3bf69 --- /dev/null +++ b/tests/core/assets/xml/utf8.xml @@ -0,0 +1,8 @@ + + +<恥ずべきフクロウ 올빼미_id="Foozle Hello, world!"]]>Barzle"> +<부끄러운:barzle> + ရှက်စရာ ဇီးကွက် + Owl of Shame + More CDATA Hello, world! Nonsense. + \ No newline at end of file diff --git a/tests/core/build.bat b/tests/core/build.bat index 176b7f175..7a214acc9 100644 --- a/tests/core/build.bat +++ b/tests/core/build.bat @@ -5,34 +5,35 @@ python3 download_assets.py echo --- echo Running core:image tests echo --- -%PATH_TO_ODIN% run image %COMMON% +%PATH_TO_ODIN% run image %COMMON% -out:test_image.exe echo --- echo Running core:compress tests echo --- -%PATH_TO_ODIN% run compress %COMMON% +%PATH_TO_ODIN% run compress %COMMON% -out:test_compress.exe echo --- echo Running core:strings tests echo --- -%PATH_TO_ODIN% run strings %COMMON% +%PATH_TO_ODIN% run strings %COMMON% -out:test_strings.exe echo --- echo Running core:hash tests echo --- -%PATH_TO_ODIN% run hash %COMMON% -o:size +%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_hash.exe echo --- echo Running core:odin tests echo --- -%PATH_TO_ODIN% run odin %COMMON% -o:size +%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_odin.exe echo --- echo Running core:crypto hash tests echo --- -%PATH_TO_ODIN% run crypto %COMMON% +%PATH_TO_ODIN% run crypto %COMMON% -o:speed -out:test_crypto.exe echo --- echo Running core:encoding tests echo --- -%PATH_TO_ODIN% run encoding %COMMON% \ No newline at end of file +%PATH_TO_ODIN% run encoding\json %COMMON% -out:test_json.exe +%PATH_TO_ODIN% run encoding\xml %COMMON% -out:test_xml.exe \ No newline at end of file diff --git a/tests/core/encoding/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin similarity index 63% rename from tests/core/encoding/test_core_json.odin rename to tests/core/encoding/json/test_core_json.odin index f536eb4c6..4f415c008 100644 --- a/tests/core/encoding/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -8,32 +8,32 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.println(message) + return + } + fmt.println(" PASS") + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } } main :: proc() { - t := testing.T{} + t := testing.T{} parse_json(&t) marshal_json(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } @test diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin new file mode 100644 index 000000000..7eefac212 --- /dev/null +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -0,0 +1,264 @@ +package test_core_xml + +import "core:encoding/xml" +import "core:testing" +import "core:mem" +import "core:fmt" + +Silent :: proc(pos: xml.Pos, fmt: string, args: ..any) { + // Custom (silent) error handler. +} + +OPTIONS :: xml.Options{ + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "", +} + +TEST_count := 0 +TEST_fail := 0 + +TEST :: struct { + filename: string, + options: xml.Options, + expected: struct { + error: xml.Error, + xml_version: string, + xml_encoding: string, + doctype: string, + }, +} + +TESTS :: []TEST{ + /* + First we test that certain files parse without error. + */ + { + filename = "assets/xml/utf8.xml", + options = OPTIONS, + expected = { + error = .None, + xml_version = "1.0", + xml_encoding = "utf-8", + doctype = "恥ずべきフクロウ", + }, + }, + { + filename = "assets/xml/nl_NL-qt-ts.ts", + options = OPTIONS, + expected = { + error = .None, + xml_version = "1.0", + xml_encoding = "utf-8", + doctype = "TS", + }, + }, + { + filename = "assets/xml/nl_NL-xliff-1.0.xliff", + options = OPTIONS, + expected = { + error = .None, + xml_version = "1.0", + xml_encoding = "UTF-8", + doctype = "", + }, + }, + { + filename = "assets/xml/nl_NL-xliff-2.0.xliff", + options = OPTIONS, + expected = { + error = .None, + xml_version = "1.0", + xml_encoding = "utf-8", + doctype = "", + }, + }, + + /* + Then we test that certain errors are returned as expected. + */ + { + filename = "assets/xml/utf8.xml", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "Odin", + }, + expected = { + error = .Invalid_DocType, + xml_version = "1.0", + xml_encoding = "utf-8", + doctype = "恥ずべきフクロウ", + }, + }, +} + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + fmt.printf("[%v] ", loc) + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.println(message) + return + } + fmt.println(" PASS") + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + t := testing.T{} + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + run_tests(&t) + + if len(track.allocation_map) > 0 { + for _, v in track.allocation_map { + err_msg := fmt.tprintf("%v Leaked %v bytes.", v.location, v.size) + expect(&t, false, err_msg) + } + } + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) +} + +@test +run_tests :: proc(t: ^testing.T) { + using fmt + + count := 0 + + for test in TESTS { + printf("Trying to parse %v\n\n", test.filename) + + doc, err := xml.parse(test.filename, test.options, Silent) + defer xml.destroy(doc) + + err_msg := tprintf("Expected return value %v, got %v", test.expected.error, err) + expect(t, err == test.expected.error, err_msg) + + if len(test.expected.xml_version) > 0 { + xml_version := "" + for attr in doc.prolog { + if attr.key == "version" { + xml_version = attr.val + } + } + + err_msg = tprintf("Expected XML version %v, got %v", test.expected.xml_version, xml_version) + expect(t, xml_version == test.expected.xml_version, err_msg) + } + + if len(test.expected.xml_encoding) > 0 { + xml_encoding := "" + for attr in doc.prolog { + if attr.key == "encoding" { + xml_encoding = attr.val + } + } + + err_msg = tprintf("Expected XML encoding %v, got %v", test.expected.xml_encoding, xml_encoding) + expect(t, xml_encoding == test.expected.xml_encoding, err_msg) + } + + err_msg = tprintf("Expected DOCTYPE %v, got %v", test.expected.doctype, doc.doctype.ident) + expect(t, doc.doctype.ident == test.expected.doctype, err_msg) + + /* + File-specific tests. + */ + switch count { + case 0: + expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") + attr := doc.root.attribs[0] + + attr_key_expected := "올빼미_id" + attr_val_expected := "Foozle Hello, world!\"]]>Barzle" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + + expect(t, len(doc.root.children) > 0, "Expected the root tag to have children.") + child := doc.root.children[0] + + first_child_ident := "부끄러운:barzle" + attr_err = tprintf("Expected first child tag's ident to be %v, got %v", first_child_ident, child.ident) + expect(t, child.ident == first_child_ident, attr_err) + + case 2: + expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") + + { + attr := doc.root.attribs[0] + + attr_key_expected := "version" + attr_val_expected := "1.2" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + } + + { + attr := doc.root.attribs[1] + + attr_key_expected := "xmlns" + attr_val_expected := "urn:oasis:names:tc:xliff:document:1.2" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + } + + case 3: + expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") + + { + attr := doc.root.attribs[0] + + attr_key_expected := "xmlns" + attr_val_expected := "urn:oasis:names:tc:xliff:document:2.0" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + } + + { + attr := doc.root.attribs[1] + + attr_key_expected := "version" + attr_val_expected := "2.0" + + attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) + expect(t, attr.key == attr_key_expected, attr_err) + + attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) + expect(t, attr.val == attr_val_expected, attr_err) + } + } + + count += 1 + } +} \ No newline at end of file From 9b2e67df67b5f801687f3c48c6701daa00c38088 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 30 Nov 2021 23:43:51 +0100 Subject: [PATCH 0071/1258] [xml] Small cleanup. --- core/encoding/xml/tokenizer.odin | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index a63dca5bd..3dcffb0d6 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -180,7 +180,7 @@ is_valid_identifier_rune :: proc(r: rune) -> bool { } } - if unicode.is_digit(r) || unicode.is_letter(r) { + if unicode.is_letter(r) || unicode.is_digit(r) { return true } return false @@ -317,17 +317,7 @@ scan :: proc(t: ^Tokenizer) -> Token { case '\n': lit = "\n" - case '\\': - token := scan(t) - if token.pos.line == pos.line { - error(t, token.pos.offset, "expected a newline after \\") - } - return token - case: - if ch != utf8.RUNE_BOM { - // error(t, t.offset, "illegal character '%r': %d", ch, ch) - } kind = .Invalid } } From 46a4927acad674b3265969bd5bde591b480d0c73 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 00:32:35 +0100 Subject: [PATCH 0072/1258] [xml] Use `io.Writer` for `xml.print(doc)`. --- core/encoding/xml/debug_print.odin | 51 ++++++++++++---------- core/encoding/xml/example/xml_example.odin | 8 +++- core/encoding/xml/xml_reader.odin | 2 +- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index 0b7ffa822..be1175cbc 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -10,64 +10,69 @@ package xml List of contributors: Jeroen van Rijn: Initial implementation. */ +import "core:io" import "core:fmt" /* Just for debug purposes. */ -print :: proc(doc: ^Document) { - assert(doc != nil) - +print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error) { + if doc == nil { return } using fmt - println("[XML Prolog]") + + written += wprintf(writer, "[XML Prolog]\n") for attr in doc.prolog { - printf("\t%v: %v\n", attr.key, attr.val) + written += wprintf(writer, "\t%v: %v\n", attr.key, attr.val) } - printf("[Encoding] %v\n", doc.encoding) - printf("[DOCTYPE] %v\n", doc.doctype.ident) + written += wprintf(writer, "[Encoding] %v\n", doc.encoding) + written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) if len(doc.doctype.rest) > 0 { - printf("\t%v\n", doc.doctype.rest) + wprintf(writer, "\t%v\n", doc.doctype.rest) } if doc.root != nil { - println(" --- ") - print_element(0, doc.root) - println(" --- ") - } + wprintln(writer, " --- ") + print_element(writer, doc.root) + wprintln(writer, " --- ") + } + + return written, .None } -print_element :: proc(indent: int, element: ^Element) { +print_element :: proc(writer: io.Writer, element: ^Element, indent := 0) -> (written: int, err: io.Error) { if element == nil { return } using fmt - tab :: proc(indent: int) { + tab :: proc(writer: io.Writer, indent: int) { tabs := "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" i := max(0, min(indent, len(tabs))) - printf("%v", tabs[:i]) + wprintf(writer, "%v", tabs[:i]) } - tab(indent) + tab(writer, indent) if element.kind == .Element { - printf("<%v>\n", element.ident) + wprintf(writer, "<%v>\n", element.ident) if len(element.value) > 0 { - tab(indent + 1) - printf("[Value] %v\n", element.value) + tab(writer, indent + 1) + wprintf(writer, "[Value] %v\n", element.value) } for attr in element.attribs { - tab(indent + 1) - printf("[Attr] %v: %v\n", attr.key, attr.val) + tab(writer, indent + 1) + wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val) } for child in element.children { - print_element(indent + 1, child) + print_element(writer, child, indent + 1) } } else if element.kind == .Comment { - printf("[COMMENT] %v\n", element.value) + wprintf(writer, "[COMMENT] %v\n", element.value) } + + return written, .None } \ No newline at end of file diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index 24a277de6..82938c223 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -2,6 +2,7 @@ package xml_example import "core:encoding/xml" import "core:mem" +import "core:strings" import "core:fmt" Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) { @@ -28,7 +29,12 @@ _main :: proc() { doc, err := xml.parse(DOC, OPTIONS, FILENAME, Error_Handler) defer xml.destroy(doc) - xml.print(doc) + buf: strings.Builder + defer strings.destroy_builder(&buf) + w := strings.to_writer(&buf) + + xml.print(w, doc) + println(strings.to_string(buf)) if err != .None { printf("Parse error: %v\n", err) diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 526be5856..34f6e65d0 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -75,6 +75,7 @@ Option_Flag :: enum { */ Decode_SGML_Entities, } +Option_Flags :: bit_set[Option_Flag; u8] Document :: struct { root: ^Element, @@ -122,7 +123,6 @@ Options :: struct { flags: Option_Flags, expected_doctype: string, } -Option_Flags :: bit_set[Option_Flag] Encoding :: enum { Unknown, From 682783a2aabad34e838493bb1e4c2437fd13058a Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 00:43:22 +0100 Subject: [PATCH 0073/1258] [xml] Tab indentation in debug printer. --- core/encoding/xml/debug_print.odin | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index be1175cbc..c4d6875cc 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -47,10 +47,9 @@ print_element :: proc(writer: io.Writer, element: ^Element, indent := 0) -> (wri using fmt tab :: proc(writer: io.Writer, indent: int) { - tabs := "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" - - i := max(0, min(indent, len(tabs))) - wprintf(writer, "%v", tabs[:i]) + for _ in 0..=indent { + wprintf(writer, "\t") + } } tab(writer, indent) From 32eab04d662b0c1128e64a4b91fb81f5f2be5a95 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 03:15:44 +0100 Subject: [PATCH 0074/1258] [xml] Allow multi-line bodies w/o CDATA. Strip trailing whitespace. --- core/encoding/xml/debug_print.odin | 9 ++++++--- core/encoding/xml/tokenizer.odin | 21 ++++++++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index c4d6875cc..65b71e30b 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -27,10 +27,13 @@ print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error } written += wprintf(writer, "[Encoding] %v\n", doc.encoding) - written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) - if len(doc.doctype.rest) > 0 { - wprintf(writer, "\t%v\n", doc.doctype.rest) + if len(doc.doctype.ident) > 0 { + written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) + + if len(doc.doctype.rest) > 0 { + wprintf(writer, "\t%v\n", doc.doctype.rest) + } } if doc.root != nil { diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 3dcffb0d6..e453552b8 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -205,7 +205,7 @@ scan_identifier :: proc(t: ^Tokenizer) -> string { return string(t.src[offset : t.offset]) } -scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false) -> (value: string, err: Error) { +scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false, multiline := true) -> (value: string, err: Error) { err = .None in_cdata := false @@ -238,7 +238,7 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close } case '\n': - if !in_cdata { + if !(multiline || in_cdata) { error(t, offset, string(t.src[offset : t.offset])) error(t, offset, "[scan_string] Not terminated\n") err = .Invalid_Tag_Value @@ -256,7 +256,22 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close advance_rune(t) } + /* + Strip trailing whitespace. + */ lit := string(t.src[offset : t.offset]) + + end := len(lit) + eat: for ; end > 0; end -= 1 { + ch := lit[end - 1] + switch ch { + case ' ', '\t', '\r', '\n': + case: + break eat + } + } + lit = lit[:end] + if consume_close { advance_rune(t) } @@ -307,7 +322,7 @@ scan :: proc(t: ^Tokenizer) -> Token { case ':': kind = .Colon case '"', '\'': - lit, err = scan_string(t, t.offset, ch, true) + lit, err = scan_string(t, t.offset, ch, true, false) if err == .None { kind = .String } else { From ec63d0bbd21aa3d3f33cd762bd656ea8eb0af4a6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 15:30:36 +0100 Subject: [PATCH 0075/1258] [xml] Robustness improvement. Can now parse https://www.w3.org/2003/entities/2007xml/unicode.xml no problem. --- core/encoding/xml/debug_print.odin | 4 ++ core/encoding/xml/xml_reader.odin | 73 ++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/core/encoding/xml/debug_print.odin b/core/encoding/xml/debug_print.odin index 65b71e30b..e6a8c9433 100644 --- a/core/encoding/xml/debug_print.odin +++ b/core/encoding/xml/debug_print.odin @@ -36,6 +36,10 @@ print :: proc(writer: io.Writer, doc: ^Document) -> (written: int, err: io.Error } } + for comment in doc.comments { + written += wprintf(writer, "[Pre-root comment] %v\n", comment) + } + if doc.root != nil { wprintln(writer, " --- ") print_element(writer, doc.root) diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 34f6e65d0..b2226e6b9 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -86,10 +86,16 @@ Document :: struct { /* We only scan the . The grammar does not allow a comment to end in ---> */ - if doc.root == nil { - return doc, .Comment_Before_Root_Element - } - expect(t, .Dash) offset := t.offset @@ -329,12 +339,17 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err } if .Intern_Comments in opts.flags { - el := new(Element) + comment := strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) - el.parent = element - el.kind = .Comment - el.value = strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) - append(&element.children, el) + if doc.root == nil { + append(&doc.comments, comment) + } else { + el := new(Element) + el.parent = element + el.kind = .Comment + el.value = comment + append(&element.children, el) + } } expect(t, .Dash) @@ -350,6 +365,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err e.g. `, which means this is an 'empty' or self-closing tag. */ end_token := scan(t) - #partial switch end_token.kind { case .Gt: /* @@ -394,9 +409,12 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err case .Slash: /* - Empty tag? + Empty tag. Close it. */ expect(t, .Gt) or_return + parent = element.parent + element = parent + tag_is_open = false case: error(t, t.offset, "Expected close tag, got: %#v\n", end_token) @@ -411,25 +429,33 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err _ = expect(t, .Gt) or_return if element.ident != ident.text { - error(t, t.offset, "Mismatched Closing Tag: %v\n", ident.text) + error(t, t.offset, "Mismatched Closing Tag. Expected %v, got %v\n", element.ident, ident.text) return doc, .Mismatched_Closing_Tag } - parent = element.parent - element = parent + parent = element.parent + element = parent + tag_is_open = false case: error(t, t.offset, "Invalid Token after <: %#v\n", open) return } - case .EOF: + case -1: + /* + End of file. + */ + if tag_is_open { + return doc, .Premature_EOF + } break loop case: /* This should be a tag's body text. */ - element.value = scan_string(t, tok.pos.offset) or_return + body_text := scan_string(t, t.offset) or_return + element.value = strings.intern_get(&doc.intern, body_text) } } @@ -480,6 +506,7 @@ destroy :: proc(doc: ^Document) { strings.intern_destroy(&doc.intern) delete(doc.prolog) + delete(doc.comments) free(doc) } From beff90e1d12391e63cd1119023f8565eda97593e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 1 Dec 2021 18:02:48 +0100 Subject: [PATCH 0076/1258] [xml] Slight optimization. About a 5% speed bump. More rigorous optimization later. --- core/encoding/xml/tokenizer.odin | 62 ++++++++++++++++++------------- core/encoding/xml/xml_reader.odin | 4 +- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index e453552b8..9247d2531 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -110,44 +110,51 @@ error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { t.error_count += 1 } +@(optimization_mode="speed") advance_rune :: proc(using t: ^Tokenizer) { - if read_offset < len(src) { - offset = read_offset - if ch == '\n' { - line_offset = offset - line_count += 1 - } - r, w := rune(src[read_offset]), 1 - switch { - case r == 0: - error(t, t.offset, "illegal character NUL") - case r >= utf8.RUNE_SELF: - r, w = utf8.decode_rune_in_string(src[read_offset:]) - if r == utf8.RUNE_ERROR && w == 1 { - error(t, t.offset, "illegal UTF-8 encoding") - } else if r == utf8.RUNE_BOM && offset > 0 { - error(t, t.offset, "illegal byte order mark") + #no_bounds_check { + /* + Already bounds-checked here. + */ + if read_offset < len(src) { + offset = read_offset + if ch == '\n' { + line_offset = offset + line_count += 1 } + r, w := rune(src[read_offset]), 1 + switch { + case r == 0: + error(t, t.offset, "illegal character NUL") + case r >= utf8.RUNE_SELF: + r, w = #force_inline utf8.decode_rune_in_string(src[read_offset:]) + if r == utf8.RUNE_ERROR && w == 1 { + error(t, t.offset, "illegal UTF-8 encoding") + } else if r == utf8.RUNE_BOM && offset > 0 { + error(t, t.offset, "illegal byte order mark") + } + } + read_offset += w + ch = r + } else { + offset = len(src) + if ch == '\n' { + line_offset = offset + line_count += 1 + } + ch = -1 } - read_offset += w - ch = r - } else { - offset = len(src) - if ch == '\n' { - line_offset = offset - line_count += 1 - } - ch = -1 } } peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte { if t.read_offset+offset < len(t.src) { - return t.src[t.read_offset+offset] + #no_bounds_check return t.src[t.read_offset+offset] } return 0 } +@(optimization_mode="speed") skip_whitespace :: proc(t: ^Tokenizer) { for { switch t.ch { @@ -159,6 +166,7 @@ skip_whitespace :: proc(t: ^Tokenizer) { } } +@(optimization_mode="speed") is_letter :: proc(r: rune) -> bool { if r < utf8.RUNE_SELF { switch r { @@ -177,6 +185,7 @@ is_valid_identifier_rune :: proc(r: rune) -> bool { case '_', '-', ':': return true case 'A'..='Z', 'a'..='z': return true case '0'..'9': return true + case -1: return false } } @@ -205,6 +214,7 @@ scan_identifier :: proc(t: ^Tokenizer) -> string { return string(t.src[offset : t.offset]) } +@(optimization_mode="speed") scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false, multiline := true) -> (value: string, err: Error) { err = .None in_cdata := false diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index b2226e6b9..35dd83b3f 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -239,7 +239,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err /* Consume peeked `<` */ - tok := scan(t) + advance_rune(t) open := scan(t) #partial switch open.kind { @@ -265,7 +265,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err skip_element(t) or_return } case: - error(t, t.offset, "Expected \" Date: Wed, 1 Dec 2021 22:01:19 +0100 Subject: [PATCH 0077/1258] [xml] Improve CDATA + comment handling in tag body. --- core/encoding/xml/tokenizer.odin | 117 ++++++++++++++++++++++++------ core/encoding/xml/xml_reader.odin | 36 +-------- 2 files changed, 96 insertions(+), 57 deletions(-) diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 9247d2531..95024518d 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -46,8 +46,11 @@ Token_Kind :: enum { EOF, } -CDATA_START :: "" +CDATA_START :: "" + +COMMENT_START :: "" Tokenizer :: struct { // Immutable data @@ -214,10 +217,83 @@ scan_identifier :: proc(t: ^Tokenizer) -> string { return string(t.src[offset : t.offset]) } +/* + A comment ends when we see -->, preceded by a character that's not a dash. + "For compatibility, the string "--" (double-hyphen) must not occur within comments." + + See: https://www.w3.org/TR/2006/REC-xml11-20060816/#dt-comment + + Thanks to the length (4) of the comment start, we also have enough lookback, + and the peek at the next byte asserts that there's at least one more character + that's a `>`. +*/ +scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) { + offset := t.offset + + for { + advance_rune(t) + ch := t.ch + + if ch < 0 { + error(t, offset, "[parse] Comment was not terminated\n") + return "", .Unclosed_Comment + } + + if string(t.src[t.offset - 1:][:2]) == "--" { + if peek_byte(t) == '>' { + break + } else { + error(t, t.offset - 1, "Invalid -- sequence in comment.\n") + return "", .Invalid_Sequence_In_Comment + } + } + } + + expect(t, .Dash) + expect(t, .Gt) + + return string(t.src[offset : t.offset - 1]), .None +} + +/* + Skip CDATA +*/ +skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) { + if t.read_offset + len(CDATA_START) >= len(t.src) { + /* + Can't be the start of a CDATA tag. + */ + return .None + } + + if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { + t.read_offset += len(CDATA_START) + offset := t.offset + + cdata_scan: for { + advance_rune(t) + if t.ch < 0 { + error(t, offset, "[scan_string] CDATA was not terminated\n") + return .Premature_EOF + } + + /* + Scan until the end of a CDATA tag. + */ + if t.read_offset + len(CDATA_END) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { + t.read_offset += len(CDATA_END) + break cdata_scan + } + } + } + } + return +} + @(optimization_mode="speed") scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false, multiline := true) -> (value: string, err: Error) { err = .None - in_cdata := false loop: for { ch := t.ch @@ -228,27 +304,23 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close return "", .Premature_EOF case '<': - /* - Might be the start of a CDATA tag. - */ - if t.read_offset + len(CDATA_START) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { - in_cdata = true - } - } - - case ']': - /* - Might be the end of a CDATA tag. - */ - if t.read_offset + len(CDATA_END) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { - in_cdata = false + if peek_byte(t) == '!' { + if peek_byte(t, 1) == '[' { + /* + Might be the start of a CDATA tag. + */ + skip_cdata(t) or_return + } else if peek_byte(t, 1) == '-' && peek_byte(t, 2) == '-' { + /* + Comment start. Eat comment. + */ + t.read_offset += 3 + _ = scan_comment(t) or_return } } case '\n': - if !(multiline || in_cdata) { + if !multiline { error(t, offset, string(t.src[offset : t.offset])) error(t, offset, "[scan_string] Not terminated\n") err = .Invalid_Tag_Value @@ -256,13 +328,12 @@ scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close } } - if ch == close && !in_cdata { + if t.ch == close { /* - If it's not a CDATA tag, it's the end of this body. + If it's not a CDATA or comment, it's the end of this body. */ break loop } - advance_rune(t) } diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 35dd83b3f..146c278cb 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -307,39 +307,10 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err The grammar does not allow a comment to end in ---> */ expect(t, .Dash) - offset := t.offset - - for { - advance_rune(t) - ch := t.ch - - /* - A comment ends when we see -->, preceded by a character that's not a dash. - "For compatibility, the string "--" (double-hyphen) must not occur within comments." - - See: https://www.w3.org/TR/2006/REC-xml11-20060816/#dt-comment - - Thanks to the length (4) of the comment start, we also have enough lookback, - and the peek at the next byte asserts that there's at least one more character - that's a `>`. - */ - if ch < 0 { - error(t, offset, "[parse] Comment was not terminated\n") - return doc, .Unclosed_Comment - } - - if string(t.src[t.offset - 1:][:2]) == "--" { - if peek_byte(t) == '>' { - break - } else { - error(t, t.offset - 1, "Invalid -- sequence in comment.\n") - return doc, .Invalid_Sequence_In_Comment - } - } - } + comment := scan_comment(t) or_return if .Intern_Comments in opts.flags { - comment := strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) + comment = strings.intern_get(&doc.intern, comment) if doc.root == nil { append(&doc.comments, comment) @@ -352,9 +323,6 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err } } - expect(t, .Dash) - expect(t, .Gt) - case: error(t, t.offset, "Invalid Token after Date: Thu, 2 Dec 2021 18:00:29 +0100 Subject: [PATCH 0078/1258] [xml] Improvements. --- core/encoding/xml/example/xml_example.odin | 71 +++++++++++-------- core/encoding/xml/helpers.odin | 49 +++++++++++++ core/encoding/xml/tokenizer.odin | 6 +- core/encoding/xml/xml_reader.odin | 2 + tests/core/assets/XML/.gitignore | 2 + tests/core/assets/{xml => XML}/nl_NL-qt-ts.ts | 0 .../assets/{xml => XML}/nl_NL-xliff-1.0.xliff | 0 .../assets/{xml => XML}/nl_NL-xliff-2.0.xliff | 0 tests/core/assets/{xml => XML}/utf8.xml | 0 tests/core/download_assets.py | 43 ++++++++--- tests/core/encoding/xml/test_core_xml.odin | 10 +-- 11 files changed, 137 insertions(+), 46 deletions(-) create mode 100644 core/encoding/xml/helpers.odin create mode 100644 tests/core/assets/XML/.gitignore rename tests/core/assets/{xml => XML}/nl_NL-qt-ts.ts (100%) rename tests/core/assets/{xml => XML}/nl_NL-xliff-1.0.xliff (100%) rename tests/core/assets/{xml => XML}/nl_NL-xliff-2.0.xliff (100%) rename tests/core/assets/{xml => XML}/utf8.xml (100%) diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index 82938c223..085252e92 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -1,45 +1,55 @@ package xml_example import "core:encoding/xml" +import "core:os" +import "core:path" import "core:mem" -import "core:strings" import "core:fmt" -Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) { +/* + Silent error handler for the parser. +*/ +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} -} +OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } -FILENAME :: "../../../../tests/core/assets/xml/nl_NL-xliff-1.0.xliff" -DOC :: #load(FILENAME) - -OPTIONS :: xml.Options{ - flags = { - .Ignore_Unsupported, .Intern_Comments, - }, - expected_doctype = "", -} - -_main :: proc() { +example :: proc() { using fmt - println("--- DOCUMENT TO PARSE ---") - println(string(DOC)) - println("--- /DOCUMENT TO PARSE ---\n") + filename := path.join(ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml") + defer delete(filename) - doc, err := xml.parse(DOC, OPTIONS, FILENAME, Error_Handler) + doc, err := xml.parse(filename, OPTIONS, Error_Handler) defer xml.destroy(doc) - buf: strings.Builder - defer strings.destroy_builder(&buf) - w := strings.to_writer(&buf) - - xml.print(w, doc) - println(strings.to_string(buf)) - if err != .None { - printf("Parse error: %v\n", err) - } else { - println("DONE!") + printf("Load/Parse error: %v\n", err) + if err == .File_Error { + printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename) + } + os.exit(1) + } + + printf("\"%v\" loaded and parsed.\n", filename) + + charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist") + if !charlist_ok { + eprintln("Could not locate top-level `` tag.") + os.exit(1) + } + + printf("Found `` with %v children.\n", len(charlist.children)) + + for char in charlist.children { + if char.ident != "character" { + eprintf("Expected ``, got `<%v>`\n", char.ident) + os.exit(1) + } + + if _, ok := xml.find_attribute_val_by_key(char, "dec"); !ok { + eprintln("`` attribute not found.") + os.exit(1) + } } } @@ -50,12 +60,13 @@ main :: proc() { mem.tracking_allocator_init(&track, context.allocator) context.allocator = mem.tracking_allocator(&track) - _main() + example() if len(track.allocation_map) > 0 { println() for _, v in track.allocation_map { printf("%v Leaked %v bytes.\n", v.location, v.size) } - } + } + println("Done and cleaned up!") } \ No newline at end of file diff --git a/core/encoding/xml/helpers.odin b/core/encoding/xml/helpers.odin new file mode 100644 index 000000000..14597ddbd --- /dev/null +++ b/core/encoding/xml/helpers.odin @@ -0,0 +1,49 @@ +package xml +/* + An XML 1.0 / 1.1 parser + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + This file contains helper functions. +*/ + + +/* + Find `tag`'s nth child with a given ident. +*/ +find_child_by_ident :: proc(tag: ^Element, ident: string, nth := 0) -> (res: ^Element, found: bool) { + if tag == nil { return nil, false } + + count := 0 + for child in tag.children { + /* + Skip commments. They have no name. + */ + if child.kind != .Element { continue } + + /* + If the ident matches and it's the nth such child, return it. + */ + if child.ident == ident { + if count == nth { return child, true } + count += 1 + } + } + return nil, false +} + +/* + Find an attribute by key. +*/ +find_attribute_val_by_key :: proc(tag: ^Element, key: string) -> (val: string, found: bool) { + if tag == nil { return "", false } + + for attr in tag.attribs { + /* + If the ident matches, we're done. There can only ever be one attribute with the same name. + */ + if attr.key == key { return attr.val, true } + } + return "", false +} \ No newline at end of file diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 95024518d..2da3b7683 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -403,11 +403,11 @@ scan :: proc(t: ^Tokenizer) -> Token { case ':': kind = .Colon case '"', '\'': + kind = .Invalid + lit, err = scan_string(t, t.offset, ch, true, false) if err == .None { kind = .String - } else { - kind = .Invalid } case '\n': @@ -418,7 +418,7 @@ scan :: proc(t: ^Tokenizer) -> Token { } } - if lit == "" { + if kind != .String && lit == "" { lit = string(t.src[offset : t.offset]) } return Token{kind, lit, pos} diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 146c278cb..563294309 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -519,6 +519,8 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) _ = expect(t, .Eq) or_return value := expect(t, .String) or_return + error(t, t.offset, "String: %v\n", value) + attr.key = strings.intern_get(&doc.intern, key.text) attr.val = strings.intern_get(&doc.intern, value.text) diff --git a/tests/core/assets/XML/.gitignore b/tests/core/assets/XML/.gitignore new file mode 100644 index 000000000..32dc58b57 --- /dev/null +++ b/tests/core/assets/XML/.gitignore @@ -0,0 +1,2 @@ +# This file will be downloaded by download_assets.py +unicode.xml \ No newline at end of file diff --git a/tests/core/assets/xml/nl_NL-qt-ts.ts b/tests/core/assets/XML/nl_NL-qt-ts.ts similarity index 100% rename from tests/core/assets/xml/nl_NL-qt-ts.ts rename to tests/core/assets/XML/nl_NL-qt-ts.ts diff --git a/tests/core/assets/xml/nl_NL-xliff-1.0.xliff b/tests/core/assets/XML/nl_NL-xliff-1.0.xliff similarity index 100% rename from tests/core/assets/xml/nl_NL-xliff-1.0.xliff rename to tests/core/assets/XML/nl_NL-xliff-1.0.xliff diff --git a/tests/core/assets/xml/nl_NL-xliff-2.0.xliff b/tests/core/assets/XML/nl_NL-xliff-2.0.xliff similarity index 100% rename from tests/core/assets/xml/nl_NL-xliff-2.0.xliff rename to tests/core/assets/XML/nl_NL-xliff-2.0.xliff diff --git a/tests/core/assets/xml/utf8.xml b/tests/core/assets/XML/utf8.xml similarity index 100% rename from tests/core/assets/xml/utf8.xml rename to tests/core/assets/XML/utf8.xml diff --git a/tests/core/download_assets.py b/tests/core/download_assets.py index d86f7f1e7..831b5b13a 100644 --- a/tests/core/download_assets.py +++ b/tests/core/download_assets.py @@ -50,10 +50,7 @@ def try_download_file(url, out_file): print("Could not download", url) return 1 -def try_download_and_unpack_zip(suite): - url = ASSETS_BASE_URL.format(suite, "{}.zip".format(suite)) - out_file = DOWNLOAD_BASE_PATH.format(suite) + "/{}.zip".format(suite) - +def try_download_and_unpack_zip(url, out_file, extract_path): print("\tDownloading {} to {}.".format(url, out_file)) if try_download_file(url, out_file) is not None: @@ -65,7 +62,6 @@ def try_download_and_unpack_zip(suite): with zipfile.ZipFile(out_file) as z: for file in z.filelist: filename = file.filename - extract_path = DOWNLOAD_BASE_PATH.format(suite) print("\t\tExtracting: {}".format(filename)) z.extract(file, extract_path) @@ -73,25 +69,56 @@ def try_download_and_unpack_zip(suite): print("Could not extract ZIP file") return 2 +def download_png_assets(): + suite = "PNG" + url = ASSETS_BASE_URL.format(suite, "{}.zip".format(suite)) + out_file = DOWNLOAD_BASE_PATH.format(suite) + "/{}.zip".format(suite) + extract_path = DOWNLOAD_BASE_PATH.format(suite) -def main(): print("Downloading PNG assets") # Make PNG assets path try: - path = DOWNLOAD_BASE_PATH.format("PNG") + path = DOWNLOAD_BASE_PATH.format(suite) os.makedirs(path) except FileExistsError: pass # Try downloading and unpacking the PNG assets - r = try_download_and_unpack_zip("PNG") + r = try_download_and_unpack_zip(url, out_file, extract_path) if r is not None: return r # We could fall back on downloading the PNG files individually, but it's slow print("Done downloading PNG assets") + +def download_unicode_assets(): + suite = "XML" + url = "https://www.w3.org/2003/entities/2007xml/unicode.xml.zip" + out_file = DOWNLOAD_BASE_PATH.format(suite) + "/{}.zip".format(suite) + extract_path = DOWNLOAD_BASE_PATH.format(suite) + + print("Downloading {}.".format(url)) + + # Make XML assets path + try: + path = DOWNLOAD_BASE_PATH.format(suite) + os.makedirs(path) + except FileExistsError: + pass + + # Try downloading and unpacking the assets + r = try_download_and_unpack_zip(url, out_file, extract_path) + if r is not None: + return r + + print("Done downloading Unicode/XML assets") + +def main(): + download_png_assets() + download_unicode_assets() + return 0 if __name__ == '__main__': diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 7eefac212..c2e0aa172 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -35,7 +35,7 @@ TESTS :: []TEST{ First we test that certain files parse without error. */ { - filename = "assets/xml/utf8.xml", + filename = "assets/XML/utf8.xml", options = OPTIONS, expected = { error = .None, @@ -45,7 +45,7 @@ TESTS :: []TEST{ }, }, { - filename = "assets/xml/nl_NL-qt-ts.ts", + filename = "assets/XML/nl_NL-qt-ts.ts", options = OPTIONS, expected = { error = .None, @@ -55,7 +55,7 @@ TESTS :: []TEST{ }, }, { - filename = "assets/xml/nl_NL-xliff-1.0.xliff", + filename = "assets/XML/nl_NL-xliff-1.0.xliff", options = OPTIONS, expected = { error = .None, @@ -65,7 +65,7 @@ TESTS :: []TEST{ }, }, { - filename = "assets/xml/nl_NL-xliff-2.0.xliff", + filename = "assets/XML/nl_NL-xliff-2.0.xliff", options = OPTIONS, expected = { error = .None, @@ -79,7 +79,7 @@ TESTS :: []TEST{ Then we test that certain errors are returned as expected. */ { - filename = "assets/xml/utf8.xml", + filename = "assets/XML/utf8.xml", options = { flags = { .Ignore_Unsupported, .Intern_Comments, From 2dd67dba89732b89adb0199bc0a99de4cbc34e8f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 2 Dec 2021 20:12:12 +0100 Subject: [PATCH 0079/1258] [core:encoding/entity] Add new package to decode &; entities. Includes generator to generate a lookup for named entitiess. --- core/encoding/entity/LICENSE_table.md | 21 + core/encoding/entity/entity.odin | 358 + .../entity/example/entity_example.odin | 122 + core/encoding/entity/example/test.html | 26 + core/encoding/entity/generated.odin | 7493 +++++++++++++++++ core/encoding/xml/xml_reader.odin | 2 - core/unicode/tools/generate_entity_table.odin | 287 + 7 files changed, 8307 insertions(+), 2 deletions(-) create mode 100644 core/encoding/entity/LICENSE_table.md create mode 100644 core/encoding/entity/entity.odin create mode 100644 core/encoding/entity/example/entity_example.odin create mode 100644 core/encoding/entity/example/test.html create mode 100644 core/encoding/entity/generated.odin create mode 100644 core/unicode/tools/generate_entity_table.odin diff --git a/core/encoding/entity/LICENSE_table.md b/core/encoding/entity/LICENSE_table.md new file mode 100644 index 000000000..51e3f34b5 --- /dev/null +++ b/core/encoding/entity/LICENSE_table.md @@ -0,0 +1,21 @@ +# License + +By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. + +Permission to copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications: + +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software Short Notice should be included (hypertext is preferred, text is permitted) within the body of any redistributed or derivative code. + +Notice of any changes or modifications to the files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.) + +# Disclaimers + +THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. + +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. + +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. + +# Notes +This version: http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 \ No newline at end of file diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin new file mode 100644 index 000000000..e40896819 --- /dev/null +++ b/core/encoding/entity/entity.odin @@ -0,0 +1,358 @@ +package unicode_entity +/* + A unicode entity encoder/decoder + + Copyright 2021 Jeroen van Rijn . + Made available under Odin's BSD-3 license. + + This code has several procedures to map unicode runes to/from different textual encodings. + - SGML/XML/HTML entity + -- &#; + -- &#x; + -- &; (If the lookup tables are compiled in). + Reference: https://www.w3.org/2003/entities/2007xml/unicode.xml + + - URL encode / decode %hex entity + Reference: https://datatracker.ietf.org/doc/html/rfc3986/#section-2.1 + + List of contributors: + Jeroen van Rijn: Initial implementation. +*/ + +import "core:unicode/utf8" +import "core:unicode" +import "core:strings" + +MAX_RUNE_CODEPOINT :: int(unicode.MAX_RUNE) + +write_rune :: strings.write_rune_builder +write_string :: strings.write_string_builder + +Error :: enum u8 { + None = 0, + Tokenizer_Is_Nil, + + Illegal_NUL_Character, + Illegal_UTF_Encoding, + Illegal_BOM, + + CDATA_Not_Terminated, + Comment_Not_Terminated, + Invalid_Entity_Encoding, +} + +Tokenizer :: struct { + r: rune, + w: int, + + src: string, + offset: int, + read_offset: int, +} + +CDATA_START :: "" + +COMMENT_START :: "" + +/* + Default: CDATA and comments are passed through unchanged. +*/ +XML_Decode_Option :: enum u8 { + /* + CDATA is unboxed. + */ + CDATA_Unbox, + + /* + Unboxed CDATA is decoded as well. + Ignored if `.CDATA_Unbox` is not given. + */ + CDATA_Decode, + + /* + Comments are stripped. + */ + Comment_Strip, +} +XML_Decode_Options :: bit_set[XML_Decode_Option; u8] + +/* + Decode a string that may include SGML/XML/HTML entities. + The caller has to free the result. +*/ +decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := context.allocator) -> (decoded: string, err: Error) { + context.allocator = allocator + + l := len(input) + if l == 0 { return "", .None } + + builder := strings.make_builder() + defer strings.destroy_builder(&builder) + + t := Tokenizer{src=input} + in_data := false + + loop: for { + advance(&t) or_return + if t.r < 0 { break loop } + + /* + Below here we're never inside a CDATA tag. + At most we'll see the start of one, but that doesn't affect the logic. + */ + switch t.r { + case '<': + /* + Might be the start of a CDATA tag or comment. + + We don't need to check if we need to write a `<`, because if it isn't CDATA or a comment, + it couldn't have been part of an XML tag body to be decoded here. + */ + in_data = _handle_xml_special(&t, &builder, options) or_return + + case ']': + /* + If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag. + */ + if in_data { + if t.read_offset + len(CDATA_END) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { + in_data = false + t.read_offset += len(CDATA_END) - 1 + } + } + continue + } else { + write_rune(&builder, ']') + } + + case: + if in_data && .CDATA_Decode not_in options { + /* + Unboxed, but undecoded. + */ + write_rune(&builder, t.r) + continue + } + + if t.r == '&' { + if entity, entity_err := _extract_xml_entity(&t); entity_err != .None { + /* + We read to the end of the string without closing the entity. + Pass through as-is. + */ + write_string(&builder, entity) + } else { + if decoded, ok := xml_decode_entity(entity); ok { + write_rune(&builder, decoded) + } else { + /* + Decode failed. Pass through original. + */ + write_string(&builder, "&") + write_string(&builder, entity) + write_string(&builder, ";") + } + + } + } else { + write_rune(&builder, t.r) + } + } + } + + return strings.clone(strings.to_string(builder), allocator), err +} + +advance :: proc(t: ^Tokenizer) -> (err: Error) { + if t == nil { return .Tokenizer_Is_Nil } + using t + + #no_bounds_check { + if read_offset < len(src) { + offset = read_offset + r, w = rune(src[read_offset]), 1 + switch { + case r == 0: + return .Illegal_NUL_Character + case r >= utf8.RUNE_SELF: + r, w = utf8.decode_rune_in_string(src[read_offset:]) + if r == utf8.RUNE_ERROR && w == 1 { + return .Illegal_UTF_Encoding + } else if r == utf8.RUNE_BOM && offset > 0 { + return .Illegal_BOM + } + } + read_offset += w + return .None + } else { + offset = len(src) + r = -1 + return + } + } +} + +xml_decode_entity :: proc(entity: string) -> (decoded: rune, ok: bool) { + entity := entity + if len(entity) == 0 { return -1, false } + + switch entity[0] { + case '#': + base := 10 + val := 0 + entity = entity[1:] + + if len(entity) == 0 { return -1, false } + + if entity[0] == 'x' || entity[0] == 'X' { + base = 16 + entity = entity[1:] + } + + for len(entity) > 0 { + r := entity[0] + switch r { + case '0'..'9': + val *= base + val += int(r - '0') + + case 'a'..'f': + if base == 10 { return -1, false } + val *= base + val += int(r - 'a' + 10) + + case 'A'..'F': + if base == 10 { return -1, false } + val *= base + val += int(r - 'A' + 10) + + case: + return -1, false + } + + if val > MAX_RUNE_CODEPOINT { return -1, false } + entity = entity[1:] + } + return rune(val), true + + case: + /* + Named entity. + */ + return named_xml_entity_to_rune(entity) + } +} + +/* + Private XML helper to extract `&;` entity. +*/ +@(private="file") +_extract_xml_entity :: proc(t: ^Tokenizer) -> (entity: string, err: Error) { + assert(t != nil && t.r == '&') + + /* + All of these would be in the ASCII range. + Even if one is not, it doesn't matter. All characters we need to compare to extract are. + */ + using t + + length := len(t.src) + found := false + + #no_bounds_check { + for read_offset < length { + if src[read_offset] == ';' { + found = true + read_offset += 1 + break + } + read_offset += 1 + } + } + + if found { + return string(src[offset + 1 : read_offset - 1]), .None + } + return string(src[offset : read_offset]), .Invalid_Entity_Encoding +} + +/* + Private XML helper for CDATA and comments. +*/ +@(private="file") +_handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: XML_Decode_Options) -> (in_data: bool, err: Error) { + assert(t != nil && t.r == '<') + if t.read_offset + len(CDATA_START) >= len(t.src) { return false, .None } + + if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { + t.read_offset += len(CDATA_START) - 1 + + if .CDATA_Unbox in options && .CDATA_Decode in options { + /* + We're unboxing _and_ decoding CDATA + */ + return true, .None + } + + /* + CDATA is passed through. + */ + offset := t.offset + + /* + Scan until end of CDATA. + */ + for { + advance(t) or_return + if t.r < 0 { return true, .CDATA_Not_Terminated } + + if t.read_offset + len(CDATA_END) < len(t.src) { + if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { + t.read_offset += len(CDATA_END) - 1 + + cdata := string(t.src[offset : t.read_offset]) + + if .CDATA_Unbox in options { + cdata = cdata[len(CDATA_START):] + cdata = cdata[:len(cdata) - len(CDATA_END)] + } + + write_string(builder, cdata) + return false, .None + } + } + } + + } else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START { + t.read_offset += len(COMMENT_START) + /* + Comment is passed through by default. + */ + offset := t.offset + + /* + Scan until end of Comment. + */ + for { + advance(t) or_return + if t.r < 0 { return true, .Comment_Not_Terminated } + + if t.read_offset + len(COMMENT_END) < len(t.src) { + if string(t.src[t.offset:][:len(COMMENT_END)]) == COMMENT_END { + t.read_offset += len(COMMENT_END) - 1 + + if .Comment_Strip not_in options { + comment := string(t.src[offset : t.read_offset]) + write_string(builder, comment) + } + return false, .None + } + } + } + + } + return false, .None +} \ No newline at end of file diff --git a/core/encoding/entity/example/entity_example.odin b/core/encoding/entity/example/entity_example.odin new file mode 100644 index 000000000..8758d9ad9 --- /dev/null +++ b/core/encoding/entity/example/entity_example.odin @@ -0,0 +1,122 @@ +package unicode_entity_example + +import "core:encoding/xml" +import "core:encoding/entity" +import "core:strings" +import "core:mem" +import "core:fmt" +import "core:time" + +OPTIONS :: xml.Options{ + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "", +} + +doc_print :: proc(doc: ^xml.Document) { + buf: strings.Builder + defer strings.destroy_builder(&buf) + w := strings.to_writer(&buf) + + xml.print(w, doc) + fmt.println(strings.to_string(buf)) +} + +_entities :: proc() { + doc: ^xml.Document + err: xml.Error + + DOC :: #load("../../../../tests/core/assets/XML/unicode.xml") + + parse_duration: time.Duration + + { + time.SCOPED_TICK_DURATION(&parse_duration) + doc, err = xml.parse(DOC, OPTIONS) + } + defer xml.destroy(doc) + + doc_print(doc) + + ms := time.duration_milliseconds(parse_duration) + + speed := (f64(1000.0) / ms) * f64(len(DOC)) / 1_024.0 / 1_024.0 + + fmt.printf("Parse time: %.2f ms (%.2f MiB/s).\n", ms, speed) + fmt.printf("Error: %v\n", err) +} + +_main :: proc() { + using fmt + + doc, err := xml.parse(#load("test.html")) + defer xml.destroy(doc) + doc_print(doc) + + if false { + val := doc.root.children[1].children[2].value + + println() + replaced, ok := entity.decode_xml(val) + defer delete(replaced) + + printf("Before: '%v', Err: %v\n", val, err) + printf("Passthrough: '%v'\nOK: %v\n", replaced, ok) + println() + } + + if false { + val := doc.root.children[1].children[2].value + + println() + replaced, ok := entity.decode_xml(val, { .CDATA_Unbox }) + defer delete(replaced) + + printf("Before: '%v', Err: %v\n", val, err) + printf("CDATA_Unbox: '%v'\nOK: %v\n", replaced, ok) + println() + } + + if true { + val := doc.root.children[1].children[2].value + + println() + replaced, ok := entity.decode_xml(val, { .CDATA_Unbox, .CDATA_Decode }) + defer delete(replaced) + + printf("Before: '%v', Err: %v\n", val, err) + printf("CDATA_Decode: '%v'\nOK: %v\n", replaced, ok) + println() + } + + if true { + val := doc.root.children[1].children[1].value + + println() + replaced, ok := entity.decode_xml(val, { .Comment_Strip }) + defer delete(replaced) + + printf("Before: '%v', Err: %v\n", val, err) + printf("Comment_Strip: '%v'\nOK: %v\n", replaced, ok) + println() + } +} + +main :: proc() { + using fmt + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + _main() + //_entities() + + if len(track.allocation_map) > 0 { + println() + for _, v in track.allocation_map { + printf("%v Leaked %v bytes.\n", v.location, v.size) + } + } +} \ No newline at end of file diff --git a/core/encoding/entity/example/test.html b/core/encoding/entity/example/test.html new file mode 100644 index 000000000..60e32bf03 --- /dev/null +++ b/core/encoding/entity/example/test.html @@ -0,0 +1,26 @@ + + + Entity Reference Test + + + +

Entity Reference Test

+
+ Foozle]! © 42&;1234& +
+
+ Foozle]! © 42&;1234& +
+
+ | | | fj ` \ ® ϱ ∳ +
+ + \ No newline at end of file diff --git a/core/encoding/entity/generated.odin b/core/encoding/entity/generated.odin new file mode 100644 index 000000000..9afdcae6d --- /dev/null +++ b/core/encoding/entity/generated.odin @@ -0,0 +1,7493 @@ +package unicode_entity + +/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ + +/* + This file is generated from "https://www.w3.org/2003/entities/2007xml/unicode.xml". + + UPDATE: + - Ensure the XML file was downloaded using "tests\core\download_assets.py". + - Run "core/unicode/tools/generate_entity_table.odin" + + Odin unicode generated tables: https://github.com/odin-lang/Odin/tree/master/core/encoding/entity + + Copyright © 2021 World Wide Web Consortium, (Massachusetts Institute of Technology, + European Research Consortium for Informatics and Mathematics, Keio University, Beihang). + + All Rights Reserved. + + This work is distributed under the W3C® Software License [1] in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + [1] http://www.w3.org/Consortium/Legal/copyright-software + + See also: LICENSE_table.md +*/ + +// `<` +XML_NAME_TO_RUNE_MIN_LENGTH :: 2 +// `∳` +XML_NAME_TO_RUNE_MAX_LENGTH :: 31 + + +/* + Input: + entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML. + + Output: + "decoded" - The decoded rune if found by name, or -1 otherwise. + "ok" - true if found, false if not. + + IMPORTANT: XML processors (including browsers) treat these names as case-sensitive. So do we. +*/ +named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { + /* + Early out if the name is too short or too long. + min as a precaution in case the generated table has a bogus value. + */ + if len(name) < min(1, XML_NAME_TO_RUNE_MIN_LENGTH) || len(name) > XML_NAME_TO_RUNE_MAX_LENGTH { + return -1, false + } + + switch rune(name[0]) { + + case 'A': + switch name { + case "AElig": + // LATIN CAPITAL LETTER AE + return rune(0xc6), true + case "AMP": + // AMPERSAND + return rune(0x26), true + case "Aacgr": + // GREEK CAPITAL LETTER ALPHA WITH TONOS + return rune(0x0386), true + case "Aacute": + // LATIN CAPITAL LETTER A WITH ACUTE + return rune(0xc1), true + case "Abreve": + // LATIN CAPITAL LETTER A WITH BREVE + return rune(0x0102), true + case "Acirc": + // LATIN CAPITAL LETTER A WITH CIRCUMFLEX + return rune(0xc2), true + case "Acy": + // CYRILLIC CAPITAL LETTER A + return rune(0x0410), true + case "Afr": + // MATHEMATICAL FRAKTUR CAPITAL A + return rune(0x01d504), true + case "Agrave": + // LATIN CAPITAL LETTER A WITH GRAVE + return rune(0xc0), true + case "Agr": + // GREEK CAPITAL LETTER ALPHA + return rune(0x0391), true + case "Alpha": + // GREEK CAPITAL LETTER ALPHA + return rune(0x0391), true + case "Amacr": + // LATIN CAPITAL LETTER A WITH MACRON + return rune(0x0100), true + case "And": + // DOUBLE LOGICAL AND + return rune(0x2a53), true + case "Aogon": + // LATIN CAPITAL LETTER A WITH OGONEK + return rune(0x0104), true + case "Aopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL A + return rune(0x01d538), true + case "ApplyFunction": + // FUNCTION APPLICATION + return rune(0x2061), true + case "Aring": + // LATIN CAPITAL LETTER A WITH RING ABOVE + return rune(0xc5), true + case "Ascr": + // MATHEMATICAL SCRIPT CAPITAL A + return rune(0x01d49c), true + case "Assign": + // COLON EQUALS + return rune(0x2254), true + case "Ast": + // TWO ASTERISKS ALIGNED VERTICALLY + return rune(0x2051), true + case "Atilde": + // LATIN CAPITAL LETTER A WITH TILDE + return rune(0xc3), true + case "Auml": + // LATIN CAPITAL LETTER A WITH DIAERESIS + return rune(0xc4), true + } + + case 'B': + switch name { + case "Backslash": + // SET MINUS + return rune(0x2216), true + case "Barint": + // INTEGRAL WITH DOUBLE STROKE + return rune(0x2a0e), true + case "Barv": + // SHORT DOWN TACK WITH OVERBAR + return rune(0x2ae7), true + case "Barwedl": + // LOGICAL AND WITH DOUBLE OVERBAR + return rune(0x2a5e), true + case "Barwed": + // PERSPECTIVE + return rune(0x2306), true + case "Bcy": + // CYRILLIC CAPITAL LETTER BE + return rune(0x0411), true + case "Because": + // BECAUSE + return rune(0x2235), true + case "Bernoullis": + // SCRIPT CAPITAL B + return rune(0x212c), true + case "Beta": + // GREEK CAPITAL LETTER BETA + return rune(0x0392), true + case "Bfr": + // MATHEMATICAL FRAKTUR CAPITAL B + return rune(0x01d505), true + case "Bgr": + // GREEK CAPITAL LETTER BETA + return rune(0x0392), true + case "Bopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL B + return rune(0x01d539), true + case "Breve": + // BREVE + return rune(0x02d8), true + case "Bscr": + // SCRIPT CAPITAL B + return rune(0x212c), true + case "Bumpeq": + // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "Bvert": + // BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL + return rune(0x2506), true + } + + case 'C': + switch name { + case "CHcy": + // CYRILLIC CAPITAL LETTER CHE + return rune(0x0427), true + case "COPY": + // COPYRIGHT SIGN + return rune(0xa9), true + case "Cacute": + // LATIN CAPITAL LETTER C WITH ACUTE + return rune(0x0106), true + case "CapitalDifferentialD": + // DOUBLE-STRUCK ITALIC CAPITAL D + return rune(0x2145), true + case "Cap": + // DOUBLE INTERSECTION + return rune(0x22d2), true + case "Cayleys": + // BLACK-LETTER CAPITAL C + return rune(0x212d), true + case "Ccaron": + // LATIN CAPITAL LETTER C WITH CARON + return rune(0x010c), true + case "Ccedil": + // LATIN CAPITAL LETTER C WITH CEDILLA + return rune(0xc7), true + case "Ccirc": + // LATIN CAPITAL LETTER C WITH CIRCUMFLEX + return rune(0x0108), true + case "Cconint": + // VOLUME INTEGRAL + return rune(0x2230), true + case "Cdot": + // LATIN CAPITAL LETTER C WITH DOT ABOVE + return rune(0x010a), true + case "Cedilla": + // CEDILLA + return rune(0xb8), true + case "CenterDot": + // MIDDLE DOT + return rune(0xb7), true + case "Cfr": + // BLACK-LETTER CAPITAL C + return rune(0x212d), true + case "Chi": + // GREEK CAPITAL LETTER CHI + return rune(0x03a7), true + case "CircleDot": + // CIRCLED DOT OPERATOR + return rune(0x2299), true + case "CircleMinus": + // CIRCLED MINUS + return rune(0x2296), true + case "CirclePlus": + // CIRCLED PLUS + return rune(0x2295), true + case "CircleTimes": + // CIRCLED TIMES + return rune(0x2297), true + case "ClockwiseContourIntegral": + // CLOCKWISE CONTOUR INTEGRAL + return rune(0x2232), true + case "CloseCurlyDoubleQuote": + // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "CloseCurlyQuote": + // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "Colon": + // PROPORTION + return rune(0x2237), true + case "Colone": + // DOUBLE COLON EQUAL + return rune(0x2a74), true + case "Congruent": + // IDENTICAL TO + return rune(0x2261), true + case "Conint": + // SURFACE INTEGRAL + return rune(0x222f), true + case "ContourIntegral": + // CONTOUR INTEGRAL + return rune(0x222e), true + case "Copf": + // DOUBLE-STRUCK CAPITAL C + return rune(0x2102), true + case "Coproduct": + // N-ARY COPRODUCT + return rune(0x2210), true + case "CounterClockwiseContourIntegral": + // ANTICLOCKWISE CONTOUR INTEGRAL + return rune(0x2233), true + case "Cross": + // VECTOR OR CROSS PRODUCT + return rune(0x2a2f), true + case "Cscr": + // MATHEMATICAL SCRIPT CAPITAL C + return rune(0x01d49e), true + case "CupCap": + // EQUIVALENT TO + return rune(0x224d), true + case "Cup": + // DOUBLE UNION + return rune(0x22d3), true + } + + case 'D': + switch name { + case "DD": + // DOUBLE-STRUCK ITALIC CAPITAL D + return rune(0x2145), true + case "DDotrahd": + // RIGHTWARDS ARROW WITH DOTTED STEM + return rune(0x2911), true + case "DJcy": + // CYRILLIC CAPITAL LETTER DJE + return rune(0x0402), true + case "DScy": + // CYRILLIC CAPITAL LETTER DZE + return rune(0x0405), true + case "DZcy": + // CYRILLIC CAPITAL LETTER DZHE + return rune(0x040f), true + case "Dagger": + // DOUBLE DAGGER + return rune(0x2021), true + case "Darr": + // DOWNWARDS TWO HEADED ARROW + return rune(0x21a1), true + case "Dashv": + // VERTICAL BAR DOUBLE LEFT TURNSTILE + return rune(0x2ae4), true + case "Dcaron": + // LATIN CAPITAL LETTER D WITH CARON + return rune(0x010e), true + case "Dcy": + // CYRILLIC CAPITAL LETTER DE + return rune(0x0414), true + case "Del": + // NABLA + return rune(0x2207), true + case "Delta": + // GREEK CAPITAL LETTER DELTA + return rune(0x0394), true + case "Dfr": + // MATHEMATICAL FRAKTUR CAPITAL D + return rune(0x01d507), true + case "Dgr": + // GREEK CAPITAL LETTER DELTA + return rune(0x0394), true + case "DiacriticalAcute": + // ACUTE ACCENT + return rune(0xb4), true + case "DiacriticalDot": + // DOT ABOVE + return rune(0x02d9), true + case "DiacriticalDoubleAcute": + // DOUBLE ACUTE ACCENT + return rune(0x02dd), true + case "DiacriticalGrave": + // GRAVE ACCENT + return rune(0x60), true + case "DiacriticalTilde": + // SMALL TILDE + return rune(0x02dc), true + case "Diamond": + // DIAMOND OPERATOR + return rune(0x22c4), true + case "DifferentialD": + // DOUBLE-STRUCK ITALIC SMALL D + return rune(0x2146), true + case "Dopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL D + return rune(0x01d53b), true + case "Dot": + // DIAERESIS + return rune(0xa8), true + case "DotDot": + // COMBINING FOUR DOTS ABOVE + return rune(0x20dc), true + case "DotEqual": + // APPROACHES THE LIMIT + return rune(0x2250), true + case "DoubleContourIntegral": + // SURFACE INTEGRAL + return rune(0x222f), true + case "DoubleDot": + // DIAERESIS + return rune(0xa8), true + case "DoubleDownArrow": + // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "DoubleLeftArrow": + // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "DoubleLeftRightArrow": + // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "DoubleLeftTee": + // VERTICAL BAR DOUBLE LEFT TURNSTILE + return rune(0x2ae4), true + case "DoubleLongLeftArrow": + // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "DoubleLongLeftRightArrow": + // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "DoubleLongRightArrow": + // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "DoubleRightArrow": + // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "DoubleRightTee": + // TRUE + return rune(0x22a8), true + case "DoubleUpArrow": + // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "DoubleUpDownArrow": + // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "DoubleVerticalBar": + // PARALLEL TO + return rune(0x2225), true + case "DownArrowUpArrow": + // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW + return rune(0x21f5), true + case "DownArrow": + // DOWNWARDS ARROW + return rune(0x2193), true + case "DownArrowBar": + // DOWNWARDS ARROW TO BAR + return rune(0x2913), true + case "DownBreve": + // COMBINING INVERTED BREVE + return rune(0x0311), true + case "DownLeftRightVector": + // LEFT BARB DOWN RIGHT BARB DOWN HARPOON + return rune(0x2950), true + case "DownLeftTeeVector": + // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295e), true + case "DownLeftVector": + // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "DownLeftVectorBar": + // LEFTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2956), true + case "DownRightTeeVector": + // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295f), true + case "DownRightVector": + // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "DownRightVectorBar": + // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2957), true + case "DownTeeArrow": + // DOWNWARDS ARROW FROM BAR + return rune(0x21a7), true + case "DownTee": + // DOWN TACK + return rune(0x22a4), true + case "Downarrow": + // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "Dscr": + // MATHEMATICAL SCRIPT CAPITAL D + return rune(0x01d49f), true + case "Dstrok": + // LATIN CAPITAL LETTER D WITH STROKE + return rune(0x0110), true + } + + case 'E': + switch name { + case "EEacgr": + // GREEK CAPITAL LETTER ETA WITH TONOS + return rune(0x0389), true + case "EEgr": + // GREEK CAPITAL LETTER ETA + return rune(0x0397), true + case "ENG": + // LATIN CAPITAL LETTER ENG + return rune(0x014a), true + case "ETH": + // LATIN CAPITAL LETTER ETH + return rune(0xd0), true + case "Eacgr": + // GREEK CAPITAL LETTER EPSILON WITH TONOS + return rune(0x0388), true + case "Eacute": + // LATIN CAPITAL LETTER E WITH ACUTE + return rune(0xc9), true + case "Ecaron": + // LATIN CAPITAL LETTER E WITH CARON + return rune(0x011a), true + case "Ecirc": + // LATIN CAPITAL LETTER E WITH CIRCUMFLEX + return rune(0xca), true + case "Ecy": + // CYRILLIC CAPITAL LETTER E + return rune(0x042d), true + case "Edot": + // LATIN CAPITAL LETTER E WITH DOT ABOVE + return rune(0x0116), true + case "Efr": + // MATHEMATICAL FRAKTUR CAPITAL E + return rune(0x01d508), true + case "Egrave": + // LATIN CAPITAL LETTER E WITH GRAVE + return rune(0xc8), true + case "Egr": + // GREEK CAPITAL LETTER EPSILON + return rune(0x0395), true + case "Element": + // ELEMENT OF + return rune(0x2208), true + case "Emacr": + // LATIN CAPITAL LETTER E WITH MACRON + return rune(0x0112), true + case "EmptySmallSquare": + // WHITE MEDIUM SQUARE + return rune(0x25fb), true + case "EmptyVerySmallSquare": + // WHITE SMALL SQUARE + return rune(0x25ab), true + case "Eogon": + // LATIN CAPITAL LETTER E WITH OGONEK + return rune(0x0118), true + case "Eopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL E + return rune(0x01d53c), true + case "Epsilon": + // GREEK CAPITAL LETTER EPSILON + return rune(0x0395), true + case "EqualTilde": + // MINUS TILDE + return rune(0x2242), true + case "Equal": + // TWO CONSECUTIVE EQUALS SIGNS + return rune(0x2a75), true + case "Equilibrium": + // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "Escr": + // SCRIPT CAPITAL E + return rune(0x2130), true + case "Esim": + // EQUALS SIGN ABOVE TILDE OPERATOR + return rune(0x2a73), true + case "Eta": + // GREEK CAPITAL LETTER ETA + return rune(0x0397), true + case "Euml": + // LATIN CAPITAL LETTER E WITH DIAERESIS + return rune(0xcb), true + case "Exists": + // THERE EXISTS + return rune(0x2203), true + case "ExponentialE": + // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true + } + + case 'F': + switch name { + case "Fcy": + // CYRILLIC CAPITAL LETTER EF + return rune(0x0424), true + case "Ffr": + // MATHEMATICAL FRAKTUR CAPITAL F + return rune(0x01d509), true + case "FilledSmallSquare": + // BLACK MEDIUM SQUARE + return rune(0x25fc), true + case "FilledVerySmallSquare": + // BLACK SMALL SQUARE + return rune(0x25aa), true + case "Fopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL F + return rune(0x01d53d), true + case "ForAll": + // FOR ALL + return rune(0x2200), true + case "Fouriertrf": + // SCRIPT CAPITAL F + return rune(0x2131), true + case "Fscr": + // SCRIPT CAPITAL F + return rune(0x2131), true + } + + case 'G': + switch name { + case "GJcy": + // CYRILLIC CAPITAL LETTER GJE + return rune(0x0403), true + case "GT": + // GREATER-THAN SIGN + return rune(0x3e), true + case "Game": + // TURNED SANS-SERIF CAPITAL G + return rune(0x2141), true + case "Gamma": + // GREEK CAPITAL LETTER GAMMA + return rune(0x0393), true + case "Gammad": + // GREEK LETTER DIGAMMA + return rune(0x03dc), true + case "Gbreve": + // LATIN CAPITAL LETTER G WITH BREVE + return rune(0x011e), true + case "Gcedil": + // LATIN CAPITAL LETTER G WITH CEDILLA + return rune(0x0122), true + case "Gcirc": + // LATIN CAPITAL LETTER G WITH CIRCUMFLEX + return rune(0x011c), true + case "Gcy": + // CYRILLIC CAPITAL LETTER GHE + return rune(0x0413), true + case "Gdot": + // LATIN CAPITAL LETTER G WITH DOT ABOVE + return rune(0x0120), true + case "Gfr": + // MATHEMATICAL FRAKTUR CAPITAL G + return rune(0x01d50a), true + case "Ggr": + // GREEK CAPITAL LETTER GAMMA + return rune(0x0393), true + case "Gg": + // VERY MUCH GREATER-THAN + return rune(0x22d9), true + case "Gopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL G + return rune(0x01d53e), true + case "GreaterEqual": + // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "GreaterEqualLess": + // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "GreaterFullEqual": + // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "GreaterGreater": + // DOUBLE NESTED GREATER-THAN + return rune(0x2aa2), true + case "GreaterLess": + // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "GreaterSlantEqual": + // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "GreaterTilde": + // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "Gscr": + // MATHEMATICAL SCRIPT CAPITAL G + return rune(0x01d4a2), true + case "Gt": + // MUCH GREATER-THAN + return rune(0x226b), true + } + + case 'H': + switch name { + case "HARDcy": + // CYRILLIC CAPITAL LETTER HARD SIGN + return rune(0x042a), true + case "Hacek": + // CARON + return rune(0x02c7), true + case "Hat": + // CIRCUMFLEX ACCENT + return rune(0x5e), true + case "Hcirc": + // LATIN CAPITAL LETTER H WITH CIRCUMFLEX + return rune(0x0124), true + case "Hfr": + // BLACK-LETTER CAPITAL H + return rune(0x210c), true + case "HilbertSpace": + // SCRIPT CAPITAL H + return rune(0x210b), true + case "Hopf": + // DOUBLE-STRUCK CAPITAL H + return rune(0x210d), true + case "HorizontalLine": + // BOX DRAWINGS LIGHT HORIZONTAL + return rune(0x2500), true + case "Hscr": + // SCRIPT CAPITAL H + return rune(0x210b), true + case "Hstrok": + // LATIN CAPITAL LETTER H WITH STROKE + return rune(0x0126), true + case "HumpDownHump": + // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "HumpEqual": + // DIFFERENCE BETWEEN + return rune(0x224f), true + } + + case 'I': + switch name { + case "IEcy": + // CYRILLIC CAPITAL LETTER IE + return rune(0x0415), true + case "IJlig": + // LATIN CAPITAL LIGATURE IJ + return rune(0x0132), true + case "IOcy": + // CYRILLIC CAPITAL LETTER IO + return rune(0x0401), true + case "Iacgr": + // GREEK CAPITAL LETTER IOTA WITH TONOS + return rune(0x038a), true + case "Iacute": + // LATIN CAPITAL LETTER I WITH ACUTE + return rune(0xcd), true + case "Icirc": + // LATIN CAPITAL LETTER I WITH CIRCUMFLEX + return rune(0xce), true + case "Icy": + // CYRILLIC CAPITAL LETTER I + return rune(0x0418), true + case "Idigr": + // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA + return rune(0x03aa), true + case "Idot": + // LATIN CAPITAL LETTER I WITH DOT ABOVE + return rune(0x0130), true + case "Ifr": + // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "Igrave": + // LATIN CAPITAL LETTER I WITH GRAVE + return rune(0xcc), true + case "Igr": + // GREEK CAPITAL LETTER IOTA + return rune(0x0399), true + case "Imacr": + // LATIN CAPITAL LETTER I WITH MACRON + return rune(0x012a), true + case "ImaginaryI": + // DOUBLE-STRUCK ITALIC SMALL I + return rune(0x2148), true + case "Implies": + // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "Im": + // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "Integral": + // INTEGRAL + return rune(0x222b), true + case "Int": + // DOUBLE INTEGRAL + return rune(0x222c), true + case "Intersection": + // N-ARY INTERSECTION + return rune(0x22c2), true + case "InvisibleComma": + // INVISIBLE SEPARATOR + return rune(0x2063), true + case "InvisibleTimes": + // INVISIBLE TIMES + return rune(0x2062), true + case "Iogon": + // LATIN CAPITAL LETTER I WITH OGONEK + return rune(0x012e), true + case "Iopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL I + return rune(0x01d540), true + case "Iota": + // GREEK CAPITAL LETTER IOTA + return rune(0x0399), true + case "Iscr": + // SCRIPT CAPITAL I + return rune(0x2110), true + case "Itilde": + // LATIN CAPITAL LETTER I WITH TILDE + return rune(0x0128), true + case "Iukcy": + // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I + return rune(0x0406), true + case "Iuml": + // LATIN CAPITAL LETTER I WITH DIAERESIS + return rune(0xcf), true + } + + case 'J': + switch name { + case "Jcirc": + // LATIN CAPITAL LETTER J WITH CIRCUMFLEX + return rune(0x0134), true + case "Jcy": + // CYRILLIC CAPITAL LETTER SHORT I + return rune(0x0419), true + case "Jfr": + // MATHEMATICAL FRAKTUR CAPITAL J + return rune(0x01d50d), true + case "Jopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL J + return rune(0x01d541), true + case "Jscr": + // MATHEMATICAL SCRIPT CAPITAL J + return rune(0x01d4a5), true + case "Jsercy": + // CYRILLIC CAPITAL LETTER JE + return rune(0x0408), true + case "Jukcy": + // CYRILLIC CAPITAL LETTER UKRAINIAN IE + return rune(0x0404), true + } + + case 'K': + switch name { + case "KHcy": + // CYRILLIC CAPITAL LETTER HA + return rune(0x0425), true + case "KHgr": + // GREEK CAPITAL LETTER CHI + return rune(0x03a7), true + case "KJcy": + // CYRILLIC CAPITAL LETTER KJE + return rune(0x040c), true + case "Kappa": + // GREEK CAPITAL LETTER KAPPA + return rune(0x039a), true + case "Kcedil": + // LATIN CAPITAL LETTER K WITH CEDILLA + return rune(0x0136), true + case "Kcy": + // CYRILLIC CAPITAL LETTER KA + return rune(0x041a), true + case "Kfr": + // MATHEMATICAL FRAKTUR CAPITAL K + return rune(0x01d50e), true + case "Kgr": + // GREEK CAPITAL LETTER KAPPA + return rune(0x039a), true + case "Kopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL K + return rune(0x01d542), true + case "Kscr": + // MATHEMATICAL SCRIPT CAPITAL K + return rune(0x01d4a6), true + } + + case 'L': + switch name { + case "LJcy": + // CYRILLIC CAPITAL LETTER LJE + return rune(0x0409), true + case "LT": + // LESS-THAN SIGN + return rune(0x3c), true + case "Lacute": + // LATIN CAPITAL LETTER L WITH ACUTE + return rune(0x0139), true + case "Lambda": + // GREEK CAPITAL LETTER LAMDA + return rune(0x039b), true + case "Lang": + // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET + return rune(0x27ea), true + case "Laplacetrf": + // SCRIPT CAPITAL L + return rune(0x2112), true + case "Larr": + // LEFTWARDS TWO HEADED ARROW + return rune(0x219e), true + case "Lcaron": + // LATIN CAPITAL LETTER L WITH CARON + return rune(0x013d), true + case "Lcedil": + // LATIN CAPITAL LETTER L WITH CEDILLA + return rune(0x013b), true + case "Lcy": + // CYRILLIC CAPITAL LETTER EL + return rune(0x041b), true + case "LeftAngleBracket": + // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "LeftArrowBar": + // LEFTWARDS ARROW TO BAR + return rune(0x21e4), true + case "LeftArrowRightArrow": + // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "LeftArrow": + // LEFTWARDS ARROW + return rune(0x2190), true + case "LeftCeiling": + // LEFT CEILING + return rune(0x2308), true + case "LeftDoubleBracket": + // MATHEMATICAL LEFT WHITE SQUARE BRACKET + return rune(0x27e6), true + case "LeftDownTeeVector": + // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2961), true + case "LeftDownVector": + // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "LeftDownVectorBar": + // DOWNWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2959), true + case "LeftFloor": + // LEFT FLOOR + return rune(0x230a), true + case "LeftRightArrow": + // LEFT RIGHT ARROW + return rune(0x2194), true + case "LeftRightVector": + // LEFT BARB UP RIGHT BARB UP HARPOON + return rune(0x294e), true + case "LeftTeeArrow": + // LEFTWARDS ARROW FROM BAR + return rune(0x21a4), true + case "LeftTeeVector": + // LEFTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295a), true + case "LeftTee": + // LEFT TACK + return rune(0x22a3), true + case "LeftTriangleBar": + // LEFT TRIANGLE BESIDE VERTICAL BAR + return rune(0x29cf), true + case "LeftTriangle": + // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "LeftTriangleEqual": + // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "LeftUpDownVector": + // UP BARB LEFT DOWN BARB LEFT HARPOON + return rune(0x2951), true + case "LeftUpTeeVector": + // UPWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2960), true + case "LeftUpVector": + // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "LeftUpVectorBar": + // UPWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2958), true + case "LeftVector": + // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "LeftVectorBar": + // LEFTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2952), true + case "Leftarrow": + // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "Leftrightarrow": + // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "LessEqualGreater": + // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "LessFullEqual": + // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "LessGreater": + // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "LessLess": + // DOUBLE NESTED LESS-THAN + return rune(0x2aa1), true + case "LessSlantEqual": + // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "LessTilde": + // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "Lfr": + // MATHEMATICAL FRAKTUR CAPITAL L + return rune(0x01d50f), true + case "Lgr": + // GREEK CAPITAL LETTER LAMDA + return rune(0x039b), true + case "Lleftarrow": + // LEFTWARDS TRIPLE ARROW + return rune(0x21da), true + case "Ll": + // VERY MUCH LESS-THAN + return rune(0x22d8), true + case "Lmidot": + // LATIN CAPITAL LETTER L WITH MIDDLE DOT + return rune(0x013f), true + case "LongLeftArrow": + // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "LongLeftRightArrow": + // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "LongRightArrow": + // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "Longleftarrow": + // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "Longleftrightarrow": + // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "Longrightarrow": + // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "Lopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL L + return rune(0x01d543), true + case "LowerLeftArrow": + // SOUTH WEST ARROW + return rune(0x2199), true + case "LowerRightArrow": + // SOUTH EAST ARROW + return rune(0x2198), true + case "Lscr": + // SCRIPT CAPITAL L + return rune(0x2112), true + case "Lsh": + // UPWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b0), true + case "Lstrok": + // LATIN CAPITAL LETTER L WITH STROKE + return rune(0x0141), true + case "Ltbar": + // DOUBLE NESTED LESS-THAN WITH UNDERBAR + return rune(0x2aa3), true + case "Lt": + // MUCH LESS-THAN + return rune(0x226a), true + } + + case 'M': + switch name { + case "Mapfrom": + // LEFTWARDS DOUBLE ARROW FROM BAR + return rune(0x2906), true + case "Mapto": + // RIGHTWARDS DOUBLE ARROW FROM BAR + return rune(0x2907), true + case "Map": + // RIGHTWARDS TWO-HEADED ARROW FROM BAR + return rune(0x2905), true + case "Mcy": + // CYRILLIC CAPITAL LETTER EM + return rune(0x041c), true + case "MediumSpace": + // MEDIUM MATHEMATICAL SPACE + return rune(0x205f), true + case "Mellintrf": + // SCRIPT CAPITAL M + return rune(0x2133), true + case "Mfr": + // MATHEMATICAL FRAKTUR CAPITAL M + return rune(0x01d510), true + case "Mgr": + // GREEK CAPITAL LETTER MU + return rune(0x039c), true + case "MinusPlus": + // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "Mopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL M + return rune(0x01d544), true + case "Mscr": + // SCRIPT CAPITAL M + return rune(0x2133), true + case "Mu": + // GREEK CAPITAL LETTER MU + return rune(0x039c), true + } + + case 'N': + switch name { + case "NJcy": + // CYRILLIC CAPITAL LETTER NJE + return rune(0x040a), true + case "Nacute": + // LATIN CAPITAL LETTER N WITH ACUTE + return rune(0x0143), true + case "Ncaron": + // LATIN CAPITAL LETTER N WITH CARON + return rune(0x0147), true + case "Ncedil": + // LATIN CAPITAL LETTER N WITH CEDILLA + return rune(0x0145), true + case "Ncy": + // CYRILLIC CAPITAL LETTER EN + return rune(0x041d), true + case "NegativeMediumSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeThickSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeThinSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "NegativeVeryThinSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "NestedGreaterGreater": + // MUCH GREATER-THAN + return rune(0x226b), true + case "NestedLessLess": + // MUCH LESS-THAN + return rune(0x226a), true + case "NewLine": + // LINE FEED (LF) + return rune(0x0a), true + case "Nfr": + // MATHEMATICAL FRAKTUR CAPITAL N + return rune(0x01d511), true + case "Ngr": + // GREEK CAPITAL LETTER NU + return rune(0x039d), true + case "NoBreak": + // WORD JOINER + return rune(0x2060), true + case "NonBreakingSpace": + // NO-BREAK SPACE + return rune(0xa0), true + case "Nopf": + // DOUBLE-STRUCK CAPITAL N + return rune(0x2115), true + case "NotDoubleVerticalBar": + // NOT PARALLEL TO + return rune(0x2226), true + case "NotElement": + // NOT AN ELEMENT OF + return rune(0x2209), true + case "NotEqualTilde": + // MINUS TILDE with slash + return rune(0x2242), true + case "NotEqual": + // NOT EQUAL TO + return rune(0x2260), true + case "NotExists": + // THERE DOES NOT EXIST + return rune(0x2204), true + case "NotHumpDownHump": + // GEOMETRICALLY EQUIVALENT TO with slash + return rune(0x224e), true + case "NotHumpEqual": + // DIFFERENCE BETWEEN with slash + return rune(0x224f), true + case "NotLessGreater": + // NEITHER LESS-THAN NOR GREATER-THAN + return rune(0x2278), true + case "NotReverseElement": + // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "NotTilde": + // NOT TILDE + return rune(0x2241), true + case "NotTildeEqual": + // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "NotTildeFullEqual": + // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO + return rune(0x2247), true + case "NotTildeTilde": + // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "NotVerticalBar": + // DOES NOT DIVIDE + return rune(0x2224), true + case "Not": + // DOUBLE STROKE NOT SIGN + return rune(0x2aec), true + case "NotCongruent": + // NOT IDENTICAL TO + return rune(0x2262), true + case "NotCupCap": + // NOT EQUIVALENT TO + return rune(0x226d), true + case "NotGreaterFullEqual": + // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "NotGreaterGreater": + // MUCH GREATER THAN with slash + return rune(0x226b), true + case "NotGreaterSlantEqual": + // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "NotGreater": + // NOT GREATER-THAN + return rune(0x226f), true + case "NotGreaterEqual": + // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "NotGreaterLess": + // NEITHER GREATER-THAN NOR LESS-THAN + return rune(0x2279), true + case "NotGreaterTilde": + // NEITHER GREATER-THAN NOR EQUIVALENT TO + return rune(0x2275), true + case "NotLeftTriangleBar": + // LEFT TRIANGLE BESIDE VERTICAL BAR with slash + return rune(0x29cf), true + case "NotLeftTriangle": + // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "NotLeftTriangleEqual": + // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "NotLessLess": + // MUCH LESS THAN with slash + return rune(0x226a), true + case "NotLessSlantEqual": + // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "NotLess": + // NOT LESS-THAN + return rune(0x226e), true + case "NotLessEqual": + // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "NotLessTilde": + // NEITHER LESS-THAN NOR EQUIVALENT TO + return rune(0x2274), true + case "NotNestedGreaterGreater": + // DOUBLE NESTED GREATER-THAN with slash + return rune(0x2aa2), true + case "NotNestedLessLess": + // DOUBLE NESTED LESS-THAN with slash + return rune(0x2aa1), true + case "NotPrecedesEqual": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "NotPrecedes": + // DOES NOT PRECEDE + return rune(0x2280), true + case "NotPrecedesSlantEqual": + // DOES NOT PRECEDE OR EQUAL + return rune(0x22e0), true + case "NotRightTriangleBar": + // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash + return rune(0x29d0), true + case "NotRightTriangle": + // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "NotRightTriangleEqual": + // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "NotSquareSubset": + // SQUARE IMAGE OF with slash + return rune(0x228f), true + case "NotSquareSubsetEqual": + // NOT SQUARE IMAGE OF OR EQUAL TO + return rune(0x22e2), true + case "NotSquareSuperset": + // SQUARE ORIGINAL OF with slash + return rune(0x2290), true + case "NotSquareSupersetEqual": + // NOT SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x22e3), true + case "NotSubset": + // SUBSET OF with vertical line + return rune(0x2282), true + case "NotSubsetEqual": + // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "NotSucceedsEqual": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "NotSucceedsTilde": + // SUCCEEDS OR EQUIVALENT TO with slash + return rune(0x227f), true + case "NotSucceeds": + // DOES NOT SUCCEED + return rune(0x2281), true + case "NotSucceedsSlantEqual": + // DOES NOT SUCCEED OR EQUAL + return rune(0x22e1), true + case "NotSuperset": + // SUPERSET OF with vertical line + return rune(0x2283), true + case "NotSupersetEqual": + // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "Nscr": + // MATHEMATICAL SCRIPT CAPITAL N + return rune(0x01d4a9), true + case "Ntilde": + // LATIN CAPITAL LETTER N WITH TILDE + return rune(0xd1), true + case "Nu": + // GREEK CAPITAL LETTER NU + return rune(0x039d), true + } + + case 'O': + switch name { + case "OElig": + // LATIN CAPITAL LIGATURE OE + return rune(0x0152), true + case "OHacgr": + // GREEK CAPITAL LETTER OMEGA WITH TONOS + return rune(0x038f), true + case "OHgr": + // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "Oacgr": + // GREEK CAPITAL LETTER OMICRON WITH TONOS + return rune(0x038c), true + case "Oacute": + // LATIN CAPITAL LETTER O WITH ACUTE + return rune(0xd3), true + case "Ocirc": + // LATIN CAPITAL LETTER O WITH CIRCUMFLEX + return rune(0xd4), true + case "Ocy": + // CYRILLIC CAPITAL LETTER O + return rune(0x041e), true + case "Odblac": + // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE + return rune(0x0150), true + case "Ofr": + // MATHEMATICAL FRAKTUR CAPITAL O + return rune(0x01d512), true + case "Ograve": + // LATIN CAPITAL LETTER O WITH GRAVE + return rune(0xd2), true + case "Ogr": + // GREEK CAPITAL LETTER OMICRON + return rune(0x039f), true + case "Omacr": + // LATIN CAPITAL LETTER O WITH MACRON + return rune(0x014c), true + case "Omega": + // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "Omicron": + // GREEK CAPITAL LETTER OMICRON + return rune(0x039f), true + case "Oopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL O + return rune(0x01d546), true + case "OpenCurlyDoubleQuote": + // LEFT DOUBLE QUOTATION MARK + return rune(0x201c), true + case "OpenCurlyQuote": + // LEFT SINGLE QUOTATION MARK + return rune(0x2018), true + case "Or": + // DOUBLE LOGICAL OR + return rune(0x2a54), true + case "Oscr": + // MATHEMATICAL SCRIPT CAPITAL O + return rune(0x01d4aa), true + case "Oslash": + // LATIN CAPITAL LETTER O WITH STROKE + return rune(0xd8), true + case "Otilde": + // LATIN CAPITAL LETTER O WITH TILDE + return rune(0xd5), true + case "Otimes": + // MULTIPLICATION SIGN IN DOUBLE CIRCLE + return rune(0x2a37), true + case "Ouml": + // LATIN CAPITAL LETTER O WITH DIAERESIS + return rune(0xd6), true + case "OverBar": + // OVERLINE + return rune(0x203e), true + case "OverBrace": + // TOP CURLY BRACKET + return rune(0x23de), true + case "OverBracket": + // TOP SQUARE BRACKET + return rune(0x23b4), true + case "OverParenthesis": + // TOP PARENTHESIS + return rune(0x23dc), true + } + + case 'P': + switch name { + case "PHgr": + // GREEK CAPITAL LETTER PHI + return rune(0x03a6), true + case "PSgr": + // GREEK CAPITAL LETTER PSI + return rune(0x03a8), true + case "PartialD": + // PARTIAL DIFFERENTIAL + return rune(0x2202), true + case "Pcy": + // CYRILLIC CAPITAL LETTER PE + return rune(0x041f), true + case "Pfr": + // MATHEMATICAL FRAKTUR CAPITAL P + return rune(0x01d513), true + case "Pgr": + // GREEK CAPITAL LETTER PI + return rune(0x03a0), true + case "Phi": + // GREEK CAPITAL LETTER PHI + return rune(0x03a6), true + case "Pi": + // GREEK CAPITAL LETTER PI + return rune(0x03a0), true + case "PlusMinus": + // PLUS-MINUS SIGN + return rune(0xb1), true + case "Poincareplane": + // BLACK-LETTER CAPITAL H + return rune(0x210c), true + case "Popf": + // DOUBLE-STRUCK CAPITAL P + return rune(0x2119), true + case "Product": + // N-ARY PRODUCT + return rune(0x220f), true + case "Proportional": + // PROPORTIONAL TO + return rune(0x221d), true + case "Proportion": + // PROPORTION + return rune(0x2237), true + case "Pr": + // DOUBLE PRECEDES + return rune(0x2abb), true + case "PrecedesEqual": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "Precedes": + // PRECEDES + return rune(0x227a), true + case "PrecedesSlantEqual": + // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "PrecedesTilde": + // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "Prime": + // DOUBLE PRIME + return rune(0x2033), true + case "Pscr": + // MATHEMATICAL SCRIPT CAPITAL P + return rune(0x01d4ab), true + case "Psi": + // GREEK CAPITAL LETTER PSI + return rune(0x03a8), true + } + + case 'Q': + switch name { + case "QUOT": + // QUOTATION MARK + return rune(0x22), true + case "Qfr": + // MATHEMATICAL FRAKTUR CAPITAL Q + return rune(0x01d514), true + case "Qopf": + // DOUBLE-STRUCK CAPITAL Q + return rune(0x211a), true + case "Qscr": + // MATHEMATICAL SCRIPT CAPITAL Q + return rune(0x01d4ac), true + } + + case 'R': + switch name { + case "RBarr": + // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW + return rune(0x2910), true + case "REG": + // REGISTERED SIGN + return rune(0xae), true + case "Racute": + // LATIN CAPITAL LETTER R WITH ACUTE + return rune(0x0154), true + case "Rang": + // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET + return rune(0x27eb), true + case "Rarr": + // RIGHTWARDS TWO HEADED ARROW + return rune(0x21a0), true + case "Rarrtl": + // RIGHTWARDS TWO-HEADED ARROW WITH TAIL + return rune(0x2916), true + case "Rcaron": + // LATIN CAPITAL LETTER R WITH CARON + return rune(0x0158), true + case "Rcedil": + // LATIN CAPITAL LETTER R WITH CEDILLA + return rune(0x0156), true + case "Rcy": + // CYRILLIC CAPITAL LETTER ER + return rune(0x0420), true + case "ReverseElement": + // CONTAINS AS MEMBER + return rune(0x220b), true + case "ReverseEquilibrium": + // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "Re": + // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "ReverseUpEquilibrium": + // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x296f), true + case "Rfr": + // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "Rgr": + // GREEK CAPITAL LETTER RHO + return rune(0x03a1), true + case "Rho": + // GREEK CAPITAL LETTER RHO + return rune(0x03a1), true + case "RightAngleBracket": + // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "RightArrowBar": + // RIGHTWARDS ARROW TO BAR + return rune(0x21e5), true + case "RightArrow": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "RightArrowLeftArrow": + // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "RightCeiling": + // RIGHT CEILING + return rune(0x2309), true + case "RightDoubleBracket": + // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + return rune(0x27e7), true + case "RightDownTeeVector": + // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295d), true + case "RightDownVector": + // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "RightDownVectorBar": + // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2955), true + case "RightFloor": + // RIGHT FLOOR + return rune(0x230b), true + case "RightTeeArrow": + // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "RightTeeVector": + // RIGHTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295b), true + case "RightTee": + // RIGHT TACK + return rune(0x22a2), true + case "RightTriangleBar": + // VERTICAL BAR BESIDE RIGHT TRIANGLE + return rune(0x29d0), true + case "RightTriangle": + // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "RightTriangleEqual": + // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "RightUpDownVector": + // UP BARB RIGHT DOWN BARB RIGHT HARPOON + return rune(0x294f), true + case "RightUpTeeVector": + // UPWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295c), true + case "RightUpVector": + // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "RightUpVectorBar": + // UPWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2954), true + case "RightVector": + // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "RightVectorBar": + // RIGHTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2953), true + case "Rightarrow": + // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "Ropf": + // DOUBLE-STRUCK CAPITAL R + return rune(0x211d), true + case "RoundImplies": + // RIGHT DOUBLE ARROW WITH ROUNDED HEAD + return rune(0x2970), true + case "Rrightarrow": + // RIGHTWARDS TRIPLE ARROW + return rune(0x21db), true + case "Rscr": + // SCRIPT CAPITAL R + return rune(0x211b), true + case "Rsh": + // UPWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b1), true + case "RuleDelayed": + // RULE-DELAYED + return rune(0x29f4), true + } + + case 'S': + switch name { + case "SHCHcy": + // CYRILLIC CAPITAL LETTER SHCHA + return rune(0x0429), true + case "SHcy": + // CYRILLIC CAPITAL LETTER SHA + return rune(0x0428), true + case "SOFTcy": + // CYRILLIC CAPITAL LETTER SOFT SIGN + return rune(0x042c), true + case "Sacute": + // LATIN CAPITAL LETTER S WITH ACUTE + return rune(0x015a), true + case "Sc": + // DOUBLE SUCCEEDS + return rune(0x2abc), true + case "Scaron": + // LATIN CAPITAL LETTER S WITH CARON + return rune(0x0160), true + case "Scedil": + // LATIN CAPITAL LETTER S WITH CEDILLA + return rune(0x015e), true + case "Scirc": + // LATIN CAPITAL LETTER S WITH CIRCUMFLEX + return rune(0x015c), true + case "Scy": + // CYRILLIC CAPITAL LETTER ES + return rune(0x0421), true + case "Sfr": + // MATHEMATICAL FRAKTUR CAPITAL S + return rune(0x01d516), true + case "Sgr": + // GREEK CAPITAL LETTER SIGMA + return rune(0x03a3), true + case "ShortDownArrow": + // DOWNWARDS ARROW + return rune(0x2193), true + case "ShortLeftArrow": + // LEFTWARDS ARROW + return rune(0x2190), true + case "ShortRightArrow": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "ShortUpArrow": + // UPWARDS ARROW + return rune(0x2191), true + case "Sigma": + // GREEK CAPITAL LETTER SIGMA + return rune(0x03a3), true + case "SmallCircle": + // RING OPERATOR + return rune(0x2218), true + case "Sopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL S + return rune(0x01d54a), true + case "Sqrt": + // SQUARE ROOT + return rune(0x221a), true + case "SquareIntersection": + // SQUARE CAP + return rune(0x2293), true + case "SquareSubset": + // SQUARE IMAGE OF + return rune(0x228f), true + case "SquareSubsetEqual": + // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "Square": + // WHITE SQUARE + return rune(0x25a1), true + case "SquareSuperset": + // SQUARE ORIGINAL OF + return rune(0x2290), true + case "SquareSupersetEqual": + // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "SquareUnion": + // SQUARE CUP + return rune(0x2294), true + case "Sscr": + // MATHEMATICAL SCRIPT CAPITAL S + return rune(0x01d4ae), true + case "Star": + // STAR OPERATOR + return rune(0x22c6), true + case "Sub": + // DOUBLE SUBSET + return rune(0x22d0), true + case "Subset": + // DOUBLE SUBSET + return rune(0x22d0), true + case "SubsetEqual": + // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "Succeeds": + // SUCCEEDS + return rune(0x227b), true + case "SucceedsEqual": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "SucceedsSlantEqual": + // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "SucceedsTilde": + // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "SuchThat": + // CONTAINS AS MEMBER + return rune(0x220b), true + case "Sum": + // N-ARY SUMMATION + return rune(0x2211), true + case "SupersetEqual": + // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "Sup": + // DOUBLE SUPERSET + return rune(0x22d1), true + case "Superset": + // SUPERSET OF + return rune(0x2283), true + case "Supset": + // DOUBLE SUPERSET + return rune(0x22d1), true + } + + case 'T': + switch name { + case "THORN": + // LATIN CAPITAL LETTER THORN + return rune(0xde), true + case "THgr": + // GREEK CAPITAL LETTER THETA + return rune(0x0398), true + case "TRADE": + // TRADE MARK SIGN + return rune(0x2122), true + case "TSHcy": + // CYRILLIC CAPITAL LETTER TSHE + return rune(0x040b), true + case "TScy": + // CYRILLIC CAPITAL LETTER TSE + return rune(0x0426), true + case "Tab": + // CHARACTER TABULATION + return rune(0x09), true + case "Tau": + // GREEK CAPITAL LETTER TAU + return rune(0x03a4), true + case "Tcaron": + // LATIN CAPITAL LETTER T WITH CARON + return rune(0x0164), true + case "Tcedil": + // LATIN CAPITAL LETTER T WITH CEDILLA + return rune(0x0162), true + case "Tcy": + // CYRILLIC CAPITAL LETTER TE + return rune(0x0422), true + case "Tfr": + // MATHEMATICAL FRAKTUR CAPITAL T + return rune(0x01d517), true + case "Tgr": + // GREEK CAPITAL LETTER TAU + return rune(0x03a4), true + case "Therefore": + // THEREFORE + return rune(0x2234), true + case "Theta": + // GREEK CAPITAL LETTER THETA + return rune(0x0398), true + case "Thetav": + // GREEK CAPITAL THETA SYMBOL + return rune(0x03f4), true + case "ThickSpace": + // space of width 5/18 em + return rune(0x205f), true + case "ThinSpace": + // THIN SPACE + return rune(0x2009), true + case "Tilde": + // TILDE OPERATOR + return rune(0x223c), true + case "TildeEqual": + // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "TildeFullEqual": + // APPROXIMATELY EQUAL TO + return rune(0x2245), true + case "TildeTilde": + // ALMOST EQUAL TO + return rune(0x2248), true + case "Topf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL T + return rune(0x01d54b), true + case "TripleDot": + // COMBINING THREE DOTS ABOVE + return rune(0x20db), true + case "Tscr": + // MATHEMATICAL SCRIPT CAPITAL T + return rune(0x01d4af), true + case "Tstrok": + // LATIN CAPITAL LETTER T WITH STROKE + return rune(0x0166), true + } + + case 'U': + switch name { + case "Uacgr": + // GREEK CAPITAL LETTER UPSILON WITH TONOS + return rune(0x038e), true + case "Uacute": + // LATIN CAPITAL LETTER U WITH ACUTE + return rune(0xda), true + case "Uarrocir": + // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE + return rune(0x2949), true + case "Uarr": + // UPWARDS TWO HEADED ARROW + return rune(0x219f), true + case "Ubrcy": + // CYRILLIC CAPITAL LETTER SHORT U + return rune(0x040e), true + case "Ubreve": + // LATIN CAPITAL LETTER U WITH BREVE + return rune(0x016c), true + case "Ucirc": + // LATIN CAPITAL LETTER U WITH CIRCUMFLEX + return rune(0xdb), true + case "Ucy": + // CYRILLIC CAPITAL LETTER U + return rune(0x0423), true + case "Udblac": + // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE + return rune(0x0170), true + case "Udigr": + // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA + return rune(0x03ab), true + case "Ufr": + // MATHEMATICAL FRAKTUR CAPITAL U + return rune(0x01d518), true + case "Ugrave": + // LATIN CAPITAL LETTER U WITH GRAVE + return rune(0xd9), true + case "Ugr": + // GREEK CAPITAL LETTER UPSILON + return rune(0x03a5), true + case "Umacr": + // LATIN CAPITAL LETTER U WITH MACRON + return rune(0x016a), true + case "UnderBar": + // LOW LINE + return rune(0x5f), true + case "UnderBrace": + // BOTTOM CURLY BRACKET + return rune(0x23df), true + case "UnderBracket": + // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "UnderParenthesis": + // BOTTOM PARENTHESIS + return rune(0x23dd), true + case "Union": + // N-ARY UNION + return rune(0x22c3), true + case "UnionPlus": + // MULTISET UNION + return rune(0x228e), true + case "Uogon": + // LATIN CAPITAL LETTER U WITH OGONEK + return rune(0x0172), true + case "Uopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL U + return rune(0x01d54c), true + case "UpArrow": + // UPWARDS ARROW + return rune(0x2191), true + case "UpArrowBar": + // UPWARDS ARROW TO BAR + return rune(0x2912), true + case "UpArrowDownArrow": + // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW + return rune(0x21c5), true + case "UpDownArrow": + // UP DOWN ARROW + return rune(0x2195), true + case "UpEquilibrium": + // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x296e), true + case "UpTee": + // UP TACK + return rune(0x22a5), true + case "UpTeeArrow": + // UPWARDS ARROW FROM BAR + return rune(0x21a5), true + case "Uparrow": + // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "Updownarrow": + // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "UpperLeftArrow": + // NORTH WEST ARROW + return rune(0x2196), true + case "UpperRightArrow": + // NORTH EAST ARROW + return rune(0x2197), true + case "Upsilon": + // GREEK CAPITAL LETTER UPSILON + return rune(0x03a5), true + case "Upsi": + // GREEK UPSILON WITH HOOK SYMBOL + return rune(0x03d2), true + case "Uring": + // LATIN CAPITAL LETTER U WITH RING ABOVE + return rune(0x016e), true + case "Uscr": + // MATHEMATICAL SCRIPT CAPITAL U + return rune(0x01d4b0), true + case "Utilde": + // LATIN CAPITAL LETTER U WITH TILDE + return rune(0x0168), true + case "Uuml": + // LATIN CAPITAL LETTER U WITH DIAERESIS + return rune(0xdc), true + } + + case 'V': + switch name { + case "VDash": + // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + return rune(0x22ab), true + case "Vbar": + // DOUBLE UP TACK + return rune(0x2aeb), true + case "Vcy": + // CYRILLIC CAPITAL LETTER VE + return rune(0x0412), true + case "Vdashl": + // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL + return rune(0x2ae6), true + case "Vdash": + // FORCES + return rune(0x22a9), true + case "Vee": + // N-ARY LOGICAL OR + return rune(0x22c1), true + case "Verbar": + // DOUBLE VERTICAL LINE + return rune(0x2016), true + case "Vert": + // DOUBLE VERTICAL LINE + return rune(0x2016), true + case "VerticalBar": + // DIVIDES + return rune(0x2223), true + case "VerticalLine": + // VERTICAL LINE + return rune(0x7c), true + case "VerticalSeparator": + // LIGHT VERTICAL BAR + return rune(0x2758), true + case "VerticalTilde": + // WREATH PRODUCT + return rune(0x2240), true + case "VeryThinSpace": + // HAIR SPACE + return rune(0x200a), true + case "Vfr": + // MATHEMATICAL FRAKTUR CAPITAL V + return rune(0x01d519), true + case "Vopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL V + return rune(0x01d54d), true + case "Vscr": + // MATHEMATICAL SCRIPT CAPITAL V + return rune(0x01d4b1), true + case "Vvdash": + // TRIPLE VERTICAL BAR RIGHT TURNSTILE + return rune(0x22aa), true + } + + case 'W': + switch name { + case "Wcirc": + // LATIN CAPITAL LETTER W WITH CIRCUMFLEX + return rune(0x0174), true + case "Wedge": + // N-ARY LOGICAL AND + return rune(0x22c0), true + case "Wfr": + // MATHEMATICAL FRAKTUR CAPITAL W + return rune(0x01d51a), true + case "Wopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL W + return rune(0x01d54e), true + case "Wscr": + // MATHEMATICAL SCRIPT CAPITAL W + return rune(0x01d4b2), true + } + + case 'X': + switch name { + case "Xfr": + // MATHEMATICAL FRAKTUR CAPITAL X + return rune(0x01d51b), true + case "Xgr": + // GREEK CAPITAL LETTER XI + return rune(0x039e), true + case "Xi": + // GREEK CAPITAL LETTER XI + return rune(0x039e), true + case "Xopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL X + return rune(0x01d54f), true + case "Xscr": + // MATHEMATICAL SCRIPT CAPITAL X + return rune(0x01d4b3), true + } + + case 'Y': + switch name { + case "YAcy": + // CYRILLIC CAPITAL LETTER YA + return rune(0x042f), true + case "YIcy": + // CYRILLIC CAPITAL LETTER YI + return rune(0x0407), true + case "YUcy": + // CYRILLIC CAPITAL LETTER YU + return rune(0x042e), true + case "Yacute": + // LATIN CAPITAL LETTER Y WITH ACUTE + return rune(0xdd), true + case "Ycirc": + // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX + return rune(0x0176), true + case "Ycy": + // CYRILLIC CAPITAL LETTER YERU + return rune(0x042b), true + case "Yfr": + // MATHEMATICAL FRAKTUR CAPITAL Y + return rune(0x01d51c), true + case "Yopf": + // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y + return rune(0x01d550), true + case "Yscr": + // MATHEMATICAL SCRIPT CAPITAL Y + return rune(0x01d4b4), true + case "Yuml": + // LATIN CAPITAL LETTER Y WITH DIAERESIS + return rune(0x0178), true + } + + case 'Z': + switch name { + case "ZHcy": + // CYRILLIC CAPITAL LETTER ZHE + return rune(0x0416), true + case "Zacute": + // LATIN CAPITAL LETTER Z WITH ACUTE + return rune(0x0179), true + case "Zcaron": + // LATIN CAPITAL LETTER Z WITH CARON + return rune(0x017d), true + case "Zcy": + // CYRILLIC CAPITAL LETTER ZE + return rune(0x0417), true + case "Zdot": + // LATIN CAPITAL LETTER Z WITH DOT ABOVE + return rune(0x017b), true + case "ZeroWidthSpace": + // ZERO WIDTH SPACE + return rune(0x200b), true + case "Zeta": + // GREEK CAPITAL LETTER ZETA + return rune(0x0396), true + case "Zfr": + // BLACK-LETTER CAPITAL Z + return rune(0x2128), true + case "Zgr": + // GREEK CAPITAL LETTER ZETA + return rune(0x0396), true + case "Zopf": + // DOUBLE-STRUCK CAPITAL Z + return rune(0x2124), true + case "Zscr": + // MATHEMATICAL SCRIPT CAPITAL Z + return rune(0x01d4b5), true + } + + case 'a': + switch name { + case "aacgr": + // GREEK SMALL LETTER ALPHA WITH TONOS + return rune(0x03ac), true + case "aacute": + // LATIN SMALL LETTER A WITH ACUTE + return rune(0xe1), true + case "abreve": + // LATIN SMALL LETTER A WITH BREVE + return rune(0x0103), true + case "acE": + // INVERTED LAZY S with double underline + return rune(0x223e), true + case "acd": + // SINE WAVE + return rune(0x223f), true + case "acute": + // ACUTE ACCENT + return rune(0xb4), true + case "ac": + // INVERTED LAZY S + return rune(0x223e), true + case "acirc": + // LATIN SMALL LETTER A WITH CIRCUMFLEX + return rune(0xe2), true + case "actuary": + // COMBINING ANNUITY SYMBOL + return rune(0x20e7), true + case "acy": + // CYRILLIC SMALL LETTER A + return rune(0x0430), true + case "aelig": + // LATIN SMALL LETTER AE + return rune(0xe6), true + case "af": + // FUNCTION APPLICATION + return rune(0x2061), true + case "afr": + // MATHEMATICAL FRAKTUR SMALL A + return rune(0x01d51e), true + case "agr": + // GREEK SMALL LETTER ALPHA + return rune(0x03b1), true + case "agrave": + // LATIN SMALL LETTER A WITH GRAVE + return rune(0xe0), true + case "alefsym": + // ALEF SYMBOL + return rune(0x2135), true + case "aleph": + // ALEF SYMBOL + return rune(0x2135), true + case "alpha": + // GREEK SMALL LETTER ALPHA + return rune(0x03b1), true + case "amacr": + // LATIN SMALL LETTER A WITH MACRON + return rune(0x0101), true + case "amalg": + // AMALGAMATION OR COPRODUCT + return rune(0x2a3f), true + case "amp": + // AMPERSAND + return rune(0x26), true + case "andand": + // TWO INTERSECTING LOGICAL AND + return rune(0x2a55), true + case "andd": + // LOGICAL AND WITH HORIZONTAL DASH + return rune(0x2a5c), true + case "andslope": + // SLOPING LARGE AND + return rune(0x2a58), true + case "andv": + // LOGICAL AND WITH MIDDLE STEM + return rune(0x2a5a), true + case "and": + // LOGICAL AND + return rune(0x2227), true + case "angdnl": + // TURNED ANGLE + return rune(0x29a2), true + case "angdnr": + // ACUTE ANGLE + return rune(0x299f), true + case "ange": + // ANGLE WITH UNDERBAR + return rune(0x29a4), true + case "angles": + // ANGLE WITH S INSIDE + return rune(0x299e), true + case "angle": + // ANGLE + return rune(0x2220), true + case "angmsdaa": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT + return rune(0x29a8), true + case "angmsdab": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT + return rune(0x29a9), true + case "angmsdac": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT + return rune(0x29aa), true + case "angmsdad": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT + return rune(0x29ab), true + case "angmsdae": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP + return rune(0x29ac), true + case "angmsdaf": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP + return rune(0x29ad), true + case "angmsdag": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN + return rune(0x29ae), true + case "angmsdah": + // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN + return rune(0x29af), true + case "angmsd": + // MEASURED ANGLE + return rune(0x2221), true + case "angrtvbd": + // MEASURED RIGHT ANGLE WITH DOT + return rune(0x299d), true + case "angrtvb": + // RIGHT ANGLE WITH ARC + return rune(0x22be), true + case "angsph": + // SPHERICAL ANGLE + return rune(0x2222), true + case "angst": + // LATIN CAPITAL LETTER A WITH RING ABOVE + return rune(0xc5), true + case "angupl": + // REVERSED ANGLE + return rune(0x29a3), true + case "angzarr": + // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW + return rune(0x237c), true + case "ang": + // ANGLE + return rune(0x2220), true + case "ang90": + // RIGHT ANGLE + return rune(0x221f), true + case "angrt": + // RIGHT ANGLE + return rune(0x221f), true + case "aogon": + // LATIN SMALL LETTER A WITH OGONEK + return rune(0x0105), true + case "aopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL A + return rune(0x01d552), true + case "apE": + // APPROXIMATELY EQUAL OR EQUAL TO + return rune(0x2a70), true + case "apacir": + // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT + return rune(0x2a6f), true + case "ape": + // ALMOST EQUAL OR EQUAL TO + return rune(0x224a), true + case "apid": + // TRIPLE TILDE + return rune(0x224b), true + case "approxeq": + // ALMOST EQUAL OR EQUAL TO + return rune(0x224a), true + case "approx": + // ALMOST EQUAL TO + return rune(0x2248), true + case "ap": + // ALMOST EQUAL TO + return rune(0x2248), true + case "apos": + // APOSTROPHE + return rune(0x27), true + case "aring": + // LATIN SMALL LETTER A WITH RING ABOVE + return rune(0xe5), true + case "arrllsr": + // LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW + return rune(0x2943), true + case "arrlrsl": + // RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW + return rune(0x2942), true + case "arrsrll": + // SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW + return rune(0x2944), true + case "ascr": + // MATHEMATICAL SCRIPT SMALL A + return rune(0x01d4b6), true + case "astb": + // SQUARED ASTERISK + return rune(0x29c6), true + case "ast": + // ASTERISK + return rune(0x2a), true + case "asympeq": + // EQUIVALENT TO + return rune(0x224d), true + case "asymp": + // ALMOST EQUAL TO + return rune(0x2248), true + case "atilde": + // LATIN SMALL LETTER A WITH TILDE + return rune(0xe3), true + case "auml": + // LATIN SMALL LETTER A WITH DIAERESIS + return rune(0xe4), true + case "awconint": + // ANTICLOCKWISE CONTOUR INTEGRAL + return rune(0x2233), true + case "awint": + // ANTICLOCKWISE INTEGRATION + return rune(0x2a11), true + } + + case 'b': + switch name { + case "b.Delta": + // MATHEMATICAL BOLD CAPITAL DELTA + return rune(0x01d6ab), true + case "b.Gamma": + // MATHEMATICAL BOLD CAPITAL GAMMA + return rune(0x01d6aa), true + case "b.Gammad": + // MATHEMATICAL BOLD CAPITAL DIGAMMA + return rune(0x01d7ca), true + case "b.Lambda": + // MATHEMATICAL BOLD CAPITAL LAMDA + return rune(0x01d6b2), true + case "b.Omega": + // MATHEMATICAL BOLD CAPITAL OMEGA + return rune(0x01d6c0), true + case "b.Phi": + // MATHEMATICAL BOLD CAPITAL PHI + return rune(0x01d6bd), true + case "b.Pi": + // MATHEMATICAL BOLD CAPITAL PI + return rune(0x01d6b7), true + case "b.Psi": + // MATHEMATICAL BOLD CAPITAL PSI + return rune(0x01d6bf), true + case "b.Sigma": + // MATHEMATICAL BOLD CAPITAL SIGMA + return rune(0x01d6ba), true + case "b.Theta": + // MATHEMATICAL BOLD CAPITAL THETA + return rune(0x01d6af), true + case "b.Upsi": + // MATHEMATICAL BOLD CAPITAL UPSILON + return rune(0x01d6bc), true + case "b.Xi": + // MATHEMATICAL BOLD CAPITAL XI + return rune(0x01d6b5), true + case "b.alpha": + // MATHEMATICAL BOLD SMALL ALPHA + return rune(0x01d6c2), true + case "b.beta": + // MATHEMATICAL BOLD SMALL BETA + return rune(0x01d6c3), true + case "b.chi": + // MATHEMATICAL BOLD SMALL CHI + return rune(0x01d6d8), true + case "b.delta": + // MATHEMATICAL BOLD SMALL DELTA + return rune(0x01d6c5), true + case "b.epsi": + // MATHEMATICAL BOLD SMALL EPSILON + return rune(0x01d6c6), true + case "b.epsiv": + // MATHEMATICAL BOLD EPSILON SYMBOL + return rune(0x01d6dc), true + case "b.eta": + // MATHEMATICAL BOLD SMALL ETA + return rune(0x01d6c8), true + case "b.gammad": + // MATHEMATICAL BOLD SMALL DIGAMMA + return rune(0x01d7cb), true + case "b.gamma": + // MATHEMATICAL BOLD SMALL GAMMA + return rune(0x01d6c4), true + case "b.iota": + // MATHEMATICAL BOLD SMALL IOTA + return rune(0x01d6ca), true + case "b.kappa": + // MATHEMATICAL BOLD SMALL KAPPA + return rune(0x01d6cb), true + case "b.kappav": + // MATHEMATICAL BOLD KAPPA SYMBOL + return rune(0x01d6de), true + case "b.lambda": + // MATHEMATICAL BOLD SMALL LAMDA + return rune(0x01d6cc), true + case "b.mu": + // MATHEMATICAL BOLD SMALL MU + return rune(0x01d6cd), true + case "b.nu": + // MATHEMATICAL BOLD SMALL NU + return rune(0x01d6ce), true + case "b.omega": + // MATHEMATICAL BOLD SMALL OMEGA + return rune(0x01d6da), true + case "b.phi": + // MATHEMATICAL BOLD SMALL PHI + return rune(0x01d6d7), true + case "b.phiv": + // MATHEMATICAL BOLD PHI SYMBOL + return rune(0x01d6df), true + case "b.pi": + // MATHEMATICAL BOLD SMALL PI + return rune(0x01d6d1), true + case "b.piv": + // MATHEMATICAL BOLD PI SYMBOL + return rune(0x01d6e1), true + case "b.psi": + // MATHEMATICAL BOLD SMALL PSI + return rune(0x01d6d9), true + case "b.rho": + // MATHEMATICAL BOLD SMALL RHO + return rune(0x01d6d2), true + case "b.rhov": + // MATHEMATICAL BOLD RHO SYMBOL + return rune(0x01d6e0), true + case "b.sigmav": + // MATHEMATICAL BOLD SMALL FINAL SIGMA + return rune(0x01d6d3), true + case "b.sigma": + // MATHEMATICAL BOLD SMALL SIGMA + return rune(0x01d6d4), true + case "b.tau": + // MATHEMATICAL BOLD SMALL TAU + return rune(0x01d6d5), true + case "b.thetas": + // MATHEMATICAL BOLD SMALL THETA + return rune(0x01d6c9), true + case "b.thetav": + // MATHEMATICAL BOLD THETA SYMBOL + return rune(0x01d6dd), true + case "b.upsi": + // MATHEMATICAL BOLD SMALL UPSILON + return rune(0x01d6d6), true + case "b.xi": + // MATHEMATICAL BOLD SMALL XI + return rune(0x01d6cf), true + case "b.zeta": + // MATHEMATICAL BOLD SMALL ZETA + return rune(0x01d6c7), true + case "bNot": + // REVERSED DOUBLE STROKE NOT SIGN + return rune(0x2aed), true + case "backcong": + // ALL EQUAL TO + return rune(0x224c), true + case "backepsilon": + // GREEK REVERSED LUNATE EPSILON SYMBOL + return rune(0x03f6), true + case "backprime": + // REVERSED PRIME + return rune(0x2035), true + case "backsimeq": + // REVERSED TILDE EQUALS + return rune(0x22cd), true + case "backsim": + // REVERSED TILDE + return rune(0x223d), true + case "barV": + // DOUBLE DOWN TACK + return rune(0x2aea), true + case "barvee": + // NOR + return rune(0x22bd), true + case "barwed": + // PROJECTIVE + return rune(0x2305), true + case "barwedge": + // PROJECTIVE + return rune(0x2305), true + case "bbrk": + // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "bbrktbrk": + // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET + return rune(0x23b6), true + case "bcong": + // ALL EQUAL TO + return rune(0x224c), true + case "bcy": + // CYRILLIC SMALL LETTER BE + return rune(0x0431), true + case "bdlhar": + // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2961), true + case "bdquo": + // DOUBLE LOW-9 QUOTATION MARK + return rune(0x201e), true + case "bdrhar": + // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295d), true + case "because": + // BECAUSE + return rune(0x2235), true + case "becaus": + // BECAUSE + return rune(0x2235), true + case "bemptyv": + // REVERSED EMPTY SET + return rune(0x29b0), true + case "bepsi": + // GREEK REVERSED LUNATE EPSILON SYMBOL + return rune(0x03f6), true + case "bernou": + // SCRIPT CAPITAL B + return rune(0x212c), true + case "beta": + // GREEK SMALL LETTER BETA + return rune(0x03b2), true + case "beth": + // BET SYMBOL + return rune(0x2136), true + case "between": + // BETWEEN + return rune(0x226c), true + case "bfr": + // MATHEMATICAL FRAKTUR SMALL B + return rune(0x01d51f), true + case "bgr": + // GREEK SMALL LETTER BETA + return rune(0x03b2), true + case "bigcap": + // N-ARY INTERSECTION + return rune(0x22c2), true + case "bigcirc": + // LARGE CIRCLE + return rune(0x25ef), true + case "bigcup": + // N-ARY UNION + return rune(0x22c3), true + case "bigodot": + // N-ARY CIRCLED DOT OPERATOR + return rune(0x2a00), true + case "bigoplus": + // N-ARY CIRCLED PLUS OPERATOR + return rune(0x2a01), true + case "bigotimes": + // N-ARY CIRCLED TIMES OPERATOR + return rune(0x2a02), true + case "bigsqcup": + // N-ARY SQUARE UNION OPERATOR + return rune(0x2a06), true + case "bigstar": + // BLACK STAR + return rune(0x2605), true + case "bigtriangledown": + // WHITE DOWN-POINTING TRIANGLE + return rune(0x25bd), true + case "bigtriangleup": + // WHITE UP-POINTING TRIANGLE + return rune(0x25b3), true + case "biguplus": + // N-ARY UNION OPERATOR WITH PLUS + return rune(0x2a04), true + case "bigvee": + // N-ARY LOGICAL OR + return rune(0x22c1), true + case "bigwedge": + // N-ARY LOGICAL AND + return rune(0x22c0), true + case "bkarow": + // RIGHTWARDS DOUBLE DASH ARROW + return rune(0x290d), true + case "blacklozenge": + // BLACK LOZENGE + return rune(0x29eb), true + case "blacksquare": + // BLACK SMALL SQUARE + return rune(0x25aa), true + case "blacktriangledown": + // BLACK DOWN-POINTING SMALL TRIANGLE + return rune(0x25be), true + case "blacktriangleleft": + // BLACK LEFT-POINTING SMALL TRIANGLE + return rune(0x25c2), true + case "blacktriangleright": + // BLACK RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b8), true + case "blacktriangle": + // BLACK UP-POINTING SMALL TRIANGLE + return rune(0x25b4), true + case "blank": + // BLANK SYMBOL + return rune(0x2422), true + case "bldhar": + // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295e), true + case "blk12": + // MEDIUM SHADE + return rune(0x2592), true + case "blk14": + // LIGHT SHADE + return rune(0x2591), true + case "blk34": + // DARK SHADE + return rune(0x2593), true + case "block": + // FULL BLOCK + return rune(0x2588), true + case "bluhar": + // LEFTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295a), true + case "bnequiv": + // IDENTICAL TO with reverse slash + return rune(0x2261), true + case "bne": + // EQUALS SIGN with reverse slash + return rune(0x3d), true + case "bnot": + // REVERSED NOT SIGN + return rune(0x2310), true + case "bopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL B + return rune(0x01d553), true + case "bot": + // UP TACK + return rune(0x22a5), true + case "bottom": + // UP TACK + return rune(0x22a5), true + case "bowtie": + // BOWTIE + return rune(0x22c8), true + case "boxDL": + // BOX DRAWINGS DOUBLE DOWN AND LEFT + return rune(0x2557), true + case "boxDR": + // BOX DRAWINGS DOUBLE DOWN AND RIGHT + return rune(0x2554), true + case "boxDl": + // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + return rune(0x2556), true + case "boxDr": + // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + return rune(0x2553), true + case "boxHD": + // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + return rune(0x2566), true + case "boxHU": + // BOX DRAWINGS DOUBLE UP AND HORIZONTAL + return rune(0x2569), true + case "boxHd": + // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + return rune(0x2564), true + case "boxHu": + // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + return rune(0x2567), true + case "boxH": + // BOX DRAWINGS DOUBLE HORIZONTAL + return rune(0x2550), true + case "boxUL": + // BOX DRAWINGS DOUBLE UP AND LEFT + return rune(0x255d), true + case "boxUR": + // BOX DRAWINGS DOUBLE UP AND RIGHT + return rune(0x255a), true + case "boxUl": + // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + return rune(0x255c), true + case "boxUr": + // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + return rune(0x2559), true + case "boxVH": + // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + return rune(0x256c), true + case "boxVL": + // BOX DRAWINGS DOUBLE VERTICAL AND LEFT + return rune(0x2563), true + case "boxVR": + // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + return rune(0x2560), true + case "boxVh": + // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + return rune(0x256b), true + case "boxVl": + // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + return rune(0x2562), true + case "boxVr": + // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + return rune(0x255f), true + case "boxV": + // BOX DRAWINGS DOUBLE VERTICAL + return rune(0x2551), true + case "boxbox": + // TWO JOINED SQUARES + return rune(0x29c9), true + case "boxdL": + // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + return rune(0x2555), true + case "boxdR": + // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + return rune(0x2552), true + case "boxdl": + // BOX DRAWINGS LIGHT DOWN AND LEFT + return rune(0x2510), true + case "boxdr": + // BOX DRAWINGS LIGHT DOWN AND RIGHT + return rune(0x250c), true + case "boxhU": + // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + return rune(0x2568), true + case "boxh": + // BOX DRAWINGS LIGHT HORIZONTAL + return rune(0x2500), true + case "boxhD": + // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + return rune(0x2565), true + case "boxhd": + // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + return rune(0x252c), true + case "boxhu": + // BOX DRAWINGS LIGHT UP AND HORIZONTAL + return rune(0x2534), true + case "boxminus": + // SQUARED MINUS + return rune(0x229f), true + case "boxplus": + // SQUARED PLUS + return rune(0x229e), true + case "boxtimes": + // SQUARED TIMES + return rune(0x22a0), true + case "boxuL": + // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + return rune(0x255b), true + case "boxuR": + // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + return rune(0x2558), true + case "boxul": + // BOX DRAWINGS LIGHT UP AND LEFT + return rune(0x2518), true + case "boxur": + // BOX DRAWINGS LIGHT UP AND RIGHT + return rune(0x2514), true + case "boxvL": + // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + return rune(0x2561), true + case "boxvR": + // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + return rune(0x255e), true + case "boxvl": + // BOX DRAWINGS LIGHT VERTICAL AND LEFT + return rune(0x2524), true + case "boxvr": + // BOX DRAWINGS LIGHT VERTICAL AND RIGHT + return rune(0x251c), true + case "boxv": + // BOX DRAWINGS LIGHT VERTICAL + return rune(0x2502), true + case "boxvH": + // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + return rune(0x256a), true + case "boxvh": + // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + return rune(0x253c), true + case "bprime": + // REVERSED PRIME + return rune(0x2035), true + case "brdhar": + // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR + return rune(0x295f), true + case "breve": + // BREVE + return rune(0x02d8), true + case "bruhar": + // RIGHTWARDS HARPOON WITH BARB UP FROM BAR + return rune(0x295b), true + case "brvbar": + // BROKEN BAR + return rune(0xa6), true + case "bscr": + // MATHEMATICAL SCRIPT SMALL B + return rune(0x01d4b7), true + case "bsemi": + // REVERSED SEMICOLON + return rune(0x204f), true + case "bsim": + // REVERSED TILDE + return rune(0x223d), true + case "bsime": + // REVERSED TILDE EQUALS + return rune(0x22cd), true + case "bsolb": + // SQUARED FALLING DIAGONAL SLASH + return rune(0x29c5), true + case "bsolhsub": + // REVERSE SOLIDUS PRECEDING SUBSET + return rune(0x27c8), true + case "bsol": + // REVERSE SOLIDUS + return rune(0x5c), true + case "btimes": + // SEMIDIRECT PRODUCT WITH BOTTOM CLOSED + return rune(0x2a32), true + case "bulhar": + // UPWARDS HARPOON WITH BARB LEFT FROM BAR + return rune(0x2960), true + case "bullet": + // BULLET + return rune(0x2022), true + case "bull": + // BULLET + return rune(0x2022), true + case "bump": + // GEOMETRICALLY EQUIVALENT TO + return rune(0x224e), true + case "bumpE": + // EQUALS SIGN WITH BUMPY ABOVE + return rune(0x2aae), true + case "bumpe": + // DIFFERENCE BETWEEN + return rune(0x224f), true + case "bumpeq": + // DIFFERENCE BETWEEN + return rune(0x224f), true + case "burhar": + // UPWARDS HARPOON WITH BARB RIGHT FROM BAR + return rune(0x295c), true + } + + case 'c': + switch name { + case "cacute": + // LATIN SMALL LETTER C WITH ACUTE + return rune(0x0107), true + case "cap": + // INTERSECTION + return rune(0x2229), true + case "capand": + // INTERSECTION WITH LOGICAL AND + return rune(0x2a44), true + case "capbrcup": + // INTERSECTION ABOVE BAR ABOVE UNION + return rune(0x2a49), true + case "capcap": + // INTERSECTION BESIDE AND JOINED WITH INTERSECTION + return rune(0x2a4b), true + case "capcup": + // INTERSECTION ABOVE UNION + return rune(0x2a47), true + case "capdot": + // INTERSECTION WITH DOT + return rune(0x2a40), true + case "capint": + // INTEGRAL WITH INTERSECTION + return rune(0x2a19), true + case "caps": + // INTERSECTION with serifs + return rune(0x2229), true + case "caret": + // CARET INSERTION POINT + return rune(0x2041), true + case "caron": + // CARON + return rune(0x02c7), true + case "ccaps": + // CLOSED INTERSECTION WITH SERIFS + return rune(0x2a4d), true + case "ccaron": + // LATIN SMALL LETTER C WITH CARON + return rune(0x010d), true + case "ccedil": + // LATIN SMALL LETTER C WITH CEDILLA + return rune(0xe7), true + case "ccirc": + // LATIN SMALL LETTER C WITH CIRCUMFLEX + return rune(0x0109), true + case "ccups": + // CLOSED UNION WITH SERIFS + return rune(0x2a4c), true + case "ccupssm": + // CLOSED UNION WITH SERIFS AND SMASH PRODUCT + return rune(0x2a50), true + case "cdot": + // LATIN SMALL LETTER C WITH DOT ABOVE + return rune(0x010b), true + case "cedil": + // CEDILLA + return rune(0xb8), true + case "cemptyv": + // EMPTY SET WITH SMALL CIRCLE ABOVE + return rune(0x29b2), true + case "centerdot": + // MIDDLE DOT + return rune(0xb7), true + case "cent": + // CENT SIGN + return rune(0xa2), true + case "cfr": + // MATHEMATICAL FRAKTUR SMALL C + return rune(0x01d520), true + case "chcy": + // CYRILLIC SMALL LETTER CHE + return rune(0x0447), true + case "check": + // CHECK MARK + return rune(0x2713), true + case "checkmark": + // CHECK MARK + return rune(0x2713), true + case "chi": + // GREEK SMALL LETTER CHI + return rune(0x03c7), true + case "circeq": + // RING EQUAL TO + return rune(0x2257), true + case "circlearrowleft": + // ANTICLOCKWISE OPEN CIRCLE ARROW + return rune(0x21ba), true + case "circlearrowright": + // CLOCKWISE OPEN CIRCLE ARROW + return rune(0x21bb), true + case "circledS": + // CIRCLED LATIN CAPITAL LETTER S + return rune(0x24c8), true + case "circledast": + // CIRCLED ASTERISK OPERATOR + return rune(0x229b), true + case "circledcirc": + // CIRCLED RING OPERATOR + return rune(0x229a), true + case "circleddash": + // CIRCLED DASH + return rune(0x229d), true + case "cire": + // RING EQUAL TO + return rune(0x2257), true + case "cir": + // WHITE CIRCLE + return rune(0x25cb), true + case "cirE": + // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT + return rune(0x29c3), true + case "cirb": + // SQUARED SMALL CIRCLE + return rune(0x29c7), true + case "circ": + // MODIFIER LETTER CIRCUMFLEX ACCENT + return rune(0x02c6), true + case "circledR": + // REGISTERED SIGN + return rune(0xae), true + case "cirdarr": + // WHITE CIRCLE WITH DOWN ARROW + return rune(0x29ec), true + case "cirerr": + // ERROR-BARRED WHITE CIRCLE + return rune(0x29f2), true + case "cirfdarr": + // BLACK CIRCLE WITH DOWN ARROW + return rune(0x29ed), true + case "cirferr": + // ERROR-BARRED BLACK CIRCLE + return rune(0x29f3), true + case "cirfnint": + // CIRCULATION FUNCTION + return rune(0x2a10), true + case "cirmid": + // VERTICAL LINE WITH CIRCLE ABOVE + return rune(0x2aef), true + case "cirscir": + // CIRCLE WITH SMALL CIRCLE TO THE RIGHT + return rune(0x29c2), true + case "closur": + // CLOSE UP + return rune(0x2050), true + case "clubs": + // BLACK CLUB SUIT + return rune(0x2663), true + case "clubsuit": + // BLACK CLUB SUIT + return rune(0x2663), true + case "colone": + // COLON EQUALS + return rune(0x2254), true + case "coloneq": + // COLON EQUALS + return rune(0x2254), true + case "colon": + // COLON + return rune(0x3a), true + case "commat": + // COMMERCIAL AT + return rune(0x40), true + case "comma": + // COMMA + return rune(0x2c), true + case "comp": + // COMPLEMENT + return rune(0x2201), true + case "compfn": + // RING OPERATOR + return rune(0x2218), true + case "complement": + // COMPLEMENT + return rune(0x2201), true + case "complexes": + // DOUBLE-STRUCK CAPITAL C + return rune(0x2102), true + case "cong": + // APPROXIMATELY EQUAL TO + return rune(0x2245), true + case "congdot": + // CONGRUENT WITH DOT ABOVE + return rune(0x2a6d), true + case "conint": + // CONTOUR INTEGRAL + return rune(0x222e), true + case "copf": + // MATHEMATICAL DOUBLE-STRUCK SMALL C + return rune(0x01d554), true + case "coprod": + // N-ARY COPRODUCT + return rune(0x2210), true + case "copysr": + // SOUND RECORDING COPYRIGHT + return rune(0x2117), true + case "copy": + // COPYRIGHT SIGN + return rune(0xa9), true + case "crarr": + // DOWNWARDS ARROW WITH CORNER LEFTWARDS + return rune(0x21b5), true + case "cross": + // BALLOT X + return rune(0x2717), true + case "cscr": + // MATHEMATICAL SCRIPT SMALL C + return rune(0x01d4b8), true + case "csub": + // CLOSED SUBSET + return rune(0x2acf), true + case "csube": + // CLOSED SUBSET OR EQUAL TO + return rune(0x2ad1), true + case "csup": + // CLOSED SUPERSET + return rune(0x2ad0), true + case "csupe": + // CLOSED SUPERSET OR EQUAL TO + return rune(0x2ad2), true + case "ctdot": + // MIDLINE HORIZONTAL ELLIPSIS + return rune(0x22ef), true + case "cudarrl": + // RIGHT-SIDE ARC CLOCKWISE ARROW + return rune(0x2938), true + case "cudarrr": + // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS + return rune(0x2935), true + case "cuepr": + // EQUAL TO OR PRECEDES + return rune(0x22de), true + case "cuesc": + // EQUAL TO OR SUCCEEDS + return rune(0x22df), true + case "cularr": + // ANTICLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b6), true + case "cularrp": + // TOP ARC ANTICLOCKWISE ARROW WITH PLUS + return rune(0x293d), true + case "cup": + // UNION + return rune(0x222a), true + case "cupbrcap": + // UNION ABOVE BAR ABOVE INTERSECTION + return rune(0x2a48), true + case "cupcap": + // UNION ABOVE INTERSECTION + return rune(0x2a46), true + case "cupcup": + // UNION BESIDE AND JOINED WITH UNION + return rune(0x2a4a), true + case "cupdot": + // MULTISET MULTIPLICATION + return rune(0x228d), true + case "cupint": + // INTEGRAL WITH UNION + return rune(0x2a1a), true + case "cupor": + // UNION WITH LOGICAL OR + return rune(0x2a45), true + case "cupre": + // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "cups": + // UNION with serifs + return rune(0x222a), true + case "curarr": + // CLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b7), true + case "curarrm": + // TOP ARC CLOCKWISE ARROW WITH MINUS + return rune(0x293c), true + case "curlyeqprec": + // EQUAL TO OR PRECEDES + return rune(0x22de), true + case "curlyeqsucc": + // EQUAL TO OR SUCCEEDS + return rune(0x22df), true + case "curlyvee": + // CURLY LOGICAL OR + return rune(0x22ce), true + case "curlywedge": + // CURLY LOGICAL AND + return rune(0x22cf), true + case "curren": + // CURRENCY SIGN + return rune(0xa4), true + case "curvearrowleft": + // ANTICLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b6), true + case "curvearrowright": + // CLOCKWISE TOP SEMICIRCLE ARROW + return rune(0x21b7), true + case "cuvee": + // CURLY LOGICAL OR + return rune(0x22ce), true + case "cuwed": + // CURLY LOGICAL AND + return rune(0x22cf), true + case "cwconint": + // CLOCKWISE CONTOUR INTEGRAL + return rune(0x2232), true + case "cwint": + // CLOCKWISE INTEGRAL + return rune(0x2231), true + case "cylcty": + // CYLINDRICITY + return rune(0x232d), true + } + + case 'd': + switch name { + case "dAarr": + // DOWNWARDS TRIPLE ARROW + return rune(0x290b), true + case "dArr": + // DOWNWARDS DOUBLE ARROW + return rune(0x21d3), true + case "dHar": + // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x2965), true + case "dagger": + // DAGGER + return rune(0x2020), true + case "dalembrt": + // SQUARE WITH CONTOURED OUTLINE + return rune(0x29e0), true + case "daleth": + // DALET SYMBOL + return rune(0x2138), true + case "darr2": + // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "darr": + // DOWNWARDS ARROW + return rune(0x2193), true + case "darrb": + // DOWNWARDS ARROW TO BAR + return rune(0x2913), true + case "darrln": + // DOWNWARDS ARROW WITH HORIZONTAL STROKE + return rune(0x2908), true + case "dashv": + // LEFT TACK + return rune(0x22a3), true + case "dash": + // HYPHEN + return rune(0x2010), true + case "dashV": + // DOUBLE VERTICAL BAR LEFT TURNSTILE + return rune(0x2ae3), true + case "dbkarow": + // RIGHTWARDS TRIPLE DASH ARROW + return rune(0x290f), true + case "dblac": + // DOUBLE ACUTE ACCENT + return rune(0x02dd), true + case "dcaron": + // LATIN SMALL LETTER D WITH CARON + return rune(0x010f), true + case "dcy": + // CYRILLIC SMALL LETTER DE + return rune(0x0434), true + case "ddarr": + // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "dd": + // DOUBLE-STRUCK ITALIC SMALL D + return rune(0x2146), true + case "ddagger": + // DOUBLE DAGGER + return rune(0x2021), true + case "ddotseq": + // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW + return rune(0x2a77), true + case "deg": + // DEGREE SIGN + return rune(0xb0), true + case "delta": + // GREEK SMALL LETTER DELTA + return rune(0x03b4), true + case "demptyv": + // EMPTY SET WITH OVERBAR + return rune(0x29b1), true + case "dfisht": + // DOWN FISH TAIL + return rune(0x297f), true + case "dfr": + // MATHEMATICAL FRAKTUR SMALL D + return rune(0x01d521), true + case "dgr": + // GREEK SMALL LETTER DELTA + return rune(0x03b4), true + case "dharl": + // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "dharr": + // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "diam": + // DIAMOND OPERATOR + return rune(0x22c4), true + case "diamdarr": + // BLACK DIAMOND WITH DOWN ARROW + return rune(0x29ea), true + case "diamerr": + // ERROR-BARRED WHITE DIAMOND + return rune(0x29f0), true + case "diamerrf": + // ERROR-BARRED BLACK DIAMOND + return rune(0x29f1), true + case "diamond": + // DIAMOND OPERATOR + return rune(0x22c4), true + case "diamondsuit": + // BLACK DIAMOND SUIT + return rune(0x2666), true + case "diams": + // BLACK DIAMOND SUIT + return rune(0x2666), true + case "die": + // DIAERESIS + return rune(0xa8), true + case "digamma": + // GREEK SMALL LETTER DIGAMMA + return rune(0x03dd), true + case "disin": + // ELEMENT OF WITH LONG HORIZONTAL STROKE + return rune(0x22f2), true + case "divideontimes": + // DIVISION TIMES + return rune(0x22c7), true + case "divonx": + // DIVISION TIMES + return rune(0x22c7), true + case "div": + // DIVISION SIGN + return rune(0xf7), true + case "divide": + // DIVISION SIGN + return rune(0xf7), true + case "djcy": + // CYRILLIC SMALL LETTER DJE + return rune(0x0452), true + case "dlarr": + // SOUTH WEST ARROW + return rune(0x2199), true + case "dlcorn": + // BOTTOM LEFT CORNER + return rune(0x231e), true + case "dlcrop": + // BOTTOM LEFT CROP + return rune(0x230d), true + case "dlharb": + // DOWNWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2959), true + case "dollar": + // DOLLAR SIGN + return rune(0x24), true + case "dopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL D + return rune(0x01d555), true + case "doteq": + // APPROACHES THE LIMIT + return rune(0x2250), true + case "doteqdot": + // GEOMETRICALLY EQUAL TO + return rune(0x2251), true + case "dotminus": + // DOT MINUS + return rune(0x2238), true + case "dotplus": + // DOT PLUS + return rune(0x2214), true + case "dotsquare": + // SQUARED DOT OPERATOR + return rune(0x22a1), true + case "dot": + // DOT ABOVE + return rune(0x02d9), true + case "doublebarwedge": + // PERSPECTIVE + return rune(0x2306), true + case "downarrow": + // DOWNWARDS ARROW + return rune(0x2193), true + case "downdownarrows": + // DOWNWARDS PAIRED ARROWS + return rune(0x21ca), true + case "downharpoonleft": + // DOWNWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21c3), true + case "downharpoonright": + // DOWNWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21c2), true + case "drarr": + // SOUTH EAST ARROW + return rune(0x2198), true + case "drbkarow": + // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW + return rune(0x2910), true + case "drcorn": + // BOTTOM RIGHT CORNER + return rune(0x231f), true + case "drcrop": + // BOTTOM RIGHT CROP + return rune(0x230c), true + case "drharb": + // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2955), true + case "dscr": + // MATHEMATICAL SCRIPT SMALL D + return rune(0x01d4b9), true + case "dscy": + // CYRILLIC SMALL LETTER DZE + return rune(0x0455), true + case "dsol": + // SOLIDUS WITH OVERBAR + return rune(0x29f6), true + case "dstrok": + // LATIN SMALL LETTER D WITH STROKE + return rune(0x0111), true + case "dtdot": + // DOWN RIGHT DIAGONAL ELLIPSIS + return rune(0x22f1), true + case "dtrif": + // BLACK DOWN-POINTING SMALL TRIANGLE + return rune(0x25be), true + case "dtri": + // WHITE DOWN-POINTING SMALL TRIANGLE + return rune(0x25bf), true + case "dtrilf": + // DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK + return rune(0x29e8), true + case "dtrirf": + // DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK + return rune(0x29e9), true + case "duarr": + // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW + return rune(0x21f5), true + case "duhar": + // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x296f), true + case "dumap": + // DOUBLE-ENDED MULTIMAP + return rune(0x29df), true + case "dwangle": + // OBLIQUE ANGLE OPENING UP + return rune(0x29a6), true + case "dzcy": + // CYRILLIC SMALL LETTER DZHE + return rune(0x045f), true + case "dzigrarr": + // LONG RIGHTWARDS SQUIGGLE ARROW + return rune(0x27ff), true + } + + case 'e': + switch name { + case "eDDot": + // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW + return rune(0x2a77), true + case "eDot": + // GEOMETRICALLY EQUAL TO + return rune(0x2251), true + case "eacgr": + // GREEK SMALL LETTER EPSILON WITH TONOS + return rune(0x03ad), true + case "eacute": + // LATIN SMALL LETTER E WITH ACUTE + return rune(0xe9), true + case "easter": + // EQUALS WITH ASTERISK + return rune(0x2a6e), true + case "ecaron": + // LATIN SMALL LETTER E WITH CARON + return rune(0x011b), true + case "ecir": + // RING IN EQUAL TO + return rune(0x2256), true + case "ecirc": + // LATIN SMALL LETTER E WITH CIRCUMFLEX + return rune(0xea), true + case "ecolon": + // EQUALS COLON + return rune(0x2255), true + case "ecy": + // CYRILLIC SMALL LETTER E + return rune(0x044d), true + case "edot": + // LATIN SMALL LETTER E WITH DOT ABOVE + return rune(0x0117), true + case "ee": + // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true + case "eeacgr": + // GREEK SMALL LETTER ETA WITH TONOS + return rune(0x03ae), true + case "eegr": + // GREEK SMALL LETTER ETA + return rune(0x03b7), true + case "efDot": + // APPROXIMATELY EQUAL TO OR THE IMAGE OF + return rune(0x2252), true + case "efr": + // MATHEMATICAL FRAKTUR SMALL E + return rune(0x01d522), true + case "egr": + // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "egs": + // SLANTED EQUAL TO OR GREATER-THAN + return rune(0x2a96), true + case "egsdot": + // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE + return rune(0x2a98), true + case "eg": + // DOUBLE-LINE EQUAL TO OR GREATER-THAN + return rune(0x2a9a), true + case "egrave": + // LATIN SMALL LETTER E WITH GRAVE + return rune(0xe8), true + case "elinters": + // ELECTRICAL INTERSECTION + return rune(0x23e7), true + case "ell": + // SCRIPT SMALL L + return rune(0x2113), true + case "els": + // SLANTED EQUAL TO OR LESS-THAN + return rune(0x2a95), true + case "elsdot": + // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE + return rune(0x2a97), true + case "el": + // DOUBLE-LINE EQUAL TO OR LESS-THAN + return rune(0x2a99), true + case "emacr": + // LATIN SMALL LETTER E WITH MACRON + return rune(0x0113), true + case "empty": + // EMPTY SET + return rune(0x2205), true + case "emptyset": + // EMPTY SET + return rune(0x2205), true + case "emptyv": + // EMPTY SET + return rune(0x2205), true + case "emsp13": + // THREE-PER-EM SPACE + return rune(0x2004), true + case "emsp14": + // FOUR-PER-EM SPACE + return rune(0x2005), true + case "emsp": + // EM SPACE + return rune(0x2003), true + case "eng": + // LATIN SMALL LETTER ENG + return rune(0x014b), true + case "ensp": + // EN SPACE + return rune(0x2002), true + case "eogon": + // LATIN SMALL LETTER E WITH OGONEK + return rune(0x0119), true + case "eopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL E + return rune(0x01d556), true + case "epar": + // EQUAL AND PARALLEL TO + return rune(0x22d5), true + case "eparsl": + // EQUALS SIGN AND SLANTED PARALLEL + return rune(0x29e3), true + case "eplus": + // EQUALS SIGN ABOVE PLUS SIGN + return rune(0x2a71), true + case "epsilon": + // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "epsis": + // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "epsiv": + // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "epsi": + // GREEK SMALL LETTER EPSILON + return rune(0x03b5), true + case "eqcirc": + // RING IN EQUAL TO + return rune(0x2256), true + case "eqcolon": + // EQUALS COLON + return rune(0x2255), true + case "eqeq": + // TWO CONSECUTIVE EQUALS SIGNS + return rune(0x2a75), true + case "eqsim": + // MINUS TILDE + return rune(0x2242), true + case "eqslantgtr": + // SLANTED EQUAL TO OR GREATER-THAN + return rune(0x2a96), true + case "eqslantless": + // SLANTED EQUAL TO OR LESS-THAN + return rune(0x2a95), true + case "equals": + // EQUALS SIGN + return rune(0x3d), true + case "equest": + // QUESTIONED EQUAL TO + return rune(0x225f), true + case "equiv": + // IDENTICAL TO + return rune(0x2261), true + case "equivDD": + // EQUIVALENT WITH FOUR DOTS ABOVE + return rune(0x2a78), true + case "eqvparsl": + // IDENTICAL TO AND SLANTED PARALLEL + return rune(0x29e5), true + case "erDot": + // IMAGE OF OR APPROXIMATELY EQUAL TO + return rune(0x2253), true + case "erarr": + // EQUALS SIGN ABOVE RIGHTWARDS ARROW + return rune(0x2971), true + case "escr": + // SCRIPT SMALL E + return rune(0x212f), true + case "esdot": + // APPROACHES THE LIMIT + return rune(0x2250), true + case "esim": + // MINUS TILDE + return rune(0x2242), true + case "eta": + // GREEK SMALL LETTER ETA + return rune(0x03b7), true + case "eth": + // LATIN SMALL LETTER ETH + return rune(0xf0), true + case "euml": + // LATIN SMALL LETTER E WITH DIAERESIS + return rune(0xeb), true + case "euro": + // EURO SIGN + return rune(0x20ac), true + case "excl": + // EXCLAMATION MARK + return rune(0x21), true + case "exist": + // THERE EXISTS + return rune(0x2203), true + case "expectation": + // SCRIPT CAPITAL E + return rune(0x2130), true + case "exponentiale": + // DOUBLE-STRUCK ITALIC SMALL E + return rune(0x2147), true + } + + case 'f': + switch name { + case "fallingdotseq": + // APPROXIMATELY EQUAL TO OR THE IMAGE OF + return rune(0x2252), true + case "fbowtie": + // BLACK BOWTIE + return rune(0x29d3), true + case "fcy": + // CYRILLIC SMALL LETTER EF + return rune(0x0444), true + case "fdiag": + // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + return rune(0x2572), true + case "fdiordi": + // FALLING DIAGONAL CROSSING RISING DIAGONAL + return rune(0x292c), true + case "fdonearr": + // FALLING DIAGONAL CROSSING NORTH EAST ARROW + return rune(0x292f), true + case "female": + // FEMALE SIGN + return rune(0x2640), true + case "ffilig": + // LATIN SMALL LIGATURE FFI + return rune(0xfb03), true + case "fflig": + // LATIN SMALL LIGATURE FF + return rune(0xfb00), true + case "ffllig": + // LATIN SMALL LIGATURE FFL + return rune(0xfb04), true + case "ffr": + // MATHEMATICAL FRAKTUR SMALL F + return rune(0x01d523), true + case "fhrglass": + // BLACK HOURGLASS + return rune(0x29d7), true + case "filig": + // LATIN SMALL LIGATURE FI + return rune(0xfb01), true + case "fjlig": + // fj ligature + return rune(0x66), true + case "flat": + // MUSIC FLAT SIGN + return rune(0x266d), true + case "fllig": + // LATIN SMALL LIGATURE FL + return rune(0xfb02), true + case "fltns": + // WHITE PARALLELOGRAM + return rune(0x25b1), true + case "fnof": + // LATIN SMALL LETTER F WITH HOOK + return rune(0x0192), true + case "fopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL F + return rune(0x01d557), true + case "forall": + // FOR ALL + return rune(0x2200), true + case "fork": + // PITCHFORK + return rune(0x22d4), true + case "forkv": + // ELEMENT OF OPENING DOWNWARDS + return rune(0x2ad9), true + case "fpartint": + // FINITE PART INTEGRAL + return rune(0x2a0d), true + case "frac12": + // VULGAR FRACTION ONE HALF + return rune(0xbd), true + case "frac13": + // VULGAR FRACTION ONE THIRD + return rune(0x2153), true + case "frac14": + // VULGAR FRACTION ONE QUARTER + return rune(0xbc), true + case "frac15": + // VULGAR FRACTION ONE FIFTH + return rune(0x2155), true + case "frac16": + // VULGAR FRACTION ONE SIXTH + return rune(0x2159), true + case "frac18": + // VULGAR FRACTION ONE EIGHTH + return rune(0x215b), true + case "frac23": + // VULGAR FRACTION TWO THIRDS + return rune(0x2154), true + case "frac25": + // VULGAR FRACTION TWO FIFTHS + return rune(0x2156), true + case "frac34": + // VULGAR FRACTION THREE QUARTERS + return rune(0xbe), true + case "frac35": + // VULGAR FRACTION THREE FIFTHS + return rune(0x2157), true + case "frac38": + // VULGAR FRACTION THREE EIGHTHS + return rune(0x215c), true + case "frac45": + // VULGAR FRACTION FOUR FIFTHS + return rune(0x2158), true + case "frac56": + // VULGAR FRACTION FIVE SIXTHS + return rune(0x215a), true + case "frac58": + // VULGAR FRACTION FIVE EIGHTHS + return rune(0x215d), true + case "frac78": + // VULGAR FRACTION SEVEN EIGHTHS + return rune(0x215e), true + case "frasl": + // FRACTION SLASH + return rune(0x2044), true + case "frown": + // FROWN + return rune(0x2322), true + case "fscr": + // MATHEMATICAL SCRIPT SMALL F + return rune(0x01d4bb), true + } + + case 'g': + switch name { + case "gE": + // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "gEl": + // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + return rune(0x2a8c), true + case "gacute": + // LATIN SMALL LETTER G WITH ACUTE + return rune(0x01f5), true + case "gammad": + // GREEK SMALL LETTER DIGAMMA + return rune(0x03dd), true + case "gamma": + // GREEK SMALL LETTER GAMMA + return rune(0x03b3), true + case "gap": + // GREATER-THAN OR APPROXIMATE + return rune(0x2a86), true + case "gbreve": + // LATIN SMALL LETTER G WITH BREVE + return rune(0x011f), true + case "gcedil": + // LATIN SMALL LETTER G WITH CEDILLA + return rune(0x0123), true + case "gcirc": + // LATIN SMALL LETTER G WITH CIRCUMFLEX + return rune(0x011d), true + case "gcy": + // CYRILLIC SMALL LETTER GHE + return rune(0x0433), true + case "gdot": + // LATIN SMALL LETTER G WITH DOT ABOVE + return rune(0x0121), true + case "ge": + // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "gel": + // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "geq": + // GREATER-THAN OR EQUAL TO + return rune(0x2265), true + case "geqq": + // GREATER-THAN OVER EQUAL TO + return rune(0x2267), true + case "geqslant": + // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "gesl": + // GREATER-THAN slanted EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "ges": + // GREATER-THAN OR SLANTED EQUAL TO + return rune(0x2a7e), true + case "gescc": + // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + return rune(0x2aa9), true + case "gesdot": + // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + return rune(0x2a80), true + case "gesdoto": + // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + return rune(0x2a82), true + case "gesdotol": + // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT + return rune(0x2a84), true + case "gesles": + // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL + return rune(0x2a94), true + case "gfr": + // MATHEMATICAL FRAKTUR SMALL G + return rune(0x01d524), true + case "gg": + // MUCH GREATER-THAN + return rune(0x226b), true + case "ggg": + // VERY MUCH GREATER-THAN + return rune(0x22d9), true + case "ggr": + // GREEK SMALL LETTER GAMMA + return rune(0x03b3), true + case "gimel": + // GIMEL SYMBOL + return rune(0x2137), true + case "gjcy": + // CYRILLIC SMALL LETTER GJE + return rune(0x0453), true + case "gl": + // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "glE": + // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL + return rune(0x2a92), true + case "gla": + // GREATER-THAN BESIDE LESS-THAN + return rune(0x2aa5), true + case "glj": + // GREATER-THAN OVERLAPPING LESS-THAN + return rune(0x2aa4), true + case "gnE": + // GREATER-THAN BUT NOT EQUAL TO + return rune(0x2269), true + case "gnap": + // GREATER-THAN AND NOT APPROXIMATE + return rune(0x2a8a), true + case "gnapprox": + // GREATER-THAN AND NOT APPROXIMATE + return rune(0x2a8a), true + case "gneqq": + // GREATER-THAN BUT NOT EQUAL TO + return rune(0x2269), true + case "gne": + // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a88), true + case "gneq": + // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a88), true + case "gnsim": + // GREATER-THAN BUT NOT EQUIVALENT TO + return rune(0x22e7), true + case "gopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL G + return rune(0x01d558), true + case "grave": + // GRAVE ACCENT + return rune(0x60), true + case "gscr": + // SCRIPT SMALL G + return rune(0x210a), true + case "gsdot": + // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gsim": + // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "gsime": + // GREATER-THAN ABOVE SIMILAR OR EQUAL + return rune(0x2a8e), true + case "gsiml": + // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN + return rune(0x2a90), true + case "gtcc": + // GREATER-THAN CLOSED BY CURVE + return rune(0x2aa7), true + case "gtcir": + // GREATER-THAN WITH CIRCLE INSIDE + return rune(0x2a7a), true + case "gtdot": + // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gtlPar": + // DOUBLE LEFT ARC GREATER-THAN BRACKET + return rune(0x2995), true + case "gtquest": + // GREATER-THAN WITH QUESTION MARK ABOVE + return rune(0x2a7c), true + case "gtrapprox": + // GREATER-THAN OR APPROXIMATE + return rune(0x2a86), true + case "gtrarr": + // GREATER-THAN ABOVE RIGHTWARDS ARROW + return rune(0x2978), true + case "gtrdot": + // GREATER-THAN WITH DOT + return rune(0x22d7), true + case "gtreqless": + // GREATER-THAN EQUAL TO OR LESS-THAN + return rune(0x22db), true + case "gtreqqless": + // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + return rune(0x2a8c), true + case "gtrless": + // GREATER-THAN OR LESS-THAN + return rune(0x2277), true + case "gtrpar": + // SPHERICAL ANGLE OPENING LEFT + return rune(0x29a0), true + case "gtrsim": + // GREATER-THAN OR EQUIVALENT TO + return rune(0x2273), true + case "gt": + // GREATER-THAN SIGN + return rune(0x3e), true + case "gvertneqq": + // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2269), true + case "gvnE": + // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2269), true + } + + case 'h': + switch name { + case "hArr": + // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "hairsp": + // HAIR SPACE + return rune(0x200a), true + case "half": + // VULGAR FRACTION ONE HALF + return rune(0xbd), true + case "hamilt": + // SCRIPT CAPITAL H + return rune(0x210b), true + case "hardcy": + // CYRILLIC SMALL LETTER HARD SIGN + return rune(0x044a), true + case "harrw": + // LEFT RIGHT WAVE ARROW + return rune(0x21ad), true + case "harr": + // LEFT RIGHT ARROW + return rune(0x2194), true + case "harrcir": + // LEFT RIGHT ARROW THROUGH SMALL CIRCLE + return rune(0x2948), true + case "hbar": + // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "hcirc": + // LATIN SMALL LETTER H WITH CIRCUMFLEX + return rune(0x0125), true + case "hearts": + // BLACK HEART SUIT + return rune(0x2665), true + case "heartsuit": + // BLACK HEART SUIT + return rune(0x2665), true + case "hellip": + // HORIZONTAL ELLIPSIS + return rune(0x2026), true + case "hercon": + // HERMITIAN CONJUGATE MATRIX + return rune(0x22b9), true + case "hfr": + // MATHEMATICAL FRAKTUR SMALL H + return rune(0x01d525), true + case "hksearow": + // SOUTH EAST ARROW WITH HOOK + return rune(0x2925), true + case "hkswarow": + // SOUTH WEST ARROW WITH HOOK + return rune(0x2926), true + case "hoarr": + // LEFT RIGHT OPEN-HEADED ARROW + return rune(0x21ff), true + case "homtht": + // HOMOTHETIC + return rune(0x223b), true + case "hookleftarrow": + // LEFTWARDS ARROW WITH HOOK + return rune(0x21a9), true + case "hookrightarrow": + // RIGHTWARDS ARROW WITH HOOK + return rune(0x21aa), true + case "hopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL H + return rune(0x01d559), true + case "horbar": + // HORIZONTAL BAR + return rune(0x2015), true + case "hrglass": + // WHITE HOURGLASS + return rune(0x29d6), true + case "hscr": + // MATHEMATICAL SCRIPT SMALL H + return rune(0x01d4bd), true + case "hslash": + // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "hstrok": + // LATIN SMALL LETTER H WITH STROKE + return rune(0x0127), true + case "htimes": + // VECTOR OR CROSS PRODUCT + return rune(0x2a2f), true + case "hybull": + // HYPHEN BULLET + return rune(0x2043), true + case "hyphen": + // HYPHEN + return rune(0x2010), true + } + + case 'i': + switch name { + case "iacgr": + // GREEK SMALL LETTER IOTA WITH TONOS + return rune(0x03af), true + case "iacute": + // LATIN SMALL LETTER I WITH ACUTE + return rune(0xed), true + case "ic": + // INVISIBLE SEPARATOR + return rune(0x2063), true + case "icirc": + // LATIN SMALL LETTER I WITH CIRCUMFLEX + return rune(0xee), true + case "icy": + // CYRILLIC SMALL LETTER I + return rune(0x0438), true + case "idiagr": + // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + return rune(0x0390), true + case "idigr": + // GREEK SMALL LETTER IOTA WITH DIALYTIKA + return rune(0x03ca), true + case "iecy": + // CYRILLIC SMALL LETTER IE + return rune(0x0435), true + case "iexcl": + // INVERTED EXCLAMATION MARK + return rune(0xa1), true + case "iff": + // LEFT RIGHT DOUBLE ARROW + return rune(0x21d4), true + case "ifr": + // MATHEMATICAL FRAKTUR SMALL I + return rune(0x01d526), true + case "igr": + // GREEK SMALL LETTER IOTA + return rune(0x03b9), true + case "igrave": + // LATIN SMALL LETTER I WITH GRAVE + return rune(0xec), true + case "iiint": + // TRIPLE INTEGRAL + return rune(0x222d), true + case "ii": + // DOUBLE-STRUCK ITALIC SMALL I + return rune(0x2148), true + case "iiiint": + // QUADRUPLE INTEGRAL OPERATOR + return rune(0x2a0c), true + case "iinfin": + // INCOMPLETE INFINITY + return rune(0x29dc), true + case "iiota": + // TURNED GREEK SMALL LETTER IOTA + return rune(0x2129), true + case "ijlig": + // LATIN SMALL LIGATURE IJ + return rune(0x0133), true + case "imacr": + // LATIN SMALL LETTER I WITH MACRON + return rune(0x012b), true + case "image": + // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "imagline": + // SCRIPT CAPITAL I + return rune(0x2110), true + case "imagpart": + // BLACK-LETTER CAPITAL I + return rune(0x2111), true + case "imath": + // LATIN SMALL LETTER DOTLESS I + return rune(0x0131), true + case "imof": + // IMAGE OF + return rune(0x22b7), true + case "imped": + // LATIN CAPITAL LETTER Z WITH STROKE + return rune(0x01b5), true + case "in": + // ELEMENT OF + return rune(0x2208), true + case "incare": + // CARE OF + return rune(0x2105), true + case "infin": + // INFINITY + return rune(0x221e), true + case "infintie": + // TIE OVER INFINITY + return rune(0x29dd), true + case "inodot": + // LATIN SMALL LETTER DOTLESS I + return rune(0x0131), true + case "int": + // INTEGRAL + return rune(0x222b), true + case "intcal": + // INTERCALATE + return rune(0x22ba), true + case "integers": + // DOUBLE-STRUCK CAPITAL Z + return rune(0x2124), true + case "intercal": + // INTERCALATE + return rune(0x22ba), true + case "intlarhk": + // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK + return rune(0x2a17), true + case "intprod": + // INTERIOR PRODUCT + return rune(0x2a3c), true + case "iocy": + // CYRILLIC SMALL LETTER IO + return rune(0x0451), true + case "iogon": + // LATIN SMALL LETTER I WITH OGONEK + return rune(0x012f), true + case "iopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL I + return rune(0x01d55a), true + case "iota": + // GREEK SMALL LETTER IOTA + return rune(0x03b9), true + case "iprod": + // INTERIOR PRODUCT + return rune(0x2a3c), true + case "iprodr": + // RIGHTHAND INTERIOR PRODUCT + return rune(0x2a3d), true + case "iquest": + // INVERTED QUESTION MARK + return rune(0xbf), true + case "iscr": + // MATHEMATICAL SCRIPT SMALL I + return rune(0x01d4be), true + case "isin": + // ELEMENT OF + return rune(0x2208), true + case "isinE": + // ELEMENT OF WITH TWO HORIZONTAL STROKES + return rune(0x22f9), true + case "isindot": + // ELEMENT OF WITH DOT ABOVE + return rune(0x22f5), true + case "isinsv": + // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22f3), true + case "isins": + // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22f4), true + case "isinv": + // ELEMENT OF + return rune(0x2208), true + case "isinvb": + // ELEMENT OF WITH UNDERBAR + return rune(0x22f8), true + case "it": + // INVISIBLE TIMES + return rune(0x2062), true + case "itilde": + // LATIN SMALL LETTER I WITH TILDE + return rune(0x0129), true + case "iukcy": + // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + return rune(0x0456), true + case "iuml": + // LATIN SMALL LETTER I WITH DIAERESIS + return rune(0xef), true + } + + case 'j': + switch name { + case "jcirc": + // LATIN SMALL LETTER J WITH CIRCUMFLEX + return rune(0x0135), true + case "jcy": + // CYRILLIC SMALL LETTER SHORT I + return rune(0x0439), true + case "jfr": + // MATHEMATICAL FRAKTUR SMALL J + return rune(0x01d527), true + case "jmath": + // LATIN SMALL LETTER DOTLESS J + return rune(0x0237), true + case "jnodot": + // LATIN SMALL LETTER DOTLESS J + return rune(0x0237), true + case "jopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL J + return rune(0x01d55b), true + case "jscr": + // MATHEMATICAL SCRIPT SMALL J + return rune(0x01d4bf), true + case "jsercy": + // CYRILLIC SMALL LETTER JE + return rune(0x0458), true + case "jukcy": + // CYRILLIC SMALL LETTER UKRAINIAN IE + return rune(0x0454), true + } + + case 'k': + switch name { + case "kappav": + // GREEK KAPPA SYMBOL + return rune(0x03f0), true + case "kappa": + // GREEK SMALL LETTER KAPPA + return rune(0x03ba), true + case "kcedil": + // LATIN SMALL LETTER K WITH CEDILLA + return rune(0x0137), true + case "kcy": + // CYRILLIC SMALL LETTER KA + return rune(0x043a), true + case "kfr": + // MATHEMATICAL FRAKTUR SMALL K + return rune(0x01d528), true + case "kgr": + // GREEK SMALL LETTER KAPPA + return rune(0x03ba), true + case "kgreen": + // LATIN SMALL LETTER KRA + return rune(0x0138), true + case "khcy": + // CYRILLIC SMALL LETTER HA + return rune(0x0445), true + case "khgr": + // GREEK SMALL LETTER CHI + return rune(0x03c7), true + case "kjcy": + // CYRILLIC SMALL LETTER KJE + return rune(0x045c), true + case "kopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL K + return rune(0x01d55c), true + case "koppa": + // GREEK LETTER KOPPA + return rune(0x03de), true + case "kscr": + // MATHEMATICAL SCRIPT SMALL K + return rune(0x01d4c0), true + } + + case 'l': + switch name { + case "lAarr": + // LEFTWARDS TRIPLE ARROW + return rune(0x21da), true + case "lArr": + // LEFTWARDS DOUBLE ARROW + return rune(0x21d0), true + case "lAtail": + // LEFTWARDS DOUBLE ARROW-TAIL + return rune(0x291b), true + case "lBarr": + // LEFTWARDS TRIPLE DASH ARROW + return rune(0x290e), true + case "lE": + // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "lEg": + // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + return rune(0x2a8b), true + case "lHar": + // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN + return rune(0x2962), true + case "lacute": + // LATIN SMALL LETTER L WITH ACUTE + return rune(0x013a), true + case "laemptyv": + // EMPTY SET WITH LEFT ARROW ABOVE + return rune(0x29b4), true + case "lagran": + // SCRIPT CAPITAL L + return rune(0x2112), true + case "lambda": + // GREEK SMALL LETTER LAMDA + return rune(0x03bb), true + case "lang": + // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "langd": + // LEFT ANGLE BRACKET WITH DOT + return rune(0x2991), true + case "langle": + // MATHEMATICAL LEFT ANGLE BRACKET + return rune(0x27e8), true + case "lap": + // LESS-THAN OR APPROXIMATE + return rune(0x2a85), true + case "laquo": + // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + return rune(0xab), true + case "larr2": + // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "larrb": + // LEFTWARDS ARROW TO BAR + return rune(0x21e4), true + case "larrhk": + // LEFTWARDS ARROW WITH HOOK + return rune(0x21a9), true + case "larrlp": + // LEFTWARDS ARROW WITH LOOP + return rune(0x21ab), true + case "larrtl": + // LEFTWARDS ARROW WITH TAIL + return rune(0x21a2), true + case "larr": + // LEFTWARDS ARROW + return rune(0x2190), true + case "larrbfs": + // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND + return rune(0x291f), true + case "larrfs": + // LEFTWARDS ARROW TO BLACK DIAMOND + return rune(0x291d), true + case "larrpl": + // LEFT-SIDE ARC ANTICLOCKWISE ARROW + return rune(0x2939), true + case "larrsim": + // LEFTWARDS ARROW ABOVE TILDE OPERATOR + return rune(0x2973), true + case "latail": + // LEFTWARDS ARROW-TAIL + return rune(0x2919), true + case "lat": + // LARGER THAN + return rune(0x2aab), true + case "late": + // LARGER THAN OR EQUAL TO + return rune(0x2aad), true + case "lates": + // LARGER THAN OR slanted EQUAL + return rune(0x2aad), true + case "lbarr": + // LEFTWARDS DOUBLE DASH ARROW + return rune(0x290c), true + case "lbbrk": + // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT + return rune(0x2772), true + case "lbrace": + // LEFT CURLY BRACKET + return rune(0x7b), true + case "lbrack": + // LEFT SQUARE BRACKET + return rune(0x5b), true + case "lbrke": + // LEFT SQUARE BRACKET WITH UNDERBAR + return rune(0x298b), true + case "lbrksld": + // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + return rune(0x298f), true + case "lbrkslu": + // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER + return rune(0x298d), true + case "lcaron": + // LATIN SMALL LETTER L WITH CARON + return rune(0x013e), true + case "lcedil": + // LATIN SMALL LETTER L WITH CEDILLA + return rune(0x013c), true + case "lceil": + // LEFT CEILING + return rune(0x2308), true + case "lcub": + // LEFT CURLY BRACKET + return rune(0x7b), true + case "lcy": + // CYRILLIC SMALL LETTER EL + return rune(0x043b), true + case "ldca": + // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS + return rune(0x2936), true + case "ldharb": + // LEFTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2956), true + case "ldot": + // LESS-THAN WITH DOT + return rune(0x22d6), true + case "ldquor": + // DOUBLE LOW-9 QUOTATION MARK + return rune(0x201e), true + case "ldquo": + // LEFT DOUBLE QUOTATION MARK + return rune(0x201c), true + case "ldrdhar": + // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + return rune(0x2967), true + case "ldrdshar": + // LEFT BARB DOWN RIGHT BARB DOWN HARPOON + return rune(0x2950), true + case "ldrushar": + // LEFT BARB DOWN RIGHT BARB UP HARPOON + return rune(0x294b), true + case "ldsh": + // DOWNWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b2), true + case "leftarrowtail": + // LEFTWARDS ARROW WITH TAIL + return rune(0x21a2), true + case "leftarrow": + // LEFTWARDS ARROW + return rune(0x2190), true + case "leftharpoondown": + // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "leftharpoonup": + // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "leftleftarrows": + // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "leftrightarrows": + // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "leftrightarrow": + // LEFT RIGHT ARROW + return rune(0x2194), true + case "leftrightharpoons": + // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "leftrightsquigarrow": + // LEFT RIGHT WAVE ARROW + return rune(0x21ad), true + case "le": + // LESS-THAN OR EQUAL TO + return rune(0x2264), true + case "leftthreetimes": + // LEFT SEMIDIRECT PRODUCT + return rune(0x22cb), true + case "leg": + // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "leq": + // LESS-THAN OR EQUAL TO + return rune(0x2264), true + case "leqq": + // LESS-THAN OVER EQUAL TO + return rune(0x2266), true + case "leqslant": + // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "lesg": + // LESS-THAN slanted EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "lessdot": + // LESS-THAN WITH DOT + return rune(0x22d6), true + case "lesseqgtr": + // LESS-THAN EQUAL TO OR GREATER-THAN + return rune(0x22da), true + case "lessgtr": + // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "lesssim": + // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "les": + // LESS-THAN OR SLANTED EQUAL TO + return rune(0x2a7d), true + case "lescc": + // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL + return rune(0x2aa8), true + case "lesdot": + // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE + return rune(0x2a7f), true + case "lesdoto": + // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE + return rune(0x2a81), true + case "lesdotor": + // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT + return rune(0x2a83), true + case "lesges": + // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL + return rune(0x2a93), true + case "lessapprox": + // LESS-THAN OR APPROXIMATE + return rune(0x2a85), true + case "lesseqqgtr": + // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + return rune(0x2a8b), true + case "lfbowtie": + // BOWTIE WITH LEFT HALF BLACK + return rune(0x29d1), true + case "lfisht": + // LEFT FISH TAIL + return rune(0x297c), true + case "lfloor": + // LEFT FLOOR + return rune(0x230a), true + case "lfr": + // MATHEMATICAL FRAKTUR SMALL L + return rune(0x01d529), true + case "lftimes": + // TIMES WITH LEFT HALF BLACK + return rune(0x29d4), true + case "lg": + // LESS-THAN OR GREATER-THAN + return rune(0x2276), true + case "lgE": + // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL + return rune(0x2a91), true + case "lgr": + // GREEK SMALL LETTER LAMDA + return rune(0x03bb), true + case "lhard": + // LEFTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21bd), true + case "lharu": + // LEFTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21bc), true + case "lharul": + // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + return rune(0x296a), true + case "lhblk": + // LOWER HALF BLOCK + return rune(0x2584), true + case "ljcy": + // CYRILLIC SMALL LETTER LJE + return rune(0x0459), true + case "llarr": + // LEFTWARDS PAIRED ARROWS + return rune(0x21c7), true + case "ll": + // MUCH LESS-THAN + return rune(0x226a), true + case "llcorner": + // BOTTOM LEFT CORNER + return rune(0x231e), true + case "llhard": + // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + return rune(0x296b), true + case "lltrif": + // BLACK LOWER LEFT TRIANGLE + return rune(0x25e3), true + case "lltri": + // LOWER LEFT TRIANGLE + return rune(0x25fa), true + case "lmidot": + // LATIN SMALL LETTER L WITH MIDDLE DOT + return rune(0x0140), true + case "lmoust": + // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION + return rune(0x23b0), true + case "lmoustache": + // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION + return rune(0x23b0), true + case "lnE": + // LESS-THAN BUT NOT EQUAL TO + return rune(0x2268), true + case "lnap": + // LESS-THAN AND NOT APPROXIMATE + return rune(0x2a89), true + case "lnapprox": + // LESS-THAN AND NOT APPROXIMATE + return rune(0x2a89), true + case "lneqq": + // LESS-THAN BUT NOT EQUAL TO + return rune(0x2268), true + case "lne": + // LESS-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a87), true + case "lneq": + // LESS-THAN AND SINGLE-LINE NOT EQUAL TO + return rune(0x2a87), true + case "lnsim": + // LESS-THAN BUT NOT EQUIVALENT TO + return rune(0x22e6), true + case "loang": + // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET + return rune(0x27ec), true + case "loarr": + // LEFTWARDS OPEN-HEADED ARROW + return rune(0x21fd), true + case "lobrk": + // MATHEMATICAL LEFT WHITE SQUARE BRACKET + return rune(0x27e6), true + case "locub": + // LEFT WHITE CURLY BRACKET + return rune(0x2983), true + case "longleftarrow": + // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "longleftrightarrow": + // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "longmapsto": + // LONG RIGHTWARDS ARROW FROM BAR + return rune(0x27fc), true + case "longrightarrow": + // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "looparrowleft": + // LEFTWARDS ARROW WITH LOOP + return rune(0x21ab), true + case "looparrowright": + // RIGHTWARDS ARROW WITH LOOP + return rune(0x21ac), true + case "lopar": + // LEFT WHITE PARENTHESIS + return rune(0x2985), true + case "lopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL L + return rune(0x01d55d), true + case "loplus": + // PLUS SIGN IN LEFT HALF CIRCLE + return rune(0x2a2d), true + case "lotimes": + // MULTIPLICATION SIGN IN LEFT HALF CIRCLE + return rune(0x2a34), true + case "lowast": + // LOW ASTERISK + return rune(0x204e), true + case "lowbar": + // LOW LINE + return rune(0x5f), true + case "lowint": + // INTEGRAL WITH UNDERBAR + return rune(0x2a1c), true + case "loz": + // LOZENGE + return rune(0x25ca), true + case "lozenge": + // LOZENGE + return rune(0x25ca), true + case "lozf": + // BLACK LOZENGE + return rune(0x29eb), true + case "lpargt": + // SPHERICAL ANGLE OPENING LEFT + return rune(0x29a0), true + case "lparlt": + // LEFT ARC LESS-THAN BRACKET + return rune(0x2993), true + case "lpar": + // LEFT PARENTHESIS + return rune(0x28), true + case "lrarr2": + // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "lrarr": + // LEFTWARDS ARROW OVER RIGHTWARDS ARROW + return rune(0x21c6), true + case "lrcorner": + // BOTTOM RIGHT CORNER + return rune(0x231f), true + case "lrhar": + // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "lrhar2": + // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + return rune(0x21cb), true + case "lrhard": + // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + return rune(0x296d), true + case "lrm": + // LEFT-TO-RIGHT MARK + return rune(0x200e), true + case "lrtri": + // RIGHT TRIANGLE + return rune(0x22bf), true + case "lsaquo": + // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + return rune(0x2039), true + case "lscr": + // MATHEMATICAL SCRIPT SMALL L + return rune(0x01d4c1), true + case "lsh": + // UPWARDS ARROW WITH TIP LEFTWARDS + return rune(0x21b0), true + case "lsim": + // LESS-THAN OR EQUIVALENT TO + return rune(0x2272), true + case "lsime": + // LESS-THAN ABOVE SIMILAR OR EQUAL + return rune(0x2a8d), true + case "lsimg": + // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN + return rune(0x2a8f), true + case "lsqb": + // LEFT SQUARE BRACKET + return rune(0x5b), true + case "lsquor": + // SINGLE LOW-9 QUOTATION MARK + return rune(0x201a), true + case "lsquo": + // LEFT SINGLE QUOTATION MARK + return rune(0x2018), true + case "lstrok": + // LATIN SMALL LETTER L WITH STROKE + return rune(0x0142), true + case "ltcc": + // LESS-THAN CLOSED BY CURVE + return rune(0x2aa6), true + case "ltcir": + // LESS-THAN WITH CIRCLE INSIDE + return rune(0x2a79), true + case "ltdot": + // LESS-THAN WITH DOT + return rune(0x22d6), true + case "lthree": + // LEFT SEMIDIRECT PRODUCT + return rune(0x22cb), true + case "ltimes": + // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT + return rune(0x22c9), true + case "ltlarr": + // LESS-THAN ABOVE LEFTWARDS ARROW + return rune(0x2976), true + case "ltquest": + // LESS-THAN WITH QUESTION MARK ABOVE + return rune(0x2a7b), true + case "ltrPar": + // DOUBLE RIGHT ARC LESS-THAN BRACKET + return rune(0x2996), true + case "ltrie": + // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "ltrif": + // BLACK LEFT-POINTING SMALL TRIANGLE + return rune(0x25c2), true + case "ltri": + // WHITE LEFT-POINTING SMALL TRIANGLE + return rune(0x25c3), true + case "ltrivb": + // LEFT TRIANGLE BESIDE VERTICAL BAR + return rune(0x29cf), true + case "lt": + // LESS-THAN SIGN + return rune(0x3c), true + case "luharb": + // LEFTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2952), true + case "lurdshar": + // LEFT BARB UP RIGHT BARB DOWN HARPOON + return rune(0x294a), true + case "luruhar": + // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP + return rune(0x2966), true + case "lurushar": + // LEFT BARB UP RIGHT BARB UP HARPOON + return rune(0x294e), true + case "lvertneqq": + // LESS-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2268), true + case "lvnE": + // LESS-THAN BUT NOT EQUAL TO - with vertical stroke + return rune(0x2268), true + } + + case 'm': + switch name { + case "mDDot": + // GEOMETRIC PROPORTION + return rune(0x223a), true + case "macr": + // MACRON + return rune(0xaf), true + case "male": + // MALE SIGN + return rune(0x2642), true + case "malt": + // MALTESE CROSS + return rune(0x2720), true + case "maltese": + // MALTESE CROSS + return rune(0x2720), true + case "mapstodown": + // DOWNWARDS ARROW FROM BAR + return rune(0x21a7), true + case "mapsto": + // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "map": + // RIGHTWARDS ARROW FROM BAR + return rune(0x21a6), true + case "mapstoleft": + // LEFTWARDS ARROW FROM BAR + return rune(0x21a4), true + case "mapstoup": + // UPWARDS ARROW FROM BAR + return rune(0x21a5), true + case "marker": + // BLACK VERTICAL RECTANGLE + return rune(0x25ae), true + case "mcomma": + // MINUS SIGN WITH COMMA ABOVE + return rune(0x2a29), true + case "mcy": + // CYRILLIC SMALL LETTER EM + return rune(0x043c), true + case "mdash": + // EM DASH + return rune(0x2014), true + case "measuredangle": + // MEASURED ANGLE + return rune(0x2221), true + case "mfr": + // MATHEMATICAL FRAKTUR SMALL M + return rune(0x01d52a), true + case "mgr": + // GREEK SMALL LETTER MU + return rune(0x03bc), true + case "mho": + // INVERTED OHM SIGN + return rune(0x2127), true + case "micro": + // MICRO SIGN + return rune(0xb5), true + case "mid": + // DIVIDES + return rune(0x2223), true + case "midast": + // ASTERISK + return rune(0x2a), true + case "midcir": + // VERTICAL LINE WITH CIRCLE BELOW + return rune(0x2af0), true + case "middot": + // MIDDLE DOT + return rune(0xb7), true + case "minus": + // MINUS SIGN + return rune(0x2212), true + case "minusb": + // SQUARED MINUS + return rune(0x229f), true + case "minusd": + // DOT MINUS + return rune(0x2238), true + case "minusdu": + // MINUS SIGN WITH DOT BELOW + return rune(0x2a2a), true + case "mlcp": + // TRANSVERSAL INTERSECTION + return rune(0x2adb), true + case "mldr": + // HORIZONTAL ELLIPSIS + return rune(0x2026), true + case "mnplus": + // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "models": + // MODELS + return rune(0x22a7), true + case "mopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL M + return rune(0x01d55e), true + case "mp": + // MINUS-OR-PLUS SIGN + return rune(0x2213), true + case "mscr": + // MATHEMATICAL SCRIPT SMALL M + return rune(0x01d4c2), true + case "mstpos": + // INVERTED LAZY S + return rune(0x223e), true + case "multimap": + // MULTIMAP + return rune(0x22b8), true + case "mumap": + // MULTIMAP + return rune(0x22b8), true + case "mu": + // GREEK SMALL LETTER MU + return rune(0x03bc), true + } + + case 'n': + switch name { + case "nGg": + // VERY MUCH GREATER-THAN with slash + return rune(0x22d9), true + case "nGtv": + // MUCH GREATER THAN with slash + return rune(0x226b), true + case "nGt": + // MUCH GREATER THAN with vertical line + return rune(0x226b), true + case "nLeftarrow": + // LEFTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cd), true + case "nLeftrightarrow": + // LEFT RIGHT DOUBLE ARROW WITH STROKE + return rune(0x21ce), true + case "nLl": + // VERY MUCH LESS-THAN with slash + return rune(0x22d8), true + case "nLtv": + // MUCH LESS THAN with slash + return rune(0x226a), true + case "nLt": + // MUCH LESS THAN with vertical line + return rune(0x226a), true + case "nRightarrow": + // RIGHTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cf), true + case "nVDash": + // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + return rune(0x22af), true + case "nVdash": + // DOES NOT FORCE + return rune(0x22ae), true + case "nabla": + // NABLA + return rune(0x2207), true + case "nacute": + // LATIN SMALL LETTER N WITH ACUTE + return rune(0x0144), true + case "nang": + // ANGLE with vertical line + return rune(0x2220), true + case "nap": + // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "napE": + // APPROXIMATELY EQUAL OR EQUAL TO with slash + return rune(0x2a70), true + case "napid": + // TRIPLE TILDE with slash + return rune(0x224b), true + case "napos": + // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + return rune(0x0149), true + case "napprox": + // NOT ALMOST EQUAL TO + return rune(0x2249), true + case "naturals": + // DOUBLE-STRUCK CAPITAL N + return rune(0x2115), true + case "natur": + // MUSIC NATURAL SIGN + return rune(0x266e), true + case "natural": + // MUSIC NATURAL SIGN + return rune(0x266e), true + case "nbsp": + // NO-BREAK SPACE + return rune(0xa0), true + case "nbump": + // GEOMETRICALLY EQUIVALENT TO with slash + return rune(0x224e), true + case "nbumpe": + // DIFFERENCE BETWEEN with slash + return rune(0x224f), true + case "ncap": + // INTERSECTION WITH OVERBAR + return rune(0x2a43), true + case "ncaron": + // LATIN SMALL LETTER N WITH CARON + return rune(0x0148), true + case "ncedil": + // LATIN SMALL LETTER N WITH CEDILLA + return rune(0x0146), true + case "ncong": + // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO + return rune(0x2247), true + case "ncongdot": + // CONGRUENT WITH DOT ABOVE with slash + return rune(0x2a6d), true + case "ncup": + // UNION WITH OVERBAR + return rune(0x2a42), true + case "ncy": + // CYRILLIC SMALL LETTER EN + return rune(0x043d), true + case "ndash": + // EN DASH + return rune(0x2013), true + case "neArr": + // NORTH EAST DOUBLE ARROW + return rune(0x21d7), true + case "nearrow": + // NORTH EAST ARROW + return rune(0x2197), true + case "nearr": + // NORTH EAST ARROW + return rune(0x2197), true + case "nedot": + // APPROACHES THE LIMIT with slash + return rune(0x2250), true + case "nesim": + // MINUS TILDE with slash + return rune(0x2242), true + case "nexist": + // THERE DOES NOT EXIST + return rune(0x2204), true + case "nexists": + // THERE DOES NOT EXIST + return rune(0x2204), true + case "ne": + // NOT EQUAL TO + return rune(0x2260), true + case "nearhk": + // NORTH EAST ARROW WITH HOOK + return rune(0x2924), true + case "neonwarr": + // NORTH EAST ARROW CROSSING NORTH WEST ARROW + return rune(0x2931), true + case "neosearr": + // NORTH EAST ARROW CROSSING SOUTH EAST ARROW + return rune(0x292e), true + case "nequiv": + // NOT IDENTICAL TO + return rune(0x2262), true + case "nesear": + // NORTH EAST ARROW AND SOUTH EAST ARROW + return rune(0x2928), true + case "neswsarr": + // NORTH EAST AND SOUTH WEST ARROW + return rune(0x2922), true + case "nfr": + // MATHEMATICAL FRAKTUR SMALL N + return rune(0x01d52b), true + case "ngE": + // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "ngeqq": + // GREATER-THAN OVER EQUAL TO with slash + return rune(0x2267), true + case "nge": + // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "ngeq": + // NEITHER GREATER-THAN NOR EQUAL TO + return rune(0x2271), true + case "ngeqslant": + // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "nges": + // GREATER-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7e), true + case "ngr": + // GREEK SMALL LETTER NU + return rune(0x03bd), true + case "ngsim": + // NEITHER GREATER-THAN NOR EQUIVALENT TO + return rune(0x2275), true + case "ngt": + // NOT GREATER-THAN + return rune(0x226f), true + case "ngtr": + // NOT GREATER-THAN + return rune(0x226f), true + case "nhArr": + // LEFT RIGHT DOUBLE ARROW WITH STROKE + return rune(0x21ce), true + case "nharr": + // LEFT RIGHT ARROW WITH STROKE + return rune(0x21ae), true + case "nhpar": + // PARALLEL WITH HORIZONTAL STROKE + return rune(0x2af2), true + case "niv": + // CONTAINS AS MEMBER + return rune(0x220b), true + case "ni": + // CONTAINS AS MEMBER + return rune(0x220b), true + case "nisd": + // CONTAINS WITH LONG HORIZONTAL STROKE + return rune(0x22fa), true + case "nis": + // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22fc), true + case "njcy": + // CYRILLIC SMALL LETTER NJE + return rune(0x045a), true + case "nlArr": + // LEFTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cd), true + case "nlE": + // LESS-THAN OVER EQUAL TO with slash + return rune(0x2266), true + case "nlarr": + // LEFTWARDS ARROW WITH STROKE + return rune(0x219a), true + case "nldr": + // TWO DOT LEADER + return rune(0x2025), true + case "nleftarrow": + // LEFTWARDS ARROW WITH STROKE + return rune(0x219a), true + case "nleftrightarrow": + // LEFT RIGHT ARROW WITH STROKE + return rune(0x21ae), true + case "nleqq": + // LESS-THAN OVER EQUAL TO with slash + return rune(0x2266), true + case "nless": + // NOT LESS-THAN + return rune(0x226e), true + case "nle": + // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "nleq": + // NEITHER LESS-THAN NOR EQUAL TO + return rune(0x2270), true + case "nleqslant": + // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "nles": + // LESS-THAN OR SLANTED EQUAL TO with slash + return rune(0x2a7d), true + case "nlsim": + // NEITHER LESS-THAN NOR EQUIVALENT TO + return rune(0x2274), true + case "nlt": + // NOT LESS-THAN + return rune(0x226e), true + case "nltri": + // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "nltrie": + // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "nltrivb": + // LEFT TRIANGLE BESIDE VERTICAL BAR with slash + return rune(0x29cf), true + case "nmid": + // DOES NOT DIVIDE + return rune(0x2224), true + case "nopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL N + return rune(0x01d55f), true + case "notin": + // NOT AN ELEMENT OF + return rune(0x2209), true + case "notinE": + // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash + return rune(0x22f9), true + case "notindot": + // ELEMENT OF WITH DOT ABOVE with slash + return rune(0x22f5), true + case "notinva": + // NOT AN ELEMENT OF + return rune(0x2209), true + case "notinvb": + // SMALL ELEMENT OF WITH OVERBAR + return rune(0x22f7), true + case "notinvc": + // ELEMENT OF WITH OVERBAR + return rune(0x22f6), true + case "notni": + // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "notniva": + // DOES NOT CONTAIN AS MEMBER + return rune(0x220c), true + case "notnivb": + // SMALL CONTAINS WITH OVERBAR + return rune(0x22fe), true + case "notnivc": + // CONTAINS WITH OVERBAR + return rune(0x22fd), true + case "not": + // NOT SIGN + return rune(0xac), true + case "npart": + // PARTIAL DIFFERENTIAL with slash + return rune(0x2202), true + case "npar": + // NOT PARALLEL TO + return rune(0x2226), true + case "nparallel": + // NOT PARALLEL TO + return rune(0x2226), true + case "nparsl": + // DOUBLE SOLIDUS OPERATOR with reverse slash + return rune(0x2afd), true + case "npolint": + // LINE INTEGRATION NOT INCLUDING THE POLE + return rune(0x2a14), true + case "nprsim": + // PRECEDES OR EQUIVALENT TO with slash + return rune(0x227e), true + case "npr": + // DOES NOT PRECEDE + return rune(0x2280), true + case "nprcue": + // DOES NOT PRECEDE OR EQUAL + return rune(0x22e0), true + case "nprec": + // DOES NOT PRECEDE + return rune(0x2280), true + case "npre": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "npreceq": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2aaf), true + case "nrArr": + // RIGHTWARDS DOUBLE ARROW WITH STROKE + return rune(0x21cf), true + case "nrarrw": + // RIGHTWARDS WAVE ARROW with slash + return rune(0x219d), true + case "nrarr": + // RIGHTWARDS ARROW WITH STROKE + return rune(0x219b), true + case "nrarrc": + // WAVE ARROW POINTING DIRECTLY RIGHT with slash + return rune(0x2933), true + case "nrightarrow": + // RIGHTWARDS ARROW WITH STROKE + return rune(0x219b), true + case "nrtri": + // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "nrtrie": + // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "nsGt": + // DOUBLE NESTED GREATER-THAN with slash + return rune(0x2aa2), true + case "nsLt": + // DOUBLE NESTED LESS-THAN with slash + return rune(0x2aa1), true + case "nscsim": + // SUCCEEDS OR EQUIVALENT TO with slash + return rune(0x227f), true + case "nsc": + // DOES NOT SUCCEED + return rune(0x2281), true + case "nsccue": + // DOES NOT SUCCEED OR EQUAL + return rune(0x22e1), true + case "nsce": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "nscr": + // MATHEMATICAL SCRIPT SMALL N + return rune(0x01d4c3), true + case "nshortmid": + // DOES NOT DIVIDE + return rune(0x2224), true + case "nshortparallel": + // NOT PARALLEL TO + return rune(0x2226), true + case "nsim": + // NOT TILDE + return rune(0x2241), true + case "nsime": + // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "nsimeq": + // NOT ASYMPTOTICALLY EQUAL TO + return rune(0x2244), true + case "nsmid": + // DOES NOT DIVIDE + return rune(0x2224), true + case "nspar": + // NOT PARALLEL TO + return rune(0x2226), true + case "nsqsub": + // SQUARE IMAGE OF with slash + return rune(0x228f), true + case "nsqsube": + // NOT SQUARE IMAGE OF OR EQUAL TO + return rune(0x22e2), true + case "nsqsup": + // SQUARE ORIGINAL OF with slash + return rune(0x2290), true + case "nsqsupe": + // NOT SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x22e3), true + case "nsubset": + // SUBSET OF with vertical line + return rune(0x2282), true + case "nsub": + // NOT A SUBSET OF + return rune(0x2284), true + case "nsubE": + // SUBSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac5), true + case "nsube": + // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "nsubseteq": + // NEITHER A SUBSET OF NOR EQUAL TO + return rune(0x2288), true + case "nsubseteqq": + // SUBSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac5), true + case "nsucc": + // DOES NOT SUCCEED + return rune(0x2281), true + case "nsucceq": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + return rune(0x2ab0), true + case "nsupset": + // SUPERSET OF with vertical line + return rune(0x2283), true + case "nsup": + // NOT A SUPERSET OF + return rune(0x2285), true + case "nsupE": + // SUPERSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac6), true + case "nsupe": + // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "nsupseteq": + // NEITHER A SUPERSET OF NOR EQUAL TO + return rune(0x2289), true + case "nsupseteqq": + // SUPERSET OF ABOVE EQUALS SIGN with slash + return rune(0x2ac6), true + case "ntgl": + // NEITHER GREATER-THAN NOR LESS-THAN + return rune(0x2279), true + case "ntilde": + // LATIN SMALL LETTER N WITH TILDE + return rune(0xf1), true + case "ntlg": + // NEITHER LESS-THAN NOR GREATER-THAN + return rune(0x2278), true + case "ntriangleleft": + // NOT NORMAL SUBGROUP OF + return rune(0x22ea), true + case "ntrianglelefteq": + // NOT NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22ec), true + case "ntriangleright": + // DOES NOT CONTAIN AS NORMAL SUBGROUP + return rune(0x22eb), true + case "ntrianglerighteq": + // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + return rune(0x22ed), true + case "numero": + // NUMERO SIGN + return rune(0x2116), true + case "numsp": + // FIGURE SPACE + return rune(0x2007), true + case "nu": + // GREEK SMALL LETTER NU + return rune(0x03bd), true + case "num": + // NUMBER SIGN + return rune(0x23), true + case "nvDash": + // NOT TRUE + return rune(0x22ad), true + case "nvHarr": + // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2904), true + case "nvap": + // EQUIVALENT TO with vertical line + return rune(0x224d), true + case "nvbrtri": + // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash + return rune(0x29d0), true + case "nvdash": + // DOES NOT PROVE + return rune(0x22ac), true + case "nvge": + // GREATER-THAN OR EQUAL TO with vertical line + return rune(0x2265), true + case "nvgt": + // GREATER-THAN SIGN with vertical line + return rune(0x3e), true + case "nvinfin": + // INFINITY NEGATED WITH VERTICAL BAR + return rune(0x29de), true + case "nvlArr": + // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2902), true + case "nvle": + // LESS-THAN OR EQUAL TO with vertical line + return rune(0x2264), true + case "nvltrie": + // NORMAL SUBGROUP OF OR EQUAL TO with vertical line + return rune(0x22b4), true + case "nvlt": + // LESS-THAN SIGN with vertical line + return rune(0x3c), true + case "nvrArr": + // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE + return rune(0x2903), true + case "nvrtrie": + // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line + return rune(0x22b5), true + case "nvsim": + // TILDE OPERATOR with vertical line + return rune(0x223c), true + case "nwArr": + // NORTH WEST DOUBLE ARROW + return rune(0x21d6), true + case "nwarhk": + // NORTH WEST ARROW WITH HOOK + return rune(0x2923), true + case "nwarrow": + // NORTH WEST ARROW + return rune(0x2196), true + case "nwarr": + // NORTH WEST ARROW + return rune(0x2196), true + case "nwnear": + // NORTH WEST ARROW AND NORTH EAST ARROW + return rune(0x2927), true + case "nwonearr": + // NORTH WEST ARROW CROSSING NORTH EAST ARROW + return rune(0x2932), true + case "nwsesarr": + // NORTH WEST AND SOUTH EAST ARROW + return rune(0x2921), true + } + + case 'o': + switch name { + case "oS": + // CIRCLED LATIN CAPITAL LETTER S + return rune(0x24c8), true + case "oacgr": + // GREEK SMALL LETTER OMICRON WITH TONOS + return rune(0x03cc), true + case "oacute": + // LATIN SMALL LETTER O WITH ACUTE + return rune(0xf3), true + case "oast": + // CIRCLED ASTERISK OPERATOR + return rune(0x229b), true + case "obsol": + // CIRCLED REVERSE SOLIDUS + return rune(0x29b8), true + case "ocir": + // CIRCLED RING OPERATOR + return rune(0x229a), true + case "ocirc": + // LATIN SMALL LETTER O WITH CIRCUMFLEX + return rune(0xf4), true + case "ocy": + // CYRILLIC SMALL LETTER O + return rune(0x043e), true + case "odash": + // CIRCLED DASH + return rune(0x229d), true + case "odblac": + // LATIN SMALL LETTER O WITH DOUBLE ACUTE + return rune(0x0151), true + case "odiv": + // CIRCLED DIVISION SIGN + return rune(0x2a38), true + case "odot": + // CIRCLED DOT OPERATOR + return rune(0x2299), true + case "odsold": + // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN + return rune(0x29bc), true + case "oelig": + // LATIN SMALL LIGATURE OE + return rune(0x0153), true + case "ofcir": + // CIRCLED BULLET + return rune(0x29bf), true + case "ofr": + // MATHEMATICAL FRAKTUR SMALL O + return rune(0x01d52c), true + case "ogon": + // OGONEK + return rune(0x02db), true + case "ogr": + // GREEK SMALL LETTER OMICRON + return rune(0x03bf), true + case "ograve": + // LATIN SMALL LETTER O WITH GRAVE + return rune(0xf2), true + case "ogt": + // CIRCLED GREATER-THAN + return rune(0x29c1), true + case "ohacgr": + // GREEK SMALL LETTER OMEGA WITH TONOS + return rune(0x03ce), true + case "ohbar": + // CIRCLE WITH HORIZONTAL BAR + return rune(0x29b5), true + case "ohgr": + // GREEK SMALL LETTER OMEGA + return rune(0x03c9), true + case "ohm": + // GREEK CAPITAL LETTER OMEGA + return rune(0x03a9), true + case "oint": + // CONTOUR INTEGRAL + return rune(0x222e), true + case "olarr": + // ANTICLOCKWISE OPEN CIRCLE ARROW + return rune(0x21ba), true + case "olcir": + // CIRCLED WHITE BULLET + return rune(0x29be), true + case "olcross": + // CIRCLE WITH SUPERIMPOSED X + return rune(0x29bb), true + case "oline": + // OVERLINE + return rune(0x203e), true + case "olt": + // CIRCLED LESS-THAN + return rune(0x29c0), true + case "omacr": + // LATIN SMALL LETTER O WITH MACRON + return rune(0x014d), true + case "omega": + // GREEK SMALL LETTER OMEGA + return rune(0x03c9), true + case "omicron": + // GREEK SMALL LETTER OMICRON + return rune(0x03bf), true + case "omid": + // CIRCLED VERTICAL BAR + return rune(0x29b6), true + case "ominus": + // CIRCLED MINUS + return rune(0x2296), true + case "oopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL O + return rune(0x01d560), true + case "opar": + // CIRCLED PARALLEL + return rune(0x29b7), true + case "operp": + // CIRCLED PERPENDICULAR + return rune(0x29b9), true + case "opfgamma": + // DOUBLE-STRUCK SMALL GAMMA + return rune(0x213d), true + case "opfpi": + // DOUBLE-STRUCK CAPITAL PI + return rune(0x213f), true + case "opfsum": + // DOUBLE-STRUCK N-ARY SUMMATION + return rune(0x2140), true + case "oplus": + // CIRCLED PLUS + return rune(0x2295), true + case "orarr": + // CLOCKWISE OPEN CIRCLE ARROW + return rune(0x21bb), true + case "or": + // LOGICAL OR + return rune(0x2228), true + case "orderof": + // SCRIPT SMALL O + return rune(0x2134), true + case "order": + // SCRIPT SMALL O + return rune(0x2134), true + case "ord": + // LOGICAL OR WITH HORIZONTAL DASH + return rune(0x2a5d), true + case "ordf": + // FEMININE ORDINAL INDICATOR + return rune(0xaa), true + case "ordm": + // MASCULINE ORDINAL INDICATOR + return rune(0xba), true + case "origof": + // ORIGINAL OF + return rune(0x22b6), true + case "oror": + // TWO INTERSECTING LOGICAL OR + return rune(0x2a56), true + case "orslope": + // SLOPING LARGE OR + return rune(0x2a57), true + case "orv": + // LOGICAL OR WITH MIDDLE STEM + return rune(0x2a5b), true + case "oscr": + // SCRIPT SMALL O + return rune(0x2134), true + case "oslash": + // LATIN SMALL LETTER O WITH STROKE + return rune(0xf8), true + case "osol": + // CIRCLED DIVISION SLASH + return rune(0x2298), true + case "otilde": + // LATIN SMALL LETTER O WITH TILDE + return rune(0xf5), true + case "otimes": + // CIRCLED TIMES + return rune(0x2297), true + case "otimesas": + // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT + return rune(0x2a36), true + case "ouml": + // LATIN SMALL LETTER O WITH DIAERESIS + return rune(0xf6), true + case "ovbar": + // APL FUNCTIONAL SYMBOL CIRCLE STILE + return rune(0x233d), true + case "ovrbrk": + // TOP SQUARE BRACKET + return rune(0x23b4), true + case "ovrcub": + // TOP CURLY BRACKET + return rune(0x23de), true + case "ovrpar": + // TOP PARENTHESIS + return rune(0x23dc), true + case "oxuarr": + // UP ARROW THROUGH CIRCLE + return rune(0x29bd), true + } + + case 'p': + switch name { + case "part": + // PARTIAL DIFFERENTIAL + return rune(0x2202), true + case "par": + // PARALLEL TO + return rune(0x2225), true + case "parallel": + // PARALLEL TO + return rune(0x2225), true + case "para": + // PILCROW SIGN + return rune(0xb6), true + case "parsim": + // PARALLEL WITH TILDE OPERATOR + return rune(0x2af3), true + case "parsl": + // DOUBLE SOLIDUS OPERATOR + return rune(0x2afd), true + case "pcy": + // CYRILLIC SMALL LETTER PE + return rune(0x043f), true + case "percnt": + // PERCENT SIGN + return rune(0x25), true + case "period": + // FULL STOP + return rune(0x2e), true + case "permil": + // PER MILLE SIGN + return rune(0x2030), true + case "perp": + // UP TACK + return rune(0x22a5), true + case "pertenk": + // PER TEN THOUSAND SIGN + return rune(0x2031), true + case "pfr": + // MATHEMATICAL FRAKTUR SMALL P + return rune(0x01d52d), true + case "pgr": + // GREEK SMALL LETTER PI + return rune(0x03c0), true + case "phgr": + // GREEK SMALL LETTER PHI + return rune(0x03c6), true + case "phis": + // GREEK PHI SYMBOL + return rune(0x03d5), true + case "phiv": + // GREEK PHI SYMBOL + return rune(0x03d5), true + case "phi": + // GREEK SMALL LETTER PHI + return rune(0x03c6), true + case "phmmat": + // SCRIPT CAPITAL M + return rune(0x2133), true + case "phone": + // BLACK TELEPHONE + return rune(0x260e), true + case "pitchfork": + // PITCHFORK + return rune(0x22d4), true + case "piv": + // GREEK PI SYMBOL + return rune(0x03d6), true + case "pi": + // GREEK SMALL LETTER PI + return rune(0x03c0), true + case "planck": + // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "planckh": + // PLANCK CONSTANT + return rune(0x210e), true + case "plankv": + // PLANCK CONSTANT OVER TWO PI + return rune(0x210f), true + case "plusacir": + // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE + return rune(0x2a23), true + case "plusb": + // SQUARED PLUS + return rune(0x229e), true + case "pluscir": + // PLUS SIGN WITH SMALL CIRCLE ABOVE + return rune(0x2a22), true + case "plusdo": + // DOT PLUS + return rune(0x2214), true + case "plusdu": + // PLUS SIGN WITH DOT BELOW + return rune(0x2a25), true + case "pluse": + // PLUS SIGN ABOVE EQUALS SIGN + return rune(0x2a72), true + case "plusmn": + // PLUS-MINUS SIGN + return rune(0xb1), true + case "plussim": + // PLUS SIGN WITH TILDE BELOW + return rune(0x2a26), true + case "plustrif": + // PLUS SIGN WITH BLACK TRIANGLE + return rune(0x2a28), true + case "plustwo": + // PLUS SIGN WITH SUBSCRIPT TWO + return rune(0x2a27), true + case "plus": + // PLUS SIGN + return rune(0x2b), true + case "pm": + // PLUS-MINUS SIGN + return rune(0xb1), true + case "pointint": + // INTEGRAL AROUND A POINT OPERATOR + return rune(0x2a15), true + case "popf": + // MATHEMATICAL DOUBLE-STRUCK SMALL P + return rune(0x01d561), true + case "pound": + // POUND SIGN + return rune(0xa3), true + case "prod": + // N-ARY PRODUCT + return rune(0x220f), true + case "prop": + // PROPORTIONAL TO + return rune(0x221d), true + case "propto": + // PROPORTIONAL TO + return rune(0x221d), true + case "pr": + // PRECEDES + return rune(0x227a), true + case "prE": + // PRECEDES ABOVE EQUALS SIGN + return rune(0x2ab3), true + case "prap": + // PRECEDES ABOVE ALMOST EQUAL TO + return rune(0x2ab7), true + case "prcue": + // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "prec": + // PRECEDES + return rune(0x227a), true + case "preccurlyeq": + // PRECEDES OR EQUAL TO + return rune(0x227c), true + case "precnsim": + // PRECEDES BUT NOT EQUIVALENT TO + return rune(0x22e8), true + case "precsim": + // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "pre": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "precapprox": + // PRECEDES ABOVE ALMOST EQUAL TO + return rune(0x2ab7), true + case "preceq": + // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2aaf), true + case "precnapprox": + // PRECEDES ABOVE NOT ALMOST EQUAL TO + return rune(0x2ab9), true + case "precneqq": + // PRECEDES ABOVE NOT EQUAL TO + return rune(0x2ab5), true + case "primes": + // DOUBLE-STRUCK CAPITAL P + return rune(0x2119), true + case "prime": + // PRIME + return rune(0x2032), true + case "prnE": + // PRECEDES ABOVE NOT EQUAL TO + return rune(0x2ab5), true + case "prnap": + // PRECEDES ABOVE NOT ALMOST EQUAL TO + return rune(0x2ab9), true + case "prnsim": + // PRECEDES BUT NOT EQUIVALENT TO + return rune(0x22e8), true + case "profalar": + // ALL AROUND-PROFILE + return rune(0x232e), true + case "profline": + // ARC + return rune(0x2312), true + case "profsurf": + // SEGMENT + return rune(0x2313), true + case "prsim": + // PRECEDES OR EQUIVALENT TO + return rune(0x227e), true + case "prurel": + // PRECEDES UNDER RELATION + return rune(0x22b0), true + case "pscr": + // MATHEMATICAL SCRIPT SMALL P + return rune(0x01d4c5), true + case "psgr": + // GREEK SMALL LETTER PSI + return rune(0x03c8), true + case "psi": + // GREEK SMALL LETTER PSI + return rune(0x03c8), true + case "puncsp": + // PUNCTUATION SPACE + return rune(0x2008), true + } + + case 'q': + switch name { + case "qfr": + // MATHEMATICAL FRAKTUR SMALL Q + return rune(0x01d52e), true + case "qint": + // QUADRUPLE INTEGRAL OPERATOR + return rune(0x2a0c), true + case "qopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL Q + return rune(0x01d562), true + case "qprime": + // QUADRUPLE PRIME + return rune(0x2057), true + case "qscr": + // MATHEMATICAL SCRIPT SMALL Q + return rune(0x01d4c6), true + case "quaternions": + // DOUBLE-STRUCK CAPITAL H + return rune(0x210d), true + case "quatint": + // QUATERNION INTEGRAL OPERATOR + return rune(0x2a16), true + case "questeq": + // QUESTIONED EQUAL TO + return rune(0x225f), true + case "quest": + // QUESTION MARK + return rune(0x3f), true + case "quot": + // QUOTATION MARK + return rune(0x22), true + } + + case 'r': + switch name { + case "rAarr": + // RIGHTWARDS TRIPLE ARROW + return rune(0x21db), true + case "rArr": + // RIGHTWARDS DOUBLE ARROW + return rune(0x21d2), true + case "rAtail": + // RIGHTWARDS DOUBLE ARROW-TAIL + return rune(0x291c), true + case "rBarr": + // RIGHTWARDS TRIPLE DASH ARROW + return rune(0x290f), true + case "rHar": + // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + return rune(0x2964), true + case "race": + // REVERSED TILDE with underline + return rune(0x223d), true + case "racute": + // LATIN SMALL LETTER R WITH ACUTE + return rune(0x0155), true + case "radic": + // SQUARE ROOT + return rune(0x221a), true + case "raemptyv": + // EMPTY SET WITH RIGHT ARROW ABOVE + return rune(0x29b3), true + case "rang": + // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "rangd": + // RIGHT ANGLE BRACKET WITH DOT + return rune(0x2992), true + case "range": + // REVERSED ANGLE WITH UNDERBAR + return rune(0x29a5), true + case "rangle": + // MATHEMATICAL RIGHT ANGLE BRACKET + return rune(0x27e9), true + case "raquo": + // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + return rune(0xbb), true + case "rarr2": + // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rarr3": + // THREE RIGHTWARDS ARROWS + return rune(0x21f6), true + case "rarrb": + // RIGHTWARDS ARROW TO BAR + return rune(0x21e5), true + case "rarrhk": + // RIGHTWARDS ARROW WITH HOOK + return rune(0x21aa), true + case "rarrlp": + // RIGHTWARDS ARROW WITH LOOP + return rune(0x21ac), true + case "rarrtl": + // RIGHTWARDS ARROW WITH TAIL + return rune(0x21a3), true + case "rarrw": + // RIGHTWARDS WAVE ARROW + return rune(0x219d), true + case "rarr": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "rarrap": + // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO + return rune(0x2975), true + case "rarrbfs": + // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND + return rune(0x2920), true + case "rarrc": + // WAVE ARROW POINTING DIRECTLY RIGHT + return rune(0x2933), true + case "rarrfs": + // RIGHTWARDS ARROW TO BLACK DIAMOND + return rune(0x291e), true + case "rarrpl": + // RIGHTWARDS ARROW WITH PLUS BELOW + return rune(0x2945), true + case "rarrsim": + // RIGHTWARDS ARROW ABOVE TILDE OPERATOR + return rune(0x2974), true + case "rarrx": + // RIGHTWARDS ARROW THROUGH X + return rune(0x2947), true + case "ratail": + // RIGHTWARDS ARROW-TAIL + return rune(0x291a), true + case "ratio": + // RATIO + return rune(0x2236), true + case "rationals": + // DOUBLE-STRUCK CAPITAL Q + return rune(0x211a), true + case "rbarr": + // RIGHTWARDS DOUBLE DASH ARROW + return rune(0x290d), true + case "rbbrk": + // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT + return rune(0x2773), true + case "rbrace": + // RIGHT CURLY BRACKET + return rune(0x7d), true + case "rbrack": + // RIGHT SQUARE BRACKET + return rune(0x5d), true + case "rbrke": + // RIGHT SQUARE BRACKET WITH UNDERBAR + return rune(0x298c), true + case "rbrksld": + // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER + return rune(0x298e), true + case "rbrkslu": + // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER + return rune(0x2990), true + case "rcaron": + // LATIN SMALL LETTER R WITH CARON + return rune(0x0159), true + case "rcedil": + // LATIN SMALL LETTER R WITH CEDILLA + return rune(0x0157), true + case "rceil": + // RIGHT CEILING + return rune(0x2309), true + case "rcub": + // RIGHT CURLY BRACKET + return rune(0x7d), true + case "rcy": + // CYRILLIC SMALL LETTER ER + return rune(0x0440), true + case "rdca": + // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS + return rune(0x2937), true + case "rdharb": + // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR + return rune(0x2957), true + case "rdiag": + // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + return rune(0x2571), true + case "rdiofdi": + // RISING DIAGONAL CROSSING FALLING DIAGONAL + return rune(0x292b), true + case "rdldhar": + // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN + return rune(0x2969), true + case "rdosearr": + // RISING DIAGONAL CROSSING SOUTH EAST ARROW + return rune(0x2930), true + case "rdquor": + // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "rdquo": + // RIGHT DOUBLE QUOTATION MARK + return rune(0x201d), true + case "rdsh": + // DOWNWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b3), true + case "realpart": + // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "reals": + // DOUBLE-STRUCK CAPITAL R + return rune(0x211d), true + case "real": + // BLACK-LETTER CAPITAL R + return rune(0x211c), true + case "realine": + // SCRIPT CAPITAL R + return rune(0x211b), true + case "rect": + // WHITE RECTANGLE + return rune(0x25ad), true + case "reg": + // REGISTERED SIGN + return rune(0xae), true + case "rfbowtie": + // BOWTIE WITH RIGHT HALF BLACK + return rune(0x29d2), true + case "rfisht": + // RIGHT FISH TAIL + return rune(0x297d), true + case "rfloor": + // RIGHT FLOOR + return rune(0x230b), true + case "rfr": + // MATHEMATICAL FRAKTUR SMALL R + return rune(0x01d52f), true + case "rftimes": + // TIMES WITH RIGHT HALF BLACK + return rune(0x29d5), true + case "rgr": + // GREEK SMALL LETTER RHO + return rune(0x03c1), true + case "rhard": + // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "rharu": + // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "rharul": + // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + return rune(0x296c), true + case "rhov": + // GREEK RHO SYMBOL + return rune(0x03f1), true + case "rho": + // GREEK SMALL LETTER RHO + return rune(0x03c1), true + case "rightarrowtail": + // RIGHTWARDS ARROW WITH TAIL + return rune(0x21a3), true + case "rightarrow": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "rightharpoondown": + // RIGHTWARDS HARPOON WITH BARB DOWNWARDS + return rune(0x21c1), true + case "rightharpoonup": + // RIGHTWARDS HARPOON WITH BARB UPWARDS + return rune(0x21c0), true + case "rightleftarrows": + // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rightleftharpoons": + // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rightrightarrows": + // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rightsquigarrow": + // RIGHTWARDS WAVE ARROW + return rune(0x219d), true + case "rightthreetimes": + // RIGHT SEMIDIRECT PRODUCT + return rune(0x22cc), true + case "rimply": + // RIGHT DOUBLE ARROW WITH ROUNDED HEAD + return rune(0x2970), true + case "ring": + // RING ABOVE + return rune(0x02da), true + case "risingdotseq": + // IMAGE OF OR APPROXIMATELY EQUAL TO + return rune(0x2253), true + case "rlarr2": + // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rlarr": + // RIGHTWARDS ARROW OVER LEFTWARDS ARROW + return rune(0x21c4), true + case "rlhar": + // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rlhar2": + // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + return rune(0x21cc), true + case "rlm": + // RIGHT-TO-LEFT MARK + return rune(0x200f), true + case "rmoust": + // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION + return rune(0x23b1), true + case "rmoustache": + // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION + return rune(0x23b1), true + case "rnmid": + // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH + return rune(0x2aee), true + case "roang": + // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET + return rune(0x27ed), true + case "roarr": + // RIGHTWARDS OPEN-HEADED ARROW + return rune(0x21fe), true + case "robrk": + // MATHEMATICAL RIGHT WHITE SQUARE BRACKET + return rune(0x27e7), true + case "rocub": + // RIGHT WHITE CURLY BRACKET + return rune(0x2984), true + case "ropar": + // RIGHT WHITE PARENTHESIS + return rune(0x2986), true + case "ropf": + // MATHEMATICAL DOUBLE-STRUCK SMALL R + return rune(0x01d563), true + case "roplus": + // PLUS SIGN IN RIGHT HALF CIRCLE + return rune(0x2a2e), true + case "rotimes": + // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE + return rune(0x2a35), true + case "rpargt": + // RIGHT ARC GREATER-THAN BRACKET + return rune(0x2994), true + case "rpar": + // RIGHT PARENTHESIS + return rune(0x29), true + case "rppolint": + // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE + return rune(0x2a12), true + case "rrarr": + // RIGHTWARDS PAIRED ARROWS + return rune(0x21c9), true + case "rsaquo": + // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + return rune(0x203a), true + case "rscr": + // MATHEMATICAL SCRIPT SMALL R + return rune(0x01d4c7), true + case "rsh": + // UPWARDS ARROW WITH TIP RIGHTWARDS + return rune(0x21b1), true + case "rsolbar": + // REVERSE SOLIDUS WITH HORIZONTAL STROKE + return rune(0x29f7), true + case "rsqb": + // RIGHT SQUARE BRACKET + return rune(0x5d), true + case "rsquor": + // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "rsquo": + // RIGHT SINGLE QUOTATION MARK + return rune(0x2019), true + case "rthree": + // RIGHT SEMIDIRECT PRODUCT + return rune(0x22cc), true + case "rtimes": + // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT + return rune(0x22ca), true + case "rtrie": + // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "rtrif": + // BLACK RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b8), true + case "rtri": + // WHITE RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b9), true + case "rtriltri": + // RIGHT TRIANGLE ABOVE LEFT TRIANGLE + return rune(0x29ce), true + case "ruharb": + // RIGHTWARDS HARPOON WITH BARB UP TO BAR + return rune(0x2953), true + case "ruluhar": + // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP + return rune(0x2968), true + case "rx": + // PRESCRIPTION TAKE + return rune(0x211e), true + } + + case 's': + switch name { + case "sacute": + // LATIN SMALL LETTER S WITH ACUTE + return rune(0x015b), true + case "samalg": + // N-ARY COPRODUCT + return rune(0x2210), true + case "sampi": + // GREEK LETTER SAMPI + return rune(0x03e0), true + case "sbquo": + // SINGLE LOW-9 QUOTATION MARK + return rune(0x201a), true + case "sbsol": + // SMALL REVERSE SOLIDUS + return rune(0xfe68), true + case "sc": + // SUCCEEDS + return rune(0x227b), true + case "scE": + // SUCCEEDS ABOVE EQUALS SIGN + return rune(0x2ab4), true + case "scap": + // SUCCEEDS ABOVE ALMOST EQUAL TO + return rune(0x2ab8), true + case "scaron": + // LATIN SMALL LETTER S WITH CARON + return rune(0x0161), true + case "sccue": + // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "scedil": + // LATIN SMALL LETTER S WITH CEDILLA + return rune(0x015f), true + case "sce": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "scirc": + // LATIN SMALL LETTER S WITH CIRCUMFLEX + return rune(0x015d), true + case "scnE": + // SUCCEEDS ABOVE NOT EQUAL TO + return rune(0x2ab6), true + case "scnap": + // SUCCEEDS ABOVE NOT ALMOST EQUAL TO + return rune(0x2aba), true + case "scnsim": + // SUCCEEDS BUT NOT EQUIVALENT TO + return rune(0x22e9), true + case "scpolint": + // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE + return rune(0x2a13), true + case "scsim": + // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "scy": + // CYRILLIC SMALL LETTER ES + return rune(0x0441), true + case "sdotb": + // SQUARED DOT OPERATOR + return rune(0x22a1), true + case "sdot": + // DOT OPERATOR + return rune(0x22c5), true + case "sdote": + // EQUALS SIGN WITH DOT BELOW + return rune(0x2a66), true + case "seArr": + // SOUTH EAST DOUBLE ARROW + return rune(0x21d8), true + case "searhk": + // SOUTH EAST ARROW WITH HOOK + return rune(0x2925), true + case "searrow": + // SOUTH EAST ARROW + return rune(0x2198), true + case "searr": + // SOUTH EAST ARROW + return rune(0x2198), true + case "sect": + // SECTION SIGN + return rune(0xa7), true + case "semi": + // SEMICOLON + return rune(0x3b), true + case "seonearr": + // SOUTH EAST ARROW CROSSING NORTH EAST ARROW + return rune(0x292d), true + case "seswar": + // SOUTH EAST ARROW AND SOUTH WEST ARROW + return rune(0x2929), true + case "setminus": + // SET MINUS + return rune(0x2216), true + case "setmn": + // SET MINUS + return rune(0x2216), true + case "sext": + // SIX POINTED BLACK STAR + return rune(0x2736), true + case "sfgr": + // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sfrown": + // FROWN + return rune(0x2322), true + case "sfr": + // MATHEMATICAL FRAKTUR SMALL S + return rune(0x01d530), true + case "sgr": + // GREEK SMALL LETTER SIGMA + return rune(0x03c3), true + case "sharp": + // MUSIC SHARP SIGN + return rune(0x266f), true + case "shchcy": + // CYRILLIC SMALL LETTER SHCHA + return rune(0x0449), true + case "shcy": + // CYRILLIC SMALL LETTER SHA + return rune(0x0448), true + case "shortmid": + // DIVIDES + return rune(0x2223), true + case "shortparallel": + // PARALLEL TO + return rune(0x2225), true + case "shuffle": + // SHUFFLE PRODUCT + return rune(0x29e2), true + case "shy": + // SOFT HYPHEN + return rune(0xad), true + case "sigma": + // GREEK SMALL LETTER SIGMA + return rune(0x03c3), true + case "sigmaf": + // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sigmav": + // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "sim": + // TILDE OPERATOR + return rune(0x223c), true + case "simdot": + // TILDE OPERATOR WITH DOT ABOVE + return rune(0x2a6a), true + case "sime": + // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "simeq": + // ASYMPTOTICALLY EQUAL TO + return rune(0x2243), true + case "simg": + // SIMILAR OR GREATER-THAN + return rune(0x2a9e), true + case "simgE": + // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN + return rune(0x2aa0), true + case "siml": + // SIMILAR OR LESS-THAN + return rune(0x2a9d), true + case "simlE": + // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN + return rune(0x2a9f), true + case "simne": + // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO + return rune(0x2246), true + case "simplus": + // PLUS SIGN WITH TILDE ABOVE + return rune(0x2a24), true + case "simrarr": + // TILDE OPERATOR ABOVE RIGHTWARDS ARROW + return rune(0x2972), true + case "slarr": + // LEFTWARDS ARROW + return rune(0x2190), true + case "slint": + // INTEGRAL AVERAGE WITH SLASH + return rune(0x2a0f), true + case "smallsetminus": + // SET MINUS + return rune(0x2216), true + case "smashp": + // SMASH PRODUCT + return rune(0x2a33), true + case "smeparsl": + // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE + return rune(0x29e4), true + case "smid": + // DIVIDES + return rune(0x2223), true + case "smile": + // SMILE + return rune(0x2323), true + case "smt": + // SMALLER THAN + return rune(0x2aaa), true + case "smte": + // SMALLER THAN OR EQUAL TO + return rune(0x2aac), true + case "smtes": + // SMALLER THAN OR slanted EQUAL + return rune(0x2aac), true + case "softcy": + // CYRILLIC SMALL LETTER SOFT SIGN + return rune(0x044c), true + case "solbar": + // APL FUNCTIONAL SYMBOL SLASH BAR + return rune(0x233f), true + case "solb": + // SQUARED RISING DIAGONAL SLASH + return rune(0x29c4), true + case "sol": + // SOLIDUS + return rune(0x2f), true + case "sopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL S + return rune(0x01d564), true + case "spades": + // BLACK SPADE SUIT + return rune(0x2660), true + case "spadesuit": + // BLACK SPADE SUIT + return rune(0x2660), true + case "spar": + // PARALLEL TO + return rune(0x2225), true + case "sqcap": + // SQUARE CAP + return rune(0x2293), true + case "sqcaps": + // SQUARE CAP with serifs + return rune(0x2293), true + case "sqcup": + // SQUARE CUP + return rune(0x2294), true + case "sqcups": + // SQUARE CUP with serifs + return rune(0x2294), true + case "sqsub": + // SQUARE IMAGE OF + return rune(0x228f), true + case "sqsube": + // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "sqsubset": + // SQUARE IMAGE OF + return rune(0x228f), true + case "sqsubseteq": + // SQUARE IMAGE OF OR EQUAL TO + return rune(0x2291), true + case "sqsup": + // SQUARE ORIGINAL OF + return rune(0x2290), true + case "sqsupe": + // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "sqsupset": + // SQUARE ORIGINAL OF + return rune(0x2290), true + case "sqsupseteq": + // SQUARE ORIGINAL OF OR EQUAL TO + return rune(0x2292), true + case "squ": + // WHITE SQUARE + return rune(0x25a1), true + case "square": + // WHITE SQUARE + return rune(0x25a1), true + case "squarf": + // BLACK SMALL SQUARE + return rune(0x25aa), true + case "squb": + // SQUARED SQUARE + return rune(0x29c8), true + case "squerr": + // ERROR-BARRED WHITE SQUARE + return rune(0x29ee), true + case "squf": + // BLACK SMALL SQUARE + return rune(0x25aa), true + case "squferr": + // ERROR-BARRED BLACK SQUARE + return rune(0x29ef), true + case "srarr": + // RIGHTWARDS ARROW + return rune(0x2192), true + case "sscr": + // MATHEMATICAL SCRIPT SMALL S + return rune(0x01d4c8), true + case "ssetmn": + // SET MINUS + return rune(0x2216), true + case "ssmile": + // SMILE + return rune(0x2323), true + case "sstarf": + // STAR OPERATOR + return rune(0x22c6), true + case "starf": + // BLACK STAR + return rune(0x2605), true + case "star": + // WHITE STAR + return rune(0x2606), true + case "stigma": + // GREEK LETTER STIGMA + return rune(0x03da), true + case "straightepsilon": + // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "straightphi": + // GREEK PHI SYMBOL + return rune(0x03d5), true + case "strns": + // MACRON + return rune(0xaf), true + case "sub": + // SUBSET OF + return rune(0x2282), true + case "subE": + // SUBSET OF ABOVE EQUALS SIGN + return rune(0x2ac5), true + case "subdot": + // SUBSET WITH DOT + return rune(0x2abd), true + case "sube": + // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "subedot": + // SUBSET OF OR EQUAL TO WITH DOT ABOVE + return rune(0x2ac3), true + case "submult": + // SUBSET WITH MULTIPLICATION SIGN BELOW + return rune(0x2ac1), true + case "subnE": + // SUBSET OF ABOVE NOT EQUAL TO + return rune(0x2acb), true + case "subne": + // SUBSET OF WITH NOT EQUAL TO + return rune(0x228a), true + case "subplus": + // SUBSET WITH PLUS SIGN BELOW + return rune(0x2abf), true + case "subrarr": + // SUBSET ABOVE RIGHTWARDS ARROW + return rune(0x2979), true + case "subset": + // SUBSET OF + return rune(0x2282), true + case "subseteq": + // SUBSET OF OR EQUAL TO + return rune(0x2286), true + case "subseteqq": + // SUBSET OF ABOVE EQUALS SIGN + return rune(0x2ac5), true + case "subsetneq": + // SUBSET OF WITH NOT EQUAL TO + return rune(0x228a), true + case "subsetneqq": + // SUBSET OF ABOVE NOT EQUAL TO + return rune(0x2acb), true + case "subsim": + // SUBSET OF ABOVE TILDE OPERATOR + return rune(0x2ac7), true + case "subsub": + // SUBSET ABOVE SUBSET + return rune(0x2ad5), true + case "subsup": + // SUBSET ABOVE SUPERSET + return rune(0x2ad3), true + case "succ": + // SUCCEEDS + return rune(0x227b), true + case "succapprox": + // SUCCEEDS ABOVE ALMOST EQUAL TO + return rune(0x2ab8), true + case "succcurlyeq": + // SUCCEEDS OR EQUAL TO + return rune(0x227d), true + case "succeq": + // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + return rune(0x2ab0), true + case "succnapprox": + // SUCCEEDS ABOVE NOT ALMOST EQUAL TO + return rune(0x2aba), true + case "succneqq": + // SUCCEEDS ABOVE NOT EQUAL TO + return rune(0x2ab6), true + case "succnsim": + // SUCCEEDS BUT NOT EQUIVALENT TO + return rune(0x22e9), true + case "succsim": + // SUCCEEDS OR EQUIVALENT TO + return rune(0x227f), true + case "sum": + // N-ARY SUMMATION + return rune(0x2211), true + case "sumint": + // SUMMATION WITH INTEGRAL + return rune(0x2a0b), true + case "sung": + // EIGHTH NOTE + return rune(0x266a), true + case "sup": + // SUPERSET OF + return rune(0x2283), true + case "sup1": + // SUPERSCRIPT ONE + return rune(0xb9), true + case "sup2": + // SUPERSCRIPT TWO + return rune(0xb2), true + case "sup3": + // SUPERSCRIPT THREE + return rune(0xb3), true + case "supE": + // SUPERSET OF ABOVE EQUALS SIGN + return rune(0x2ac6), true + case "supdot": + // SUPERSET WITH DOT + return rune(0x2abe), true + case "supdsub": + // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET + return rune(0x2ad8), true + case "supe": + // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "supedot": + // SUPERSET OF OR EQUAL TO WITH DOT ABOVE + return rune(0x2ac4), true + case "suphsol": + // SUPERSET PRECEDING SOLIDUS + return rune(0x27c9), true + case "suphsub": + // SUPERSET BESIDE SUBSET + return rune(0x2ad7), true + case "suplarr": + // SUPERSET ABOVE LEFTWARDS ARROW + return rune(0x297b), true + case "supmult": + // SUPERSET WITH MULTIPLICATION SIGN BELOW + return rune(0x2ac2), true + case "supnE": + // SUPERSET OF ABOVE NOT EQUAL TO + return rune(0x2acc), true + case "supne": + // SUPERSET OF WITH NOT EQUAL TO + return rune(0x228b), true + case "supplus": + // SUPERSET WITH PLUS SIGN BELOW + return rune(0x2ac0), true + case "supset": + // SUPERSET OF + return rune(0x2283), true + case "supseteq": + // SUPERSET OF OR EQUAL TO + return rune(0x2287), true + case "supseteqq": + // SUPERSET OF ABOVE EQUALS SIGN + return rune(0x2ac6), true + case "supsetneq": + // SUPERSET OF WITH NOT EQUAL TO + return rune(0x228b), true + case "supsetneqq": + // SUPERSET OF ABOVE NOT EQUAL TO + return rune(0x2acc), true + case "supsim": + // SUPERSET OF ABOVE TILDE OPERATOR + return rune(0x2ac8), true + case "supsub": + // SUPERSET ABOVE SUBSET + return rune(0x2ad4), true + case "supsup": + // SUPERSET ABOVE SUPERSET + return rune(0x2ad6), true + case "swArr": + // SOUTH WEST DOUBLE ARROW + return rune(0x21d9), true + case "swarhk": + // SOUTH WEST ARROW WITH HOOK + return rune(0x2926), true + case "swarrow": + // SOUTH WEST ARROW + return rune(0x2199), true + case "swarr": + // SOUTH WEST ARROW + return rune(0x2199), true + case "swnwar": + // SOUTH WEST ARROW AND NORTH WEST ARROW + return rune(0x292a), true + case "szlig": + // LATIN SMALL LETTER SHARP S + return rune(0xdf), true + } + + case 't': + switch name { + case "target": + // POSITION INDICATOR + return rune(0x2316), true + case "tau": + // GREEK SMALL LETTER TAU + return rune(0x03c4), true + case "tbrk": + // TOP SQUARE BRACKET + return rune(0x23b4), true + case "tcaron": + // LATIN SMALL LETTER T WITH CARON + return rune(0x0165), true + case "tcedil": + // LATIN SMALL LETTER T WITH CEDILLA + return rune(0x0163), true + case "tcy": + // CYRILLIC SMALL LETTER TE + return rune(0x0442), true + case "tdot": + // COMBINING THREE DOTS ABOVE + return rune(0x20db), true + case "telrec": + // TELEPHONE RECORDER + return rune(0x2315), true + case "tfr": + // MATHEMATICAL FRAKTUR SMALL T + return rune(0x01d531), true + case "tgr": + // GREEK SMALL LETTER TAU + return rune(0x03c4), true + case "there4": + // THEREFORE + return rune(0x2234), true + case "therefore": + // THEREFORE + return rune(0x2234), true + case "thermod": + // THERMODYNAMIC + return rune(0x29e7), true + case "thetasym": + // GREEK THETA SYMBOL + return rune(0x03d1), true + case "thetas": + // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thetav": + // GREEK THETA SYMBOL + return rune(0x03d1), true + case "theta": + // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thgr": + // GREEK SMALL LETTER THETA + return rune(0x03b8), true + case "thickapprox": + // ALMOST EQUAL TO + return rune(0x2248), true + case "thicksim": + // TILDE OPERATOR + return rune(0x223c), true + case "thinsp": + // THIN SPACE + return rune(0x2009), true + case "thkap": + // ALMOST EQUAL TO + return rune(0x2248), true + case "thksim": + // TILDE OPERATOR + return rune(0x223c), true + case "thorn": + // LATIN SMALL LETTER THORN + return rune(0xfe), true + case "tilde": + // SMALL TILDE + return rune(0x02dc), true + case "timeint": + // INTEGRAL WITH TIMES SIGN + return rune(0x2a18), true + case "timesb": + // SQUARED TIMES + return rune(0x22a0), true + case "timesbar": + // MULTIPLICATION SIGN WITH UNDERBAR + return rune(0x2a31), true + case "timesd": + // MULTIPLICATION SIGN WITH DOT ABOVE + return rune(0x2a30), true + case "times": + // MULTIPLICATION SIGN + return rune(0xd7), true + case "tint": + // TRIPLE INTEGRAL + return rune(0x222d), true + case "toea": + // NORTH EAST ARROW AND SOUTH EAST ARROW + return rune(0x2928), true + case "top": + // DOWN TACK + return rune(0x22a4), true + case "topbot": + // APL FUNCTIONAL SYMBOL I-BEAM + return rune(0x2336), true + case "topcir": + // DOWN TACK WITH CIRCLE BELOW + return rune(0x2af1), true + case "topfork": + // PITCHFORK WITH TEE TOP + return rune(0x2ada), true + case "topf": + // MATHEMATICAL DOUBLE-STRUCK SMALL T + return rune(0x01d565), true + case "tosa": + // SOUTH EAST ARROW AND SOUTH WEST ARROW + return rune(0x2929), true + case "tprime": + // TRIPLE PRIME + return rune(0x2034), true + case "trade": + // TRADE MARK SIGN + return rune(0x2122), true + case "triS": + // S IN TRIANGLE + return rune(0x29cc), true + case "trianglelefteq": + // NORMAL SUBGROUP OF OR EQUAL TO + return rune(0x22b4), true + case "triangleq": + // DELTA EQUAL TO + return rune(0x225c), true + case "trianglerighteq": + // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + return rune(0x22b5), true + case "triangle": + // WHITE UP-POINTING SMALL TRIANGLE + return rune(0x25b5), true + case "triangledown": + // WHITE DOWN-POINTING SMALL TRIANGLE + return rune(0x25bf), true + case "triangleleft": + // WHITE LEFT-POINTING SMALL TRIANGLE + return rune(0x25c3), true + case "triangleright": + // WHITE RIGHT-POINTING SMALL TRIANGLE + return rune(0x25b9), true + case "tribar": + // TRIANGLE WITH UNDERBAR + return rune(0x29cb), true + case "tridot": + // WHITE UP-POINTING TRIANGLE WITH DOT + return rune(0x25ec), true + case "tridoto": + // TRIANGLE WITH DOT ABOVE + return rune(0x29ca), true + case "trie": + // DELTA EQUAL TO + return rune(0x225c), true + case "triminus": + // MINUS SIGN IN TRIANGLE + return rune(0x2a3a), true + case "triplus": + // PLUS SIGN IN TRIANGLE + return rune(0x2a39), true + case "trisb": + // TRIANGLE WITH SERIFS AT BOTTOM + return rune(0x29cd), true + case "tritime": + // MULTIPLICATION SIGN IN TRIANGLE + return rune(0x2a3b), true + case "trpezium": + // WHITE TRAPEZIUM + return rune(0x23e2), true + case "tscr": + // MATHEMATICAL SCRIPT SMALL T + return rune(0x01d4c9), true + case "tscy": + // CYRILLIC SMALL LETTER TSE + return rune(0x0446), true + case "tshcy": + // CYRILLIC SMALL LETTER TSHE + return rune(0x045b), true + case "tstrok": + // LATIN SMALL LETTER T WITH STROKE + return rune(0x0167), true + case "tverbar": + // TRIPLE VERTICAL BAR DELIMITER + return rune(0x2980), true + case "twixt": + // BETWEEN + return rune(0x226c), true + case "twoheadleftarrow": + // LEFTWARDS TWO HEADED ARROW + return rune(0x219e), true + case "twoheadrightarrow": + // RIGHTWARDS TWO HEADED ARROW + return rune(0x21a0), true + } + + case 'u': + switch name { + case "uAarr": + // UPWARDS TRIPLE ARROW + return rune(0x290a), true + case "uArr": + // UPWARDS DOUBLE ARROW + return rune(0x21d1), true + case "uHar": + // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + return rune(0x2963), true + case "uacgr": + // GREEK SMALL LETTER UPSILON WITH TONOS + return rune(0x03cd), true + case "uacute": + // LATIN SMALL LETTER U WITH ACUTE + return rune(0xfa), true + case "uarr2": + // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "uarr": + // UPWARDS ARROW + return rune(0x2191), true + case "uarrb": + // UPWARDS ARROW TO BAR + return rune(0x2912), true + case "uarrln": + // UPWARDS ARROW WITH HORIZONTAL STROKE + return rune(0x2909), true + case "ubrcy": + // CYRILLIC SMALL LETTER SHORT U + return rune(0x045e), true + case "ubreve": + // LATIN SMALL LETTER U WITH BREVE + return rune(0x016d), true + case "ucirc": + // LATIN SMALL LETTER U WITH CIRCUMFLEX + return rune(0xfb), true + case "ucy": + // CYRILLIC SMALL LETTER U + return rune(0x0443), true + case "udarr": + // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW + return rune(0x21c5), true + case "udblac": + // LATIN SMALL LETTER U WITH DOUBLE ACUTE + return rune(0x0171), true + case "udhar": + // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + return rune(0x296e), true + case "udiagr": + // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + return rune(0x03b0), true + case "udigr": + // GREEK SMALL LETTER UPSILON WITH DIALYTIKA + return rune(0x03cb), true + case "udrbrk": + // BOTTOM SQUARE BRACKET + return rune(0x23b5), true + case "udrcub": + // BOTTOM CURLY BRACKET + return rune(0x23df), true + case "udrpar": + // BOTTOM PARENTHESIS + return rune(0x23dd), true + case "ufisht": + // UP FISH TAIL + return rune(0x297e), true + case "ufr": + // MATHEMATICAL FRAKTUR SMALL U + return rune(0x01d532), true + case "ugr": + // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "ugrave": + // LATIN SMALL LETTER U WITH GRAVE + return rune(0xf9), true + case "uharl": + // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "uharr": + // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "uhblk": + // UPPER HALF BLOCK + return rune(0x2580), true + case "ulcorn": + // TOP LEFT CORNER + return rune(0x231c), true + case "ulcorner": + // TOP LEFT CORNER + return rune(0x231c), true + case "ulcrop": + // TOP LEFT CROP + return rune(0x230f), true + case "uldlshar": + // UP BARB LEFT DOWN BARB LEFT HARPOON + return rune(0x2951), true + case "ulharb": + // UPWARDS HARPOON WITH BARB LEFT TO BAR + return rune(0x2958), true + case "ultri": + // UPPER LEFT TRIANGLE + return rune(0x25f8), true + case "umacr": + // LATIN SMALL LETTER U WITH MACRON + return rune(0x016b), true + case "uml": + // DIAERESIS + return rune(0xa8), true + case "uogon": + // LATIN SMALL LETTER U WITH OGONEK + return rune(0x0173), true + case "uopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL U + return rune(0x01d566), true + case "uparrow": + // UPWARDS ARROW + return rune(0x2191), true + case "updownarrow": + // UP DOWN ARROW + return rune(0x2195), true + case "upharpoonleft": + // UPWARDS HARPOON WITH BARB LEFTWARDS + return rune(0x21bf), true + case "upharpoonright": + // UPWARDS HARPOON WITH BARB RIGHTWARDS + return rune(0x21be), true + case "upint": + // INTEGRAL WITH OVERBAR + return rune(0x2a1b), true + case "uplus": + // MULTISET UNION + return rune(0x228e), true + case "upsih": + // GREEK UPSILON WITH HOOK SYMBOL + return rune(0x03d2), true + case "upsilon": + // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "upsi": + // GREEK SMALL LETTER UPSILON + return rune(0x03c5), true + case "upuparrows": + // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "urcorn": + // TOP RIGHT CORNER + return rune(0x231d), true + case "urcorner": + // TOP RIGHT CORNER + return rune(0x231d), true + case "urcrop": + // TOP RIGHT CROP + return rune(0x230e), true + case "urdrshar": + // UP BARB RIGHT DOWN BARB RIGHT HARPOON + return rune(0x294f), true + case "urharb": + // UPWARDS HARPOON WITH BARB RIGHT TO BAR + return rune(0x2954), true + case "uring": + // LATIN SMALL LETTER U WITH RING ABOVE + return rune(0x016f), true + case "urtrif": + // BLACK UPPER RIGHT TRIANGLE + return rune(0x25e5), true + case "urtri": + // UPPER RIGHT TRIANGLE + return rune(0x25f9), true + case "uscr": + // MATHEMATICAL SCRIPT SMALL U + return rune(0x01d4ca), true + case "utdot": + // UP RIGHT DIAGONAL ELLIPSIS + return rune(0x22f0), true + case "utilde": + // LATIN SMALL LETTER U WITH TILDE + return rune(0x0169), true + case "utrif": + // BLACK UP-POINTING SMALL TRIANGLE + return rune(0x25b4), true + case "utri": + // WHITE UP-POINTING SMALL TRIANGLE + return rune(0x25b5), true + case "uuarr": + // UPWARDS PAIRED ARROWS + return rune(0x21c8), true + case "uuml": + // LATIN SMALL LETTER U WITH DIAERESIS + return rune(0xfc), true + case "uwangle": + // OBLIQUE ANGLE OPENING DOWN + return rune(0x29a7), true + } + + case 'v': + switch name { + case "vArr": + // UP DOWN DOUBLE ARROW + return rune(0x21d5), true + case "vBar": + // SHORT UP TACK WITH UNDERBAR + return rune(0x2ae8), true + case "vBarv": + // SHORT UP TACK ABOVE SHORT DOWN TACK + return rune(0x2ae9), true + case "vDash": + // TRUE + return rune(0x22a8), true + case "vDdash": + // VERTICAL BAR TRIPLE RIGHT TURNSTILE + return rune(0x2ae2), true + case "vangrt": + // RIGHT ANGLE VARIANT WITH SQUARE + return rune(0x299c), true + case "varepsilon": + // GREEK LUNATE EPSILON SYMBOL + return rune(0x03f5), true + case "varkappa": + // GREEK KAPPA SYMBOL + return rune(0x03f0), true + case "varnothing": + // EMPTY SET + return rune(0x2205), true + case "varphi": + // GREEK PHI SYMBOL + return rune(0x03d5), true + case "varpi": + // GREEK PI SYMBOL + return rune(0x03d6), true + case "varpropto": + // PROPORTIONAL TO + return rune(0x221d), true + case "varr": + // UP DOWN ARROW + return rune(0x2195), true + case "varrho": + // GREEK RHO SYMBOL + return rune(0x03f1), true + case "varsigma": + // GREEK SMALL LETTER FINAL SIGMA + return rune(0x03c2), true + case "varsubsetneq": + // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228a), true + case "varsubsetneqq": + // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acb), true + case "varsupsetneq": + // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228b), true + case "varsupsetneqq": + // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acc), true + case "vartheta": + // GREEK THETA SYMBOL + return rune(0x03d1), true + case "vartriangleleft": + // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "vartriangleright": + // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "vbrtri": + // VERTICAL BAR BESIDE RIGHT TRIANGLE + return rune(0x29d0), true + case "vcy": + // CYRILLIC SMALL LETTER VE + return rune(0x0432), true + case "vdash": + // RIGHT TACK + return rune(0x22a2), true + case "vee": + // LOGICAL OR + return rune(0x2228), true + case "veeBar": + // LOGICAL OR WITH DOUBLE UNDERBAR + return rune(0x2a63), true + case "veebar": + // XOR + return rune(0x22bb), true + case "veeeq": + // EQUIANGULAR TO + return rune(0x225a), true + case "vellip": + // VERTICAL ELLIPSIS + return rune(0x22ee), true + case "vellip4": + // DOTTED FENCE + return rune(0x2999), true + case "vellipv": + // TRIPLE COLON OPERATOR + return rune(0x2af6), true + case "verbar": + // VERTICAL LINE + return rune(0x7c), true + case "vert3": + // TRIPLE VERTICAL BAR BINARY RELATION + return rune(0x2af4), true + case "vert": + // VERTICAL LINE + return rune(0x7c), true + case "vfr": + // MATHEMATICAL FRAKTUR SMALL V + return rune(0x01d533), true + case "vldash": + // LEFT SQUARE BRACKET LOWER CORNER + return rune(0x23a3), true + case "vltri": + // NORMAL SUBGROUP OF + return rune(0x22b2), true + case "vnsub": + // SUBSET OF with vertical line + return rune(0x2282), true + case "vnsup": + // SUPERSET OF with vertical line + return rune(0x2283), true + case "vopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL V + return rune(0x01d567), true + case "vprime": + // PRIME + return rune(0x2032), true + case "vprop": + // PROPORTIONAL TO + return rune(0x221d), true + case "vrtri": + // CONTAINS AS NORMAL SUBGROUP + return rune(0x22b3), true + case "vscr": + // MATHEMATICAL SCRIPT SMALL V + return rune(0x01d4cb), true + case "vsubnE": + // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acb), true + case "vsubne": + // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228a), true + case "vsupnE": + // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + return rune(0x2acc), true + case "vsupne": + // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + return rune(0x228b), true + case "vzigzag": + // VERTICAL ZIGZAG LINE + return rune(0x299a), true + } + + case 'w': + switch name { + case "wcirc": + // LATIN SMALL LETTER W WITH CIRCUMFLEX + return rune(0x0175), true + case "wedbar": + // LOGICAL AND WITH UNDERBAR + return rune(0x2a5f), true + case "wedge": + // LOGICAL AND + return rune(0x2227), true + case "wedgeq": + // ESTIMATES + return rune(0x2259), true + case "weierp": + // SCRIPT CAPITAL P + return rune(0x2118), true + case "wfr": + // MATHEMATICAL FRAKTUR SMALL W + return rune(0x01d534), true + case "wopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL W + return rune(0x01d568), true + case "wp": + // SCRIPT CAPITAL P + return rune(0x2118), true + case "wreath": + // WREATH PRODUCT + return rune(0x2240), true + case "wr": + // WREATH PRODUCT + return rune(0x2240), true + case "wscr": + // MATHEMATICAL SCRIPT SMALL W + return rune(0x01d4cc), true + } + + case 'x': + switch name { + case "xandand": + // TWO LOGICAL AND OPERATOR + return rune(0x2a07), true + case "xbsol": + // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + return rune(0x2571), true + case "xcap": + // N-ARY INTERSECTION + return rune(0x22c2), true + case "xcirc": + // LARGE CIRCLE + return rune(0x25ef), true + case "xcup": + // N-ARY UNION + return rune(0x22c3), true + case "xcupdot": + // N-ARY UNION OPERATOR WITH DOT + return rune(0x2a03), true + case "xdtri": + // WHITE DOWN-POINTING TRIANGLE + return rune(0x25bd), true + case "xfr": + // MATHEMATICAL FRAKTUR SMALL X + return rune(0x01d535), true + case "xgr": + // GREEK SMALL LETTER XI + return rune(0x03be), true + case "xhArr": + // LONG LEFT RIGHT DOUBLE ARROW + return rune(0x27fa), true + case "xharr": + // LONG LEFT RIGHT ARROW + return rune(0x27f7), true + case "xi": + // GREEK SMALL LETTER XI + return rune(0x03be), true + case "xlArr": + // LONG LEFTWARDS DOUBLE ARROW + return rune(0x27f8), true + case "xlarr": + // LONG LEFTWARDS ARROW + return rune(0x27f5), true + case "xmap": + // LONG RIGHTWARDS ARROW FROM BAR + return rune(0x27fc), true + case "xnis": + // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE + return rune(0x22fb), true + case "xodot": + // N-ARY CIRCLED DOT OPERATOR + return rune(0x2a00), true + case "xopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL X + return rune(0x01d569), true + case "xoplus": + // N-ARY CIRCLED PLUS OPERATOR + return rune(0x2a01), true + case "xoror": + // TWO LOGICAL OR OPERATOR + return rune(0x2a08), true + case "xotime": + // N-ARY CIRCLED TIMES OPERATOR + return rune(0x2a02), true + case "xrArr": + // LONG RIGHTWARDS DOUBLE ARROW + return rune(0x27f9), true + case "xrarr": + // LONG RIGHTWARDS ARROW + return rune(0x27f6), true + case "xscr": + // MATHEMATICAL SCRIPT SMALL X + return rune(0x01d4cd), true + case "xsol": + // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + return rune(0x2572), true + case "xsqcap": + // N-ARY SQUARE INTERSECTION OPERATOR + return rune(0x2a05), true + case "xsqcup": + // N-ARY SQUARE UNION OPERATOR + return rune(0x2a06), true + case "xsqu": + // WHITE MEDIUM SQUARE + return rune(0x25fb), true + case "xsquf": + // BLACK MEDIUM SQUARE + return rune(0x25fc), true + case "xtimes": + // N-ARY TIMES OPERATOR + return rune(0x2a09), true + case "xuplus": + // N-ARY UNION OPERATOR WITH PLUS + return rune(0x2a04), true + case "xutri": + // WHITE UP-POINTING TRIANGLE + return rune(0x25b3), true + case "xvee": + // N-ARY LOGICAL OR + return rune(0x22c1), true + case "xwedge": + // N-ARY LOGICAL AND + return rune(0x22c0), true + } + + case 'y': + switch name { + case "yacute": + // LATIN SMALL LETTER Y WITH ACUTE + return rune(0xfd), true + case "yacy": + // CYRILLIC SMALL LETTER YA + return rune(0x044f), true + case "ycirc": + // LATIN SMALL LETTER Y WITH CIRCUMFLEX + return rune(0x0177), true + case "ycy": + // CYRILLIC SMALL LETTER YERU + return rune(0x044b), true + case "yen": + // YEN SIGN + return rune(0xa5), true + case "yfr": + // MATHEMATICAL FRAKTUR SMALL Y + return rune(0x01d536), true + case "yicy": + // CYRILLIC SMALL LETTER YI + return rune(0x0457), true + case "yopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL Y + return rune(0x01d56a), true + case "yscr": + // MATHEMATICAL SCRIPT SMALL Y + return rune(0x01d4ce), true + case "yucy": + // CYRILLIC SMALL LETTER YU + return rune(0x044e), true + case "yuml": + // LATIN SMALL LETTER Y WITH DIAERESIS + return rune(0xff), true + } + + case 'z': + switch name { + case "zacute": + // LATIN SMALL LETTER Z WITH ACUTE + return rune(0x017a), true + case "zcaron": + // LATIN SMALL LETTER Z WITH CARON + return rune(0x017e), true + case "zcy": + // CYRILLIC SMALL LETTER ZE + return rune(0x0437), true + case "zdot": + // LATIN SMALL LETTER Z WITH DOT ABOVE + return rune(0x017c), true + case "zeetrf": + // BLACK-LETTER CAPITAL Z + return rune(0x2128), true + case "zeta": + // GREEK SMALL LETTER ZETA + return rune(0x03b6), true + case "zfr": + // MATHEMATICAL FRAKTUR SMALL Z + return rune(0x01d537), true + case "zgr": + // GREEK SMALL LETTER ZETA + return rune(0x03b6), true + case "zhcy": + // CYRILLIC SMALL LETTER ZHE + return rune(0x0436), true + case "zigrarr": + // RIGHTWARDS SQUIGGLE ARROW + return rune(0x21dd), true + case "zopf": + // MATHEMATICAL DOUBLE-STRUCK SMALL Z + return rune(0x01d56b), true + case "zscr": + // MATHEMATICAL SCRIPT SMALL Z + return rune(0x01d4cf), true + case "zwj": + // ZERO WIDTH JOINER + return rune(0x200d), true + case "zwnj": + // ZERO WIDTH NON-JOINER + return rune(0x200c), true + } + } + return -1, false +} + +/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/ diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 563294309..146c278cb 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -519,8 +519,6 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) _ = expect(t, .Eq) or_return value := expect(t, .String) or_return - error(t, t.offset, "String: %v\n", value) - attr.key = strings.intern_get(&doc.intern, key.text) attr.val = strings.intern_get(&doc.intern, value.text) diff --git a/core/unicode/tools/generate_entity_table.odin b/core/unicode/tools/generate_entity_table.odin new file mode 100644 index 000000000..075ec1cca --- /dev/null +++ b/core/unicode/tools/generate_entity_table.odin @@ -0,0 +1,287 @@ +package xml_example + +import "core:encoding/xml" +import "core:os" +import "core:path" +import "core:mem" +import "core:strings" +import "core:strconv" +import "core:slice" +import "core:fmt" + +/* + Silent error handler for the parser. +*/ +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} + +OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } + +Entity :: struct { + name: string, + codepoint: rune, + description: string, +} + +generate_encoding_entity_table :: proc() { + using fmt + + filename := path.join(ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml") + defer delete(filename) + + generated_filename := path.join(ODIN_ROOT, "core", "encoding", "entity", "generated.odin") + defer delete(generated_filename) + + doc, err := xml.parse(filename, OPTIONS, Error_Handler) + defer xml.destroy(doc) + + if err != .None { + printf("Load/Parse error: %v\n", err) + if err == .File_Error { + printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename) + } + os.exit(1) + } + + printf("\"%v\" loaded and parsed.\n", filename) + + generated_buf: strings.Builder + defer strings.destroy_builder(&generated_buf) + w := strings.to_writer(&generated_buf) + + charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist") + if !charlist_ok { + eprintln("Could not locate top-level `` tag.") + os.exit(1) + } + + printf("Found `` with %v children.\n", len(charlist.children)) + + entity_map: map[string]Entity + names: [dynamic]string + + min_name_length := max(int) + max_name_length := min(int) + shortest_name: string + longest_name: string + + count := 0 + for char in charlist.children { + if char.ident != "character" { + eprintf("Expected ``, got `<%v>`\n", char.ident) + os.exit(1) + } + + if codepoint_string, ok := xml.find_attribute_val_by_key(char, "dec"); !ok { + eprintln("`` attribute not found.") + os.exit(1) + } else { + codepoint := strconv.atoi(codepoint_string) + + desc, desc_ok := xml.find_child_by_ident(char, "description") + description := desc.value if desc_ok else "" + + /* + For us to be interested in this codepoint, it has to have at least one entity. + */ + + nth := 0 + for { + character_entity, entity_ok := xml.find_child_by_ident(char, "entity", nth) + if !entity_ok { break } + + nth += 1 + if name, name_ok := xml.find_attribute_val_by_key(character_entity, "id"); name_ok { + + if len(name) == 0 { + /* + Invalid name. Skip. + */ + continue + } + + if name == "\"\"" { + printf("%#v\n", char) + printf("%#v\n", character_entity) + } + + if len(name) > max_name_length { longest_name = name } + if len(name) < min_name_length { shortest_name = name } + + min_name_length = min(min_name_length, len(name)) + max_name_length = max(max_name_length, len(name)) + + e := Entity{ + name = name, + codepoint = rune(codepoint), + description = description, + } + + if _, seen := entity_map[name]; seen { + continue + } + + entity_map[name] = e + append(&names, name) + count += 1 + } + } + } + } + + /* + Sort by name. + */ + slice.sort(names[:]) + + printf("Found %v unique `&name;` -> rune mappings.\n", count) + printf("Shortest name: %v (%v)\n", shortest_name, min_name_length) + printf("Longest name: %v (%v)\n", longest_name, max_name_length) + + // println(rune_to_string(1234)) + + /* + Generate table. + */ + wprintln(w, "package unicode_entity") + wprintln(w, "") + wprintln(w, GENERATED) + wprintln(w, "") + wprintf (w, TABLE_FILE_PROLOG) + wprintln(w, "") + + wprintf (w, "// `&%v;`\n", shortest_name) + wprintf (w, "XML_NAME_TO_RUNE_MIN_LENGTH :: %v\n", min_name_length) + wprintf (w, "// `&%v;`\n", longest_name) + wprintf (w, "XML_NAME_TO_RUNE_MAX_LENGTH :: %v\n", max_name_length) + wprintln(w, "") + + wprintln(w, +` +/* + Input: + entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML. + + Output: + "decoded" - The decoded rune if found by name, or -1 otherwise. + "ok" - true if found, false if not. + + IMPORTANT: XML processors (including browsers) treat these names as case-sensitive. So do we. +*/ +named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { + /* + Early out if the name is too short or too long. + min as a precaution in case the generated table has a bogus value. + */ + if len(name) < min(1, XML_NAME_TO_RUNE_MIN_LENGTH) || len(name) > XML_NAME_TO_RUNE_MAX_LENGTH { + return -1, false + } + + switch rune(name[0]) { +`) + + prefix := '?' + should_close := false + + for v in names { + if rune(v[0]) != prefix { + if should_close { + wprintln(w, "\t\t}\n") + } + + prefix = rune(v[0]) + wprintf (w, "\tcase '%v':\n", prefix) + wprintln(w, "\t\tswitch name {") + } + + e := entity_map[v] + + wprintf(w, "\t\t\tcase \"%v\": \n", e.name) + wprintf(w, "\t\t\t\t// %v\n", e.description) + wprintf(w, "\t\t\t\treturn %v, true\n", rune_to_string(e.codepoint)) + + should_close = true + } + wprintln(w, "\t\t}") + wprintln(w, "\t}") + wprintln(w, "\treturn -1, false") + wprintln(w, "}\n") + wprintln(w, GENERATED) + + println() + println(strings.to_string(generated_buf)) + println() + + written := os.write_entire_file(generated_filename, transmute([]byte)strings.to_string(generated_buf)) + + if written { + fmt.printf("Successfully written generated \"%v\".", generated_filename) + } else { + fmt.printf("Failed to write generated \"%v\".", generated_filename) + } + + delete(entity_map) + delete(names) + for name in &names { + free(&name) + } +} + +GENERATED :: `/* + ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ DO NOT EDIT ------ GENERATED ------ +*/` + +TABLE_FILE_PROLOG :: `/* + This file is generated from "https://www.w3.org/2003/entities/2007xml/unicode.xml". + + UPDATE: + - Ensure the XML file was downloaded using "tests\core\download_assets.py". + - Run "core/unicode/tools/generate_entity_table.odin" + + Odin unicode generated tables: https://github.com/odin-lang/Odin/tree/master/core/encoding/entity + + Copyright © 2021 World Wide Web Consortium, (Massachusetts Institute of Technology, + European Research Consortium for Informatics and Mathematics, Keio University, Beihang). + + All Rights Reserved. + + This work is distributed under the W3C® Software License [1] in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + [1] http://www.w3.org/Consortium/Legal/copyright-software + + See also: LICENSE_table.md +*/ +` + +rune_to_string :: proc(r: rune) -> (res: string) { + res = fmt.tprintf("%08x", int(r)) + for len(res) > 2 && res[:2] == "00" { + res = res[2:] + } + return fmt.tprintf("rune(0x%v)", res) +} + +is_dotted_name :: proc(name: string) -> (dotted: bool) { + for r in name { + if r == '.' { return true} + } + return false +} + +main :: proc() { + using fmt + + track: mem.Tracking_Allocator + mem.tracking_allocator_init(&track, context.allocator) + context.allocator = mem.tracking_allocator(&track) + + generate_encoding_entity_table() + + if len(track.allocation_map) > 0 { + println() + for _, v in track.allocation_map { + printf("%v Leaked %v bytes.\n", v.location, v.size) + } + } + println("Done and cleaned up!") +} \ No newline at end of file From 3d72e80ccf0f382f03a1c9407c4728862c5bca91 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 2 Dec 2021 21:07:40 +0100 Subject: [PATCH 0080/1258] [xml] Implement optional unboxing of CDATA and decoding of tag values. --- core/encoding/entity/entity.odin | 39 ++++++----- .../entity/example/entity_example.odin | 67 +++---------------- core/encoding/entity/example/test.html | 2 + core/encoding/xml/xml_reader.odin | 41 ++++++------ 4 files changed, 56 insertions(+), 93 deletions(-) diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin index e40896819..8742446e6 100644 --- a/core/encoding/entity/entity.odin +++ b/core/encoding/entity/entity.odin @@ -60,16 +60,22 @@ COMMENT_END :: "-->" Default: CDATA and comments are passed through unchanged. */ XML_Decode_Option :: enum u8 { + /* + Do not decode & entities. It decodes by default. + If given, overrides `Decode_CDATA`. + */ + No_Entity_Decode, + /* CDATA is unboxed. */ - CDATA_Unbox, + Unbox_CDATA, /* Unboxed CDATA is decoded as well. - Ignored if `.CDATA_Unbox` is not given. + Ignored if `.Unbox_CDATA` is not given. */ - CDATA_Decode, + Decode_CDATA, /* Comments are stripped. @@ -129,7 +135,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := } case: - if in_data && .CDATA_Decode not_in options { + if in_data && .Decode_CDATA not_in options { /* Unboxed, but undecoded. */ @@ -145,17 +151,20 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := */ write_string(&builder, entity) } else { - if decoded, ok := xml_decode_entity(entity); ok { - write_rune(&builder, decoded) - } else { - /* - Decode failed. Pass through original. - */ - write_string(&builder, "&") - write_string(&builder, entity) - write_string(&builder, ";") + + if .No_Entity_Decode not_in options { + if decoded, ok := xml_decode_entity(entity); ok { + write_rune(&builder, decoded) + continue + } } + /* + Literal passthrough because the decode failed or we want entities not decoded. + */ + write_string(&builder, "&") + write_string(&builder, entity) + write_string(&builder, ";") } } else { write_rune(&builder, t.r) @@ -290,7 +299,7 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { t.read_offset += len(CDATA_START) - 1 - if .CDATA_Unbox in options && .CDATA_Decode in options { + if .Unbox_CDATA in options && .Decode_CDATA in options { /* We're unboxing _and_ decoding CDATA */ @@ -315,7 +324,7 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X cdata := string(t.src[offset : t.read_offset]) - if .CDATA_Unbox in options { + if .Unbox_CDATA in options { cdata = cdata[len(CDATA_START):] cdata = cdata[:len(cdata) - len(CDATA_END)] } diff --git a/core/encoding/entity/example/entity_example.odin b/core/encoding/entity/example/entity_example.odin index 8758d9ad9..161a44827 100644 --- a/core/encoding/entity/example/entity_example.odin +++ b/core/encoding/entity/example/entity_example.odin @@ -1,19 +1,11 @@ package unicode_entity_example import "core:encoding/xml" -import "core:encoding/entity" import "core:strings" import "core:mem" import "core:fmt" import "core:time" -OPTIONS :: xml.Options{ - flags = { - .Ignore_Unsupported, .Intern_Comments, - }, - expected_doctype = "", -} - doc_print :: proc(doc: ^xml.Document) { buf: strings.Builder defer strings.destroy_builder(&buf) @@ -29,6 +21,13 @@ _entities :: proc() { DOC :: #load("../../../../tests/core/assets/XML/unicode.xml") + OPTIONS :: xml.Options{ + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "", + } + parse_duration: time.Duration { @@ -50,57 +49,11 @@ _entities :: proc() { _main :: proc() { using fmt - doc, err := xml.parse(#load("test.html")) + options := xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities }} + doc, _ := xml.parse(#load("test.html"), options) + defer xml.destroy(doc) doc_print(doc) - - if false { - val := doc.root.children[1].children[2].value - - println() - replaced, ok := entity.decode_xml(val) - defer delete(replaced) - - printf("Before: '%v', Err: %v\n", val, err) - printf("Passthrough: '%v'\nOK: %v\n", replaced, ok) - println() - } - - if false { - val := doc.root.children[1].children[2].value - - println() - replaced, ok := entity.decode_xml(val, { .CDATA_Unbox }) - defer delete(replaced) - - printf("Before: '%v', Err: %v\n", val, err) - printf("CDATA_Unbox: '%v'\nOK: %v\n", replaced, ok) - println() - } - - if true { - val := doc.root.children[1].children[2].value - - println() - replaced, ok := entity.decode_xml(val, { .CDATA_Unbox, .CDATA_Decode }) - defer delete(replaced) - - printf("Before: '%v', Err: %v\n", val, err) - printf("CDATA_Decode: '%v'\nOK: %v\n", replaced, ok) - println() - } - - if true { - val := doc.root.children[1].children[1].value - - println() - replaced, ok := entity.decode_xml(val, { .Comment_Strip }) - defer delete(replaced) - - printf("Before: '%v', Err: %v\n", val, err) - printf("Comment_Strip: '%v'\nOK: %v\n", replaced, ok) - println() - } } main :: proc() { diff --git a/core/encoding/entity/example/test.html b/core/encoding/entity/example/test.html index 60e32bf03..62a0bb35a 100644 --- a/core/encoding/entity/example/test.html +++ b/core/encoding/entity/example/test.html @@ -16,9 +16,11 @@
Foozle]! © 42&;1234&
+
Foozle]! © 42&;1234&
+
| | | fj ` \ ® ϱ ∳
diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 146c278cb..6f49b8e08 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -18,10 +18,6 @@ package xml - We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences. - <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options. - TODO: - - Optional CDATA unboxing. - - Optional `>`, ` `, ` ` and other escape substitution in tag bodies. - MAYBE: - XML writer? - Serialize/deserialize Odin types? @@ -31,6 +27,7 @@ package xml */ import "core:strings" +import "core:encoding/entity" import "core:mem" import "core:os" @@ -196,12 +193,6 @@ Error :: enum { Duplicate_Attribute, Conflicting_Options, - - /* - Unhandled TODO: - */ - Unhandled_CDATA_Unboxing, - Unhandled_SGML_Entity_Decoding, } /* @@ -422,8 +413,25 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err /* This should be a tag's body text. */ - body_text := scan_string(t, t.offset) or_return - element.value = strings.intern_get(&doc.intern, body_text) + body_text := scan_string(t, t.offset) or_return + + decode_opts := entity.XML_Decode_Options{ .Comment_Strip } + + if .Decode_SGML_Entities not_in opts.flags { + decode_opts += { .No_Entity_Decode } + } + if .Unbox_CDATA in opts.flags { + decode_opts += { .Unbox_CDATA, .Decode_CDATA } + } + + decoded, decode_err := entity.decode_xml(body_text, decode_opts) + defer delete(decoded) + + if decode_err == .None { + element.value = strings.intern_get(&doc.intern, decoded) + } else { + element.value = strings.intern_get(&doc.intern, body_text) + } } } @@ -488,15 +496,6 @@ validate_options :: proc(options: Options) -> (validated: Options, err: Error) { if .Error_on_Unsupported in validated.flags && .Ignore_Unsupported in validated.flags { return options, .Conflicting_Options } - - if .Unbox_CDATA in validated.flags { - return options, .Unhandled_CDATA_Unboxing - } - - if .Decode_SGML_Entities in validated.flags { - return options, .Unhandled_SGML_Entity_Decoding - } - return validated, .None } From d65d6edb0e1887871c4de6a4e8a1630927153eae Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 5 Dec 2021 02:17:48 +0100 Subject: [PATCH 0081/1258] [xml] Improve XML tests, test `core:encoding/entity`. --- core/encoding/entity/entity.odin | 7 + .../entity/example/entity_example.odin | 1 + core/encoding/entity/example/test.html | 2 +- tests/core/assets/XML/entities.html | 29 ++ ...-xliff-1.0.xliff => nl_NL-xliff-1.2.xliff} | 0 tests/core/assets/XML/utf8.xml | 2 +- tests/core/encoding/xml/test_core_xml.odin | 426 +++++++++++------- 7 files changed, 291 insertions(+), 176 deletions(-) create mode 100644 tests/core/assets/XML/entities.html rename tests/core/assets/XML/{nl_NL-xliff-1.0.xliff => nl_NL-xliff-1.2.xliff} (100%) diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin index 8742446e6..db1a5ad0b 100644 --- a/core/encoding/entity/entity.odin +++ b/core/encoding/entity/entity.odin @@ -115,7 +115,14 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := We don't need to check if we need to write a `<`, because if it isn't CDATA or a comment, it couldn't have been part of an XML tag body to be decoded here. + + Keep in mind that we could already *be* inside a CDATA tag. + If so, write `>` as a literal and continue. */ + if in_data { + write_rune(&builder, '<') + continue + } in_data = _handle_xml_special(&t, &builder, options) or_return case ']': diff --git a/core/encoding/entity/example/entity_example.odin b/core/encoding/entity/example/entity_example.odin index 161a44827..882203f48 100644 --- a/core/encoding/entity/example/entity_example.odin +++ b/core/encoding/entity/example/entity_example.odin @@ -50,6 +50,7 @@ _main :: proc() { using fmt options := xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities }} + doc, _ := xml.parse(#load("test.html"), options) defer xml.destroy(doc) diff --git a/core/encoding/entity/example/test.html b/core/encoding/entity/example/test.html index 62a0bb35a..ebbc6470c 100644 --- a/core/encoding/entity/example/test.html +++ b/core/encoding/entity/example/test.html @@ -22,7 +22,7 @@
- | | | fj ` \ ® ϱ ∳ + | | | fj ` \ ® ϱ ∳ ⁏
\ No newline at end of file diff --git a/tests/core/assets/XML/entities.html b/tests/core/assets/XML/entities.html new file mode 100644 index 000000000..05a6b107e --- /dev/null +++ b/tests/core/assets/XML/entities.html @@ -0,0 +1,29 @@ + + + Entity Reference Test + + + +

Entity Reference Test

+
+ Foozle]! © 42&;1234& +
+ + +
+ Foozle]! © 42&;1234& +
+ +
+ | | | fj ` \ ® ϱ ∳ ⁏ +
+ + \ No newline at end of file diff --git a/tests/core/assets/XML/nl_NL-xliff-1.0.xliff b/tests/core/assets/XML/nl_NL-xliff-1.2.xliff similarity index 100% rename from tests/core/assets/XML/nl_NL-xliff-1.0.xliff rename to tests/core/assets/XML/nl_NL-xliff-1.2.xliff diff --git a/tests/core/assets/XML/utf8.xml b/tests/core/assets/XML/utf8.xml index c9ed3bf69..6e1a897ea 100644 --- a/tests/core/assets/XML/utf8.xml +++ b/tests/core/assets/XML/utf8.xml @@ -4,5 +4,5 @@ <부끄러운:barzle> ရှက်စရာ ဇီးကွက် Owl of Shame - More CDATA Hello, world! Nonsense. + More CDATA Hello, world! Nonsense. \ No newline at end of file diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index c2e0aa172..5cb59e001 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -3,16 +3,16 @@ package test_core_xml import "core:encoding/xml" import "core:testing" import "core:mem" +import "core:strings" +import "core:io" import "core:fmt" +import "core:hash" Silent :: proc(pos: xml.Pos, fmt: string, args: ..any) { // Custom (silent) error handler. } -OPTIONS :: xml.Options{ - flags = { - .Ignore_Unsupported, .Intern_Comments, - }, +OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, }, expected_doctype = "", } @@ -22,76 +22,153 @@ TEST_fail := 0 TEST :: struct { filename: string, options: xml.Options, - expected: struct { - error: xml.Error, - xml_version: string, - xml_encoding: string, - doctype: string, - }, + err: xml.Error, + crc32: u32, } +/* + Relative to ODIN_ROOT +*/ +TEST_FILE_PATH_PREFIX :: "tests/core/assets/XML" + TESTS :: []TEST{ /* First we test that certain files parse without error. */ + { - filename = "assets/XML/utf8.xml", - options = OPTIONS, - expected = { - error = .None, - xml_version = "1.0", - xml_encoding = "utf-8", - doctype = "恥ずべきフクロウ", + /* + + + <恥ずべきフクロウ 올빼미_id="Foozle Hello, world!"]]>Barzle"> + <부끄러운:barzle> + ရှက်စရာ ဇီးကွက် + Owl of Shame + More CDATA Hello, world! Nonsense. + + */ + + /* + Tests UTF-8 idents and values. + Test namespaced ident. + Tests that nested partial CDATA start doesn't trip up parser. + */ + filename = "utf8.xml", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "恥ずべきフクロウ", }, + crc32 = 0x30d82264, }, + { - filename = "assets/XML/nl_NL-qt-ts.ts", - options = OPTIONS, - expected = { - error = .None, - xml_version = "1.0", - xml_encoding = "utf-8", - doctype = "TS", + /* + Same as above. + Unbox CDATA in data tag. + */ + filename = "utf8.xml", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, + }, + expected_doctype = "恥ずべきフクロウ", }, + crc32 = 0x6d38ac58, }, + { - filename = "assets/XML/nl_NL-xliff-1.0.xliff", - options = OPTIONS, - expected = { - error = .None, - xml_version = "1.0", - xml_encoding = "UTF-8", - doctype = "", + /* + Simple Qt TS translation file. + `core:i18n` requires it to be parsed properly. + */ + filename = "nl_NL-qt-ts.ts", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, + }, + expected_doctype = "TS", }, + crc32 = 0x7bce2630, }, + { - filename = "assets/XML/nl_NL-xliff-2.0.xliff", - options = OPTIONS, - expected = { - error = .None, - xml_version = "1.0", - xml_encoding = "utf-8", - doctype = "", + /* + Simple XLiff 1.2 file. + `core:i18n` requires it to be parsed properly. + */ + filename = "nl_NL-xliff-1.2.xliff", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, + }, + expected_doctype = "xliff", }, + crc32 = 0x43f19d61, + }, + + { + /* + Simple XLiff 2.0 file. + `core:i18n` requires it to be parsed properly. + */ + filename = "nl_NL-xliff-2.0.xliff", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, + }, + expected_doctype = "xliff", + }, + crc32 = 0x961e7635, + }, + + { + filename = "entities.html", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, + }, + expected_doctype = "html", + }, + crc32 = 0xdb4a1e79, + }, + + { + filename = "entities.html", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, + }, + expected_doctype = "html", + }, + crc32 = 0x82588917, + }, + + { + filename = "entities.html", + options = { + flags = { + .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities, + }, + expected_doctype = "html", + }, + crc32 = 0x5e74d8a6, }, /* Then we test that certain errors are returned as expected. */ { - filename = "assets/XML/utf8.xml", + filename = "utf8.xml", options = { flags = { .Ignore_Unsupported, .Intern_Comments, }, expected_doctype = "Odin", }, - expected = { - error = .Invalid_DocType, - xml_version = "1.0", - xml_encoding = "utf-8", - doctype = "恥ずべきフクロウ", - }, + err = .Invalid_DocType, + crc32 = 0x49b83d0a, }, } @@ -115,6 +192,136 @@ when ODIN_TEST { } } +test_file_path :: proc(filename: string) -> (path: string) { + + path = fmt.tprintf("%v%v/%v", ODIN_ROOT, TEST_FILE_PATH_PREFIX, filename) + temp := transmute([]u8)path + + for r, i in path { + if r == '\\' { + temp[i] = '/' + } + } + return path +} + +doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { + /* + Effectively a clone of the debug printer in the xml package. + We duplicate it here so that the way it prints an XML document to a string is stable. + + This way we can hash the output. If it changes, it means that the document or how it was parsed changed, + not how it was printed. One less source of variability. + */ + print :: proc(writer: io.Writer, doc: ^xml.Document) -> (written: int, err: io.Error) { + if doc == nil { return } + using fmt + + written += wprintf(writer, "[XML Prolog]\n") + + for attr in doc.prolog { + written += wprintf(writer, "\t%v: %v\n", attr.key, attr.val) + } + + written += wprintf(writer, "[Encoding] %v\n", doc.encoding) + + if len(doc.doctype.ident) > 0 { + written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) + + if len(doc.doctype.rest) > 0 { + wprintf(writer, "\t%v\n", doc.doctype.rest) + } + } + + for comment in doc.comments { + written += wprintf(writer, "[Pre-root comment] %v\n", comment) + } + + if doc.root != nil { + wprintln(writer, " --- ") + print_element(writer, doc.root) + wprintln(writer, " --- ") + } + + return written, .None + } + + print_element :: proc(writer: io.Writer, element: ^xml.Element, indent := 0) -> (written: int, err: io.Error) { + if element == nil { return } + using fmt + + tab :: proc(writer: io.Writer, indent: int) { + for _ in 0..=indent { + wprintf(writer, "\t") + } + } + + tab(writer, indent) + + if element.kind == .Element { + wprintf(writer, "<%v>\n", element.ident) + if len(element.value) > 0 { + tab(writer, indent + 1) + wprintf(writer, "[Value] %v\n", element.value) + } + + for attr in element.attribs { + tab(writer, indent + 1) + wprintf(writer, "[Attr] %v: %v\n", attr.key, attr.val) + } + + for child in element.children { + print_element(writer, child, indent + 1) + } + } else if element.kind == .Comment { + wprintf(writer, "[COMMENT] %v\n", element.value) + } + + return written, .None + } + + buf: strings.Builder + defer strings.destroy_builder(&buf) + + print(strings.to_writer(&buf), doc) + return strings.clone(strings.to_string(buf)) +} + +@test +run_tests :: proc(t: ^testing.T) { + using fmt + + for test in TESTS { + path := test_file_path(test.filename) + printf("\nTrying to parse %v\n\n", path) + + doc, err := xml.parse(path, test.options, Silent) + defer xml.destroy(doc) + + tree_string := doc_to_string(doc) + tree_bytes := transmute([]u8)tree_string + defer delete(tree_bytes) + + crc32 := hash.crc32(tree_bytes) + + failed := err != test.err + err_msg := tprintf("Expected return value %v, got %v", test.err, err) + expect(t, err == test.err, err_msg) + + failed |= crc32 != test.crc32 + err_msg = tprintf("Expected CRC 0x%08x, got 0x%08x", test.crc32, crc32) + expect(t, crc32 == test.crc32, err_msg) + + if failed { + /* + Don't fully print big trees. + */ + tree_string = tree_string[:min(2_048, len(tree_string))] + println(tree_string) + } + } +} + main :: proc() { t := testing.T{} @@ -132,133 +339,4 @@ main :: proc() { } fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) -} - -@test -run_tests :: proc(t: ^testing.T) { - using fmt - - count := 0 - - for test in TESTS { - printf("Trying to parse %v\n\n", test.filename) - - doc, err := xml.parse(test.filename, test.options, Silent) - defer xml.destroy(doc) - - err_msg := tprintf("Expected return value %v, got %v", test.expected.error, err) - expect(t, err == test.expected.error, err_msg) - - if len(test.expected.xml_version) > 0 { - xml_version := "" - for attr in doc.prolog { - if attr.key == "version" { - xml_version = attr.val - } - } - - err_msg = tprintf("Expected XML version %v, got %v", test.expected.xml_version, xml_version) - expect(t, xml_version == test.expected.xml_version, err_msg) - } - - if len(test.expected.xml_encoding) > 0 { - xml_encoding := "" - for attr in doc.prolog { - if attr.key == "encoding" { - xml_encoding = attr.val - } - } - - err_msg = tprintf("Expected XML encoding %v, got %v", test.expected.xml_encoding, xml_encoding) - expect(t, xml_encoding == test.expected.xml_encoding, err_msg) - } - - err_msg = tprintf("Expected DOCTYPE %v, got %v", test.expected.doctype, doc.doctype.ident) - expect(t, doc.doctype.ident == test.expected.doctype, err_msg) - - /* - File-specific tests. - */ - switch count { - case 0: - expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") - attr := doc.root.attribs[0] - - attr_key_expected := "올빼미_id" - attr_val_expected := "Foozle Hello, world!\"]]>Barzle" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - - expect(t, len(doc.root.children) > 0, "Expected the root tag to have children.") - child := doc.root.children[0] - - first_child_ident := "부끄러운:barzle" - attr_err = tprintf("Expected first child tag's ident to be %v, got %v", first_child_ident, child.ident) - expect(t, child.ident == first_child_ident, attr_err) - - case 2: - expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") - - { - attr := doc.root.attribs[0] - - attr_key_expected := "version" - attr_val_expected := "1.2" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - } - - { - attr := doc.root.attribs[1] - - attr_key_expected := "xmlns" - attr_val_expected := "urn:oasis:names:tc:xliff:document:1.2" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - } - - case 3: - expect(t, len(doc.root.attribs) > 0, "Expected the root tag to have an attribute.") - - { - attr := doc.root.attribs[0] - - attr_key_expected := "xmlns" - attr_val_expected := "urn:oasis:names:tc:xliff:document:2.0" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - } - - { - attr := doc.root.attribs[1] - - attr_key_expected := "version" - attr_val_expected := "2.0" - - attr_err := tprintf("Expected %v, got %v", attr_key_expected, attr.key) - expect(t, attr.key == attr_key_expected, attr_err) - - attr_err = tprintf("Expected %v, got %v", attr_val_expected, attr.val) - expect(t, attr.val == attr_val_expected, attr_err) - } - } - - count += 1 - } } \ No newline at end of file From d7200f61441b6acfc4f0b47e900095f08490da58 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 5 Dec 2021 02:40:13 +0100 Subject: [PATCH 0082/1258] Improve tests in general. Less spammy core tests: They don't print PASSes now, only logs and failures. `core:image` and `core:encoding/xml` tests also find their assets relative to `ODIN_ROOT` now. --- tests/core/compress/test_core_compress.odin | 9 +- tests/core/crypto/test_core_crypto.odin | 1691 +++++++++--------- tests/core/encoding/json/test_core_json.odin | 9 +- tests/core/encoding/xml/test_core_xml.odin | 43 +- tests/core/hash/test_core_hash.odin | 9 +- tests/core/image/test_core_image.odin | 51 +- tests/core/odin/test_parser.odin | 37 +- tests/core/strings/test_core_strings.odin | 59 +- 8 files changed, 948 insertions(+), 960 deletions(-) diff --git a/tests/core/compress/test_core_compress.odin b/tests/core/compress/test_core_compress.odin index c925c0258..908ef12e4 100644 --- a/tests/core/compress/test_core_compress.odin +++ b/tests/core/compress/test_core_compress.odin @@ -30,18 +30,15 @@ when ODIN_TEST { log :: testing.log } else { expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) TEST_count += 1 if !condition { TEST_fail += 1 - fmt.println(message) + fmt.printf("[%v] %v\n", loc, message) return } - fmt.println(" PASS") } log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) } } @@ -51,7 +48,7 @@ main :: proc() { zlib_test(&t) gzip_test(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } @test diff --git a/tests/core/crypto/test_core_crypto.odin b/tests/core/crypto/test_core_crypto.odin index 2ad00be66..6d3a9f8e4 100644 --- a/tests/core/crypto/test_core_crypto.odin +++ b/tests/core/crypto/test_core_crypto.odin @@ -1,15 +1,15 @@ package test_core_crypto /* - Copyright 2021 zhibog - Made available under the BSD-3 license. + Copyright 2021 zhibog + Made available under the BSD-3 license. - List of contributors: - zhibog, dotbmp: Initial implementation. - Jeroen van Rijn: Test runner setup. + List of contributors: + zhibog, dotbmp: Initial implementation. + Jeroen van Rijn: Test runner setup. - Tests for the hashing algorithms within the crypto library. - Where possible, the official test vectors are used to validate the implementation. + Tests for the hashing algorithms within the crypto library. + Where possible, the official test vectors are used to validate the implementation. */ import "core:testing" @@ -41,1065 +41,1062 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } main :: proc() { - t := testing.T{} - test_md2(&t) - test_md4(&t) - test_md5(&t) - test_sha1(&t) - test_sha224(&t) - test_sha256(&t) - test_sha384(&t) - test_sha512(&t) - test_sha3_224(&t) - test_sha3_256(&t) - test_sha3_384(&t) - test_sha3_512(&t) - test_shake_128(&t) - test_shake_256(&t) - test_keccak_224(&t) - test_keccak_256(&t) - test_keccak_384(&t) - test_keccak_512(&t) - test_whirlpool(&t) - test_gost(&t) - test_streebog_256(&t) - test_streebog_512(&t) - test_blake_224(&t) - test_blake_256(&t) - test_blake_384(&t) - test_blake_512(&t) - test_blake2b(&t) - test_blake2s(&t) - test_ripemd_128(&t) - test_ripemd_160(&t) - test_ripemd_256(&t) - test_ripemd_320(&t) - test_tiger_128(&t) - test_tiger_160(&t) - test_tiger_192(&t) - test_tiger2_128(&t) - test_tiger2_160(&t) - test_tiger2_192(&t) - test_sm3(&t) - test_jh_224(&t) - test_jh_256(&t) - test_jh_384(&t) - test_jh_512(&t) - test_groestl_224(&t) - test_groestl_256(&t) - test_groestl_384(&t) - test_groestl_512(&t) - test_haval_128(&t) - test_haval_160(&t) - test_haval_192(&t) - test_haval_224(&t) - test_haval_256(&t) + t := testing.T{} + test_md2(&t) + test_md4(&t) + test_md5(&t) + test_sha1(&t) + test_sha224(&t) + test_sha256(&t) + test_sha384(&t) + test_sha512(&t) + test_sha3_224(&t) + test_sha3_256(&t) + test_sha3_384(&t) + test_sha3_512(&t) + test_shake_128(&t) + test_shake_256(&t) + test_keccak_224(&t) + test_keccak_256(&t) + test_keccak_384(&t) + test_keccak_512(&t) + test_whirlpool(&t) + test_gost(&t) + test_streebog_256(&t) + test_streebog_512(&t) + test_blake_224(&t) + test_blake_256(&t) + test_blake_384(&t) + test_blake_512(&t) + test_blake2b(&t) + test_blake2s(&t) + test_ripemd_128(&t) + test_ripemd_160(&t) + test_ripemd_256(&t) + test_ripemd_320(&t) + test_tiger_128(&t) + test_tiger_160(&t) + test_tiger_192(&t) + test_tiger2_128(&t) + test_tiger2_160(&t) + test_tiger2_192(&t) + test_sm3(&t) + test_jh_224(&t) + test_jh_256(&t) + test_jh_384(&t) + test_jh_512(&t) + test_groestl_224(&t) + test_groestl_256(&t) + test_groestl_384(&t) + test_groestl_512(&t) + test_haval_128(&t) + test_haval_160(&t) + test_haval_192(&t) + test_haval_224(&t) + test_haval_256(&t) - // "modern" crypto tests - test_chacha20(&t) - test_poly1305(&t) - test_chacha20poly1305(&t) - test_x25519(&t) - test_rand_bytes(&t) + // "modern" crypto tests + test_chacha20(&t) + test_poly1305(&t) + test_chacha20poly1305(&t) + test_x25519(&t) + test_rand_bytes(&t) - bench_modern(&t) + bench_modern(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } TestHash :: struct { - hash: string, - str: string, + hash: string, + str: string, } hex_string :: proc(bytes: []byte, allocator := context.temp_allocator) -> string { - lut: [16]byte = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} - buf := make([]byte, len(bytes) * 2, allocator) - for i := 0; i < len(bytes); i += 1 { - buf[i * 2 + 0] = lut[bytes[i] >> 4 & 0xf] - buf[i * 2 + 1] = lut[bytes[i] & 0xf] - } - return string(buf) + lut: [16]byte = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'} + buf := make([]byte, len(bytes) * 2, allocator) + for i := 0; i < len(bytes); i += 1 { + buf[i * 2 + 0] = lut[bytes[i] >> 4 & 0xf] + buf[i * 2 + 1] = lut[bytes[i] & 0xf] + } + return string(buf) } @(test) test_md2 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1319 - test_vectors := [?]TestHash { - TestHash{"8350e5a3e24c153df2275c9f80692773", ""}, - TestHash{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"}, - TestHash{"da853b0d3f88d99b30283a69e6ded6bb", "abc"}, - TestHash{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"}, - TestHash{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md2.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1319 + test_vectors := [?]TestHash { + TestHash{"8350e5a3e24c153df2275c9f80692773", ""}, + TestHash{"32ec01ec4a6dac72c0ab96fb34c0b5d1", "a"}, + TestHash{"da853b0d3f88d99b30283a69e6ded6bb", "abc"}, + TestHash{"ab4f496bfb2a530b219ff33031fe06b0", "message digest"}, + TestHash{"4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md2.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_md4 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 - test_vectors := [?]TestHash { - TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, - TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, - TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, - TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, - TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md4.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1320 + test_vectors := [?]TestHash { + TestHash{"31d6cfe0d16ae931b73c59d7e0c089c0", ""}, + TestHash{"bde52cb31de33e46245e05fbdbd6fb24", "a"}, + TestHash{"a448017aaf21d8525fc10ae87aa6729d", "abc"}, + TestHash{"d9130a8164549fe818874806e1c7014b", "message digest"}, + TestHash{"d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md4.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_md5 :: proc(t: ^testing.T) { - // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 - test_vectors := [?]TestHash { - TestHash{"d41d8cd98f00b204e9800998ecf8427e", ""}, - TestHash{"0cc175b9c0f1b6a831c399e269772661", "a"}, - TestHash{"900150983cd24fb0d6963f7d28e17f72", "abc"}, - TestHash{"f96b697d7cb7938d525a2f31aaf161d0", "message digest"}, - TestHash{"c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := md5.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Official test vectors from https://datatracker.ietf.org/doc/html/rfc1321 + test_vectors := [?]TestHash { + TestHash{"d41d8cd98f00b204e9800998ecf8427e", ""}, + TestHash{"0cc175b9c0f1b6a831c399e269772661", "a"}, + TestHash{"900150983cd24fb0d6963f7d28e17f72", "abc"}, + TestHash{"f96b697d7cb7938d525a2f31aaf161d0", "message digest"}, + TestHash{"c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := md5.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha1 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, - TestHash{"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, - TestHash{"f9537c23893d2014f365adf8ffe33b8eb0297ed1", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"346fb528a24b48f563cb061470bcfd23740427ad", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, - TestHash{"c729c8996ee0a6f74f4f3248e8957edf704fb624", "01234567012345670123456701234567"}, - TestHash{"84983e441c3bd26ebaae4aa1f95129e5e54670f1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha1.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""}, + TestHash{"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"}, + TestHash{"f9537c23893d2014f365adf8ffe33b8eb0297ed1", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"346fb528a24b48f563cb061470bcfd23740427ad", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"}, + TestHash{"c729c8996ee0a6f74f4f3248e8957edf704fb624", "01234567012345670123456701234567"}, + TestHash{"84983e441c3bd26ebaae4aa1f95129e5e54670f1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha1.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, - TestHash{"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, - TestHash{"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""}, + TestHash{"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"}, + TestHash{"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, - TestHash{"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, - TestHash{"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""}, + TestHash{"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"}, + TestHash{"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""}, - TestHash{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"}, - TestHash{"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""}, + TestHash{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"}, + TestHash{"3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""}, - TestHash{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"}, - TestHash{"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha2.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""}, + TestHash{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"}, + TestHash{"204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha2.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", ""}, - TestHash{"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc"}, - TestHash{"10241ac5187380bd501192e4e56b5280908727dd8fe0d10d4e5ad91e", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"fd645fe07d814c397e85e85f92fe58b949f55efa4d3468b2468da45a", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", "a"}, - TestHash{"6961f694b2ff3ed6f0c830d2c66da0c5e7ca9445f7c0dca679171112", "01234567012345670123456701234567"}, - TestHash{"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", ""}, + TestHash{"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", "abc"}, + TestHash{"10241ac5187380bd501192e4e56b5280908727dd8fe0d10d4e5ad91e", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"fd645fe07d814c397e85e85f92fe58b949f55efa4d3468b2468da45a", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", "a"}, + TestHash{"6961f694b2ff3ed6f0c830d2c66da0c5e7ca9445f7c0dca679171112", "01234567012345670123456701234567"}, + TestHash{"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", ""}, - TestHash{"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc"}, - TestHash{"565ada1ced21278cfaffdde00dea0107964121ac25e4e978abc59412be74550a", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"8cc1709d520f495ce972ece48b0d2e1f74ec80d53bc5c47457142158fae15d98", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", "a"}, - TestHash{"e4786de5f88f7d374b7288f225ea9f2f7654da200bab5d417e1fb52d49202767", "01234567012345670123456701234567"}, - TestHash{"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", ""}, + TestHash{"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", "abc"}, + TestHash{"565ada1ced21278cfaffdde00dea0107964121ac25e4e978abc59412be74550a", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"8cc1709d520f495ce972ece48b0d2e1f74ec80d53bc5c47457142158fae15d98", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", "a"}, + TestHash{"e4786de5f88f7d374b7288f225ea9f2f7654da200bab5d417e1fb52d49202767", "01234567012345670123456701234567"}, + TestHash{"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", ""}, - TestHash{"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", "abc"}, - TestHash{"9aa92dbb716ebb573def0d5e3cdd28d6add38ada310b602b8916e690a3257b7144e5ddd3d0dbbc559c48480d34d57a9a", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"77c90323d7392bcdee8a3e7f74f19f47b7d1b1a825ac6a2d8d882a72317879cc26597035f1fc24fe65090b125a691282", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", "a"}, - TestHash{"51072590ad4c51b27ff8265590d74f92de7cc55284168e414ca960087c693285b08a283c6b19d77632994cb9eb93f1be", "01234567012345670123456701234567"}, - TestHash{"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", ""}, + TestHash{"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", "abc"}, + TestHash{"9aa92dbb716ebb573def0d5e3cdd28d6add38ada310b602b8916e690a3257b7144e5ddd3d0dbbc559c48480d34d57a9a", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"77c90323d7392bcdee8a3e7f74f19f47b7d1b1a825ac6a2d8d882a72317879cc26597035f1fc24fe65090b125a691282", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", "a"}, + TestHash{"51072590ad4c51b27ff8265590d74f92de7cc55284168e414ca960087c693285b08a283c6b19d77632994cb9eb93f1be", "01234567012345670123456701234567"}, + TestHash{"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sha3_512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", ""}, - TestHash{"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", "abc"}, - TestHash{"9f9a327944a35988d67effc4fa748b3c07744f736ac70b479d8e12a3d10d6884d00a7ef593690305462e9e9030a67c51636fd346fd8fa0ee28a5ac2aee103d2e", "abcdbcdecdefdefgefghfghighijhi"}, - TestHash{"dbb124a0deda966eb4d199d0844fa0beb0770ea1ccddabcd335a7939a931ac6fb4fa6aebc6573f462ced2e4e7178277803be0d24d8bc2864626d9603109b7891", "jkijkljklmklmnlmnomnopnopq"}, - TestHash{"697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", "a"}, - TestHash{"5679e353bc8eeea3e801ca60448b249bcfd3ac4a6c3abe429a807bcbd4c9cd12da87a5a9dc74fde64c0d44718632cae966b078397c6f9ec155c6a238f2347cf1", "01234567012345670123456701234567"}, - TestHash{"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, - } - for v, _ in test_vectors { - computed := sha3.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", ""}, + TestHash{"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", "abc"}, + TestHash{"9f9a327944a35988d67effc4fa748b3c07744f736ac70b479d8e12a3d10d6884d00a7ef593690305462e9e9030a67c51636fd346fd8fa0ee28a5ac2aee103d2e", "abcdbcdecdefdefgefghfghighijhi"}, + TestHash{"dbb124a0deda966eb4d199d0844fa0beb0770ea1ccddabcd335a7939a931ac6fb4fa6aebc6573f462ced2e4e7178277803be0d24d8bc2864626d9603109b7891", "jkijkljklmklmnlmnomnopnopq"}, + TestHash{"697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a", "a"}, + TestHash{"5679e353bc8eeea3e801ca60448b249bcfd3ac4a6c3abe429a807bcbd4c9cd12da87a5a9dc74fde64c0d44718632cae966b078397c6f9ec155c6a238f2347cf1", "01234567012345670123456701234567"}, + TestHash{"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"}, + } + for v, _ in test_vectors { + computed := sha3.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_shake_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"7f9c2ba4e88f827d616045507605853e", ""}, - TestHash{"f4202e3c5852f9182a0430fd8144f0a7", "The quick brown fox jumps over the lazy dog"}, - TestHash{"853f4538be0db9621a6cea659a06c110", "The quick brown fox jumps over the lazy dof"}, - } - for v, _ in test_vectors { - computed := shake.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"7f9c2ba4e88f827d616045507605853e", ""}, + TestHash{"f4202e3c5852f9182a0430fd8144f0a7", "The quick brown fox jumps over the lazy dog"}, + TestHash{"853f4538be0db9621a6cea659a06c110", "The quick brown fox jumps over the lazy dof"}, + } + for v, _ in test_vectors { + computed := shake.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_shake_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f", ""}, - TestHash{"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca", "The quick brown fox jumps over the lazy dog"}, - TestHash{"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401", "The quick brown fox jumps over the lazy dof"}, - } - for v, _ in test_vectors { - computed := shake.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f", ""}, + TestHash{"2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca", "The quick brown fox jumps over the lazy dog"}, + TestHash{"46b1ebb2e142c38b9ac9081bef72877fe4723959640fa57119b366ce6899d401", "The quick brown fox jumps over the lazy dof"}, + } + for v, _ in test_vectors { + computed := shake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_224 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", ""}, - TestHash{"c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", ""}, + TestHash{"c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", ""}, - TestHash{"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", ""}, + TestHash{"4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_384 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", ""}, - TestHash{"f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", ""}, + TestHash{"f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_keccak_512 :: proc(t: ^testing.T) { - // Test vectors from - // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf - // https://www.di-mgt.com.au/sha_testvectors.html - test_vectors := [?]TestHash { - TestHash{"0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", ""}, - TestHash{"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc"}, - } - for v, _ in test_vectors { - computed := keccak.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/examples/sha_all.pdf + // https://www.di-mgt.com.au/sha_testvectors.html + test_vectors := [?]TestHash { + TestHash{"0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", ""}, + TestHash{"18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", "abc"}, + } + for v, _ in test_vectors { + computed := keccak.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_whirlpool :: proc(t: ^testing.T) { - // Test vectors from - // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html - test_vectors := [?]TestHash { - TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, - TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, - TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, - TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, - TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, - TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, - TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, - TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, - TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, - TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, - TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, - TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, - TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, - } - for v, _ in test_vectors { - computed := whirlpool.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html + test_vectors := [?]TestHash { + TestHash{"19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288febcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3", ""}, + TestHash{"8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413aeff63a42391a39145a591a92200d560195e53b478584fdae231a", "a"}, + TestHash{"33e24e6cbebf168016942df8a7174048f9cebc45cbd829c3b94b401a498acb11c5abcca7f2a1238aaf534371e87a4e4b19758965d5a35a7cad87cf5517043d97", "ab"}, + TestHash{"4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5", "abc"}, + TestHash{"bda164f0b930c43a1bacb5df880b205d15ac847add35145bf25d991ae74f0b72b1ac794f8aacda5fcb3c47038c954742b1857b5856519de4d1e54bfa2fa4eac5", "abcd"}, + TestHash{"5d745e26ccb20fe655d39c9e7f69455758fbae541cb892b3581e4869244ab35b4fd6078f5d28b1f1a217452a67d9801033d92724a221255a5e377fe9e9e5f0b2", "abcde"}, + TestHash{"a73e425459567308ba5f9eb2ae23570d0d0575eb1357ecf6ac88d4e0358b0ac3ea2371261f5d4c070211784b525911b9eec0ad968429bb7c7891d341cff4e811", "abcdef"}, + TestHash{"08b388f68fd3eb51906ac3d3c699b8e9c3ac65d7ceb49d2e34f8a482cbc3082bc401cead90e85a97b8647c948bf35e448740b79659f3bee42145f0bd653d1f25", "abcdefg"}, + TestHash{"1f1a84d30612820243afe2022712f9dac6d07c4c8bb41b40eacab0184c8d82275da5bcadbb35c7ca1960ff21c90acbae8c14e48d9309e4819027900e882c7ad9", "abcdefgh"}, + TestHash{"11882bc9a31ac1cf1c41dcd9fd6fdd3ccdb9b017fc7f4582680134f314d7bb49af4c71f5a920bc0a6a3c1ff9a00021bf361d9867fe636b0bc1da1552e4237de4", "abcdefghi"}, + TestHash{"717163de24809ffcf7ff6d5aba72b8d67c2129721953c252a4ddfb107614be857cbd76a9d5927de14633d6bdc9ddf335160b919db5c6f12cb2e6549181912eef", "abcdefghij"}, + TestHash{"b97de512e91e3828b40d2b0fdce9ceb3c4a71f9bea8d88e75c4fa854df36725fd2b52eb6544edcacd6f8beddfea403cb55ae31f03ad62a5ef54e42ee82c3fb35", "The quick brown fox jumps over the lazy dog"}, + TestHash{"c27ba124205f72e6847f3e19834f925cc666d0974167af915bb462420ed40cc50900d85a1f923219d832357750492d5c143011a76988344c2635e69d06f2d38c", "The quick brown fox jumps over the lazy eog"}, + } + for v, _ in test_vectors { + computed := whirlpool.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_gost :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, - TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, - TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, - TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, - TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, - TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, - TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, - } - for v, _ in test_vectors { - computed := gost.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", ""}, + TestHash{"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011", "a"}, + TestHash{"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c", "abc"}, + TestHash{"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0", "message digest"}, + TestHash{"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76", "The quick brown fox jumps over the lazy dog"}, + TestHash{"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"6bc7b38989b28cf93ae8842bf9d752905910a7528a61e5bce0782de43e610c90", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", "This is message, length=32 bytes"}, + TestHash{"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", "Suppose the original message has length = 50 bytes"}, + } + for v, _ in test_vectors { + computed := gost.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_streebog_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, - TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, - TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb", ""}, + TestHash{"3e7dea7f2384b6c5a3d0e24aaa29c05e89ddd762145030ec22c71a6db8b2c1f4", "The quick brown fox jumps over the lazy dog"}, + TestHash{"36816a824dcbe7d6171aa58500741f2ea2757ae2e1784ab72c5c3c6c198d71da", "The quick brown fox jumps over the lazy dog."}, + } + for v, _ in test_vectors { + computed := streebog.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_streebog_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, - TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, - TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, - } - for v, _ in test_vectors { - computed := streebog.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a", ""}, + TestHash{"d2b793a0bb6cb5904828b5b6dcfb443bb8f33efc06ad09368878ae4cdc8245b97e60802469bed1e7c21a64ff0b179a6a1e0bb74d92965450a0adab69162c00fe", "The quick brown fox jumps over the lazy dog"}, + TestHash{"fe0c42f267d921f940faa72bd9fcf84f9f1bd7e9d055e9816e4c2ace1ec83be82d2957cd59b86e123d8f5adee80b3ca08a017599a9fc1a14d940cf87c77df070", "The quick brown fox jumps over the lazy dog."}, + } + for v, _ in test_vectors { + computed := streebog.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", ""}, - TestHash{"304c27fdbf308aea06955e331adc6814223a21fccd24c09fde9eda7b", "ube"}, - TestHash{"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"7dc5313b1c04512a174bd6503b89607aecbee0903d40a8a569c94eed", ""}, + TestHash{"304c27fdbf308aea06955e331adc6814223a21fccd24c09fde9eda7b", "ube"}, + TestHash{"cfb6848add73e1cb47994c4765df33b8f973702705a30a71fe4747a3", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", ""}, - TestHash{"e802fe2a73fbe5853408f051d040aeb3a76a4d7a0fc5c3415d1af090f76a2c81", "ube"}, - TestHash{"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"716f6e863f744b9ac22c97ec7b76ea5f5908bc5b2f67c61510bfc4751384ea7a", ""}, + TestHash{"e802fe2a73fbe5853408f051d040aeb3a76a4d7a0fc5c3415d1af090f76a2c81", "ube"}, + TestHash{"07663e00cf96fbc136cf7b1ee099c95346ba3920893d18cc8851f22ee2e36aa6", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"c6cbd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", ""}, - TestHash{"8f22f120b2b99dd4fd32b98c8c83bd87abd6413f7317be936b1997511247fc68ae781c6f42113224ccbc1567b0e88593", "ube"}, - TestHash{"f28742f7243990875d07e6afcff962edabdf7e9d19ddea6eae31d094c7fa6d9b00c8213a02ddf1e2d9894f3162345d85", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"c6cbd89c926ab525c242e6621f2f5fa73aa4afe3d9e24aed727faaadd6af38b620bdb623dd2b4788b1c8086984af8706", ""}, + TestHash{"8f22f120b2b99dd4fd32b98c8c83bd87abd6413f7317be936b1997511247fc68ae781c6f42113224ccbc1567b0e88593", "ube"}, + TestHash{"f28742f7243990875d07e6afcff962edabdf7e9d19ddea6eae31d094c7fa6d9b00c8213a02ddf1e2d9894f3162345d85", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"a8cfbbd73726062df0c6864dda65defe58ef0cc52a5625090fa17601e1eecd1b628e94f396ae402a00acc9eab77b4d4c2e852aaaa25a636d80af3fc7913ef5b8", ""}, - TestHash{"49a24ca8f230936f938c19484d46b58f13ea4448ddadafecdf01419b1e1dd922680be2de84069187973ab61b10574da2ee50cbeaade68ea9391c8ec041b76be0", "ube"}, - TestHash{"7bf805d0d8de36802b882e65d0515aa7682a2be97a9d9ec1399f4be2eff7de07684d7099124c8ac81c1c7c200d24ba68c6222e75062e04feb0e9dd589aa6e3b7", "BLAKE"}, - } - for v, _ in test_vectors { - computed := blake.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"a8cfbbd73726062df0c6864dda65defe58ef0cc52a5625090fa17601e1eecd1b628e94f396ae402a00acc9eab77b4d4c2e852aaaa25a636d80af3fc7913ef5b8", ""}, + TestHash{"49a24ca8f230936f938c19484d46b58f13ea4448ddadafecdf01419b1e1dd922680be2de84069187973ab61b10574da2ee50cbeaade68ea9391c8ec041b76be0", "ube"}, + TestHash{"7bf805d0d8de36802b882e65d0515aa7682a2be97a9d9ec1399f4be2eff7de07684d7099124c8ac81c1c7c200d24ba68c6222e75062e04feb0e9dd589aa6e3b7", "BLAKE"}, + } + for v, _ in test_vectors { + computed := blake.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake2b :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", ""}, - TestHash{"a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := blake2b.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", ""}, + TestHash{"a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := blake2b.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_blake2s :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9", ""}, - TestHash{"606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := blake2s.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9", ""}, + TestHash{"606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := blake2s.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_128 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"cdf26213a150dc3ecb610f18f6b38b46", ""}, - TestHash{"86be7afa339d0fc7cfc785e72f578d33", "a"}, - TestHash{"c14a12199c66e4ba84636b0f69144c77", "abc"}, - TestHash{"9e327b3d6e523062afc1132d7df9d1b8", "message digest"}, - TestHash{"fd2aa607f71dc8f510714922b371834e", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"a1aa0689d0fafa2ddc22e88b49133a06", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"d1e959eb179c911faea4624c60c5c702", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"cdf26213a150dc3ecb610f18f6b38b46", ""}, + TestHash{"86be7afa339d0fc7cfc785e72f578d33", "a"}, + TestHash{"c14a12199c66e4ba84636b0f69144c77", "abc"}, + TestHash{"9e327b3d6e523062afc1132d7df9d1b8", "message digest"}, + TestHash{"fd2aa607f71dc8f510714922b371834e", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"a1aa0689d0fafa2ddc22e88b49133a06", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"d1e959eb179c911faea4624c60c5c702", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_160 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, - TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, - TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, - TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, - TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, + TestHash{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, + TestHash{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, + TestHash{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, + TestHash{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_256 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", ""}, - TestHash{"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", "a"}, - TestHash{"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", "abc"}, - TestHash{"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", "message digest"}, - TestHash{"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", ""}, + TestHash{"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", "a"}, + TestHash{"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", "abc"}, + TestHash{"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", "message digest"}, + TestHash{"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_ripemd_320 :: proc(t: ^testing.T) { - // Test vectors from - // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html - test_vectors := [?]TestHash { - TestHash{"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", ""}, - TestHash{"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", "a"}, - TestHash{"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", "abc"}, - TestHash{"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", "message digest"}, - TestHash{"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors { - computed := ripemd.hash_320(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + // Test vectors from + // https://homes.esat.kuleuven.be/~bosselae/ripemd160.html + test_vectors := [?]TestHash { + TestHash{"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", ""}, + TestHash{"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", "a"}, + TestHash{"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", "abc"}, + TestHash{"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", "message digest"}, + TestHash{"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors { + computed := ripemd.hash_320(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e1616", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a52", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c62", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e16167a4e5849", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c517fca1a", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a0b11602f", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651890ffbcc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cab", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, - TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, - TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, - TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, - TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, - } - for v, _ in test_vectors { - computed := tiger.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3", ""}, + TestHash{"77befbef2e7ef8ab2ec8f93bf587a7fc613e247f5f247809", "a"}, + TestHash{"2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93", "abc"}, + TestHash{"d981f8cb78201a950dcf3048751e441c517fca1aa55a29f6", "message digest"}, + TestHash{"1714a472eee57d30040412bfcc55032a0b11602ff37beee9", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"0f7bf9a19b9c58f2b7610df7e84f0ac3a71c631e7b53f78e", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"8dcea680a17583ee502ba38a3c368651890ffbccdc49a8cc", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + TestHash{"1c14795529fd9f207a958f84c52f11e887fa0cabdfd91bfd", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + TestHash{"6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075", "The quick brown fox jumps over the lazy dog"}, + } + for v, _ in test_vectors { + computed := tiger.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_128 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b92", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec62", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_128(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b92", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec62", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_128(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_160 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b924aa8313f", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb8555", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_160(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b924aa8313f", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb8555", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_160(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_tiger2_192 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"4441be75f6018773c206c22745374b924aa8313fef919f41", ""}, - TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb85558b4976d8", "The quick brown fox jumps over the lazy dog"}, - TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8d9bdd3df", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := tiger2.hash_192(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"4441be75f6018773c206c22745374b924aa8313fef919f41", ""}, + TestHash{"976abff8062a2e9dcea3a1ace966ed9c19cb85558b4976d8", "The quick brown fox jumps over the lazy dog"}, + TestHash{"09c11330283a27efb51930aa7dc1ec624ff738a8d9bdd3df", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := tiger2.hash_192(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_sm3 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", ""}, - TestHash{"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", "abc"}, - TestHash{"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"}, - TestHash{"5fdfe814b8573ca021983970fc79b2218c9570369b4859684e2e4c3fc76cb8ea", "The quick brown fox jumps over the lazy dog"}, - TestHash{"ca27d14a42fc04c1e5ecf574a95a8c2d70ecb5805e9b429026ccac8f28b20098", "The quick brown fox jumps over the lazy cog"}, - } - for v, _ in test_vectors { - computed := sm3.hash(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", ""}, + TestHash{"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", "abc"}, + TestHash{"debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"}, + TestHash{"5fdfe814b8573ca021983970fc79b2218c9570369b4859684e2e4c3fc76cb8ea", "The quick brown fox jumps over the lazy dog"}, + TestHash{"ca27d14a42fc04c1e5ecf574a95a8c2d70ecb5805e9b429026ccac8f28b20098", "The quick brown fox jumps over the lazy cog"}, + } + for v, _ in test_vectors { + computed := sm3.hash(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"2c99df889b019309051c60fecc2bd285a774940e43175b76b2626630", ""}, - TestHash{"e715f969fb61b203a97e494aab92d91a9cec52f0933436b0d63bf722", "a"}, - TestHash{"c2b1967e635bd55b6a4d36f863ac4a877be302251d68692873007281", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"2c99df889b019309051c60fecc2bd285a774940e43175b76b2626630", ""}, + TestHash{"e715f969fb61b203a97e494aab92d91a9cec52f0933436b0d63bf722", "a"}, + TestHash{"c2b1967e635bd55b6a4d36f863ac4a877be302251d68692873007281", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"46e64619c18bb0a92a5e87185a47eef83ca747b8fcc8e1412921357e326df434", ""}, - TestHash{"d52c0c130a1bc0ae5136375637a52773e150c71efe1c968df8956f6745b05386", "a"}, - TestHash{"fc4214867025a8af94c614353b3553b10e561ae749fc18c40e5fd44a7a4ecd1b", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"46e64619c18bb0a92a5e87185a47eef83ca747b8fcc8e1412921357e326df434", ""}, + TestHash{"d52c0c130a1bc0ae5136375637a52773e150c71efe1c968df8956f6745b05386", "a"}, + TestHash{"fc4214867025a8af94c614353b3553b10e561ae749fc18c40e5fd44a7a4ecd1b", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"2fe5f71b1b3290d3c017fb3c1a4d02a5cbeb03a0476481e25082434a881994b0ff99e078d2c16b105ad069b569315328", ""}, - TestHash{"77de897ca4fd5dadfbcbd1d8d4ea3c3c1426855e38661325853e92b069f3fe156729f6bbb9a5892c7c18a77f1cb9d0bb", "a"}, - TestHash{"6f73d9b9b8ed362f8180fb26020725b40bd6ca75b3b947405f26c4c37a885ce028876dc42e379d2faf6146fed3ea0e42", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"2fe5f71b1b3290d3c017fb3c1a4d02a5cbeb03a0476481e25082434a881994b0ff99e078d2c16b105ad069b569315328", ""}, + TestHash{"77de897ca4fd5dadfbcbd1d8d4ea3c3c1426855e38661325853e92b069f3fe156729f6bbb9a5892c7c18a77f1cb9d0bb", "a"}, + TestHash{"6f73d9b9b8ed362f8180fb26020725b40bd6ca75b3b947405f26c4c37a885ce028876dc42e379d2faf6146fed3ea0e42", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_jh_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"90ecf2f76f9d2c8017d979ad5ab96b87d58fc8fc4b83060f3f900774faa2c8fabe69c5f4ff1ec2b61d6b316941cedee117fb04b1f4c5bc1b919ae841c50eec4f", ""}, - TestHash{"f12c87e986daff17c481c81a99a39b603ca6bafcd320c5735523b97cb9a26f7681bad62ffad9aad0e21160a05f773fb0d1434ca4cbcb0483f480a171ada1561b", "a"}, - TestHash{"bafb8e710b35eabeb1a48220c4b0987c2c985b6e73b7b31d164bfb9d67c94d99d7bc43b474a25e647cd6cc36334b6a00a5f2a85fae74907fd2885c6168132fe7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := jh.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"90ecf2f76f9d2c8017d979ad5ab96b87d58fc8fc4b83060f3f900774faa2c8fabe69c5f4ff1ec2b61d6b316941cedee117fb04b1f4c5bc1b919ae841c50eec4f", ""}, + TestHash{"f12c87e986daff17c481c81a99a39b603ca6bafcd320c5735523b97cb9a26f7681bad62ffad9aad0e21160a05f773fb0d1434ca4cbcb0483f480a171ada1561b", "a"}, + TestHash{"bafb8e710b35eabeb1a48220c4b0987c2c985b6e73b7b31d164bfb9d67c94d99d7bc43b474a25e647cd6cc36334b6a00a5f2a85fae74907fd2885c6168132fe7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := jh.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_224 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"f2e180fb5947be964cd584e22e496242c6a329c577fc4ce8c36d34c3", ""}, - TestHash{"2dfa5bd326c23c451b1202d99e6cee98a98c45927e1a31077f538712", "a"}, - TestHash{"c8a3e7274d599900ae673419683c3626a2e49ed57308ed2687508bef", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_224(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"f2e180fb5947be964cd584e22e496242c6a329c577fc4ce8c36d34c3", ""}, + TestHash{"2dfa5bd326c23c451b1202d99e6cee98a98c45927e1a31077f538712", "a"}, + TestHash{"c8a3e7274d599900ae673419683c3626a2e49ed57308ed2687508bef", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_224(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_256 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"1a52d11d550039be16107f9c58db9ebcc417f16f736adb2502567119f0083467", ""}, - TestHash{"3645c245bb31223ad93c80885b719aa40b4bed0a9d9d6e7c11fe99e59ca350b5", "a"}, - TestHash{"2679d98913bee62e57fdbdde97ddb328373548c6b24fc587cc3d08f2a02a529c", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_256(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"1a52d11d550039be16107f9c58db9ebcc417f16f736adb2502567119f0083467", ""}, + TestHash{"3645c245bb31223ad93c80885b719aa40b4bed0a9d9d6e7c11fe99e59ca350b5", "a"}, + TestHash{"2679d98913bee62e57fdbdde97ddb328373548c6b24fc587cc3d08f2a02a529c", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_256(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_384 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"ac353c1095ace21439251007862d6c62f829ddbe6de4f78e68d310a9205a736d8b11d99bffe448f57a1cfa2934f044a5", ""}, - TestHash{"13fce7bd9fc69b67cc12c77e765a0a97794c585f89df39fbff32408e060d7d9225c7e80fd87da647686888bda896c342", "a"}, - TestHash{"1c446cd70a6de52c9db386f5305aae029fe5a4120bc6230b7cd3a5e1ef1949cc8e6d2548c24cd7347b5ba512628a62f6", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_384(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"ac353c1095ace21439251007862d6c62f829ddbe6de4f78e68d310a9205a736d8b11d99bffe448f57a1cfa2934f044a5", ""}, + TestHash{"13fce7bd9fc69b67cc12c77e765a0a97794c585f89df39fbff32408e060d7d9225c7e80fd87da647686888bda896c342", "a"}, + TestHash{"1c446cd70a6de52c9db386f5305aae029fe5a4120bc6230b7cd3a5e1ef1949cc8e6d2548c24cd7347b5ba512628a62f6", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_384(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_groestl_512 :: proc(t: ^testing.T) { - test_vectors := [?]TestHash { - TestHash{"6d3ad29d279110eef3adbd66de2a0345a77baede1557f5d099fce0c03d6dc2ba8e6d4a6633dfbd66053c20faa87d1a11f39a7fbe4a6c2f009801370308fc4ad8", ""}, - TestHash{"9ef345a835ee35d6d0d462ce45f722d84b5ca41fde9c81a98a22cfb4f7425720511b03a258cdc055bf8e9179dc9bdb5d88bed906c71125d4cf0cd39d3d7bebc7", "a"}, - TestHash{"862849fd911852cd54beefa88759db4cead0ef8e36aaf15398303c5c4cbc016d9b4c42b32081cbdcba710d2693e7663d244fae116ec29ffb40168baf44f944e7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, - } - for v, _ in test_vectors { - computed := groestl.hash_512(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors := [?]TestHash { + TestHash{"6d3ad29d279110eef3adbd66de2a0345a77baede1557f5d099fce0c03d6dc2ba8e6d4a6633dfbd66053c20faa87d1a11f39a7fbe4a6c2f009801370308fc4ad8", ""}, + TestHash{"9ef345a835ee35d6d0d462ce45f722d84b5ca41fde9c81a98a22cfb4f7425720511b03a258cdc055bf8e9179dc9bdb5d88bed906c71125d4cf0cd39d3d7bebc7", "a"}, + TestHash{"862849fd911852cd54beefa88759db4cead0ef8e36aaf15398303c5c4cbc016d9b4c42b32081cbdcba710d2693e7663d244fae116ec29ffb40168baf44f944e7", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, + } + for v, _ in test_vectors { + computed := groestl.hash_512(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_128 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"c68f39913f901f3ddf44c707357a7d70", ""}, - TestHash{"0cd40739683e15f01ca5dbceef4059f1", "a"}, - TestHash{"9e40ed883fb63e985d299b40cda2b8f2", "abc"}, - TestHash{"3caf4a79e81adcd6d1716bcc1cef4573", "message digest"}, - TestHash{"dc502247fb3eb8376109eda32d361d82", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"44068770868768964d1f2c3bff4aa3d8", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"de5eb3f7d9eb08fae7a07d68e3047ec6", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_128_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"ee6bbf4d6a46a679b3a856c88538bb98", ""}, - TestHash{"5cd07f03330c3b5020b29ba75911e17d", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_128_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"184b8482a0c050dca54b59c7f05bf5dd", ""}, - TestHash{"f23fbe704be8494bfa7a7fb4f8ab09e5", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_128_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"c68f39913f901f3ddf44c707357a7d70", ""}, + TestHash{"0cd40739683e15f01ca5dbceef4059f1", "a"}, + TestHash{"9e40ed883fb63e985d299b40cda2b8f2", "abc"}, + TestHash{"3caf4a79e81adcd6d1716bcc1cef4573", "message digest"}, + TestHash{"dc502247fb3eb8376109eda32d361d82", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"44068770868768964d1f2c3bff4aa3d8", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"de5eb3f7d9eb08fae7a07d68e3047ec6", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_128_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"ee6bbf4d6a46a679b3a856c88538bb98", ""}, + TestHash{"5cd07f03330c3b5020b29ba75911e17d", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_128_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"184b8482a0c050dca54b59c7f05bf5dd", ""}, + TestHash{"f23fbe704be8494bfa7a7fb4f8ab09e5", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_128_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_160 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"d353c3ae22a25401d257643836d7231a9a95f953", ""}, - TestHash{"4da08f514a7275dbc4cece4a347385983983a830", "a"}, - TestHash{"b21e876c4d391e2a897661149d83576b5530a089", "abc"}, - TestHash{"43a47f6f1c016207f08be8115c0977bf155346da", "message digest"}, - TestHash{"eba9fa6050f24c07c29d1834a60900ea4e32e61b", "abcdefghijklmnopqrstuvwxyz"}, - TestHash{"c30bce448cf8cfe957c141e90c0a063497cdfeeb", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, - TestHash{"97dc988d97caae757be7523c4e8d4ea63007a4b9", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_160_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"1d33aae1be4146dbaaca0b6e70d7a11f10801525", ""}, - TestHash{"e0a5be29627332034d4dd8a910a1a0e6fe04084d", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_160_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"255158cfc1eed1a7be7c55ddd64d9790415b933b", ""}, - TestHash{"f5147df7abc5e3c81b031268927c2b5761b5a2b5", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_160_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"d353c3ae22a25401d257643836d7231a9a95f953", ""}, + TestHash{"4da08f514a7275dbc4cece4a347385983983a830", "a"}, + TestHash{"b21e876c4d391e2a897661149d83576b5530a089", "abc"}, + TestHash{"43a47f6f1c016207f08be8115c0977bf155346da", "message digest"}, + TestHash{"eba9fa6050f24c07c29d1834a60900ea4e32e61b", "abcdefghijklmnopqrstuvwxyz"}, + TestHash{"c30bce448cf8cfe957c141e90c0a063497cdfeeb", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, + TestHash{"97dc988d97caae757be7523c4e8d4ea63007a4b9", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_160_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"1d33aae1be4146dbaaca0b6e70d7a11f10801525", ""}, + TestHash{"e0a5be29627332034d4dd8a910a1a0e6fe04084d", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_160_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"255158cfc1eed1a7be7c55ddd64d9790415b933b", ""}, + TestHash{"f5147df7abc5e3c81b031268927c2b5761b5a2b5", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_160_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_192 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"e9c48d7903eaf2a91c5b350151efcb175c0fc82de2289a4e", ""}, - TestHash{"b359c8835647f5697472431c142731ff6e2cddcacc4f6e08", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_192_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"4a8372945afa55c7dead800311272523ca19d42ea47b72da", ""}, - TestHash{"856c19f86214ea9a8a2f0c4b758b973cce72a2d8ff55505c", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_192_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"4839d0626f95935e17ee2fc4509387bbe2cc46cb382ffe85", ""}, - TestHash{"5ffa3b3548a6e2cfc06b7908ceb5263595df67cf9c4b9341", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_192_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"e9c48d7903eaf2a91c5b350151efcb175c0fc82de2289a4e", ""}, + TestHash{"b359c8835647f5697472431c142731ff6e2cddcacc4f6e08", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_192_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"4a8372945afa55c7dead800311272523ca19d42ea47b72da", ""}, + TestHash{"856c19f86214ea9a8a2f0c4b758b973cce72a2d8ff55505c", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_192_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"4839d0626f95935e17ee2fc4509387bbe2cc46cb382ffe85", ""}, + TestHash{"5ffa3b3548a6e2cfc06b7908ceb5263595df67cf9c4b9341", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_192_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_224 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"c5aae9d47bffcaaf84a8c6e7ccacd60a0dd1932be7b1a192b9214b6d", ""}, - TestHash{"731814ba5605c59b673e4caae4ad28eeb515b3abc2b198336794e17b", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_224_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"3e56243275b3b81561750550e36fcd676ad2f5dd9e15f2e89e6ed78e", ""}, - TestHash{"742f1dbeeaf17f74960558b44f08aa98bdc7d967e6c0ab8f799b3ac1", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_224_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"4a0513c032754f5582a758d35917ac9adf3854219b39e3ac77d1837e", ""}, - TestHash{"67b3cb8d4068e3641fa4f156e03b52978b421947328bfb9168c7655d", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_224_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"c5aae9d47bffcaaf84a8c6e7ccacd60a0dd1932be7b1a192b9214b6d", ""}, + TestHash{"731814ba5605c59b673e4caae4ad28eeb515b3abc2b198336794e17b", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_224_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"3e56243275b3b81561750550e36fcd676ad2f5dd9e15f2e89e6ed78e", ""}, + TestHash{"742f1dbeeaf17f74960558b44f08aa98bdc7d967e6c0ab8f799b3ac1", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_224_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"4a0513c032754f5582a758d35917ac9adf3854219b39e3ac77d1837e", ""}, + TestHash{"67b3cb8d4068e3641fa4f156e03b52978b421947328bfb9168c7655d", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_224_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } @(test) test_haval_256 :: proc(t: ^testing.T) { - test_vectors_3 := [?]TestHash { - TestHash{"4f6938531f0bc8991f62da7bbd6f7de3fad44562b8c6f4ebf146d5b4e46f7c17", ""}, - TestHash{"47c838fbb4081d9525a0ff9b1e2c05a98f625714e72db289010374e27db021d8", "a"}, - } - for v, _ in test_vectors_3 { - computed := haval.hash_256_3(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_4 := [?]TestHash { - TestHash{"c92b2e23091e80e375dadce26982482d197b1a2521be82da819f8ca2c579b99b", ""}, - TestHash{"e686d2394a49b44d306ece295cf9021553221db132b36cc0ff5b593d39295899", "a"}, - } - for v, _ in test_vectors_4 { - computed := haval.hash_256_4(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } - test_vectors_5 := [?]TestHash { - TestHash{"be417bb4dd5cfb76c7126f4f8eeb1553a449039307b1a3cd451dbfdc0fbbe330", ""}, - TestHash{"de8fd5ee72a5e4265af0a756f4e1a1f65c9b2b2f47cf17ecf0d1b88679a3e22f", "a"}, - } - for v, _ in test_vectors_5 { - computed := haval.hash_256_5(v.str) - computed_str := hex_string(computed[:]) - expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) - } + test_vectors_3 := [?]TestHash { + TestHash{"4f6938531f0bc8991f62da7bbd6f7de3fad44562b8c6f4ebf146d5b4e46f7c17", ""}, + TestHash{"47c838fbb4081d9525a0ff9b1e2c05a98f625714e72db289010374e27db021d8", "a"}, + } + for v, _ in test_vectors_3 { + computed := haval.hash_256_3(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_4 := [?]TestHash { + TestHash{"c92b2e23091e80e375dadce26982482d197b1a2521be82da819f8ca2c579b99b", ""}, + TestHash{"e686d2394a49b44d306ece295cf9021553221db132b36cc0ff5b593d39295899", "a"}, + } + for v, _ in test_vectors_4 { + computed := haval.hash_256_4(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } + test_vectors_5 := [?]TestHash { + TestHash{"be417bb4dd5cfb76c7126f4f8eeb1553a449039307b1a3cd451dbfdc0fbbe330", ""}, + TestHash{"de8fd5ee72a5e4265af0a756f4e1a1f65c9b2b2f47cf17ecf0d1b88679a3e22f", "a"}, + } + for v, _ in test_vectors_5 { + computed := haval.hash_256_5(v.str) + computed_str := hex_string(computed[:]) + expect(t, computed_str == v.hash, fmt.tprintf("Expected: %s for input of %s, but got %s instead", v.hash, v.str, computed_str)) + } } diff --git a/tests/core/encoding/json/test_core_json.odin b/tests/core/encoding/json/test_core_json.odin index 4f415c008..6f2e8c35a 100644 --- a/tests/core/encoding/json/test_core_json.odin +++ b/tests/core/encoding/json/test_core_json.odin @@ -12,18 +12,15 @@ when ODIN_TEST { log :: testing.log } else { expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) TEST_count += 1 if !condition { TEST_fail += 1 - fmt.println(message) + fmt.printf("[%v] %v\n", loc, message) return } - fmt.println(" PASS") } log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) } } @@ -33,7 +30,7 @@ main :: proc() { parse_json(&t) marshal_json(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } @test diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 5cb59e001..f9f7a2992 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -173,23 +173,20 @@ TESTS :: []TEST{ } when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } test_file_path :: proc(filename: string) -> (path: string) { @@ -229,7 +226,7 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { written += wprintf(writer, "[DOCTYPE] %v\n", doc.doctype.ident) if len(doc.doctype.rest) > 0 { - wprintf(writer, "\t%v\n", doc.doctype.rest) + wprintf(writer, "\t%v\n", doc.doctype.rest) } } @@ -238,9 +235,9 @@ doc_to_string :: proc(doc: ^xml.Document) -> (result: string) { } if doc.root != nil { - wprintln(writer, " --- ") - print_element(writer, doc.root) - wprintln(writer, " --- ") + wprintln(writer, " --- ") + print_element(writer, doc.root) + wprintln(writer, " --- ") } return written, .None @@ -293,7 +290,7 @@ run_tests :: proc(t: ^testing.T) { for test in TESTS { path := test_file_path(test.filename) - printf("\nTrying to parse %v\n\n", path) + log(t, fmt.tprintf("Trying to parse %v", path)) doc, err := xml.parse(path, test.options, Silent) defer xml.destroy(doc) @@ -323,7 +320,7 @@ run_tests :: proc(t: ^testing.T) { } main :: proc() { - t := testing.T{} + t := testing.T{} track: mem.Tracking_Allocator mem.tracking_allocator_init(&track, context.allocator) @@ -338,5 +335,5 @@ main :: proc() { } } - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } \ No newline at end of file diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index 8baa604b6..b81af01a5 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -14,18 +14,15 @@ when ODIN_TEST { log :: testing.log } else { expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) TEST_count += 1 if !condition { TEST_fail += 1 - fmt.println(" FAIL:", message) + fmt.printf("[%v] %v", loc, message) return } - fmt.println(" PASS") } log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) } } @@ -34,7 +31,7 @@ main :: proc() { test_benchmark_runner(&t) test_xxhash_vectors(&t) test_crc64_vectors(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } /* diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 155b69298..48d9ca1d2 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -25,38 +25,49 @@ import "core:time" import "core:runtime" -WRITE_PPM_ON_FAIL :: #config(WRITE_PPM_ON_FAIL, false) -TEST_SUITE_PATH :: "assets/PNG" +WRITE_PPM_ON_FAIL :: #config(WRITE_PPM_ON_FAIL, false) +TEST_FILE_PATH_PREFIX :: "tests/core/assets/PNG" TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } + I_Error :: image.Error main :: proc() { t := testing.T{} png_test(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) +} + +test_file_path :: proc(filename: string, extension := "png") -> (path: string) { + + path = fmt.tprintf("%v%v/%v.%v", ODIN_ROOT, TEST_FILE_PATH_PREFIX, filename, extension) + temp := transmute([]u8)path + + for r, i in path { + if r == '\\' { + temp[i] = '/' + } + } + return path } PNG_Test :: struct { @@ -1461,7 +1472,7 @@ run_png_suite :: proc(t: ^testing.T, suite: []PNG_Test) -> (subtotal: int) { context = runtime.default_context() for file in suite { - test_file := fmt.tprintf("%v/%v.png", TEST_SUITE_PATH, file.file) + test_file := test_file_path(file.file) img: ^png.Image err: png.Error diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index 90d913d10..53711d3ec 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -10,34 +10,29 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } - main :: proc() { - t := testing.T{} - test_parse_demo(&t) + t := testing.T{} + test_parse_demo(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } - @test test_parse_demo :: proc(t: ^testing.T) { pkg, ok := parser.parse_package_from_path("examples/demo") diff --git a/tests/core/strings/test_core_strings.odin b/tests/core/strings/test_core_strings.odin index fc1518349..c5436f5c1 100644 --- a/tests/core/strings/test_core_strings.odin +++ b/tests/core/strings/test_core_strings.odin @@ -8,56 +8,53 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect :: testing.expect + log :: testing.log } else { - expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { - fmt.printf("[%v] ", loc) - TEST_count += 1 - if !condition { - TEST_fail += 1 - fmt.println(message) - return - } - fmt.println(" PASS") - } - log :: proc(t: ^testing.T, v: any, loc := #caller_location) { - fmt.printf("[%v] ", loc) - fmt.printf("log: %v\n", v) - } + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] LOG:\n\t%v\n", loc, v) + } } main :: proc() { - t := testing.T{} - test_index_any_small_string_not_found(&t) - test_index_any_larger_string_not_found(&t) - test_index_any_small_string_found(&t) - test_index_any_larger_string_found(&t) + t := testing.T{} + test_index_any_small_string_not_found(&t) + test_index_any_larger_string_not_found(&t) + test_index_any_small_string_found(&t) + test_index_any_larger_string_found(&t) - fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + fmt.printf("\n%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) } @test test_index_any_small_string_not_found :: proc(t: ^testing.T) { - index := strings.index_any(".", "/:\"") - log(t, index) - expect(t, index == -1, "index_any should be negative") + index := strings.index_any(".", "/:\"") + log(t, index) + expect(t, index == -1, "index_any should be negative") } @test test_index_any_larger_string_not_found :: proc(t: ^testing.T) { - index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"") - expect(t, index == -1, "index_any should be negative") + index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"") + expect(t, index == -1, "index_any should be negative") } @test test_index_any_small_string_found :: proc(t: ^testing.T) { - index := strings.index_any(".", "/:.\"") - expect(t, index == 0, "index_any should be 0") + index := strings.index_any(".", "/:.\"") + expect(t, index == 0, "index_any should be 0") } @test test_index_any_larger_string_found :: proc(t: ^testing.T) { - index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"") - expect(t, index == 8, "index_any should be 8") + index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"") + expect(t, index == 8, "index_any should be 8") } From 7ec88d24302dcdea38ac09996a2279f4de4f6a25 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 5 Dec 2021 21:06:33 +0100 Subject: [PATCH 0083/1258] [xml] Add option. --- .../entity/example/entity_example.odin | 4 +- core/encoding/xml/example/xml_example.odin | 53 +++++++++++-------- core/encoding/xml/xml_reader.odin | 26 +++++++-- tests/core/encoding/xml/test_core_xml.odin | 10 ++-- 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/core/encoding/entity/example/entity_example.odin b/core/encoding/entity/example/entity_example.odin index 882203f48..6fc377f9d 100644 --- a/core/encoding/entity/example/entity_example.odin +++ b/core/encoding/entity/example/entity_example.odin @@ -64,8 +64,8 @@ main :: proc() { mem.tracking_allocator_init(&track, context.allocator) context.allocator = mem.tracking_allocator(&track) - _main() - //_entities() + // _main() + _entities() if len(track.allocation_map) > 0 { println() diff --git a/core/encoding/xml/example/xml_example.odin b/core/encoding/xml/example/xml_example.odin index 085252e92..daa3c5dab 100644 --- a/core/encoding/xml/example/xml_example.odin +++ b/core/encoding/xml/example/xml_example.odin @@ -2,35 +2,40 @@ package xml_example import "core:encoding/xml" import "core:os" -import "core:path" import "core:mem" import "core:fmt" - -/* - Silent error handler for the parser. -*/ -Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} - -OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } +import "core:time" +import "core:strings" +import "core:hash" example :: proc() { using fmt - filename := path.join(ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml") - defer delete(filename) + doc: ^xml.Document + err: xml.Error - doc, err := xml.parse(filename, OPTIONS, Error_Handler) + DOC :: #load("../../../../tests/core/assets/XML/unicode.xml") + + parse_duration: time.Duration + { + time.SCOPED_TICK_DURATION(&parse_duration) + doc, err = xml.parse(DOC, xml.Options{flags={.Ignore_Unsupported}}) + } defer xml.destroy(doc) + ms := time.duration_milliseconds(parse_duration) + speed := (f64(1000.0) / ms) * f64(len(DOC)) / 1_024.0 / 1_024.0 + fmt.printf("Parse time: %v bytes in %.2f ms (%.2f MiB/s).\n", len(DOC), ms, speed) + if err != .None { printf("Load/Parse error: %v\n", err) if err == .File_Error { - printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename) + println("\"unicode.xml\" not found. Did you run \"tests\\download_assets.py\"?") } os.exit(1) } - printf("\"%v\" loaded and parsed.\n", filename) + println("\"unicode.xml\" loaded and parsed.") charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist") if !charlist_ok { @@ -40,17 +45,19 @@ example :: proc() { printf("Found `` with %v children.\n", len(charlist.children)) - for char in charlist.children { - if char.ident != "character" { - eprintf("Expected ``, got `<%v>`\n", char.ident) - os.exit(1) - } + crc32 := doc_hash(doc) + printf("[%v] CRC32: 0x%08x\n", "🎉" if crc32 == 0xcaa042b9 else "🤬", crc32) +} - if _, ok := xml.find_attribute_val_by_key(char, "dec"); !ok { - eprintln("`` attribute not found.") - os.exit(1) - } - } +doc_hash :: proc(doc: ^xml.Document, print := false) -> (crc32: u32) { + buf: strings.Builder + defer strings.destroy_builder(&buf) + w := strings.to_writer(&buf) + + xml.print(w, doc) + tree := strings.to_string(buf) + if print { fmt.println(tree) } + return hash.crc32(transmute([]u8)tree) } main :: proc() { diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index 6f49b8e08..b169bd57a 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -71,6 +71,12 @@ Option_Flag :: enum { This option decodes them when encountered. */ Decode_SGML_Entities, + + /* + If a tag body has a comment, it will be stripped unless this option is given. + */ + Keep_Tag_Body_Comments, + } Option_Flags :: bit_set[Option_Flag; u8] @@ -413,15 +419,29 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err /* This should be a tag's body text. */ - body_text := scan_string(t, t.offset) or_return + body_text := scan_string(t, t.offset) or_return + needs_processing := .Unbox_CDATA in opts.flags + needs_processing |= .Decode_SGML_Entities in opts.flags - decode_opts := entity.XML_Decode_Options{ .Comment_Strip } + if !needs_processing { + element.value = strings.intern_get(&doc.intern, body_text) + continue + } + + decode_opts := entity.XML_Decode_Options{} + if .Keep_Tag_Body_Comments not_in opts.flags { + decode_opts += { .Comment_Strip } + } if .Decode_SGML_Entities not_in opts.flags { decode_opts += { .No_Entity_Decode } } + if .Unbox_CDATA in opts.flags { - decode_opts += { .Unbox_CDATA, .Decode_CDATA } + decode_opts += { .Unbox_CDATA } + if .Decode_SGML_Entities in opts.flags { + decode_opts += { .Decode_CDATA } + } } decoded, decode_err := entity.decode_xml(body_text, decode_opts) diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index f9f7a2992..7669afe97 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -8,9 +8,7 @@ import "core:io" import "core:fmt" import "core:hash" -Silent :: proc(pos: xml.Pos, fmt: string, args: ..any) { - // Custom (silent) error handler. -} +Silent :: proc(pos: xml.Pos, format: string, args: ..any) {} OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, }, expected_doctype = "", @@ -75,7 +73,7 @@ TESTS :: []TEST{ }, expected_doctype = "恥ずべきフクロウ", }, - crc32 = 0x6d38ac58, + crc32 = 0xad31d8e8, }, { @@ -131,7 +129,7 @@ TESTS :: []TEST{ }, expected_doctype = "html", }, - crc32 = 0xdb4a1e79, + crc32 = 0x573c1033, }, { @@ -306,7 +304,7 @@ run_tests :: proc(t: ^testing.T) { expect(t, err == test.err, err_msg) failed |= crc32 != test.crc32 - err_msg = tprintf("Expected CRC 0x%08x, got 0x%08x", test.crc32, crc32) + err_msg = tprintf("Expected CRC 0x%08x, got 0x%08x, with options %v", test.crc32, crc32, test.options) expect(t, crc32 == test.crc32, err_msg) if failed { From a7138b22a5d98631c2d4fa3f573a249252da556f Mon Sep 17 00:00:00 2001 From: Phil H Date: Wed, 1 Dec 2021 14:16:23 -0800 Subject: [PATCH 0084/1258] Fix 'unmarsal' typo --- core/encoding/json/unmarshal.odin | 50 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index fe3137b7e..bd48011f1 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -52,11 +52,11 @@ unmarshal_any :: proc(data: []byte, v: any, spec := DEFAULT_SPECIFICATION, alloc if p.spec == .MJSON { #partial switch p.curr_token.kind { case .Ident, .String: - return unmarsal_object(&p, data, .EOF) + return unmarshal_object(&p, data, .EOF) } } - return unmarsal_value(&p, data) + return unmarshal_value(&p, data) } @@ -148,7 +148,7 @@ assign_float :: proc(val: any, f: $T) -> bool { @(private) -unmarsal_string :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.Type_Info) -> bool { +unmarshal_string_token :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.Type_Info) -> bool { val := val switch dst in &val { case string: @@ -198,7 +198,7 @@ unmarsal_string :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.Type_Inf @(private) -unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { +unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token} token := p.curr_token @@ -257,7 +257,7 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { case .Ident: advance_token(p) if p.spec == .MJSON { - if unmarsal_string(p, any{v.data, ti.id}, token.text, ti) { + if unmarshal_string_token(p, any{v.data, ti.id}, token.text, ti) { return nil } } @@ -266,7 +266,7 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { case .String: advance_token(p) str := unquote_string(token, p.spec, p.allocator) or_return - if unmarsal_string(p, any{v.data, ti.id}, str, ti) { + if unmarshal_string_token(p, any{v.data, ti.id}, str, ti) { return nil } delete(str, p.allocator) @@ -274,10 +274,10 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { case .Open_Brace: - return unmarsal_object(p, v, .Close_Brace) + return unmarshal_object(p, v, .Close_Brace) case .Open_Bracket: - return unmarsal_array(p, v) + return unmarshal_array(p, v) case: if p.spec != .JSON { @@ -312,16 +312,16 @@ unmarsal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { @(private) -unmarsal_expect_token :: proc(p: ^Parser, kind: Token_Kind, loc := #caller_location) -> Token { +unmarshal_expect_token :: proc(p: ^Parser, kind: Token_Kind, loc := #caller_location) -> Token { prev := p.curr_token err := expect_token(p, kind) - assert(err == nil, "unmarsal_expect_token") + assert(err == nil, "unmarshal_expect_token") return prev } @(private) -unmarsal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unmarshal_Error) { +unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unmarshal_Error) { UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token} if end_token == .Close_Brace { @@ -342,7 +342,7 @@ unmarsal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unma key, _ := parse_object_key(p, p.allocator) defer delete(key, p.allocator) - unmarsal_expect_token(p, .Colon) + unmarshal_expect_token(p, .Colon) fields := reflect.struct_fields_zipped(ti.id) @@ -378,7 +378,7 @@ unmarsal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unma field_ptr := rawptr(uintptr(v.data) + offset) field := any{field_ptr, type.id} - unmarsal_value(p, field) or_return + unmarshal_value(p, field) or_return if parse_comma(p) { break struct_loop @@ -407,11 +407,11 @@ unmarsal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unma map_loop: for p.curr_token.kind != end_token { key, _ := parse_object_key(p, p.allocator) - unmarsal_expect_token(p, .Colon) + unmarshal_expect_token(p, .Colon) mem.zero_slice(elem_backing) - if err := unmarsal_value(p, map_backing_value); err != nil { + if err := unmarshal_value(p, map_backing_value); err != nil { delete(key, p.allocator) return err } @@ -443,7 +443,7 @@ unmarsal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unma enumerated_array_loop: for p.curr_token.kind != end_token { key, _ := parse_object_key(p, p.allocator) - unmarsal_expect_token(p, .Colon) + unmarshal_expect_token(p, .Colon) defer delete(key, p.allocator) index := -1 @@ -460,7 +460,7 @@ unmarsal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unma index_ptr := rawptr(uintptr(v.data) + uintptr(index*t.elem_size)) index_any := any{index_ptr, t.elem.id} - unmarsal_value(p, index_any) or_return + unmarshal_value(p, index_any) or_return if parse_comma(p) { break enumerated_array_loop @@ -480,10 +480,10 @@ unmarsal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unma @(private) -unmarsal_count_array :: proc(p: ^Parser) -> (length: uintptr) { +unmarshal_count_array :: proc(p: ^Parser) -> (length: uintptr) { p_backup := p^ p.allocator = mem.nil_allocator() - unmarsal_expect_token(p, .Open_Bracket) + unmarshal_expect_token(p, .Open_Bracket) array_length_loop: for p.curr_token.kind != .Close_Bracket { _, _ = parse_value(p) length += 1 @@ -497,9 +497,9 @@ unmarsal_count_array :: proc(p: ^Parser) -> (length: uintptr) { } @(private) -unmarsal_array :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { +unmarshal_array :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { assign_array :: proc(p: ^Parser, base: rawptr, elem: ^reflect.Type_Info, length: uintptr) -> Unmarshal_Error { - unmarsal_expect_token(p, .Open_Bracket) + unmarshal_expect_token(p, .Open_Bracket) for idx: uintptr = 0; p.curr_token.kind != .Close_Bracket; idx += 1 { assert(idx < length) @@ -507,14 +507,14 @@ unmarsal_array :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { elem_ptr := rawptr(uintptr(base) + idx*uintptr(elem.size)) elem := any{elem_ptr, elem.id} - unmarsal_value(p, elem) or_return + unmarshal_value(p, elem) or_return if parse_comma(p) { break } } - unmarsal_expect_token(p, .Close_Bracket) + unmarshal_expect_token(p, .Close_Bracket) return nil @@ -524,7 +524,7 @@ unmarsal_array :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { ti := reflect.type_info_base(type_info_of(v.id)) - length := unmarsal_count_array(p) + length := unmarshal_count_array(p) #partial switch t in ti.variant { case reflect.Type_Info_Slice: @@ -578,4 +578,4 @@ unmarsal_array :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { } return UNSUPPORTED_TYPE -} \ No newline at end of file +} From 6e61abc7d06f22129f93110a9f652c3eec21f0c6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 6 Dec 2021 12:04:59 +0100 Subject: [PATCH 0085/1258] [xml] Initial optimization. --- core/encoding/xml/xml_reader.odin | 68 +++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index b169bd57a..0315b0e05 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -26,6 +26,7 @@ package xml Jeroen van Rijn: Initial implementation. */ +import "core:bytes" import "core:strings" import "core:encoding/entity" import "core:mem" @@ -39,6 +40,12 @@ DEFAULT_Options :: Options{ } Option_Flag :: enum { + /* + If the caller says that input may be modified, we can perform in-situ parsing. + If this flag isn't provided, the XML parser first duplicates the input so that it can. + */ + Input_May_Be_Modified, + /* Document MUST start with ` (doc: ^Document, err: Error) { + data := data context.allocator = allocator opts := validate_options(options) or_return + /* + If `.Input_May_Be_Modified` is not specified, we duplicate the input so that we can modify it in-place. + */ + if .Input_May_Be_Modified not_in opts.flags { + data = bytes.clone(data) + } + t := &Tokenizer{} init(t, string(data), path, error_handler) doc = new(Document) doc.allocator = allocator doc.tokenizer = t + doc.input = data - strings.intern_init(&doc.intern, allocator, allocator) + // strings.intern_init(&doc.intern, allocator, allocator) - err = .Unexpected_Token - element, parent: ^Element + err = .Unexpected_Token + element, parent: ^Element tag_is_open := false @@ -292,8 +313,7 @@ parse_from_slice :: proc(data: []u8, options := DEFAULT_Options, path := "", err case: if .Error_on_Unsupported in opts.flags { error(t, t.offset, "Unhandled: (doc: ^Document, err: Error) { context.allocator = allocator + options := options data, data_ok := os.read_entire_file(filename) - defer delete(data) - if !data_ok { return {}, .File_Error } + options.flags += { .Input_May_Be_Modified } + return parse_from_slice(data, options, filename, error_handler, allocator) } @@ -499,10 +517,16 @@ destroy :: proc(doc: ^Document) { if doc == nil { return } free_element(doc.root) - strings.intern_destroy(&doc.intern) delete(doc.prolog) delete(doc.comments) + delete(doc.input) + + for s in doc.strings_to_free { + delete(s) + } + delete(doc.strings_to_free) + free(doc) } @@ -538,8 +562,8 @@ parse_attribute :: proc(doc: ^Document) -> (attr: Attr, offset: int, err: Error) _ = expect(t, .Eq) or_return value := expect(t, .String) or_return - attr.key = strings.intern_get(&doc.intern, key.text) - attr.val = strings.intern_get(&doc.intern, value.text) + attr.key = key.text + attr.val = value.text err = .None return @@ -651,7 +675,7 @@ parse_doctype :: proc(doc: ^Document) -> (err: Error) { t := doc.tokenizer tok := expect(t, .Ident) or_return - doc.doctype.ident = strings.intern_get(&doc.intern, tok.text) + doc.doctype.ident = tok.text skip_whitespace(t) offset := t.offset @@ -660,6 +684,6 @@ parse_doctype :: proc(doc: ^Document) -> (err: Error) { /* -1 because the current offset is that of the closing tag, so the rest of the DOCTYPE tag ends just before it. */ - doc.doctype.rest = strings.intern_get(&doc.intern, string(t.src[offset : t.offset - 1])) + doc.doctype.rest = string(t.src[offset : t.offset - 1]) return .None } \ No newline at end of file From 9d4fe9035626f4f36ae84ca731ffc5fca00ebe17 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 7 Dec 2021 17:35:41 +0000 Subject: [PATCH 0086/1258] Fix bugs in big.Rat caused by typos --- core/math/big/rat.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/math/big/rat.odin b/core/math/big/rat.odin index 121f0ab50..837af6fd3 100644 --- a/core/math/big/rat.odin +++ b/core/math/big/rat.odin @@ -112,14 +112,14 @@ rat_set_u64 :: proc(dst: ^Rat, x: u64, allocator := context.allocator) -> (err: assert_if_nil(dst) context.allocator = allocator internal_set(&dst.a, x) or_return - internal_set(&dst.a, 1) or_return + internal_set(&dst.b, 1) or_return return } rat_set_i64 :: proc(dst: ^Rat, x: i64, allocator := context.allocator) -> (err: Error) { assert_if_nil(dst) context.allocator = allocator internal_set(&dst.a, x) or_return - internal_set(&dst.a, 1) or_return + internal_set(&dst.b, 1) or_return return } @@ -265,7 +265,7 @@ rat_mul_rat :: proc(dst, x, y: ^Rat, allocator := context.allocator) -> (err: Er return } - int_sub(&dst.a, &x.a, &y.a) or_return + int_mul(&dst.a, &x.a, &y.a) or_return internal_int_mul_denom(&dst.b, &x.b, &y.b) or_return return internal_rat_norm(dst) } From c94098c2ab550425075509e3031bacc3a588a6db Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 9 Dec 2021 16:14:04 +0100 Subject: [PATCH 0087/1258] [math/big] Fix int_set and int_get. --- core/math/big/common.odin | 13 +++---- core/math/big/internal.odin | 67 ++++++++++++++++++++++++------------- tests/core/math/big/test.py | 27 +++++++++------ 3 files changed, 66 insertions(+), 41 deletions(-) diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 5b7d162bc..c9aab4afa 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -158,13 +158,14 @@ Error :: enum int { Invalid_Pointer = 2, Invalid_Argument = 3, - Assignment_To_Immutable = 4, - Max_Iterations_Reached = 5, - Buffer_Overflow = 6, - Integer_Overflow = 7, + Assignment_To_Immutable = 10, + Max_Iterations_Reached = 11, + Buffer_Overflow = 12, + Integer_Overflow = 13, + Integer_Underflow = 14, - Division_by_Zero = 8, - Math_Domain_Error = 9, + Division_by_Zero = 30, + Math_Domain_Error = 31, Cannot_Open_File = 50, Cannot_Read_File = 51, diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 4702e76a3..abe592f9b 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -34,6 +34,10 @@ package math_big import "core:mem" import "core:intrinsics" import rnd "core:math/rand" +import "core:builtin" + +import "core:fmt" +__ :: fmt /* Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7. @@ -1880,8 +1884,6 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al where intrinsics.type_is_integer(T) { context.allocator = allocator - src := src - internal_error_if_immutable(dest) or_return /* Most internal procs asssume an Int to have already been initialize, @@ -1892,13 +1894,27 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al dest.flags = {} // We're not -Inf, Inf, NaN or Immutable. dest.used = 0 - dest.sign = .Zero_or_Positive if src >= 0 else .Negative - src = internal_abs(src) + dest.sign = .Negative if src < 0 else .Zero_or_Positive - #no_bounds_check for src != 0 { - dest.digit[dest.used] = DIGIT(src) & _MASK + temp := src + + is_maximally_negative := src == min(T) + if is_maximally_negative { + /* + Prevent overflow on abs() + */ + temp += 1 + } + temp = -temp if temp < 0 else temp + + #no_bounds_check for temp != 0 { + dest.digit[dest.used] = DIGIT(temp) & _MASK dest.used += 1 - src >>= _DIGIT_BITS + temp >>= _DIGIT_BITS + } + + if is_maximally_negative { + return internal_sub(dest, dest, 1) } internal_zero_unused(dest) return nil @@ -2307,28 +2323,31 @@ internal_int_get_i32 :: proc(a: ^Int) -> (res: i32, err: Error) { } internal_get_i32 :: proc { internal_int_get_i32, } -/* - TODO: Think about using `count_bits` to check if the value could be returned completely, - and maybe return max(T), .Integer_Overflow if not? -*/ internal_int_get :: proc(a: ^Int, $T: typeid) -> (res: T, err: Error) where intrinsics.type_is_integer(T) { - size_in_bits := int(size_of(T) * 8) - i := int((size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS) - i = min(int(a.used), i) - - #no_bounds_check for ; i >= 0; i -= 1 { - res <<= uint(0) if size_in_bits <= _DIGIT_BITS else _DIGIT_BITS - res |= T(a.digit[i]) - if size_in_bits <= _DIGIT_BITS { - break + /* + Calculate target bit size. + */ + target_bit_size := int(size_of(T) * 8) + when !intrinsics.type_is_unsigned(T) { + if a.sign == .Zero_or_Positive { + target_bit_size -= 1 } } + bits_used := internal_count_bits(a) + + if bits_used > target_bit_size { + if a.sign == .Negative { + return min(T), .Integer_Underflow + } + return max(T), .Integer_Overflow + } + + for i := a.used; i > 0; i -= 1 { + res <<= _DIGIT_BITS + res |= T(a.digit[i - 1]) + } when !intrinsics.type_is_unsigned(T) { - /* - Mask off sign bit. - */ - res ~= 1 << uint(size_in_bits - 1) /* Set the sign. */ diff --git a/tests/core/math/big/test.py b/tests/core/math/big/test.py index 6b17336bc..629e76e6e 100644 --- a/tests/core/math/big/test.py +++ b/tests/core/math/big/test.py @@ -127,17 +127,22 @@ def we_iterate(): # Error enum values # class Error(Enum): - Okay = 0 - Out_Of_Memory = 1 - Invalid_Pointer = 2 - Invalid_Argument = 3 - Unknown_Error = 4 - Max_Iterations_Reached = 5 - Buffer_Overflow = 6 - Integer_Overflow = 7 - Division_by_Zero = 8 - Math_Domain_Error = 9 - Unimplemented = 127 + Okay = 0 + Out_Of_Memory = 1 + Invalid_Pointer = 2 + Invalid_Argument = 3 + Unknown_Error = 4 + Assignment_To_Immutable = 10 + Max_Iterations_Reached = 11 + Buffer_Overflow = 12 + Integer_Overflow = 13 + Integer_Underflow = 14 + Division_by_Zero = 30 + Math_Domain_Error = 31 + Cannot_Open_File = 50 + Cannot_Read_File = 51 + Cannot_Write_File = 52 + Unimplemented = 127 # # Disable garbage collection From b2b79b86f00a229cc9d9cc0226ffb594a4e4d910 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 9 Dec 2021 16:31:54 +0100 Subject: [PATCH 0088/1258] [math/big] Return 0, .Integer_Underflow if trying to get a negative number to an unsigned int. --- core/math/big/internal.odin | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index abe592f9b..70914228e 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2332,7 +2332,12 @@ internal_int_get :: proc(a: ^Int, $T: typeid) -> (res: T, err: Error) where intr if a.sign == .Zero_or_Positive { target_bit_size -= 1 } + } else { + if a.sign == .Negative { + return 0, .Integer_Underflow + } } + bits_used := internal_count_bits(a) if bits_used > target_bit_size { From 1e9b30666fc9ff462877b413a92d15d11870ec35 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 9 Dec 2021 15:34:17 +0000 Subject: [PATCH 0089/1258] Minor style change --- core/math/big/common.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 5b7d162bc..d534cc90e 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -215,7 +215,7 @@ _MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS) /* Maximum number of digits. - Must be small enough such that `_bit_count` does not overflow. - - Must be small enough such that `_radix_size` for base 2 does not overflow. + - Must be small enough such that `_radix_size` for base 2 does not overflow. `_radix_size` needs two additional bytes for zero termination and sign. */ _MAX_BIT_COUNT :: (max(int) - 2) @@ -251,7 +251,7 @@ Order :: enum i8 { } Endianness :: enum i8 { - Little = -1, - Platform = 0, - Big = 1, -}; \ No newline at end of file + Little = -1, + Platform = 0, + Big = 1, +} \ No newline at end of file From 1e17d5d86f135d1c1f004a475a4700bd082773ba Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 9 Dec 2021 15:34:35 +0000 Subject: [PATCH 0090/1258] Add utility procedures to get low values --- core/math/big/internal.odin | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 4702e76a3..a5e1e7ba3 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2307,6 +2307,35 @@ internal_int_get_i32 :: proc(a: ^Int) -> (res: i32, err: Error) { } internal_get_i32 :: proc { internal_int_get_i32, } +internal_get_low_u32 :: proc(a: ^Int) -> u32 #no_bounds_check { + if a == nil { + return 0 + } + + if a.used == 0 { + return 0 + } + + return u32(a.digit[0]) +} +internal_get_low_u64 :: proc(a: ^Int) -> u64 #no_bounds_check { + if a == nil { + return 0 + } + + if a.used == 0 { + return 0 + } + + v := u64(a.digit[0]) + when size_of(DIGIT) == 4 { + if a.used > 1 { + return u64(a.digit[1])<<32 | v + } + } + return v +} + /* TODO: Think about using `count_bits` to check if the value could be returned completely, and maybe return max(T), .Integer_Overflow if not? From 1d7c9cf87223971620e1812ca3c84c9581a1c43a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 9 Dec 2021 15:35:00 +0000 Subject: [PATCH 0091/1258] Make `strconv` more robust --- core/strconv/strconv.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 6b3a91b4c..6ea8b39e6 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -882,7 +882,9 @@ unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: str return -1 } - assert(len(lit) >= 2) + if len(lit) < 2 { + return + } if lit[0] == '`' { return lit[1:len(lit)-1], false, true } From e2f53ee107862d7c5b7dca6df3e68add74273336 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 11 Dec 2021 12:02:23 +0000 Subject: [PATCH 0092/1258] Fix #1362 `strings.index_any` --- core/strings/strings.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index a8199e0cf..7a9744d83 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -504,8 +504,8 @@ index_any :: proc(s, chars: string) -> int { } } - for c in chars { - if i := index_rune(s, c); i >= 0 { + for c in s { + if i := index_rune(chars, c); i >= 0 { return i } } From 85f8c8df91022fae3fef996cd45b9e631e6b2a66 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 11 Dec 2021 12:04:34 +0000 Subject: [PATCH 0093/1258] Fix `fields_proc` in `strings` and `bytes` --- core/bytes/bytes.odin | 2 +- core/strings/strings.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/bytes/bytes.odin b/core/bytes/bytes.odin index cbc1e2506..1e83b93c8 100644 --- a/core/bytes/bytes.odin +++ b/core/bytes/bytes.odin @@ -1143,7 +1143,7 @@ fields_proc :: proc(s: []byte, f: proc(rune) -> bool, allocator := context.alloc } if start >= 0 { - append(&subslices, s[start : end]) + append(&subslices, s[start : len(s)]) } return subslices[:] diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 7a9744d83..72f29e5d6 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1288,7 +1288,7 @@ fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.alloc } if start >= 0 { - append(&substrings, s[start : end]) + append(&substrings, s[start : len(s)]) } return substrings[:] From 84b84d9f7de0d17e74ca0b482f784497b509c282 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 11 Dec 2021 12:47:05 +0000 Subject: [PATCH 0094/1258] Fix `rat_set_f64` --- core/math/big/rat.odin | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/math/big/rat.odin b/core/math/big/rat.odin index 837af6fd3..c3efc30aa 100644 --- a/core/math/big/rat.odin +++ b/core/math/big/rat.odin @@ -42,9 +42,9 @@ rat_set_f64 :: proc(dst: ^Rat, f: f64, allocator := context.allocator) -> (err: dst.a.sign = .Negative if f < 0 else .Zero_or_Positive if shift > 0 { - internal_int_shl_digit(&dst.b, shift) or_return + internal_int_shl(&dst.b, &dst.b, shift) or_return } else { - internal_int_shl_digit(&dst.a, -shift) or_return + internal_int_shl(&dst.a, &dst.a, -shift) or_return } return internal_rat_norm(dst) @@ -389,9 +389,9 @@ internal_rat_to_float :: proc($T: typeid, z: ^Rat, allocator := context.allocato internal_int_abs(b2, b) or_return if shift := MSIZE2 - exp; shift > 0 { - internal_int_shl_digit(a2, shift) or_return - } else { - internal_int_shl_digit(b2, -shift) or_return + internal_int_shl(a2, a2, shift) or_return + } else if shift < 0 { + internal_int_shl(b2, b2, -shift) or_return } q, r := &Int{}, &Int{} From 938744b2760193ff1dffc8ae03c740e91a4dfec5 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 11 Dec 2021 15:22:24 +0100 Subject: [PATCH 0095/1258] [math/big] Rename `internal_int_shl_digit` to `_private_int_shl_leg`. Same for the SHR variant. These are pure implementation details to shift by a leg/word at a time. Prevent accidental usage. --- core/math/big/internal.odin | 74 +-------------------- core/math/big/logical.odin | 33 +--------- core/math/big/private.odin | 118 +++++++++++++++++++++++++++------- tests/core/math/big/test.odin | 8 +-- tests/core/math/big/test.py | 32 ++++----- 5 files changed, 116 insertions(+), 149 deletions(-) diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 69497b150..437f6e5fc 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2648,7 +2648,7 @@ internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, all Shift by as many digits in the bit count. */ if bits >= _DIGIT_BITS { - internal_shr_digit(quotient, bits / _DIGIT_BITS) or_return + _private_int_shr_leg(quotient, bits / _DIGIT_BITS) or_return } /* @@ -2687,37 +2687,6 @@ internal_int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.all } internal_shr :: proc { internal_int_shr, } -/* - Shift right by `digits` * _DIGIT_BITS bits. -*/ -internal_int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { - context.allocator = allocator - - if digits <= 0 { return nil } - - /* - If digits > used simply zero and return. - */ - if digits > quotient.used { return internal_zero(quotient) } - - /* - Much like `int_shl_digit`, this is implemented using a sliding window, - except the window goes the other way around. - - b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> - /\ | ----> - \-------------------/ ----> - */ - - #no_bounds_check for x := 0; x < (quotient.used - digits); x += 1 { - quotient.digit[x] = quotient.digit[x + digits] - } - quotient.used -= digits - internal_zero_unused(quotient) - return internal_clamp(quotient) -} -internal_shr_digit :: proc { internal_int_shr_digit, } - /* Shift right by a certain bit count with sign extension. */ @@ -2756,7 +2725,7 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca Shift by as many digits in the bit count as we have. */ if bits >= _DIGIT_BITS { - internal_shl_digit(dest, bits / _DIGIT_BITS) or_return + _private_int_shl_leg(dest, bits / _DIGIT_BITS) or_return } /* @@ -2786,45 +2755,6 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca } internal_shl :: proc { internal_int_shl, } - -/* - Shift left by `digits` * _DIGIT_BITS bits. -*/ -internal_int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { - context.allocator = allocator - - if digits <= 0 { return nil } - - /* - No need to shift a zero. - */ - if #force_inline internal_is_zero(quotient) { - return nil - } - - /* - Resize `quotient` to accomodate extra digits. - */ - #force_inline internal_grow(quotient, quotient.used + digits) or_return - - /* - Increment the used by the shift amount then copy upwards. - */ - - /* - Much like `int_shr_digit`, this is implemented using a sliding window, - except the window goes the other way around. - */ - #no_bounds_check for x := quotient.used; x > 0; x -= 1 { - quotient.digit[x+digits-1] = quotient.digit[x-1] - } - - quotient.used += digits - mem.zero_slice(quotient.digit[:digits]) - return nil -} -internal_shl_digit :: proc { internal_int_shl_digit, } - /* Count bits in an `Int`. Assumes `a` not to be `nil` and to have been initialized. diff --git a/core/math/big/logical.odin b/core/math/big/logical.odin index dbcf566c8..e7e55cc47 100644 --- a/core/math/big/logical.odin +++ b/core/math/big/logical.odin @@ -86,21 +86,6 @@ int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.allocator) - } shr :: proc { int_shr, } -/* - Shift right by `digits` * _DIGIT_BITS bits. -*/ -int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { - /* - Check that `quotient` is usable. - */ - assert_if_nil(quotient) - context.allocator = allocator - - internal_clear_if_uninitialized(quotient) or_return - return #force_inline internal_int_shr_digit(quotient, digits) -} -shr_digit :: proc { int_shr_digit, } - /* Shift right by a certain bit count with sign extension. */ @@ -124,20 +109,4 @@ int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> ( internal_clear_if_uninitialized(dest, src) or_return return #force_inline internal_int_shl(dest, src, bits) } -shl :: proc { int_shl, } - - -/* - Shift left by `digits` * _DIGIT_BITS bits. -*/ -int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { - /* - Check that `quotient` is usable. - */ - assert_if_nil(quotient) - context.allocator = allocator - - internal_clear_if_uninitialized(quotient) or_return - return #force_inline internal_int_shl_digit(quotient, digits) -} -shl_digit :: proc { int_shl_digit, }; \ No newline at end of file +shl :: proc { int_shl, } \ No newline at end of file diff --git a/core/math/big/private.odin b/core/math/big/private.odin index 14a27f600..9989a208a 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -211,12 +211,12 @@ _private_int_mul_toom :: proc(dest, a, b: ^Int, allocator := context.allocator) /* P = b1*x^4+ S2*x^3+ S1*x^2+ a1*x + a0; */ - internal_shl_digit(b1, 4 * B) or_return - internal_shl_digit(S2, 3 * B) or_return + _private_int_shl_leg(b1, 4 * B) or_return + _private_int_shl_leg(S2, 3 * B) or_return internal_add(b1, b1, S2) or_return - internal_shl_digit(S1, 2 * B) or_return + _private_int_shl_leg(S1, 2 * B) or_return internal_add(b1, b1, S1) or_return - internal_shl_digit(a1, 1 * B) or_return + _private_int_shl_leg(a1, 1 * B) or_return internal_add(b1, b1, a1) or_return internal_add(dest, b1, a0) or_return @@ -317,8 +317,8 @@ _private_int_mul_karatsuba :: proc(dest, a, b: ^Int, allocator := context.alloca /* shift by B. */ - internal_shl_digit(t1, B) or_return /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<= n then x = x - n @@ -2026,7 +2026,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> ( /* q1 = x / b**(k-1) */ - internal_shr_digit(q, um - 1) + _private_int_shr_leg(q, um - 1) /* According to HAC this optimization is ok. @@ -2040,7 +2040,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> ( /* q3 = q2 / b**(k+1) */ - internal_shr_digit(q, um + 1) + _private_int_shr_leg(q, um + 1) /* x = x mod b**(k+1), quick (no division) @@ -2062,7 +2062,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> ( */ if internal_is_negative(x) { internal_set(q, 1) or_return - internal_shl_digit(q, um + 1) or_return + _private_int_shl_leg(q, um + 1) or_return internal_add(x, x, q) or_return } @@ -3192,6 +3192,74 @@ _private_copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0)) -> return nil } + +/* + Shift left by `digits` * _DIGIT_BITS bits. +*/ +_private_int_shl_leg :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + if digits <= 0 { return nil } + + /* + No need to shift a zero. + */ + if #force_inline internal_is_zero(quotient) { + return nil + } + + /* + Resize `quotient` to accomodate extra digits. + */ + #force_inline internal_grow(quotient, quotient.used + digits) or_return + + /* + Increment the used by the shift amount then copy upwards. + */ + + /* + Much like `_private_int_shr_leg`, this is implemented using a sliding window, + except the window goes the other way around. + */ + #no_bounds_check for x := quotient.used; x > 0; x -= 1 { + quotient.digit[x+digits-1] = quotient.digit[x-1] + } + + quotient.used += digits + mem.zero_slice(quotient.digit[:digits]) + return nil +} + +/* + Shift right by `digits` * _DIGIT_BITS bits. +*/ +_private_int_shr_leg :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { + context.allocator = allocator + + if digits <= 0 { return nil } + + /* + If digits > used simply zero and return. + */ + if digits > quotient.used { return internal_zero(quotient) } + + /* + Much like `int_shl_digit`, this is implemented using a sliding window, + except the window goes the other way around. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + + #no_bounds_check for x := 0; x < (quotient.used - digits); x += 1 { + quotient.digit[x] = quotient.digit[x + digits] + } + quotient.used -= digits + internal_zero_unused(quotient) + return internal_clamp(quotient) +} + /* ======================== End of private procedures ======================= diff --git a/tests/core/math/big/test.odin b/tests/core/math/big/test.odin index 07fa0364b..81f1956dc 100644 --- a/tests/core/math/big/test.odin +++ b/tests/core/math/big/test.odin @@ -208,7 +208,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { /* dest = shr_digit(src, digits) */ -@export test_shr_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { +@export test_shr_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { context = runtime.default_context() err: big.Error @@ -216,7 +216,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { defer big.internal_destroy(src) if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err} } - if err = #force_inline big.internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} } + if err = #force_inline big._private_int_shr_leg(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} } r := print_to_buffer(src) return PyRes{res = r, err = nil} @@ -225,7 +225,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { /* dest = shl_digit(src, digits) */ -@export test_shl_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { +@export test_shl_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { context = runtime.default_context() err: big.Error @@ -233,7 +233,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { defer big.internal_destroy(src) if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err} } - if err = #force_inline big.internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} } + if err = #force_inline big._private_int_shl_leg(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} } r := print_to_buffer(src) return PyRes{res = r, err = nil} diff --git a/tests/core/math/big/test.py b/tests/core/math/big/test.py index 629e76e6e..d292a3ff4 100644 --- a/tests/core/math/big/test.py +++ b/tests/core/math/big/test.py @@ -187,8 +187,8 @@ int_sqrt = load(l.test_sqrt, [c_char_p ], Res) int_root_n = load(l.test_root_n, [c_char_p, c_longlong], Res) # Logical operations -int_shl_digit = load(l.test_shl_digit, [c_char_p, c_longlong], Res) -int_shr_digit = load(l.test_shr_digit, [c_char_p, c_longlong], Res) +int_shl_leg = load(l.test_shl_leg, [c_char_p, c_longlong], Res) +int_shr_leg = load(l.test_shr_leg, [c_char_p, c_longlong], Res) int_shl = load(l.test_shl, [c_char_p, c_longlong], Res) int_shr = load(l.test_shr, [c_char_p, c_longlong], Res) int_shr_signed = load(l.test_shr_signed, [c_char_p, c_longlong], Res) @@ -402,17 +402,17 @@ def test_root_n(number = 0, root = 0, expected_error = Error.Okay): return test("test_root_n", res, [number, root], expected_error, expected_result) -def test_shl_digit(a = 0, digits = 0, expected_error = Error.Okay): +def test_shl_leg(a = 0, digits = 0, expected_error = Error.Okay): args = [arg_to_odin(a), digits] - res = int_shl_digit(*args) + res = int_shl_leg(*args) expected_result = None if expected_error == Error.Okay: expected_result = a << (digits * 60) - return test("test_shl_digit", res, [a, digits], expected_error, expected_result) + return test("test_shl_leg", res, [a, digits], expected_error, expected_result) -def test_shr_digit(a = 0, digits = 0, expected_error = Error.Okay): +def test_shr_leg(a = 0, digits = 0, expected_error = Error.Okay): args = [arg_to_odin(a), digits] - res = int_shr_digit(*args) + res = int_shr_leg(*args) expected_result = None if expected_error == Error.Okay: if a < 0: @@ -421,7 +421,7 @@ def test_shr_digit(a = 0, digits = 0, expected_error = Error.Okay): else: expected_result = a >> (digits * 60) - return test("test_shr_digit", res, [a, digits], expected_error, expected_result) + return test("test_shr_leg", res, [a, digits], expected_error, expected_result) def test_shl(a = 0, bits = 0, expected_error = Error.Okay): args = [arg_to_odin(a), bits] @@ -556,12 +556,12 @@ TESTS = { test_root_n: [ [ 1298074214633706907132624082305024, 2, Error.Okay, ], ], - test_shl_digit: [ + test_shl_leg: [ [ 3192, 1 ], [ 1298074214633706907132624082305024, 2 ], [ 1024, 3 ], ], - test_shr_digit: [ + test_shr_leg: [ [ 3680125442705055547392, 1 ], [ 1725436586697640946858688965569256363112777243042596638790631055949824, 2 ], [ 219504133884436710204395031992179571, 2 ], @@ -619,10 +619,10 @@ total_failures = 0 # test_shr_signed also tests shr, so we're not going to test shr randomly. # RANDOM_TESTS = [ - test_add, test_sub, test_mul, test_sqr, test_div, - test_log, test_pow, test_sqrt, test_root_n, - test_shl_digit, test_shr_digit, test_shl, test_shr_signed, - test_gcd, test_lcm, test_is_square, + test_add, test_sub, test_mul, test_sqr, + test_log, test_pow, test_sqrt, test_root_n, + test_shl_leg, test_shr_leg, test_shl, test_shr_signed, + test_gcd, test_lcm, test_is_square, test_div, ] SKIP_LARGE = [ test_pow, test_root_n, # test_gcd, @@ -719,9 +719,9 @@ if __name__ == '__main__': a = randint(1, 1 << BITS) b = TEST_ROOT_N_PARAMS[index] index = (index + 1) % len(TEST_ROOT_N_PARAMS) - elif test_proc == test_shl_digit: + elif test_proc == test_shl_leg: b = randint(0, 10); - elif test_proc == test_shr_digit: + elif test_proc == test_shr_leg: a = abs(a) b = randint(0, 10); elif test_proc == test_shl: From b7c78da1fbabca7288088e0ce257c06c058bcf73 Mon Sep 17 00:00:00 2001 From: Rehkitzdev Date: Sat, 11 Dec 2021 18:38:32 +0100 Subject: [PATCH 0096/1258] Fix storeInt call in webgl glue code --- vendor/wasm/WebGL/runtime.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vendor/wasm/WebGL/runtime.js b/vendor/wasm/WebGL/runtime.js index b6994a8ec..18b540b5c 100644 --- a/vendor/wasm/WebGL/runtime.js +++ b/vendor/wasm/WebGL/runtime.js @@ -416,7 +416,7 @@ class WebGLInterface { log = log.substring(0, n); this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log)) - storeInt(length_ptr, n); + this.mem.storeInt(length_ptr, n); } }, GetShaderInfoLog: (shader, buf_ptr, buf_len, length_ptr) => { @@ -429,7 +429,7 @@ class WebGLInterface { log = log.substring(0, n); this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log)) - storeInt(length_ptr, n); + this.mem.storeInt(length_ptr, n); } }, GetShaderiv: (shader, pname, p) => { @@ -439,11 +439,11 @@ class WebGLInterface { if (log === null) { log = "(unknown error)"; } - storeInt(p, log.length+1); + this.mem.storeInt(p, log.length+1); } else if (pname == 35720) { let source = this.ctx.getShaderSource(this.shaders[shader]); let sourceLength = (source === null || source.length == 0) ? 0 : source.length+1; - storeInt(p, sourceLength); + this.mem.storeInt(p, sourceLength); } else { let param = this.ctx.getShaderParameter(this.shaders[shader], pname); this.mem.storeI32(p, param); @@ -994,7 +994,7 @@ class WebGLInterface { let n = Math.min(buf_len, name.length); name = name.substring(0, n); this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(name)) - storeInt(length_ptr, n); + this.mem.storeInt(length_ptr, n); }, UniformBlockBinding: (program, uniformBlockIndex, uniformBlockBinding) => { this.assertWebGL2(); From 08a081ed45520eac4c4ebd8501fa3ab7970b5c77 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 11 Dec 2021 17:42:58 +0000 Subject: [PATCH 0097/1258] Improve debug symbol retention with `-debug -opt:0` --- src/llvm_backend_opt.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index de925655f..5b8468799 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -48,12 +48,6 @@ LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data return LLVMIsAAllocaInst(value) != nullptr; } -void lb_add_must_preserve_predicate_pass(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level) { - if (false && optimization_level == 0 && m->debug_builder) { - // LLVMAddInternalizePassWithMustPreservePredicate(fpm, m, lb_must_preserve_predicate_callback); - } -} - #if LLVM_VERSION_MAJOR < 12 #define LLVM_ADD_CONSTANT_VALUE_PASS(fpm) LLVMAddConstantPropagationPass(fpm) @@ -61,7 +55,10 @@ void lb_add_must_preserve_predicate_pass(lbModule *m, LLVMPassManagerRef fpm, i3 #define LLVM_ADD_CONSTANT_VALUE_PASS(fpm) #endif -void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm) { +void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) { + if (optimization_level == 0 && build_context.ODIN_DEBUG) { + return; + } LLVMAddPromoteMemoryToRegisterPass(fpm); LLVMAddMergedLoadStoreMotionPass(fpm); LLVM_ADD_CONSTANT_VALUE_PASS(fpm); @@ -78,14 +75,12 @@ void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool // TODO(bill): Determine which opt definitions should exist in the first place optimization_level = gb_clamp(optimization_level, 0, 2); - lb_add_must_preserve_predicate_pass(m, fpm, optimization_level); - if (ignore_memcpy_pass) { - lb_basic_populate_function_pass_manager(fpm); + lb_basic_populate_function_pass_manager(fpm, optimization_level); return; } else if (optimization_level == 0) { LLVMAddMemCpyOptPass(fpm); - lb_basic_populate_function_pass_manager(fpm); + lb_basic_populate_function_pass_manager(fpm, optimization_level); return; } @@ -96,7 +91,7 @@ void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool LLVMPassManagerBuilderPopulateFunctionPassManager(pmb, fpm); #else LLVMAddMemCpyOptPass(fpm); - lb_basic_populate_function_pass_manager(fpm); + lb_basic_populate_function_pass_manager(fpm, optimization_level); LLVMAddSCCPPass(fpm); @@ -114,11 +109,9 @@ void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef // TODO(bill): Determine which opt definitions should exist in the first place optimization_level = gb_clamp(optimization_level, 0, 2); - lb_add_must_preserve_predicate_pass(m, fpm, optimization_level); - if (optimization_level == 0) { LLVMAddMemCpyOptPass(fpm); - lb_basic_populate_function_pass_manager(fpm); + lb_basic_populate_function_pass_manager(fpm, optimization_level); return; } @@ -191,6 +184,9 @@ void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPa // NOTE(bill): Treat -opt:3 as if it was -opt:2 // TODO(bill): Determine which opt definitions should exist in the first place optimization_level = gb_clamp(optimization_level, 0, 2); + if (optimization_level == 0 && build_context.ODIN_DEBUG) { + return; + } LLVMAddAlwaysInlinerPass(mpm); LLVMAddStripDeadPrototypesPass(mpm); From 4423bc0706a6a1a64cf419720fd65bc723fdf58a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 12 Dec 2021 01:10:40 +0000 Subject: [PATCH 0098/1258] Fix typo --- core/strings/strings.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 72f29e5d6..3f703372f 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -504,8 +504,8 @@ index_any :: proc(s, chars: string) -> int { } } - for c in s { - if i := index_rune(chars, c); i >= 0 { + for c, i in s { + if index_rune(chars, c) >= 0 { return i } } From d0240b8981068b3f2bcbecae51d1ca8246e0113a Mon Sep 17 00:00:00 2001 From: ryuukk <44361234+ryuukk@users.noreply.github.com> Date: Wed, 15 Dec 2021 06:12:26 +0100 Subject: [PATCH 0099/1258] [WASM] Added missing zoffset parameters to some gl functions --- vendor/wasm/WebGL/runtime.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vendor/wasm/WebGL/runtime.js b/vendor/wasm/WebGL/runtime.js index 18b540b5c..3dc5186ca 100644 --- a/vendor/wasm/WebGL/runtime.js +++ b/vendor/wasm/WebGL/runtime.js @@ -672,9 +672,9 @@ class WebGLInterface { this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, null); } }, - TexSubImage3D: (target, level, xoffset, yoffset, width, height, depth, format, type, size, data) => { + TexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, size, data) => { this.assertWebGL2(); - this.ctx.texSubImage3D(target, level, xoffset, yoffset, width, height, depth, format, type, this.mem.loadBytes(data, size)); + this.ctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, this.mem.loadBytes(data, size)); }, CompressedTexImage3D: (target, level, internalformat, width, height, depth, border, imageSize, data) => { this.assertWebGL2(); @@ -684,12 +684,12 @@ class WebGLInterface { this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, null); } }, - CompressedTexSubImage3D: (target, level, xoffset, yoffset, width, height, depth, format, imageSize, data) => { + CompressedTexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) => { this.assertWebGL2(); if (data) { - this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, width, height, depth, format, this.mem.loadBytes(data, imageSize)); + this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, this.mem.loadBytes(data, imageSize)); } else { - this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, width, height, depth, format, null); + this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, null); } }, @@ -1031,4 +1031,4 @@ class WebGLInterface { }; -export {WebGLInterface}; \ No newline at end of file +export {WebGLInterface}; From 4ebdb6740ef041f4b600663b3b597e882c3fc42d Mon Sep 17 00:00:00 2001 From: gilles Date: Thu, 16 Dec 2021 18:20:10 +0100 Subject: [PATCH 0100/1258] fix math.prod accumulator was not initialized to one --- core/math/math.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/math/math.odin b/core/math/math.odin index caaa6f51b..b81598da9 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -1196,6 +1196,7 @@ sum :: proc "contextless" (x: $T/[]$E) -> (res: E) prod :: proc "contextless" (x: $T/[]$E) -> (res: E) where intrinsics.type_is_numeric(E) { + res = 1 for i in x { res *= i } From 0548db423067bce16d45af651819bf56feb5d411 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 17 Dec 2021 11:06:17 +0000 Subject: [PATCH 0101/1258] Disallow `@(static)` and `@(thread_local)` within `defer` statements --- src/check_stmt.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1a424240c..396388629 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2243,6 +2243,9 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { error(e->token, "The 'static' attribute is not allowed to be applied to '_'"); } else { e->flags |= EntityFlag_Static; + if (ctx->in_defer) { + error(e->token, "'static' variables cannot be declared within a defer statement"); + } } } if (ac.thread_local_model != "") { @@ -2251,9 +2254,13 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { error(e->token, "The 'thread_local' attribute is not allowed to be applied to '_'"); } else { e->flags |= EntityFlag_Static; + if (ctx->in_defer) { + error(e->token, "'thread_local' variables cannot be declared within a defer statement"); + } } e->Variable.thread_local_model = ac.thread_local_model; } + if (ac.is_static && ac.thread_local_model != "") { error(e->token, "The 'static' attribute is not needed if 'thread_local' is applied"); From 29ca6ee420f36381ee0fba6bd409dc51716ab206 Mon Sep 17 00:00:00 2001 From: CiD- Date: Fri, 17 Dec 2021 10:41:49 -0500 Subject: [PATCH 0102/1258] add zeroing to new region from realloc --- core/os/os.odin | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/core/os/os.odin b/core/os/os.odin index 83158be80..9230bc22c 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -206,11 +206,20 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, } } - aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, mem.Allocator_Error) { + aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> (new_memory: []byte, err: mem.Allocator_Error) { if p == nil { return nil, nil } - return aligned_alloc(new_size, new_alignment, p) + + new_memory = aligned_alloc(new_size, new_alignment, p) or_return + when ODIN_OS != "windows" { + // NOTE: realloc does not zero the new memory, so we do it + if new_size > old_size { + new_region := mem.raw_data(new_memory[old_size:]) + mem.zero(new_region, new_size - old_size) + } + } + return } switch mode { From ebdb3ab43a8cdc49cb715ecb6f5fd38522912aa5 Mon Sep 17 00:00:00 2001 From: CiD- Date: Fri, 17 Dec 2021 12:04:05 -0500 Subject: [PATCH 0103/1258] added notes about _unix_alloc --- core/os/os_darwin.odin | 2 ++ core/os/os_freebsd.odin | 2 ++ core/os/os_linux.odin | 2 ++ 3 files changed, 6 insertions(+) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index d40c80aeb..6fa43bf09 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -530,6 +530,8 @@ heap_alloc :: proc(size: int) -> rawptr { return _unix_calloc(1, size) } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on + // POSIX platforms. Ensure your caller takes this into account. return _unix_realloc(ptr, new_size) } heap_free :: proc(ptr: rawptr) { diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index e9314b468..82317532d 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -378,6 +378,8 @@ heap_alloc :: proc(size: int) -> rawptr { } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on + // POSIX platforms. Ensure your caller takes this into account. return _unix_realloc(ptr, c.size_t(new_size)); } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 260a051ce..116fbdba5 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -543,6 +543,8 @@ heap_alloc :: proc(size: int) -> rawptr { } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on + // POSIX platforms. Ensure your caller takes this into account. return _unix_realloc(ptr, c.size_t(new_size)) } From a48317deee95b956430ace83f0db3e34bef590dd Mon Sep 17 00:00:00 2001 From: Wes Hardee Date: Sat, 18 Dec 2021 12:43:24 -0600 Subject: [PATCH 0104/1258] use '___$startup_runtime' for MacOS MacOS needs 3 underscores unlike the 2 needed by Linux. --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 7b4bc92ee..36b30112f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -439,13 +439,14 @@ i32 linker_stage(lbGenerator *gen) { // so use ld instead. // :UseLDForShared linker = "ld"; - link_settings = gb_string_appendc(link_settings, "-init '__$startup_runtime' "); // Shared libraries are .dylib on MacOS and .so on Linux. #if defined(GB_SYSTEM_OSX) output_ext = STR_LIT(".dylib"); + link_settings = gb_string_appendc(link_settings, "-init '___$startup_runtime' "); link_settings = gb_string_appendc(link_settings, "-dylib -dynamic "); #else output_ext = STR_LIT(".so"); + link_settings = gb_string_appendc(link_settings, "-init '__$startup_runtime' "); link_settings = gb_string_appendc(link_settings, "-shared "); #endif } else { From 3e465c7e84490ea73f9419286fd53e95ba911c38 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Sun, 19 Dec 2021 21:51:51 +0100 Subject: [PATCH 0105/1258] Changes to required llvm version 13 as both 12 and 11 don't work correctly on macOS Apple Silicon --- Makefile | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 23fb7be66..a7aecbb2d 100644 --- a/Makefile +++ b/Makefile @@ -8,11 +8,21 @@ CC=clang OS=$(shell uname) ifeq ($(OS), Darwin) + ARCH=$(shell uname -m) LLVM_CONFIG=llvm-config - ifneq ($(shell llvm-config --version | grep '^11\.'),) + + # LLVM Version Setting + LLVM_VERSION_PATTERN="^11\." + LLVM_VERSION="11" + ifeq ($(ARCH), arm64) + LLVM_VERSION="13" + LLVM_VERSION_PATTERN="^13" + endif + + ifneq ($(shell llvm-config --version | grep $(LLVM_VERSION_PATTERN)),) LLVM_CONFIG=llvm-config else - $(error "Requirement: llvm-config must be version 11") + $(error "Requirement: llvm-config must be version $(LLVM_VERSION)") endif LDFLAGS:=$(LDFLAGS) -liconv From e2b36c4004130f8566ec63037cfc584b7318c91c Mon Sep 17 00:00:00 2001 From: Tetralux Date: Tue, 21 Dec 2021 02:11:56 +0000 Subject: [PATCH 0106/1258] Rename slice.to_dynamic to slice.clone_to_dynamic --- core/slice/slice.odin | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 487dd46c2..a82c5fa96 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -185,7 +185,7 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T) { return } -// copies slice into a new dynamic array +// copies a slice into a new slice clone :: proc(a: $T/[]$E, allocator := context.allocator) -> []E { d := make([]E, len(a), allocator) copy(d[:], a) @@ -194,11 +194,12 @@ clone :: proc(a: $T/[]$E, allocator := context.allocator) -> []E { // copies slice into a new dynamic array -to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> [dynamic]E { +clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> [dynamic]E { d := make([dynamic]E, len(a), allocator) copy(d[:], a) return d } +to_dynamic :: clone_to_dynamic // Converts slice into a dynamic array without cloning or allocating memory into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E { From 8dbeed8a9faba5b341823ae3a4ea4f7a453f3f87 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Thu, 23 Dec 2021 01:59:31 +0100 Subject: [PATCH 0107/1258] Removes unneeded lookups / Adds sret to call site which fixes the mac bug --- src/llvm_abi.cpp | 12 ++++++------ src/llvm_backend_proc.cpp | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index e18dc344b..c30f6531a 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -981,16 +981,16 @@ namespace lbAbiArm64 { if (size <= 16) { LLVMTypeRef cast_type = nullptr; if (size <= 1) { - cast_type = LLVMIntTypeInContext(c, 8); + cast_type = LLVMInt8TypeInContext(c); } else if (size <= 2) { - cast_type = LLVMIntTypeInContext(c, 16); + cast_type = LLVMInt16TypeInContext(c); } else if (size <= 4) { - cast_type = LLVMIntTypeInContext(c, 32); + cast_type = LLVMInt32TypeInContext(c); } else if (size <= 8) { - cast_type = LLVMIntTypeInContext(c, 64); + cast_type = LLVMInt64TypeInContext(c); } else { unsigned count = cast(unsigned)((size+7)/8); - cast_type = LLVMArrayType(LLVMIntTypeInContext(c, 64), count); + cast_type = LLVMArrayType(LLVMInt64TypeInContext(c), count); } return lb_arg_type_direct(type, cast_type, nullptr, nullptr); } else { @@ -999,7 +999,7 @@ namespace lbAbiArm64 { } } } - + Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) { auto args = array_make(heap_allocator(), arg_count); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 25b27ee47..84fddd9e2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -736,6 +736,10 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, LLVMValueRef ret = LLVMBuildCall2(p->builder, fnp, fn, args, arg_count, ""); + if (return_ptr.value != nullptr) { + LLVMAddCallSiteAttribute(ret, 1, lb_create_enum_attribute_with_type(p->module->ctx, "sret", LLVMTypeOf(args[0]))); + } + switch (inlining) { case ProcInlining_none: break; From dce120258fbca70dfaa9a738bc168463df7a3dda Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Thu, 23 Dec 2021 02:46:32 +0000 Subject: [PATCH 0108/1258] src: Add preliminary support for Linux AArch64 Tested via `tests/core`, on a Raspberry Pi 4 running the latest 64-bit Raspberry Pi OS image (LLVM 11). --- src/build_settings.cpp | 14 ++++++++++++++ src/gb/gb.h | 2 ++ src/threading.cpp | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 29abd441c..b8d50898d 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -300,6 +300,14 @@ gb_global TargetMetrics target_linux_amd64 = { str_lit("x86_64-pc-linux-gnu"), str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; +gb_global TargetMetrics target_linux_arm64 = { + TargetOs_linux, + TargetArch_arm64, + 8, + 16, + str_lit("aarch64-linux-elf"), + str_lit("e-m:e-i8:8:32-i16:32-i64:64-i128:128-n32:64-S128"), +}; gb_global TargetMetrics target_darwin_amd64 = { TargetOs_darwin, @@ -394,6 +402,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("essence_amd64"), &target_essence_amd64 }, { str_lit("linux_386"), &target_linux_386 }, { str_lit("linux_amd64"), &target_linux_amd64 }, + { str_lit("linux_arm64"), &target_linux_arm64 }, { str_lit("windows_386"), &target_windows_386 }, { str_lit("windows_amd64"), &target_windows_amd64 }, { str_lit("freebsd_386"), &target_freebsd_386 }, @@ -880,6 +889,8 @@ void init_build_context(TargetMetrics *cross_target) { #endif #elif defined(GB_SYSTEM_FREEBSD) metrics = &target_freebsd_amd64; + #elif defined(GB_CPU_ARM) + metrics = &target_linux_arm64; #else metrics = &target_linux_amd64; #endif @@ -959,6 +970,9 @@ void init_build_context(TargetMetrics *cross_target) { case TargetOs_darwin: bc->link_flags = str_lit("-arch arm64 "); break; + case TargetOs_linux: + bc->link_flags = str_lit("-arch aarch64 "); + break; } } else if (is_arch_wasm()) { gbString link_flags = gb_string_make(heap_allocator(), " "); diff --git a/src/gb/gb.h b/src/gb/gb.h index f716b0840..d9bf09436 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -3355,6 +3355,8 @@ gb_inline u32 gb_thread_current_id(void) { __asm__("mov %%gs:0x08,%0" : "=r"(thread_id)); #elif defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86) __asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); +#elif defined(GB_SYSTEM_LINUX) + thread_id = gettid(); #else #error Unsupported architecture for gb_thread_current_id() #endif diff --git a/src/threading.cpp b/src/threading.cpp index e9412b411..b318e4ff1 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -296,6 +296,8 @@ u32 thread_current_id(void) { __asm__("mov %%gs:0x08,%0" : "=r"(thread_id)); #elif defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86) __asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); +#elif defined(GB_SYSTEM_LINUX) + thread_id = gettid(); #else #error Unsupported architecture for thread_current_id() #endif @@ -315,6 +317,8 @@ gb_inline void yield_thread(void) { #endif #elif defined(GB_CPU_X86) _mm_pause(); +#elif defined(GB_CPU_ARM) + __asm__ volatile ("yield" : : : "memory"); #else #error Unknown architecture #endif From 5d80e242244501a5eb256a72ed6ad5ca180bc49d Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Thu, 23 Dec 2021 12:49:40 +0100 Subject: [PATCH 0109/1258] Add slice/scanner proc --- core/slice/slice.odin | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index a82c5fa96..69aae1e39 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -304,6 +304,27 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) - return r[:] } +scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U)->V, allocator := context.allocator) -> []V { + if len(s) == 0 { return {} } + p := as_ptr(s) + + res := make([]V, len(s), allocator) + + q := as_ptr(res) + l := len(res) + + r := initializer + + for l > 0 { + r = f(r, p^) + q^ = r + p = intrinsics.ptr_offset(p, 1) + q = intrinsics.ptr_offset(q, 1) + l -= 1 + } + + return res +} min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok { From 9b2fe56d149fa23b03b678de2eb51c4f599d2711 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Sat, 25 Dec 2021 18:53:20 +0000 Subject: [PATCH 0110/1258] Parse #no_nil on unions --- core/odin/ast/ast.odin | 1 + core/odin/parser/parser.odin | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 260979d89..9db57541b 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -711,6 +711,7 @@ Union_Type :: struct { poly_params: ^Field_List, align: ^Expr, is_maybe: bool, + is_no_nil: bool, where_token: tokenizer.Token, where_clauses: []^Expr, variants: []^Expr, diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 52d4b5e5a..aade2051a 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2600,6 +2600,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { poly_params: ^ast.Field_List align: ^ast.Expr is_maybe: bool + is_no_nil: bool if allow_token(p, .Open_Paren) { param_count: int @@ -2626,6 +2627,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { error(p, tag.pos, "duplicate union tag '#%s'", tag.text) } is_maybe = true + case "no_nil": + if is_no_nil { + error(p, tag.pos, "duplicate union tag '#%s'", tag.text) + } + is_no_nil = true case: error(p, tag.pos, "invalid union tag '#%s", tag.text) } @@ -2669,6 +2675,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { ut.where_token = where_token ut.where_clauses = where_clauses ut.is_maybe = is_maybe + ut.is_no_nil = is_no_nil return ut From a60667e900f3e7f3b6253019961a17b65b76e479 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Sat, 25 Dec 2021 19:17:34 +0000 Subject: [PATCH 0111/1258] core:odin/parser: Fix parsing of Allman style braces in for loops --- core/odin/parser/parser.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 52d4b5e5a..679623108 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -888,6 +888,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { error(p, body.pos, "the body of a 'do' must be on the same line as the 'for' token") } } else { + allow_token(p, .Semicolon) body = parse_body(p) } From 516065d7c22c19aa953edf1d4ab1537f07742dec Mon Sep 17 00:00:00 2001 From: Henry Dooley Date: Sat, 25 Dec 2021 16:27:52 -0600 Subject: [PATCH 0112/1258] factor out alloca generation into a helper --- src/llvm_backend.hpp | 2 ++ src/llvm_backend_const.cpp | 6 +++--- src/llvm_backend_general.cpp | 18 +++++++++++------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e70b1f84c..5616701f8 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -459,6 +459,8 @@ void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t); bool lb_is_expr_untyped_const(Ast *expr); +LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment); + void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment); void lb_emit_init_context(lbProcedure *p, lbAddr addr); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 5862a7add..bc14b099b 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -413,9 +413,9 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); LLVMTypeRef llvm_type = lb_type(m, t); - array_data = LLVMBuildAlloca(p->builder, llvm_type, ""); - LLVMSetAlignment(array_data, 16); // TODO(bill): Make this configurable - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + + array_data = llvm_alloca(p, llvm_type, 16); + LLVMBuildStore(p->builder, backing_array.value, array_data); { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 17eeb0bea..9f77cef65 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -216,6 +216,14 @@ LLVMValueRef llvm_one(lbModule *m) { return LLVMConstInt(lb_type(m, t_i32), 1, false); } +LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment) { + LLVMValueRef val = LLVMBuildAlloca(p->builder, llvm_type, ""); + LLVMSetAlignment(val, alignment); + LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + + return val; +} + lbValue lb_zero(lbModule *m, Type *t) { lbValue v = {}; v.value = LLVMConstInt(lb_type(m, t), 0, false); @@ -2267,11 +2275,10 @@ general_end:; GB_ASSERT(p->decl_block != p->curr_block); LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); - LLVMValueRef ptr = LLVMBuildAlloca(p->builder, dst_type, ""); - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type)); max_align = gb_max(max_align, 4); - LLVMSetAlignment(ptr, cast(unsigned)max_align); + + LLVMValueRef ptr = llvm_alloca(p, dst_type, max_align); LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); LLVMBuildStore(p->builder, val, nptr); @@ -2642,16 +2649,13 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p } LLVMTypeRef llvm_type = lb_type(p->module, type); - LLVMValueRef ptr = LLVMBuildAlloca(p->builder, llvm_type, name); unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(llvm_type)); if (is_type_matrix(type)) { alignment *= 2; // NOTE(bill): Just in case } - LLVMSetAlignment(ptr, alignment); - - LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + LLVMValueRef ptr = llvm_alloca(p, llvm_type, alignment); if (!zero_init && !force_no_init) { // If there is any padding of any kind, just zero init regardless of zero_init parameter From 069c05669f5c7bbe0a2f5c82b1daa334481cd0cb Mon Sep 17 00:00:00 2001 From: Henry Dooley Date: Sat, 25 Dec 2021 16:46:02 -0600 Subject: [PATCH 0113/1258] cast isize to unsigned int for llvm api, add defaulted name parameter to helper. --- src/llvm_backend.hpp | 2 +- src/llvm_backend_general.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 5616701f8..9aea75be9 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -459,7 +459,7 @@ void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t); bool lb_is_expr_untyped_const(Ast *expr); -LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment); +LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const* name = ""); void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 9f77cef65..46b5fdb88 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -216,9 +216,9 @@ LLVMValueRef llvm_one(lbModule *m) { return LLVMConstInt(lb_type(m, t_i32), 1, false); } -LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment) { - LLVMValueRef val = LLVMBuildAlloca(p->builder, llvm_type, ""); - LLVMSetAlignment(val, alignment); +LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const* name) { + LLVMValueRef val = LLVMBuildAlloca(p->builder, llvm_type, name); + LLVMSetAlignment(val, cast(unsigned int)alignment); LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); return val; @@ -2655,7 +2655,7 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p alignment *= 2; // NOTE(bill): Just in case } - LLVMValueRef ptr = llvm_alloca(p, llvm_type, alignment); + LLVMValueRef ptr = llvm_alloca(p, llvm_type, alignment, name); if (!zero_init && !force_no_init) { // If there is any padding of any kind, just zero init regardless of zero_init parameter From 86f831ddd19e5f4e21179b32d603a6ae2cc6ce2f Mon Sep 17 00:00:00 2001 From: Platin21 Date: Mon, 27 Dec 2021 22:10:52 +0100 Subject: [PATCH 0114/1258] This adds code which checks how big the return is and if it is to big returns the value via sret --- src/llvm_abi.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index c30f6531a..42f05bb27 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -965,6 +965,10 @@ namespace lbAbiArm64 { } return false; } + + unsigned is_homogenous_aggregate_small_enough(LLVMTypeRef *base_type_, unsigned member_count_) { + return (member_count_ <= 4); + } lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef type, bool return_is_defined) { LLVMTypeRef homo_base_type = {}; @@ -975,7 +979,16 @@ namespace lbAbiArm64 { } else if (is_register(type)) { return non_struct(c, type); } else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) { - return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr); + if(is_homogenous_aggregate_small_enough(&homo_base_type, homo_member_count)) { + return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr); + } else { + //TODO(Platin): do i need to create stuff that can handle the diffrent return type? + // else this needs a fix in llvm_backend_proc as we would need to cast it to the correct array type + + //LLVMTypeRef array_type = LLVMArrayType(homo_base_type, homo_member_count); + LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type); + return lb_arg_type_indirect(type, attr); + } } else { i64 size = lb_sizeof(type); if (size <= 16) { From 7f61a90ea1be96c22cae87fdbfdc08b30f2421d6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 Dec 2021 14:05:09 +0000 Subject: [PATCH 0115/1258] Remove `core:container` contents --- core/container/array.odin | 216 ----------------- core/container/bloom_filter.odin | 80 ------ core/container/map.odin | 377 ----------------------------- core/container/priority_queue.odin | 121 --------- core/container/queue.odin | 175 ------------- core/container/ring.odin | 74 ------ core/container/set.odin | 240 ------------------ core/container/small_array.odin | 95 -------- 8 files changed, 1378 deletions(-) delete mode 100644 core/container/array.odin delete mode 100644 core/container/bloom_filter.odin delete mode 100644 core/container/map.odin delete mode 100644 core/container/priority_queue.odin delete mode 100644 core/container/queue.odin delete mode 100644 core/container/ring.odin delete mode 100644 core/container/set.odin delete mode 100644 core/container/small_array.odin diff --git a/core/container/array.odin b/core/container/array.odin deleted file mode 100644 index 2d5a64ec3..000000000 --- a/core/container/array.odin +++ /dev/null @@ -1,216 +0,0 @@ -package container - -import "core:mem" -import "core:runtime" - -Array :: struct($T: typeid) { - data: ^T, - len: int, - cap: int, - allocator: mem.Allocator, -} - -ARRAY_DEFAULT_CAPACITY :: 16 - -/* -array_init :: proc { - array_init_none, - array_init_len, - array_init_len_cap, -} -array_init -array_delete -array_len -array_cap -array_space -array_slice -array_get -array_get_ptr -array_set -array_reserve -array_resize -array_push = array_append :: proc{ - array_push_back, - array_push_back_elems, -} -array_push_front -array_pop_back -array_pop_front -array_consume -array_trim -array_clear -array_clone -array_set_capacity -array_grow -*/ - - -array_init_none :: proc(a: ^$A/Array, allocator := context.allocator) { - array_init_len_cap(a, 0, ARRAY_DEFAULT_CAPACITY, allocator) -} -array_init_len :: proc(a: ^$A/Array, len: int, allocator := context.allocator) { - array_init_len_cap(a, len, len, allocator) -} -array_init_len_cap :: proc(a: ^$A/Array($T), len: int, cap: int, allocator := context.allocator) { - a.allocator = allocator - a.data = (^T)(mem.alloc(size_of(T)*cap, align_of(T), a.allocator)) - a.len = len - a.cap = cap -} - -array_init :: proc{array_init_none, array_init_len, array_init_len_cap} - -array_delete :: proc(a: $A/Array) { - mem.free(a.data, a.allocator) -} - -array_len :: proc(a: $A/Array) -> int { - return a.len -} - -array_cap :: proc(a: $A/Array) -> int { - return a.cap -} - -array_space :: proc(a: $A/Array) -> int { - return a.cap - a.len -} - -array_slice :: proc(a: $A/Array($T)) -> []T { - s := mem.Raw_Slice{a.data, a.len} - return transmute([]T)s -} - -array_cap_slice :: proc(a: $A/Array($T)) -> []T { - s := mem.Raw_Slice{a.data, a.cap} - return transmute([]T)s -} - -array_get :: proc(a: $A/Array($T), index: int, loc := #caller_location) -> T { - runtime.bounds_check_error_loc(loc, index, array_len(a)) - return (^T)(uintptr(a.data) + size_of(T)*uintptr(index))^ -} -array_get_ptr :: proc(a: $A/Array($T), index: int, loc := #caller_location) -> ^T { - runtime.bounds_check_error_loc(loc, index, array_len(a)) - return (^T)(uintptr(a.data) + size_of(T)*uintptr(index)) -} - -array_set :: proc(a: ^$A/Array($T), index: int, item: T, loc := #caller_location) { - runtime.bounds_check_error_loc(loc, index, array_len(a^)) - (^T)(uintptr(a.data) + size_of(T)*uintptr(index))^ = item -} - - -array_reserve :: proc(a: ^$A/Array, capacity: int) { - if capacity > a.len { - array_set_capacity(a, capacity) - } -} - -array_resize :: proc(a: ^$A/Array, length: int) { - if length > a.len { - array_set_capacity(a, length) - } - a.len = length -} - - - -array_push_back :: proc(a: ^$A/Array($T), item: T) { - if array_space(a^) == 0 { - array_grow(a) - } - - a.len += 1 - array_set(a, a.len-1, item) -} - -array_push_front :: proc(a: ^$A/Array($T), item: T) { - if array_space(a^) == 0 { - array_grow(a) - } - - a.len += 1 - data := array_slice(a^) - copy(data[1:], data[:]) - data[0] = item -} - -array_pop_back :: proc(a: ^$A/Array($T), loc := #caller_location) -> T { - assert(condition=a.len > 0, loc=loc) - item := array_get(a^, a.len-1) - a.len -= 1 - return item -} - -array_pop_front :: proc(a: ^$A/Array($T), loc := #caller_location) -> T { - assert(condition=a.len > 0, loc=loc) - item := array_get(a^, 0) - s := array_slice(a^) - copy(s[:], s[1:]) - a.len -= 1 - return item -} - - -array_consume :: proc(a: ^$A/Array($T), count: int, loc := #caller_location) { - assert(condition=a.len >= count, loc=loc) - a.len -= count -} - - -array_trim :: proc(a: ^$A/Array($T)) { - array_set_capacity(a, a.len) -} - -array_clear :: proc(a: ^$A/Array($T)) { - array_resize(a, 0) -} - -array_clone :: proc(a: $A/Array($T), allocator := context.allocator) -> A { - res: A - array_init(&res, array_len(a), array_len(a), allocator) - copy(array_slice(res), array_slice(a)) - return res -} - -array_push_back_elems :: proc(a: ^$A/Array($T), items: ..T) { - if array_space(a^) < len(items) { - array_grow(a, a.len + len(items)) - } - offset := a.len - data := array_cap_slice(a^) - n := copy(data[a.len:], items) - a.len += n -} - -array_push :: proc{array_push_back, array_push_back_elems} -array_append :: proc{array_push_back, array_push_back_elems} - -array_set_capacity :: proc(a: ^$A/Array($T), new_capacity: int) { - if new_capacity == a.cap { - return - } - - if new_capacity < a.len { - array_resize(a, new_capacity) - } - - new_data: ^T - if new_capacity > 0 { - if a.allocator.procedure == nil { - a.allocator = context.allocator - } - new_data = (^T)(mem.alloc(size_of(T)*new_capacity, align_of(T), a.allocator)) - if new_data != nil { - mem.copy(new_data, a.data, size_of(T)*a.len) - } - } - mem.free(a.data, a.allocator) - a.data = new_data - a.cap = new_capacity -} -array_grow :: proc(a: ^$A/Array, min_capacity: int = 0) { - new_capacity := max(array_len(a^)*2 + 8, min_capacity) - array_set_capacity(a, new_capacity) -} diff --git a/core/container/bloom_filter.odin b/core/container/bloom_filter.odin deleted file mode 100644 index 8af7aeb85..000000000 --- a/core/container/bloom_filter.odin +++ /dev/null @@ -1,80 +0,0 @@ -package container - -import "core:mem" - -Bloom_Hash_Proc :: #type proc(data: []byte) -> u32 - -Bloom_Hash :: struct { - hash_proc: Bloom_Hash_Proc, - next: ^Bloom_Hash, -} - -Bloom_Filter :: struct { - allocator: mem.Allocator, - hash: ^Bloom_Hash, - bits: []byte, -} - -bloom_filter_init :: proc(b: ^Bloom_Filter, size: int, allocator := context.allocator) { - b.allocator = allocator - b.bits = make([]byte, size, allocator) -} - -bloom_filter_destroy :: proc(b: ^Bloom_Filter) { - context.allocator = b.allocator - delete(b.bits) - for b.hash != nil { - hash := b.hash - b.hash = b.hash.next - free(hash) - } -} - -bloom_filter_add_hash_proc :: proc(b: ^Bloom_Filter, hash_proc: Bloom_Hash_Proc) { - context.allocator = b.allocator - h := new(Bloom_Hash) - h.hash_proc = hash_proc - - head := &b.hash - for head^ != nil { - head = &(head^.next) - } - head^ = h -} - -bloom_filter_add :: proc(b: ^Bloom_Filter, item: []byte) { - #no_bounds_check for h := b.hash; h != nil; h = h.next { - hash := h.hash_proc(item) - hash %= u32(len(b.bits) * 8) - b.bits[hash >> 3] |= 1 << (hash & 3) - } -} - -bloom_filter_add_string :: proc(b: ^Bloom_Filter, item: string) { - bloom_filter_add(b, transmute([]byte)item) -} - -bloom_filter_add_raw :: proc(b: ^Bloom_Filter, data: rawptr, size: int) { - item := mem.slice_ptr((^byte)(data), size) - bloom_filter_add(b, item) -} - -bloom_filter_test :: proc(b: ^Bloom_Filter, item: []byte) -> bool { - #no_bounds_check for h := b.hash; h != nil; h = h.next { - hash := h.hash_proc(item) - hash %= u32(len(b.bits) * 8) - if (b.bits[hash >> 3] & (1 << (hash & 3)) == 0) { - return false - } - } - return true -} - -bloom_filter_test_string :: proc(b: ^Bloom_Filter, item: string) -> bool { - return bloom_filter_test(b, transmute([]byte)item) -} - -bloom_filter_test_raw :: proc(b: ^Bloom_Filter, data: rawptr, size: int) -> bool { - item := mem.slice_ptr((^byte)(data), size) - return bloom_filter_test(b, item) -} diff --git a/core/container/map.odin b/core/container/map.odin deleted file mode 100644 index 54cbc22fc..000000000 --- a/core/container/map.odin +++ /dev/null @@ -1,377 +0,0 @@ -package container - -import "core:intrinsics" -_ :: intrinsics - - -Map :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) { - hash: Array(int), - entries: Array(Map_Entry(Key, Value)), -} - -Map_Entry :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) { - hash: uintptr, - next: int, - key: Key, - value: Value, -} - - -/* -map_init :: proc{ - map_init_none, - map_init_cap, -} -map_delete - -map_has -map_get -map_get_default -map_get_ptr -map_set -map_remove -map_reserve -map_clear - -// Multi Map - -multi_map_find_first -multi_map_find_next -multi_map_count -multi_map_get :: proc{ - multi_map_get_array, - multi_map_get_slice, -}; -multi_map_get_as_slice -multi_map_insert -multi_map_remove -multi_map_remove_all - -*/ - -map_init :: proc{map_init_none, map_init_cap} - -map_init_none :: proc(m: ^$M/Map($Key, $Value), allocator := context.allocator) { - m.hash.allocator = allocator - m.entries.allocator = allocator -} - -map_init_cap :: proc(m: ^$M/Map($Key, $Value), cap: int, allocator := context.allocator) { - m.hash.allocator = allocator - m.entries.allocator = allocator - map_reserve(m, cap) -} - -map_delete :: proc(m: $M/Map($Key, $Value)) { - array_delete(m.hash) - array_delete(m.entries) -} - - -map_has :: proc(m: $M/Map($Key, $Value), key: Key) -> bool { - return _map_find_or_fail(m, key) >= 0 -} - -map_get :: proc(m: $M/Map($Key, $Value), key: Key) -> (res: Value, ok: bool) #optional_ok { - i := _map_find_or_fail(m, key) - if i < 0 { - return {}, false - } - return array_get(m.entries, i).value, true -} - -map_get_default :: proc(m: $M/Map($Key, $Value), key: Key, default: Value) -> (res: Value, ok: bool) #optional_ok { - i := _map_find_or_fail(m, key) - if i < 0 { - return default, false - } - return array_get(m.entries, i).value, true -} - -map_get_ptr :: proc(m: $M/Map($Key, $Value), key: Key) -> ^Value { - i := _map_find_or_fail(m, key) - if i < 0 { - return nil - } - return array_get_ptr(m.entries, i).value -} - -map_set :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) { - if array_len(m.hash) == 0 { - _map_grow(m) - } - - i := _map_find_or_make(m, key) - array_get_ptr(m.entries, i).value = value - if _map_full(m^) { - _map_grow(m) - } -} - -map_remove :: proc(m: ^$M/Map($Key, $Value), key: Key) { - fr := _map_find_key(m^, key) - if fr.entry_index >= 0 { - _map_erase(m, fr) - } -} - - -map_reserve :: proc(m: ^$M/Map($Key, $Value), new_size: int) { - nm: M - map_init(&nm, m.hash.allocator) - array_resize(&nm.hash, new_size) - array_reserve(&nm.entries, array_len(m.entries)) - - for i in 0.. ^Map_Entry(Key, Value) { - i := _map_find_or_fail(m, key) - if i < 0 { - return nil - } - return array_get_ptr(m.entries, i) -} - -multi_map_find_next :: proc(m: $M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) -> ^Map_Entry(Key, Value) { - i := e.next - for i >= 0 { - it := array_get_ptr(m.entries, i) - if it.hash == e.hash && it.key == e.key { - return it - } - i = it.next - } - return nil -} - -multi_map_count :: proc(m: $M/Map($Key, $Value), key: Key) -> int { - n := 0 - e := multi_map_find_first(m, key) - for e != nil { - n += 1 - e = multi_map_find_next(m, e) - } - return n -} - -multi_map_get :: proc{multi_map_get_array, multi_map_get_slice} - -multi_map_get_array :: proc(m: $M/Map($Key, $Value), key: Key, items: ^Array(Value)) { - if items == nil { - return - } - e := multi_map_find_first(m, key) - for e != nil { - array_append(items, e.value) - e = multi_map_find_next(m, e) - } -} - -multi_map_get_slice :: proc(m: $M/Map($Key, $Value), key: Key, items: []Value) { - e := multi_map_find_first(m, key) - i := 0 - for e != nil && i < len(items) { - items[i] = e.value - i += 1 - e = multi_map_find_next(m, e) - } -} - -multi_map_get_as_slice :: proc(m: $M/Map($Key, $Value), key: Key) -> []Value { - items: Array(Value) - array_init(&items, 0) - - e := multi_map_find_first(m, key) - for e != nil { - array_append(&items, e.value) - e = multi_map_find_next(m, e) - } - - return array_slice(items) -} - - -multi_map_insert :: proc(m: ^$M/Map($Key, $Value), key: Key, value: Value) { - if array_len(m.hash) == 0 { - _map_grow(m) - } - - i := _map_make(m, key) - array_get_ptr(m.entries, i).value = value - if _map_full(m^) { - _map_grow(m) - } -} - -multi_map_remove :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) { - fr := _map_find_entry(m, e) - if fr.entry_index >= 0 { - _map_erase(m, fr) - } -} - -multi_map_remove_all :: proc(m: ^$M/Map($Key, $Value), key: Key) { - for map_exist(m^, key) { - map_remove(m, key) - } -} - - -/// Internal - - -Map_Find_Result :: struct { - hash_index: int, - entry_prev: int, - entry_index: int, -} - -_map_add_entry :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int where intrinsics.type_is_valid_map_key(Key) { - hasher := intrinsics.type_hasher_proc(Key) - - e: Map_Entry(Key, Value) - e.key = key - e.hash = hasher(&e.key, 0) - e.next = -1 - idx := array_len(m.entries) - array_push(&m.entries, e) - return idx -} - -_map_erase :: proc(m: ^$M/Map, fr: Map_Find_Result) { - if fr.entry_prev < 0 { - array_set(&m.hash, fr.hash_index, array_get(m.entries, fr.entry_index).next) - } else { - array_get_ptr(m.entries, fr.entry_prev).next = array_get(m.entries, fr.entry_index).next - } - - if fr.entry_index == array_len(m.entries)-1 { - array_pop_back(&m.entries) - return - } - - array_set(&m.entries, fr.entry_index, array_get(m.entries, array_len(m.entries)-1)) - last := _map_find_key(m^, array_get(m.entries, fr.entry_index).key) - - if last.entry_prev < 0 { - array_get_ptr(m.entries, last.entry_prev).next = fr.entry_index - } else { - array_set(&m.hash, last.hash_index, fr.entry_index) - } -} - - -_map_find_key :: proc(m: $M/Map($Key, $Value), key: Key) -> Map_Find_Result where intrinsics.type_is_valid_map_key(Key) { - fr: Map_Find_Result - fr.hash_index = -1 - fr.entry_prev = -1 - fr.entry_index = -1 - - if array_len(m.hash) == 0 { - return fr - } - - hasher := intrinsics.type_hasher_proc(Key) - - key := key - hash := hasher(&key, 0) - - fr.hash_index = int(hash % uintptr(array_len(m.hash))) - fr.entry_index = array_get(m.hash, fr.hash_index) - for fr.entry_index >= 0 { - it := array_get_ptr(m.entries, fr.entry_index) - if it.hash == hash && it.key == key { - return fr - } - fr.entry_prev = fr.entry_index - fr.entry_index = it.next - } - return fr -} - -_map_find_entry :: proc(m: ^$M/Map($Key, $Value), e: ^Map_Entry(Key, Value)) -> Map_Find_Result { - fr: Map_Find_Result - fr.hash_index = -1 - fr.entry_prev = -1 - fr.entry_index = -1 - - if array_len(m.hash) == 0 { - return fr - } - - fr.hash_index = int(e.hash % uintptr(array_len(m.hash))) - fr.entry_index = array_get(m.hash, fr.hash_index) - for fr.entry_index >= 0 { - it := array_get_ptr(m.entries, fr.entry_index) - if it == e { - return fr - } - fr.entry_prev = fr.entry_index - fr.entry_index = it.next - } - return fr -} - -_map_find_or_fail :: proc(m: $M/Map($Key, $Value), key: Key) -> int { - return _map_find_key(m, key).entry_index -} -_map_find_or_make :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int { - fr := _map_find_key(m^, key) - if fr.entry_index >= 0 { - return fr.entry_index - } - - i := _map_add_entry(m, key) - if fr.entry_prev < 0 { - array_set(&m.hash, fr.hash_index, i) - } else { - array_get_ptr(m.entries, fr.entry_prev).next = i - } - return i -} - - -_map_make :: proc(m: ^$M/Map($Key, $Value), key: Key) -> int { - fr := _map_find_key(m^, key) - i := _map_add_entry(m, key) - - if fr.entry_prev < 0 { - array_set(&m.hash, fr.hash_index, i) - } else { - array_get_ptr(m.entries, fr.entry_prev).next = i - } - - array_get_ptr(m.entries, i).next = fr.entry_index - - return i -} - - -_map_full :: proc(m: $M/Map($Key, $Value)) -> bool { - // TODO(bill): Determine good max load factor - return array_len(m.entries) >= (array_len(m.hash) / 4)*3 -} - -_map_grow :: proc(m: ^$M/Map($Key, $Value)) { - new_size := array_len(m.entries) * 4 + 7 // TODO(bill): Determine good grow rate - map_reserve(m, new_size) -} - - diff --git a/core/container/priority_queue.odin b/core/container/priority_queue.odin deleted file mode 100644 index c54e964a6..000000000 --- a/core/container/priority_queue.odin +++ /dev/null @@ -1,121 +0,0 @@ -package container - -Priority_Queue :: struct($T: typeid) { - data: Array(T), - len: int, - priority: proc(item: T) -> int, -} - -priority_queue_init_none :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, allocator := context.allocator) { - queue_init_len(q, f, 0, allocator) -} -priority_queue_init_len :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, allocator := context.allocator) { - queue_init_len_cap(q, f, 0, 16, allocator) -} -priority_queue_init_len_cap :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, cap: int, allocator := context.allocator) { - array_init(&q.data, len, cap, allocator) - q.len = len - q.priority = f -} - -priority_queue_init :: proc{priority_queue_init_none, priority_queue_init_len, priority_queue_init_len_cap} - - -priority_queue_delete :: proc(q: $Q/Priority_Queue($T)) { - array_delete(q.data) -} - -priority_queue_clear :: proc(q: ^$Q/Priority_Queue($T)) { - q.len = 0 -} - -priority_queue_len :: proc(q: $Q/Priority_Queue($T)) -> int { - return q.len -} - -priority_queue_cap :: proc(q: $Q/Priority_Queue($T)) -> int { - return array_cap(q.data) -} - -priority_queue_space :: proc(q: $Q/Priority_Queue($T)) -> int { - return array_len(q.data) - q.len -} - -priority_queue_reserve :: proc(q: ^$Q/Priority_Queue($T), capacity: int) { - if capacity > q.len { - array_resize(&q.data, new_capacity) - } -} - -priority_queue_resize :: proc(q: ^$Q/Priority_Queue($T), length: int) { - if length > q.len { - array_resize(&q.data, new_capacity) - } - q.len = length -} - -_priority_queue_grow :: proc(q: ^$Q/Priority_Queue($T), min_capacity: int = 0) { - new_capacity := max(array_len(q.data)*2 + 8, min_capacity) - array_resize(&q.data, new_capacity) -} - - -priority_queue_push :: proc(q: ^$Q/Priority_Queue($T), item: T) { - if array_len(q.data) - q.len == 0 { - _priority_queue_grow(q) - } - - s := array_slice(q.data) - s[q.len] = item - - i := q.len - for i > 0 { - p := (i - 1) / 2 - if q.priority(s[p]) <= q.priority(item) { - break - } - s[i] = s[p] - i = p - } - - q.len += 1 - if q.len > 0 { - s[i] = item - } -} - - - -priority_queue_pop :: proc(q: ^$Q/Priority_Queue($T)) -> T { - assert(q.len > 0) - - s := array_slice(q.data) - min := s[0] - root := s[q.len-1] - q.len -= 1 - - i := 0 - for i * 2 + 1 < q.len { - a := i * 2 + 1 - b := i * 2 + 2 - c := b < q.len && q.priority(s[b]) < q.priority(s[a]) ? b : a - - if q.priority(s[c]) >= q.priority(root) { - break - } - s[i] = s[c] - i = c - } - - if q.len > 0 { - s[i] = root - } - return min -} - -priority_queue_peek :: proc(q: ^$Q/Priority_Queue($T)) -> T { - assert(q.len > 0) - - s := array_slice(q.data) - return s[0] -} diff --git a/core/container/queue.odin b/core/container/queue.odin deleted file mode 100644 index bab4a18e6..000000000 --- a/core/container/queue.odin +++ /dev/null @@ -1,175 +0,0 @@ -package container - -Queue :: struct($T: typeid) { - data: Array(T), - len: int, - offset: int, -} - -/* -queue_init :: proc{ - queue_init_none, - queue_init_len, - queue_init_len_cap, -} -queue_delete -queue_clear -queue_len -queue_cap -queue_space -queue_get -queue_set -queue_reserve -queue_resize -queue_push :: proc{ - queue_push_back, - queue_push_elems, -}; -queue_push_front -queue_pop_front -queue_pop_back -queue_consume -*/ - -queue_init_none :: proc(q: ^$Q/Queue($T), allocator := context.allocator) { - queue_init_len(q, 0, allocator) -} -queue_init_len :: proc(q: ^$Q/Queue($T), len: int, allocator := context.allocator) { - queue_init_len_cap(q, 0, 16, allocator) -} -queue_init_len_cap :: proc(q: ^$Q/Queue($T), len: int, cap: int, allocator := context.allocator) { - array_init(&q.data, len, cap, allocator) - q.len = len - q.offset = 0 -} - -queue_init :: proc{queue_init_none, queue_init_len, queue_init_len_cap} - -queue_delete :: proc(q: $Q/Queue($T)) { - array_delete(q.data) -} - -queue_clear :: proc(q: ^$Q/Queue($T)) { - q.len = 0 -} - -queue_len :: proc(q: $Q/Queue($T)) -> int { - return q.len -} - -queue_cap :: proc(q: $Q/Queue($T)) -> int { - return array_cap(q.data) -} - -queue_space :: proc(q: $Q/Queue($T)) -> int { - return array_len(q.data) - q.len -} - -queue_get :: proc(q: $Q/Queue($T), index: int) -> T { - i := (index + q.offset) % array_len(q.data) - data := array_slice(q.data) - return data[i] -} - -queue_set :: proc(q: ^$Q/Queue($T), index: int, item: T) { - i := (index + q.offset) % array_len(q.data) - data := array_slice(q.data) - data[i] = item -} - - -queue_reserve :: proc(q: ^$Q/Queue($T), capacity: int) { - if capacity > q.len { - _queue_increase_capacity(q, capacity) - } -} - -queue_resize :: proc(q: ^$Q/Queue($T), length: int) { - if length > q.len { - _queue_increase_capacity(q, length) - } - q.len = length -} - -queue_push_back :: proc(q: ^$Q/Queue($T), item: T) { - if queue_space(q^) == 0 { - _queue_grow(q) - } - - queue_set(q, q.len, item) - q.len += 1 -} - -queue_push_front :: proc(q: ^$Q/Queue($T), item: T) { - if queue_space(q^) == 0 { - _queue_grow(q) - } - - q.offset = (q.offset - 1 + array_len(q.data)) % array_len(q.data) - q.len += 1 - queue_set(q, 0, item) -} - -queue_pop_front :: proc(q: ^$Q/Queue($T)) -> T { - assert(q.len > 0) - item := queue_get(q^, 0) - q.offset = (q.offset + 1) % array_len(q.data) - q.len -= 1 - if q.len == 0 { - q.offset = 0 - } - return item -} - -queue_pop_back :: proc(q: ^$Q/Queue($T)) -> T { - assert(q.len > 0) - item := queue_get(q^, q.len-1) - q.len -= 1 - return item -} - -queue_consume :: proc(q: ^$Q/Queue($T), count: int) { - q.offset = (q.offset + count) & array_len(q.data) - q.len -= count -} - - -queue_push_elems :: proc(q: ^$Q/Queue($T), items: ..T) { - if queue_space(q^) < len(items) { - _queue_grow(q, q.len + len(items)) - } - size := array_len(q.data) - insert := (q.offset + q.len) % size - - to_insert := len(items) - if insert + to_insert > size { - to_insert = size - insert - } - - the_items := items[:] - - data := array_slice(q.data) - - q.len += copy(data[insert:][:to_insert], the_items) - the_items = the_items[to_insert:] - q.len += copy(data[:], the_items) -} - -queue_push :: proc{queue_push_back, queue_push_elems} - - - -_queue_increase_capacity :: proc(q: ^$Q/Queue($T), new_capacity: int) { - end := array_len(q.data) - array_resize(&q.data, new_capacity) - if q.offset + q.len > end { - end_items := q.len + end - data := array_slice(q.data) - copy(data[new_capacity-end_items:][:end_items], data[q.offset:][:end_items]) - q.offset += new_capacity - end - } -} -_queue_grow :: proc(q: ^$Q/Queue($T), min_capacity: int = 0) { - new_capacity := max(array_len(q.data)*2 + 8, min_capacity) - _queue_increase_capacity(q, new_capacity) -} diff --git a/core/container/ring.odin b/core/container/ring.odin deleted file mode 100644 index 61492ec84..000000000 --- a/core/container/ring.odin +++ /dev/null @@ -1,74 +0,0 @@ -package container - - -Ring :: struct($T: typeid) { - next, prev: ^Ring(T), - value: T, -} - -ring_init :: proc(r: ^$R/Ring) -> ^R { - r.prev, r.next = r, r - return r -} - -ring_next :: proc(r: ^$R/Ring) -> ^R { - if r.next == nil { - return ring_init(r) - } - return r.next -} -ring_prev :: proc(r: ^$R/Ring) -> ^R { - if r.prev == nil { - return ring_init(r) - } - return r.prev -} - - -ring_move :: proc(r: ^$R/Ring, n: int) -> ^R { - r := r - if r.next == nil { - return ring_init(r) - } - - switch { - case n < 0: - for _ in n..<0 { - r = r.prev - } - case n > 0: - for _ in 0.. ^R { - n := ring_next(r) - if s != nil { - p := ring_prev(s) - r.next = s - s.prev = r - n.prev = p - p.next = n - } - return n -} -ring_unlink :: proc(r: ^$R/Ring, n: int) -> ^R { - if n <= 0 { - return nil - } - return ring_link(r, ring_move(r, n+1)) -} -ring_len :: proc(r: ^$R/Ring) -> int { - n := 0 - if r != nil { - n = 1 - for p := ring_next(r); p != r; p = p.next { - n += 1 - } - } - return n -} - diff --git a/core/container/set.odin b/core/container/set.odin deleted file mode 100644 index 562ac5409..000000000 --- a/core/container/set.odin +++ /dev/null @@ -1,240 +0,0 @@ -package container - -Set :: struct { - hash: Array(int), - entries: Array(Set_Entry), -} - -Set_Entry :: struct { - key: u64, - next: int, -} - - -/* -set_init :: proc{ - set_init_none, - set_init_cap, -} -set_delete - -set_in -set_not_in -set_add -set_remove -set_reserve -set_clear -*/ - -set_init :: proc{set_init_none, set_init_cap} - -set_init_none :: proc(m: ^Set, allocator := context.allocator) { - m.hash.allocator = allocator - m.entries.allocator = allocator -} - -set_init_cap :: proc(m: ^Set, cap: int, allocator := context.allocator) { - m.hash.allocator = allocator - m.entries.allocator = allocator - set_reserve(m, cap) -} - -set_delete :: proc(m: Set) { - array_delete(m.hash) - array_delete(m.entries) -} - - -set_in :: proc(m: Set, key: u64) -> bool { - return _set_find_or_fail(m, key) >= 0 -} -set_not_in :: proc(m: Set, key: u64) -> bool { - return _set_find_or_fail(m, key) < 0 -} - -set_add :: proc(m: ^Set, key: u64) { - if array_len(m.hash) == 0 { - _set_grow(m) - } - - _ = _set_find_or_make(m, key) - if _set_full(m^) { - _set_grow(m) - } -} - -set_remove :: proc(m: ^Set, key: u64) { - fr := _set_find_key(m^, key) - if fr.entry_index >= 0 { - _set_erase(m, fr) - } -} - - -set_reserve :: proc(m: ^Set, new_size: int) { - nm: Set - set_init(&nm, m.hash.allocator) - array_resize(&nm.hash, new_size) - array_reserve(&nm.entries, array_len(m.entries)) - - for i in 0.. bool { - a_entries := array_slice(a.entries) - b_entries := array_slice(b.entries) - if len(a_entries) != len(b_entries) { - return false - } - for e in a_entries { - if set_not_in(b, e.key) { - return false - } - } - - return true -} - - - -/// Internal - -_set_add_entry :: proc(m: ^Set, key: u64) -> int { - e: Set_Entry - e.key = key - e.next = -1 - idx := array_len(m.entries) - array_push(&m.entries, e) - return idx -} - -_set_erase :: proc(m: ^Set, fr: Map_Find_Result) { - if fr.entry_prev < 0 { - array_set(&m.hash, fr.hash_index, array_get(m.entries, fr.entry_index).next) - } else { - array_get_ptr(m.entries, fr.entry_prev).next = array_get(m.entries, fr.entry_index).next - } - - if fr.entry_index == array_len(m.entries)-1 { - array_pop_back(&m.entries) - return - } - - array_set(&m.entries, fr.entry_index, array_get(m.entries, array_len(m.entries)-1)) - last := _set_find_key(m^, array_get(m.entries, fr.entry_index).key) - - if last.entry_prev < 0 { - array_get_ptr(m.entries, last.entry_prev).next = fr.entry_index - } else { - array_set(&m.hash, last.hash_index, fr.entry_index) - } -} - - -_set_find_key :: proc(m: Set, key: u64) -> Map_Find_Result { - fr: Map_Find_Result - fr.hash_index = -1 - fr.entry_prev = -1 - fr.entry_index = -1 - - if array_len(m.hash) == 0 { - return fr - } - - fr.hash_index = int(key % u64(array_len(m.hash))) - fr.entry_index = array_get(m.hash, fr.hash_index) - for fr.entry_index >= 0 { - it := array_get_ptr(m.entries, fr.entry_index) - if it.key == key { - return fr - } - fr.entry_prev = fr.entry_index - fr.entry_index = it.next - } - return fr -} - -_set_find_entry :: proc(m: ^Set, e: ^Set_Entry) -> Map_Find_Result { - fr: Map_Find_Result - fr.hash_index = -1 - fr.entry_prev = -1 - fr.entry_index = -1 - - if array_len(m.hash) == 0 { - return fr - } - - fr.hash_index = int(e.key % u64(array_len(m.hash))) - fr.entry_index = array_get(m.hash, fr.hash_index) - for fr.entry_index >= 0 { - it := array_get_ptr(m.entries, fr.entry_index) - if it == e { - return fr - } - fr.entry_prev = fr.entry_index - fr.entry_index = it.next - } - return fr -} - -_set_find_or_fail :: proc(m: Set, key: u64) -> int { - return _set_find_key(m, key).entry_index -} -_set_find_or_make :: proc(m: ^Set, key: u64) -> int { - fr := _set_find_key(m^, key) - if fr.entry_index >= 0 { - return fr.entry_index - } - - i := _set_add_entry(m, key) - if fr.entry_prev < 0 { - array_set(&m.hash, fr.hash_index, i) - } else { - array_get_ptr(m.entries, fr.entry_prev).next = i - } - return i -} - - -_set_make :: proc(m: ^Set, key: u64) -> int { - fr := _set_find_key(m^, key) - i := _set_add_entry(m, key) - - if fr.entry_prev < 0 { - array_set(&m.hash, fr.hash_index, i) - } else { - array_get_ptr(m.entries, fr.entry_prev).next = i - } - - array_get_ptr(m.entries, i).next = fr.entry_index - - return i -} - - -_set_full :: proc(m: Set) -> bool { - // TODO(bill): Determine good max load factor - return array_len(m.entries) >= (array_len(m.hash) / 4)*3 -} - -_set_grow :: proc(m: ^Set) { - new_size := array_len(m.entries) * 4 + 7 // TODO(bill): Determine good grow rate - set_reserve(m, new_size) -} - - diff --git a/core/container/small_array.odin b/core/container/small_array.odin deleted file mode 100644 index 43b879d2d..000000000 --- a/core/container/small_array.odin +++ /dev/null @@ -1,95 +0,0 @@ -package container - -Small_Array :: struct($N: int, $T: typeid) where N >= 0 { - data: [N]T, - len: int, -} - - -small_array_len :: proc(a: $A/Small_Array) -> int { - return a.len -} - -small_array_cap :: proc(a: $A/Small_Array) -> int { - return len(a.data) -} - -small_array_space :: proc(a: $A/Small_Array) -> int { - return len(a.data) - a.len -} - -small_array_slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T { - return a.data[:a.len] -} - - -small_array_get :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> T { - return a.data[index] -} -small_array_get_ptr :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> ^T { - return &a.data[index] -} - -small_array_set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T, loc := #caller_location) { - a.data[index] = item -} - -small_array_resize :: proc(a: ^$A/Small_Array, length: int) { - a.len = min(length, len(a.data)) -} - - -small_array_push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool { - if a.len < len(a.data) { - a.len += 1 - a.data[a.len-1] = item - return true - } - return false -} - -small_array_push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool { - if a.len < len(a.data) { - a.len += 1 - data := small_array_slice(a) - copy(data[1:], data[:]) - data[0] = item - return true - } - return false -} - -small_array_pop_back :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T { - assert(condition=a.len > 0, loc=loc) - item := a.data[a.len-1] - a.len -= 1 - return item -} - -small_array_pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T { - assert(condition=a.len > 0, loc=loc) - item := a.data[0] - s := small_array_slice(a) - copy(s[:], s[1:]) - a.len -= 1 - return item -} - - -small_array_consume :: proc(a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) { - assert(condition=a.len >= count, loc=loc) - a.len -= count -} - -small_array_clear :: proc(a: ^$A/Small_Array($N, $T)) { - small_array_resize(a, 0) -} - -small_array_push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) { - n := copy(a.data[a.len:], items[:]) - a.len += n -} - -small_array_push :: proc{small_array_push_back, small_array_push_back_elems} -small_array_append :: proc{small_array_push_back, small_array_push_back_elems} - From dbf42d2469eec3980c6525c784aa6e594f49565e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 Dec 2021 14:16:27 +0000 Subject: [PATCH 0116/1258] make `slice.as_ptr` return `[^]E` --- core/slice/slice.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index a82c5fa96..c06e796ce 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -273,7 +273,7 @@ get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) { return } -as_ptr :: proc(array: $T/[]$E) -> ^E { +as_ptr :: proc(array: $T/[]$E) -> [^]E { return raw_data(array) } From 53e30e4621558f5d003eacc7b4a7f209723670c4 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 7 Dec 2021 18:45:46 +0100 Subject: [PATCH 0117/1258] [core:container/bit_vector] Create new package. A dynamic bit array, optionally allowing negative indices. --- core/container/bit_array/bit_array.odin | 124 ++++++++++++++++++++++++ core/container/bit_array/doc.odin | 52 ++++++++++ 2 files changed, 176 insertions(+) create mode 100644 core/container/bit_array/bit_array.odin create mode 100644 core/container/bit_array/doc.odin diff --git a/core/container/bit_array/bit_array.odin b/core/container/bit_array/bit_array.odin new file mode 100644 index 000000000..61f6f86e8 --- /dev/null +++ b/core/container/bit_array/bit_array.odin @@ -0,0 +1,124 @@ +package dynamic_bit_array + +import "core:intrinsics" + +/* + Note that these constants are dependent on the backing being a u64. +*/ +@(private="file") +INDEX_SHIFT :: 6 + +@(private="file") +INDEX_MASK :: 63 + +Bit_Array :: struct { + bits: [dynamic]u64, + bias: int, +} + +/* + In: + - ba: ^Bit_Array - a pointer to the Bit Array + - index: The bit index. Can be an enum member. + + Out: + - res: The bit you're interested in. + - ok: Whether the index was valid. Returns `false` if the index is smaller than the bias. + + The `ok` return value may be ignored. +*/ +get :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (res: bool, ok: bool) { + idx := int(index) - ba.bias + + if ba == nil || int(index) < ba.bias { return false, false } + context.allocator = allocator + + leg_index := idx >> INDEX_SHIFT + bit_index := idx & INDEX_MASK + + /* + If we `get` a bit that doesn't fit in the Bit Array, it's naturally `false`. + This early-out prevents unnecessary resizing. + */ + if leg_index + 1 > len(ba.bits) { return false, true } + + val := u64(1 << uint(bit_index)) + res = ba.bits[leg_index] & val == val + + return res, true +} + +/* + In: + - ba: ^Bit_Array - a pointer to the Bit Array + - index: The bit index. Can be an enum member. + + Out: + - ok: Whether or not we managed to set requested bit. + + `set` automatically resizes the Bit Array to accommodate the requested index if needed. +*/ +set :: proc(ba: ^Bit_Array, #any_int index: uint, allocator := context.allocator) -> (ok: bool) { + + idx := int(index) - ba.bias + + if ba == nil || int(index) < ba.bias { return false } + context.allocator = allocator + + leg_index := idx >> INDEX_SHIFT + bit_index := idx & INDEX_MASK + + resize_if_needed(ba, leg_index) or_return + + ba.bits[leg_index] |= 1 << uint(bit_index) + return true +} + +/* + A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative). +*/ +create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -> (res: Bit_Array, ok: bool) #optional_ok { + context.allocator = allocator + size_in_bits := max_index - min_index + + if size_in_bits < 1 { return {}, false } + + legs := size_in_bits >> INDEX_SHIFT + + res = Bit_Array{ + bias = min_index, + } + return res, resize_if_needed(&res, size_in_bits) +} + +/* + Sets all bits to `false`. +*/ +clear :: proc(ba: ^Bit_Array) { + if ba == nil { return } + ba.bits = {} +} + +/* + Releases the memory used by the Bit Array. +*/ +destroy :: proc(ba: ^Bit_Array) { + if ba == nil { return } + delete(ba.bits) +} + +/* + Resizes the Bit Array. For internal use. + If you want to reserve the memory for a given-sized Bit Array up front, you can use `create`. +*/ +@(private="file") +resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocator) -> (ok: bool) { + if ba == nil { return false } + + context.allocator = allocator + + if legs + 1 > len(ba.bits) { + resize(&ba.bits, legs + 1) + } + return len(ba.bits) > legs +} \ No newline at end of file diff --git a/core/container/bit_array/doc.odin b/core/container/bit_array/doc.odin new file mode 100644 index 000000000..91e1362dd --- /dev/null +++ b/core/container/bit_array/doc.odin @@ -0,0 +1,52 @@ +package dynamic_bit_array + +/* + The Bit Array can be used in several ways: + + -- By default you don't need to instantiate a Bit Array: + + package test + + import "core:fmt" + import "core:container/bit_array" + + main :: proc() { + using bit_array + + bits: Bit_Array + + // returns `true` + fmt.println(set(&bits, 42)) + + // returns `false`, `false`, because this Bit Array wasn't created to allow negative indices. + was_set, was_retrieved := get(&bits, -1) + fmt.println(was_set, was_retrieved) + } + + -- A Bit Array can optionally allow for negative indices, if the mininum value was given during creation: + + package test + + import "core:fmt" + import "core:container/bit_array" + + main :: proc() { + Foo :: enum int { + Negative_Test = -42, + Bar = 420, + Leaves = 69105, + } + + using bit_array + + bits := create(int(max(Foo)), int(min(Foo))) + defer destroy(&bits) + + fmt.printf("Set(Bar): %v\n", set(&bits, Foo.Bar)) + fmt.printf("Get(Bar): %v, %v\n", get(&bits, Foo.Bar)) + fmt.printf("Set(Negative_Test): %v\n", set(&bits, Foo.Negative_Test)) + fmt.printf("Get(Leaves): %v, %v\n", get(&bits, Foo.Leaves)) + fmt.printf("Get(Negative_Test): %v, %v\n", get(&bits, Foo.Negative_Test)) + fmt.printf("Freed.\n") + } +*/ \ No newline at end of file From 92e70b9a589038bdcfd0f715bb1172b15432caa6 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Tue, 28 Dec 2021 16:19:38 +0100 Subject: [PATCH 0118/1258] use multipointers instead of simple pointers --- core/slice/slice.odin | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 992efb3f1..426829a22 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -306,21 +306,17 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) - scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U)->V, allocator := context.allocator) -> []V { if len(s) == 0 { return {} } - p := as_ptr(s) res := make([]V, len(s), allocator) - + p := as_ptr(s) q := as_ptr(res) - l := len(res) + r := initializer - r := initializer - - for l > 0 { - r = f(r, p^) - q^ = r - p = intrinsics.ptr_offset(p, 1) - q = intrinsics.ptr_offset(q, 1) - l -= 1 + for l := len(s); l > 0; l -= 1 { + r = f(r, p[0]) + q[0] = r + p = p[1:] + q = q[1:] } return res From 865d88dd56a8b048e861787e048f364a4579da2b Mon Sep 17 00:00:00 2001 From: Henry Dooley Date: Tue, 28 Dec 2021 10:50:34 -0600 Subject: [PATCH 0119/1258] review feedback --- src/llvm_backend_const.cpp | 2 -- src/llvm_backend_general.cpp | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index bc14b099b..2eedbb7c9 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -410,8 +410,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc // NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs // its backing data on the stack lbProcedure *p = m->curr_procedure; - LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); - LLVMTypeRef llvm_type = lb_type(m, t); array_data = llvm_alloca(p, llvm_type, 16); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 46b5fdb88..1f97826f4 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -217,8 +217,11 @@ LLVMValueRef llvm_one(lbModule *m) { } LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const* name) { + LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); + LLVMValueRef val = LLVMBuildAlloca(p->builder, llvm_type, name); LLVMSetAlignment(val, cast(unsigned int)alignment); + LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); return val; @@ -2273,7 +2276,6 @@ general_end:; return loaded_val; } else { GB_ASSERT(p->decl_block != p->curr_block); - LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type)); max_align = gb_max(max_align, 4); From c46e7eda1db0d509589dfca140802fdd3f2580eb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 29 Dec 2021 11:26:22 +0000 Subject: [PATCH 0120/1258] Add `core:container/small_array` --- core/container/small_array/small_array.odin | 117 ++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 core/container/small_array/small_array.odin diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin new file mode 100644 index 000000000..60c22837c --- /dev/null +++ b/core/container/small_array/small_array.odin @@ -0,0 +1,117 @@ +package container_small_array + +import "core:builtin" + +Small_Array :: struct($N: int, $T: typeid) where N >= 0 { + data: [N]T, + len: int, +} + + +len :: proc(a: $A/Small_Array) -> int { + return a.len +} + +cap :: proc(a: $A/Small_Array) -> int { + return builtin.len(a.data) +} + +space :: proc(a: $A/Small_Array) -> int { + return builtin.len(a.data) - a.len +} + +slice :: proc(a: ^$A/Small_Array($N, $T)) -> []T { + return a.data[:a.len] +} + + +get :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> T { + return a.data[index] +} +get_ptr :: proc(a: $A/Small_Array($N, $T), index: int, loc := #caller_location) -> ^T { + return &a.data[index] +} + +set :: proc(a: ^$A/Small_Array($N, $T), index: int, item: T, loc := #caller_location) { + a.data[index] = item +} + +resize :: proc(a: ^$A/Small_Array, length: int) { + a.len = min(length, builtin.len(a.data)) +} + + +push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool { + if a.len < builtin.len(a.data) { + a.len += 1 + a.data[a.len-1] = item + return true + } + return false +} + +push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool { + if a.len < builtin.len(a.data) { + a.len += 1 + data := slice(a) + copy(data[1:], data[:]) + data[0] = item + return true + } + return false +} + +pop_back :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T { + assert(condition=(N > 0 && a.len > 0), loc=loc) + item := a.data[a.len-1] + a.len -= 1 + return item +} + +pop_front :: proc(a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T { + assert(condition=(N > 0 && a.len > 0), loc=loc) + item := a.data[0] + s := slice(a) + copy(s[:], s[1:]) + a.len -= 1 + return item +} + +pop_back_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) { + if N > 0 && a.len > 0 { + item = a.data[a.len-1] + a.len -= 1 + ok = true + } + return +} + +pop_front_safe :: proc(a: ^$A/Small_Array($N, $T)) -> (T, bool) { + if N > 0 && a.len > 0 { + item = a.data[0] + s := slice(a) + copy(s[:], s[1:]) + a.len -= 1 + ok = true + } + return +} + +consume :: proc(a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) { + assert(condition=a.len >= count, loc=loc) + a.len -= count +} + +clear :: proc(a: ^$A/Small_Array($N, $T)) { + resize(a, 0) +} + +push_back_elems :: proc(a: ^$A/Small_Array($N, $T), items: ..T) { + n := copy(a.data[a.len:], items[:]) + a.len += n +} + +append_elem :: push_back +append_elems :: push_back_elems +push :: proc{push_back, push_back_elems} +append :: proc{push_back, push_back_elems} \ No newline at end of file From a66f859fb49b2d31809767aaa8b4d8872b73c062 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 29 Dec 2021 11:58:27 +0000 Subject: [PATCH 0121/1258] Minor improvements to `core:container/small_array` --- core/container/small_array/small_array.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin index 60c22837c..d09e0c81c 100644 --- a/core/container/small_array/small_array.odin +++ b/core/container/small_array/small_array.odin @@ -42,16 +42,16 @@ resize :: proc(a: ^$A/Small_Array, length: int) { push_back :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool { - if a.len < builtin.len(a.data) { + if a.len < cap(a^) { + a.data[a.len] = item a.len += 1 - a.data[a.len-1] = item return true } return false } push_front :: proc(a: ^$A/Small_Array($N, $T), item: T) -> bool { - if a.len < builtin.len(a.data) { + if a.len < cap(a^) { a.len += 1 data := slice(a) copy(data[1:], data[:]) From a9b17b5a37b611dae51da6153de8239dfa08f202 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 29 Dec 2021 12:01:07 +0000 Subject: [PATCH 0122/1258] Add `hash.djbx33a` --- core/hash/djbx33a.odin | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 core/hash/djbx33a.odin diff --git a/core/hash/djbx33a.odin b/core/hash/djbx33a.odin new file mode 100644 index 000000000..db286b660 --- /dev/null +++ b/core/hash/djbx33a.odin @@ -0,0 +1,18 @@ +package hash + +djbx33a :: proc(data: []byte) -> (result: [16]byte) #no_bounds_check { + state := [4]u32{5381, 5381, 5381, 5381} + + s: u32 = 0 + for p in data { + state[s] = (state[s] << 5) + state[s] + u32(p) + s = (s + 1) & 3 + } + + + (^u32le)(&result[0])^ = u32le(state[0]) + (^u32le)(&result[4])^ = u32le(state[1]) + (^u32le)(&result[8])^ = u32le(state[2]) + (^u32le)(&result[12])^ = u32le(state[3]) + return +} \ No newline at end of file From c987b8429219d9d823a658fd25a6661fe949bebd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 29 Dec 2021 12:24:47 +0000 Subject: [PATCH 0123/1258] Move bash.djbx33a to hash.odin --- core/hash/djbx33a.odin | 18 ------------------ core/hash/hash.odin | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 18 deletions(-) delete mode 100644 core/hash/djbx33a.odin diff --git a/core/hash/djbx33a.odin b/core/hash/djbx33a.odin deleted file mode 100644 index db286b660..000000000 --- a/core/hash/djbx33a.odin +++ /dev/null @@ -1,18 +0,0 @@ -package hash - -djbx33a :: proc(data: []byte) -> (result: [16]byte) #no_bounds_check { - state := [4]u32{5381, 5381, 5381, 5381} - - s: u32 = 0 - for p in data { - state[s] = (state[s] << 5) + state[s] + u32(p) - s = (s + 1) & 3 - } - - - (^u32le)(&result[0])^ = u32le(state[0]) - (^u32le)(&result[4])^ = u32le(state[1]) - (^u32le)(&result[8])^ = u32le(state[2]) - (^u32le)(&result[12])^ = u32le(state[3]) - return -} \ No newline at end of file diff --git a/core/hash/hash.odin b/core/hash/hash.odin index f0d01bd25..5044d567a 100644 --- a/core/hash/hash.odin +++ b/core/hash/hash.odin @@ -55,6 +55,23 @@ djb2 :: proc(data: []byte, seed := u32(5381)) -> u32 { return hash } +djbx33a :: proc(data: []byte, seed := u32(5381)) -> (result: [16]byte) #no_bounds_check { + state := [4]u32{seed, seed, seed, seed} + + s: u32 = 0 + for p in data { + state[s] = (state[s] << 5) + state[s] + u32(p) // hash * 33 + u32(b) + s = (s + 1) & 3 + } + + + (^u32le)(&result[0])^ = u32le(state[0]) + (^u32le)(&result[4])^ = u32le(state[1]) + (^u32le)(&result[8])^ = u32le(state[2]) + (^u32le)(&result[12])^ = u32le(state[3]) + return +} + @(optimization_mode="speed") fnv32 :: proc(data: []byte, seed := u32(0x811c9dc5)) -> u32 { h: u32 = seed From ed8b20da787edd3747cc85708a0b9dd2c2e256d1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 29 Dec 2021 14:38:39 +0000 Subject: [PATCH 0124/1258] Add `core:container/priority_queue` --- .../priority_queue/priority_queue.odin | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 core/container/priority_queue/priority_queue.odin diff --git a/core/container/priority_queue/priority_queue.odin b/core/container/priority_queue/priority_queue.odin new file mode 100644 index 000000000..f53dced38 --- /dev/null +++ b/core/container/priority_queue/priority_queue.odin @@ -0,0 +1,140 @@ +package container_priority_queue + +import "core:builtin" + +Priority_Queue :: struct($T: typeid) { + data: [dynamic]T, + len: int, + priority: proc(item: T) -> int, +} + +DEFAULT_CAPACITY :: 16 + +init_none :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, allocator := context.allocator) { + init_len(q, f, 0, allocator) +} +init_len :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, allocator := context.allocator) { + init_len_cap(q, f, 0, DEFAULT_CAPACITY, allocator) +} +init_len_cap :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, cap: int, allocator := context.allocator) { + if q.data.allocator.procedure == nil { + q.data.allocator = allocator + } + builtin.resize(&q.data, cap) + q.len = len + q.priority = f +} + +init :: proc{init_none, init_len, init_len_cap} + + +delete :: proc(q: $Q/Priority_Queue($T)) { + builtin.delete(q.data) +} + +clear :: proc(q: ^$Q/Priority_Queue($T)) { + q.len = 0 +} + +len :: proc(q: $Q/Priority_Queue($T)) -> int { + return q.len +} + +cap :: proc(q: $Q/Priority_Queue($T)) -> int { + return builtin.cap(q.data) +} + +space :: proc(q: $Q/Priority_Queue($T)) -> int { + return builtin.len(q.data) - q.len +} + +reserve :: proc(q: ^$Q/Priority_Queue($T), capacity: int) { + if capacity > q.len { + builtin.resize(&q.data, capacity) + } +} + +resize :: proc(q: ^$Q/Priority_Queue($T), length: int) { + if length > q.len { + builtin.resize(&q.data, length) + } + q.len = length +} + +_grow :: proc(q: ^$Q/Priority_Queue($T), min_capacity: int = 8) { + new_capacity := max(builtin.len(q.data)*2, min_capacity, 1) + builtin.resize(&q.data, new_capacity) +} + + +push :: proc(q: ^$Q/Priority_Queue($T), item: T) { + if builtin.len(q.data) - q.len == 0 { + _grow(q) + } + + s := q.data[:] + s[q.len] = item + + i := q.len + for i > 0 { + p := (i - 1) / 2 + if q.priority(s[p]) <= q.priority(item) { + break + } + s[i] = s[p] + i = p + } + + q.len += 1 + if q.len > 0 { + s[i] = item + } +} + +pop :: proc(q: ^$Q/Priority_Queue($T), loc := #caller_location) -> T { + val, ok := pop_safe(q) + assert(condition=ok, loc=loc) + return val +} + + +pop_safe :: proc(q: ^$Q/Priority_Queue($T)) -> (T, bool) { + if q.len > 0 { + s := q.data[:] + min := s[0] + root := s[q.len-1] + q.len -= 1 + + i := 0 + for i * 2 + 1 < q.len { + a := i * 2 + 1 + b := i * 2 + 2 + c := b < q.len && q.priority(s[b]) < q.priority(s[a]) ? b : a + + if q.priority(s[c]) >= q.priority(root) { + break + } + s[i] = s[c] + i = c + } + + if q.len > 0 { + s[i] = root + } + return min, true + } + return T{}, false +} + +peek :: proc(q: ^$Q/Priority_Queue($T), loc := #caller_location) -> T { + assert(condition=q.len > 0, loc=loc) + + return q.data[0] +} + +peek_safe :: proc(q: ^$Q/Priority_Queue($T)) -> (T, bool) { + if q.len > 0 { + return q.data[0], true + } + return T{}, false +} \ No newline at end of file From ed742846cb6447d9d9ff6a4cfde285d7f4bb0eb9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 29 Dec 2021 15:01:56 +0000 Subject: [PATCH 0125/1258] Correct `lb_emit_ptr_offset` bug caused by `LLVMConstGEP` assuming a signed index --- src/llvm_backend_utility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 0350f7287..3fe96459f 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1200,7 +1200,7 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { } lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { - index = lb_correct_endianness(p, index); + index = lb_emit_conv(p, index, t_int); LLVMValueRef indices[1] = {index.value}; lbValue res = {}; res.type = ptr.type; From 750ee4ecdbe4c0f9d2eb72fa0fc0710f11ba035f Mon Sep 17 00:00:00 2001 From: kleeon Date: Thu, 30 Dec 2021 15:00:45 +0300 Subject: [PATCH 0126/1258] Fixed wrong function name in README.md --- vendor/OpenGL/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/OpenGL/README.md b/vendor/OpenGL/README.md index 9e7a7bbbc..928d5eb5d 100644 --- a/vendor/OpenGL/README.md +++ b/vendor/OpenGL/README.md @@ -9,7 +9,7 @@ gl.load_up_to(4, 5, proc(p: rawptr, name: cstring) do (cast(^rawptr)p)^ = glfw.G ``` [odin-glfw](https://github.com/vassvik/odin-glfw) also provides a useful helper you can pass straight to `gl.load_up_to`: ```go -gl.load_up_to(4, 5, glfw.set_proc_address); +gl.load_up_to(4, 5, glfw.gl_set_proc_address); ``` #### NOTE: It is recommended to put this into the shared collection: From c7ff296bef1b51004cfee2470d5d95abe391dabe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 30 Dec 2021 13:42:10 +0000 Subject: [PATCH 0127/1258] Change the implementation of `Priority_Queue` to have a better interface that allows for a `less` and `swap` procedure --- .../priority_queue/priority_queue.odin | 220 +++++++++--------- 1 file changed, 109 insertions(+), 111 deletions(-) diff --git a/core/container/priority_queue/priority_queue.odin b/core/container/priority_queue/priority_queue.odin index f53dced38..df26edb1b 100644 --- a/core/container/priority_queue/priority_queue.odin +++ b/core/container/priority_queue/priority_queue.odin @@ -3,138 +3,136 @@ package container_priority_queue import "core:builtin" Priority_Queue :: struct($T: typeid) { - data: [dynamic]T, - len: int, - priority: proc(item: T) -> int, + queue: [dynamic]T, + + less: proc(a, b: T) -> bool, + swap: proc(q: []T, i, j: int), } DEFAULT_CAPACITY :: 16 -init_none :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, allocator := context.allocator) { - init_len(q, f, 0, allocator) -} -init_len :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, allocator := context.allocator) { - init_len_cap(q, f, 0, DEFAULT_CAPACITY, allocator) -} -init_len_cap :: proc(q: ^$Q/Priority_Queue($T), f: proc(item: T) -> int, len: int, cap: int, allocator := context.allocator) { - if q.data.allocator.procedure == nil { - q.data.allocator = allocator +init :: proc(pq: ^$Q/Priority_Queue($T), less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int), capacity := DEFAULT_CAPACITY, allocator := context.allocator) { + if pq.queue.allocator.procedure == nil { + pq.queue.allocator = allocator } - builtin.resize(&q.data, cap) - q.len = len - q.priority = f + reserve(pq, capacity) + pq.less = less + pq.swap = swap } -init :: proc{init_none, init_len, init_len_cap} - - -delete :: proc(q: $Q/Priority_Queue($T)) { - builtin.delete(q.data) -} - -clear :: proc(q: ^$Q/Priority_Queue($T)) { - q.len = 0 -} - -len :: proc(q: $Q/Priority_Queue($T)) -> int { - return q.len -} - -cap :: proc(q: $Q/Priority_Queue($T)) -> int { - return builtin.cap(q.data) -} - -space :: proc(q: $Q/Priority_Queue($T)) -> int { - return builtin.len(q.data) - q.len -} - -reserve :: proc(q: ^$Q/Priority_Queue($T), capacity: int) { - if capacity > q.len { - builtin.resize(&q.data, capacity) +init_from_dynamic_array :: proc(pq: ^$Q/Priority_Queue($T), queue: [dynamic]T, less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int)) { + pq.queue = queue + pq.less = less + pq.swap = swap + n := builtin.len(pq.queue) + for i := n/2 - 1; i >= 0; i -= 1 { + _shift_down(pq, i, n) } } -resize :: proc(q: ^$Q/Priority_Queue($T), length: int) { - if length > q.len { - builtin.resize(&q.data, length) - } - q.len = length +destroy :: proc(pq: ^$Q/Priority_Queue($T)) { + clear(pq) + delete(pq.queue) } -_grow :: proc(q: ^$Q/Priority_Queue($T), min_capacity: int = 8) { - new_capacity := max(builtin.len(q.data)*2, min_capacity, 1) - builtin.resize(&q.data, new_capacity) +reserve :: proc(pq: ^$Q/Priority_Queue($T), capacity: int) { + builtin.reserve(&pq.queue, capacity) +} +clear :: proc(pq: ^$Q/Priority_Queue($T)) { + builtin.clear(&pq.queue) +} +len :: proc(pq: $Q/Priority_Queue($T)) -> int { + return builtin.len(pq.queue) +} +cap :: proc(pq: $Q/Priority_Queue($T)) -> int { + return builtin.cap(pq.queue) } - -push :: proc(q: ^$Q/Priority_Queue($T), item: T) { - if builtin.len(q.data) - q.len == 0 { - _grow(q) +_shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool { + // O(n log n) + i := i0 + j, j1, j2: int + if 0 > i || i > n { + return false } - - s := q.data[:] - s[q.len] = item - - i := q.len - for i > 0 { - p := (i - 1) / 2 - if q.priority(s[p]) <= q.priority(item) { - break + + queue := pq.queue[:] + + for { + j1 := 2*i + 1 + if 0 > j1 || j1 >= n { + break } - s[i] = s[p] - i = p - } - - q.len += 1 - if q.len > 0 { - s[i] = item - } -} - -pop :: proc(q: ^$Q/Priority_Queue($T), loc := #caller_location) -> T { - val, ok := pop_safe(q) - assert(condition=ok, loc=loc) - return val -} - - -pop_safe :: proc(q: ^$Q/Priority_Queue($T)) -> (T, bool) { - if q.len > 0 { - s := q.data[:] - min := s[0] - root := s[q.len-1] - q.len -= 1 - - i := 0 - for i * 2 + 1 < q.len { - a := i * 2 + 1 - b := i * 2 + 2 - c := b < q.len && q.priority(s[b]) < q.priority(s[a]) ? b : a - - if q.priority(s[c]) >= q.priority(root) { - break - } - s[i] = s[c] - i = c + j, j2 = j1, j1+1 + if j1 < n && pq.less(queue[j2], queue[j1]) { + j1 = j2 } - - if q.len > 0 { - s[i] = root + if !pq.less(queue[i], queue[j]) { + break } - return min, true + + pq.swap(queue, i, j) + i = j } - return T{}, false + return i > i0 } -peek :: proc(q: ^$Q/Priority_Queue($T), loc := #caller_location) -> T { - assert(condition=q.len > 0, loc=loc) - - return q.data[0] +_shift_up :: proc(pq: ^$Q/Priority_Queue($T), j: int) { + j := j + queue := pq.queue[:] + n := builtin.len(queue) + for 0 <= j && j < n { + i := (j-1)/2 + if i == j || !pq.less(queue[j], queue[i]) { + break + } + pq.swap(queue, i, j) + j = i + } } -peek_safe :: proc(q: ^$Q/Priority_Queue($T)) -> (T, bool) { - if q.len > 0 { - return q.data[0], true +// NOTE(bill): When an element at index 'i' has changed its value, this will fix the +// the heap ordering. This is using a basic "heapsort" with shift up and a shift down parts. +fix :: proc(pq: ^$Q/Priority_Queue($T), i: int) { + if !_shift_down(pq, i, builtin.len(pq.queue)) { + _shift_up(pq, i) } - return T{}, false -} \ No newline at end of file +} + +push :: proc(pq: ^$Q/Priority_Queue($T), value: T) { + append(&pq.queue, value) + _shift_up(pq, builtin.len(pq.queue)-1) +} + +pop :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value: T) { + assert(condition=builtin.len(pq.queue)>0, loc=loc) + + n := builtin.len(pq.queue)-1 + pq.swap(pq.queue[:], 0, n) + _shift_down(pq, 0, n) + return builtin.pop(&pq.queue) +} + +pop_safe :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value: T, ok: bool) { + if builtin.len(pq.queue) > 0 { + n := builtin.len(pq.queue)-1 + pq.swap(pq.queue[:], 0, n) + _shift_down(pq, 0, n) + return builtin.pop_safe(&pq.queue) + } + return +} + +remove :: proc(pq: ^$Q/Priority_Queue($T), i: int) -> (value: T, ok: bool) { + n := builtin.len(pq.queue) + if 0 <= i && i < n { + if n != i { + pq.swap(pq.queue[:], i, n) + _shift_down(pq, i, n) + _shift_up(pq, i) + } + value, ok = builtin.pop_safe(&pq.queue) + } + return +} + From 42033ea808ae3b97d909f538e422e63dadfd8f6c Mon Sep 17 00:00:00 2001 From: zhibog Date: Fri, 31 Dec 2021 13:16:11 +0100 Subject: [PATCH 0128/1258] Extended crypto API by variants that write the result into a destination buffer, instead of returning it --- core/crypto/README.md | 8 +- core/crypto/blake/blake.odin | 145 +++++-- core/crypto/blake2b/blake2b.odin | 40 +- core/crypto/blake2s/blake2s.odin | 40 +- core/crypto/gost/gost.odin | 36 +- core/crypto/groestl/groestl.odin | 145 +++++-- core/crypto/haval/haval.odin | 564 +++++++++++++++++++++----- core/crypto/jh/jh.odin | 145 +++++-- core/crypto/keccak/keccak.odin | 167 ++++++-- core/crypto/md2/md2.odin | 64 ++- core/crypto/md4/md4.odin | 40 +- core/crypto/md5/md5.odin | 40 +- core/crypto/ripemd/ripemd.odin | 141 +++++-- core/crypto/sha1/sha1.odin | 37 +- core/crypto/sha2/sha2.odin | 145 +++++-- core/crypto/sha3/sha3.odin | 161 ++++++-- core/crypto/shake/shake.odin | 85 +++- core/crypto/sm3/sm3.odin | 43 +- core/crypto/streebog/streebog.odin | 72 +++- core/crypto/tiger/tiger.odin | 109 ++++- core/crypto/tiger2/tiger2.odin | 109 ++++- core/crypto/whirlpool/whirlpool.odin | 36 +- vendor/botan/README.md | 8 +- vendor/botan/blake2b/blake2b.odin | 37 +- vendor/botan/gost/gost.odin | 37 +- vendor/botan/keccak/keccak.odin | 37 +- vendor/botan/md4/md4.odin | 37 +- vendor/botan/md5/md5.odin | 37 +- vendor/botan/ripemd/ripemd.odin | 37 +- vendor/botan/sha1/sha1.odin | 37 +- vendor/botan/sha2/sha2.odin | 145 +++++-- vendor/botan/sha3/sha3.odin | 145 +++++-- vendor/botan/shake/shake.odin | 73 +++- vendor/botan/skein512/skein512.odin | 94 ++++- vendor/botan/sm3/sm3.odin | 37 +- vendor/botan/streebog/streebog.odin | 73 +++- vendor/botan/tiger/tiger.odin | 109 ++++- vendor/botan/whirlpool/whirlpool.odin | 37 +- 38 files changed, 2690 insertions(+), 662 deletions(-) diff --git a/core/crypto/README.md b/core/crypto/README.md index 5955f9c56..ddcb12d81 100644 --- a/core/crypto/README.md +++ b/core/crypto/README.md @@ -32,9 +32,11 @@ Please see the chart below for the options. #### High level API Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`\*. -Included in these groups are four procedures. +Included in these groups are six procedures. * `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally * `hash_bytes` - Hash a given byte slice and return the computed hash +* `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally +* `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash * `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it * `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true) @@ -59,6 +61,10 @@ main :: proc() { // Compute the hash, using the high level API computed_hash := md4.hash(input) + // Variant that takes a destination buffer, instead of returning the computed hash + hash := make([]byte, md4.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash + md4.hash(input, hash[:]) + // Compute the hash, using the low level API ctx: md4.Md4_Context computed_hash_low: [16]byte diff --git a/core/crypto/blake/blake.odin b/core/crypto/blake/blake.odin index 9d53f8a89..81924ab1e 100644 --- a/core/crypto/blake/blake.odin +++ b/core/crypto/blake/blake.odin @@ -17,16 +17,21 @@ import "core:io" High level API */ +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_384 :: 48 +DIGEST_SIZE_512 :: 64 + // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc "contextless" (data: string) -> [28]byte { +hash_string_224 :: proc "contextless" (data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc "contextless" (data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: Blake256_Context ctx.is224 = true init(&ctx) @@ -35,10 +40,29 @@ hash_bytes_224 :: proc "contextless" (data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: Blake256_Context + ctx.is224 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_224 will read the stream in chunks and compute a // hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: Blake256_Context ctx.is224 = true init(&ctx) @@ -57,7 +81,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224 will read the file provided by the given handle // and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224(os.stream_from_handle(hd)) } else { @@ -65,7 +89,7 @@ hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) return hash_bytes_224(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { @@ -73,18 +97,20 @@ hash_224 :: proc { hash_file_224, hash_bytes_224, hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc "contextless" (data: string) -> [32]byte { +hash_string_256 :: proc "contextless" (data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc "contextless" (data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Blake256_Context ctx.is224 = false init(&ctx) @@ -93,10 +119,29 @@ hash_bytes_256 :: proc "contextless" (data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Blake256_Context + ctx.is224 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Blake256_Context ctx.is224 = false init(&ctx) @@ -115,7 +160,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -123,7 +168,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -131,18 +176,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc "contextless" (data: string) -> [48]byte { +hash_string_384 :: proc "contextless" (data: string) -> [DIGEST_SIZE_384]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc "contextless" (data: []byte) -> [48]byte { - hash: [48]byte +hash_bytes_384 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte { + hash: [DIGEST_SIZE_384]byte ctx: Blake512_Context ctx.is384 = true init(&ctx) @@ -151,10 +198,29 @@ hash_bytes_384 :: proc "contextless" (data: []byte) -> [48]byte { return hash } +// hash_string_to_buffer_384 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_384(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_384 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") + ctx: Blake512_Context + ctx.is384 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_384 will read the stream in chunks and compute a // hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte +hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { + hash: [DIGEST_SIZE_384]byte ctx: Blake512_Context ctx.is384 = true init(&ctx) @@ -173,7 +239,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { // hash_file_384 will read the file provided by the given handle // and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { +hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { if !load_at_once { return hash_stream_384(os.stream_from_handle(hd)) } else { @@ -181,7 +247,7 @@ hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) return hash_bytes_384(buf[:]), ok } } - return [48]byte{}, false + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { @@ -189,18 +255,20 @@ hash_384 :: proc { hash_file_384, hash_bytes_384, hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc "contextless" (data: string) -> [64]byte { +hash_string_512 :: proc "contextless" (data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc "contextless" (data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: Blake512_Context ctx.is384 = false init(&ctx) @@ -209,10 +277,29 @@ hash_bytes_512 :: proc "contextless" (data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: Blake512_Context + ctx.is384 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: Blake512_Context ctx.is384 = false init(&ctx) @@ -231,7 +318,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -239,7 +326,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -247,6 +334,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index 85f9611f9..6d4689b88 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -20,16 +20,18 @@ import "../_blake2" High level API */ +DIGEST_SIZE :: 64 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [64]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: _blake2.Blake2b_Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2B_SIZE @@ -40,10 +42,32 @@ hash_bytes :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: _blake2.Blake2b_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2B_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + _blake2.update(&ctx, data) + _blake2.final(&ctx, hash) +} + + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: _blake2.Blake2b_Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2B_SIZE @@ -64,7 +88,7 @@ hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -72,7 +96,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { return hash_bytes(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -80,6 +104,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index 72d15b227..ad2e800fd 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -20,16 +20,18 @@ import "../_blake2" High level API */ +DIGEST_SIZE :: 32 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [32]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: _blake2.Blake2s_Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2S_SIZE @@ -40,10 +42,32 @@ hash_bytes :: proc(data: []byte) -> [32]byte { return hash } + +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: _blake2.Blake2s_Context + cfg: _blake2.Blake2_Config + cfg.size = _blake2.BLAKE2S_SIZE + ctx.cfg = cfg + _blake2.init(&ctx) + _blake2.update(&ctx, data) + _blake2.final(&ctx, hash) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: _blake2.Blake2s_Context cfg: _blake2.Blake2_Config cfg.size = _blake2.BLAKE2S_SIZE @@ -64,7 +88,7 @@ hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -72,7 +96,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { return hash_bytes(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -80,6 +104,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/core/crypto/gost/gost.odin b/core/crypto/gost/gost.odin index c687e9080..eed684f72 100644 --- a/core/crypto/gost/gost.odin +++ b/core/crypto/gost/gost.odin @@ -18,16 +18,18 @@ import "core:io" High level API */ +DIGEST_SIZE :: 32 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [32]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: Gost_Context init(&ctx) update(&ctx, data) @@ -35,10 +37,28 @@ hash_bytes :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Gost_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: Gost_Context init(&ctx) buf := make([]byte, 512) @@ -56,7 +76,7 @@ hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -64,7 +84,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { return hash_bytes(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -72,6 +92,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/core/crypto/groestl/groestl.odin b/core/crypto/groestl/groestl.odin index 0d305a1d1..5434e31e0 100644 --- a/core/crypto/groestl/groestl.odin +++ b/core/crypto/groestl/groestl.odin @@ -17,16 +17,21 @@ import "core:io" High level API */ +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_384 :: 48 +DIGEST_SIZE_512 :: 64 + // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc(data: string) -> [28]byte { +hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: Groestl_Context ctx.hashbitlen = 224 init(&ctx) @@ -35,10 +40,29 @@ hash_bytes_224 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: Groestl_Context + ctx.hashbitlen = 224 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_224 will read the stream in chunks and compute a // hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: Groestl_Context ctx.hashbitlen = 224 init(&ctx) @@ -57,7 +81,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224 will read the file provided by the given handle // and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224(os.stream_from_handle(hd)) } else { @@ -65,7 +89,7 @@ hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) return hash_bytes_224(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { @@ -73,18 +97,20 @@ hash_224 :: proc { hash_file_224, hash_bytes_224, hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Groestl_Context ctx.hashbitlen = 256 init(&ctx) @@ -93,10 +119,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Groestl_Context + ctx.hashbitlen = 256 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Groestl_Context ctx.hashbitlen = 256 init(&ctx) @@ -115,7 +160,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -123,7 +168,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -131,18 +176,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc(data: string) -> [48]byte { +hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc(data: []byte) -> [48]byte { - hash: [48]byte +hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { + hash: [DIGEST_SIZE_384]byte ctx: Groestl_Context ctx.hashbitlen = 384 init(&ctx) @@ -151,10 +198,29 @@ hash_bytes_384 :: proc(data: []byte) -> [48]byte { return hash } +// hash_string_to_buffer_384 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_384(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_384 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") + ctx: Groestl_Context + ctx.hashbitlen = 384 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_384 will read the stream in chunks and compute a // hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte +hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { + hash: [DIGEST_SIZE_384]byte ctx: Groestl_Context ctx.hashbitlen = 384 init(&ctx) @@ -173,7 +239,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { // hash_file_384 will read the file provided by the given handle // and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { +hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { if !load_at_once { return hash_stream_384(os.stream_from_handle(hd)) } else { @@ -181,7 +247,7 @@ hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) return hash_bytes_384(buf[:]), ok } } - return [48]byte{}, false + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { @@ -189,18 +255,20 @@ hash_384 :: proc { hash_file_384, hash_bytes_384, hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: Groestl_Context ctx.hashbitlen = 512 init(&ctx) @@ -209,10 +277,29 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: Groestl_Context + ctx.hashbitlen = 512 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: Groestl_Context ctx.hashbitlen = 512 init(&ctx) @@ -231,7 +318,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -239,7 +326,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -247,6 +334,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/core/crypto/haval/haval.odin b/core/crypto/haval/haval.odin index 76532d4cd..f95ea344d 100644 --- a/core/crypto/haval/haval.odin +++ b/core/crypto/haval/haval.odin @@ -20,16 +20,22 @@ import "../util" High level API */ +DIGEST_SIZE_128 :: 16 +DIGEST_SIZE_160 :: 20 +DIGEST_SIZE_192 :: 24 +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 + // hash_string_128_3 will hash the given input and return the // computed hash -hash_string_128_3 :: proc(data: string) -> [16]byte { +hash_string_128_3 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128_3(transmute([]byte)(data)) } // hash_bytes_128_3 will hash the given input and return the // computed hash -hash_bytes_128_3 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128_3 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: Haval_Context ctx.hashbitlen = 128 ctx.rounds = 3 @@ -40,10 +46,31 @@ hash_bytes_128_3 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128_3 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128_3 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128_3(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128_3 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128_3 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_128_3 will read the stream in chunks and compute a // hash from its contents -hash_stream_128_3 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: Haval_Context ctx.hashbitlen = 128 ctx.rounds = 3 @@ -64,7 +91,7 @@ hash_stream_128_3 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128_3 will read the file provided by the given handle // and compute a hash -hash_file_128_3 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128_3(os.stream_from_handle(hd)) } else { @@ -72,7 +99,7 @@ hash_file_128_3 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool return hash_bytes_128_3(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128_3 :: proc { @@ -80,18 +107,20 @@ hash_128_3 :: proc { hash_file_128_3, hash_bytes_128_3, hash_string_128_3, + hash_bytes_to_buffer_128_3, + hash_string_to_buffer_128_3, } // hash_string_128_4 will hash the given input and return the // computed hash -hash_string_128_4 :: proc(data: string) -> [16]byte { +hash_string_128_4 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128_4(transmute([]byte)(data)) } // hash_bytes_128_4 will hash the given input and return the // computed hash -hash_bytes_128_4 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128_4 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: Haval_Context ctx.hashbitlen = 128 ctx.rounds = 4 @@ -102,10 +131,31 @@ hash_bytes_128_4 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128_4 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128_4 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128_4(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128_4 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128_4 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_128_4 will read the stream in chunks and compute a // hash from its contents -hash_stream_128_4 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: Haval_Context ctx.hashbitlen = 128 ctx.rounds = 4 @@ -126,7 +176,7 @@ hash_stream_128_4 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128_4 will read the file provided by the given handle // and compute a hash -hash_file_128_4 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128_4(os.stream_from_handle(hd)) } else { @@ -134,7 +184,7 @@ hash_file_128_4 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool return hash_bytes_128_4(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128_4 :: proc { @@ -142,18 +192,20 @@ hash_128_4 :: proc { hash_file_128_4, hash_bytes_128_4, hash_string_128_4, + hash_bytes_to_buffer_128_4, + hash_string_to_buffer_128_4, } // hash_string_128_5 will hash the given input and return the // computed hash -hash_string_128_5 :: proc(data: string) -> [16]byte { +hash_string_128_5 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128_5(transmute([]byte)(data)) } // hash_bytes_128_5 will hash the given input and return the // computed hash -hash_bytes_128_5 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128_5 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: Haval_Context ctx.hashbitlen = 128 ctx.rounds = 5 @@ -164,10 +216,31 @@ hash_bytes_128_5 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128_5 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128_5 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128_5(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128_5 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128_5 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 128 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_128_5 will read the stream in chunks and compute a // hash from its contents -hash_stream_128_5 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: Haval_Context ctx.hashbitlen = 128 ctx.rounds = 5 @@ -188,7 +261,7 @@ hash_stream_128_5 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128_5 will read the file provided by the given handle // and compute a hash -hash_file_128_5 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128_5(os.stream_from_handle(hd)) } else { @@ -196,7 +269,7 @@ hash_file_128_5 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool return hash_bytes_128_5(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128_5 :: proc { @@ -204,18 +277,20 @@ hash_128_5 :: proc { hash_file_128_5, hash_bytes_128_5, hash_string_128_5, + hash_bytes_to_buffer_128_5, + hash_string_to_buffer_128_5, } // hash_string_160_3 will hash the given input and return the // computed hash -hash_string_160_3 :: proc(data: string) -> [20]byte { +hash_string_160_3 :: proc(data: string) -> [DIGEST_SIZE_160]byte { return hash_bytes_160_3(transmute([]byte)(data)) } // hash_bytes_160_3 will hash the given input and return the // computed hash -hash_bytes_160_3 :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes_160_3 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { + hash: [DIGEST_SIZE_160]byte ctx: Haval_Context ctx.hashbitlen = 160 ctx.rounds = 3 @@ -226,10 +301,31 @@ hash_bytes_160_3 :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer_160_3 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_160_3 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_160_3(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_160_3 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_160_3 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_160_3 will read the stream in chunks and compute a // hash from its contents -hash_stream_160_3 :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream_160_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { + hash: [DIGEST_SIZE_160]byte ctx: Haval_Context ctx.hashbitlen = 160 ctx.rounds = 3 @@ -250,7 +346,7 @@ hash_stream_160_3 :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file_160_3 will read the file provided by the given handle // and compute a hash -hash_file_160_3 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file_160_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { if !load_at_once { return hash_stream_160_3(os.stream_from_handle(hd)) } else { @@ -258,7 +354,7 @@ hash_file_160_3 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool return hash_bytes_160_3(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE_160]byte{}, false } hash_160_3 :: proc { @@ -266,18 +362,20 @@ hash_160_3 :: proc { hash_file_160_3, hash_bytes_160_3, hash_string_160_3, + hash_bytes_to_buffer_160_3, + hash_string_to_buffer_160_3, } // hash_string_160_4 will hash the given input and return the // computed hash -hash_string_160_4 :: proc(data: string) -> [20]byte { +hash_string_160_4 :: proc(data: string) -> [DIGEST_SIZE_160]byte { return hash_bytes_160_4(transmute([]byte)(data)) } // hash_bytes_160_4 will hash the given input and return the // computed hash -hash_bytes_160_4 :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes_160_4 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { + hash: [DIGEST_SIZE_160]byte ctx: Haval_Context ctx.hashbitlen = 160 ctx.rounds = 4 @@ -288,10 +386,31 @@ hash_bytes_160_4 :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer_160_4 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_160_4 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_160_4(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_160_4 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_160_4 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_160_4 will read the stream in chunks and compute a // hash from its contents -hash_stream_160_4 :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream_160_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { + hash: [DIGEST_SIZE_160]byte ctx: Haval_Context ctx.hashbitlen = 160 ctx.rounds = 4 @@ -312,7 +431,7 @@ hash_stream_160_4 :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file_160_4 will read the file provided by the given handle // and compute a hash -hash_file_160_4 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file_160_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { if !load_at_once { return hash_stream_160_4(os.stream_from_handle(hd)) } else { @@ -320,7 +439,7 @@ hash_file_160_4 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool return hash_bytes_160_4(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE_160]byte{}, false } hash_160_4 :: proc { @@ -328,18 +447,20 @@ hash_160_4 :: proc { hash_file_160_4, hash_bytes_160_4, hash_string_160_4, + hash_bytes_to_buffer_160_4, + hash_string_to_buffer_160_4, } // hash_string_160_5 will hash the given input and return the // computed hash -hash_string_160_5 :: proc(data: string) -> [20]byte { +hash_string_160_5 :: proc(data: string) -> [DIGEST_SIZE_160]byte { return hash_bytes_160_5(transmute([]byte)(data)) } // hash_bytes_160_5 will hash the given input and return the // computed hash -hash_bytes_160_5 :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes_160_5 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { + hash: [DIGEST_SIZE_160]byte ctx: Haval_Context ctx.hashbitlen = 160 ctx.rounds = 5 @@ -350,10 +471,31 @@ hash_bytes_160_5 :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer_160_5 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_160_5 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_160_5(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_160_5 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_160_5 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 160 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_160_5 will read the stream in chunks and compute a // hash from its contents -hash_stream_160_5 :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream_160_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { + hash: [DIGEST_SIZE_160]byte ctx: Haval_Context ctx.hashbitlen = 160 ctx.rounds = 5 @@ -374,7 +516,7 @@ hash_stream_160_5 :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file_160_5 will read the file provided by the given handle // and compute a hash -hash_file_160_5 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file_160_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { if !load_at_once { return hash_stream_160_5(os.stream_from_handle(hd)) } else { @@ -382,7 +524,7 @@ hash_file_160_5 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool return hash_bytes_160_5(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE_160]byte{}, false } hash_160_5 :: proc { @@ -390,18 +532,20 @@ hash_160_5 :: proc { hash_file_160_5, hash_bytes_160_5, hash_string_160_5, + hash_bytes_to_buffer_160_5, + hash_string_to_buffer_160_5, } // hash_string_192_3 will hash the given input and return the // computed hash -hash_string_192_3 :: proc(data: string) -> [24]byte { +hash_string_192_3 :: proc(data: string) -> [DIGEST_SIZE_192]byte { return hash_bytes_192_3(transmute([]byte)(data)) } // hash_bytes_192_3 will hash the given input and return the // computed hash -hash_bytes_192_3 :: proc(data: []byte) -> [24]byte { - hash: [24]byte +hash_bytes_192_3 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { + hash: [DIGEST_SIZE_192]byte ctx: Haval_Context ctx.hashbitlen = 192 ctx.rounds = 3 @@ -412,10 +556,31 @@ hash_bytes_192_3 :: proc(data: []byte) -> [24]byte { return hash } +// hash_string_to_buffer_192_3 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_192_3 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_192_3(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_192_3 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_192_3 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_192_3 will read the stream in chunks and compute a // hash from its contents -hash_stream_192_3 :: proc(s: io.Stream) -> ([24]byte, bool) { - hash: [24]byte +hash_stream_192_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { + hash: [DIGEST_SIZE_192]byte ctx: Haval_Context ctx.hashbitlen = 192 ctx.rounds = 3 @@ -436,7 +601,7 @@ hash_stream_192_3 :: proc(s: io.Stream) -> ([24]byte, bool) { // hash_file_192_3 will read the file provided by the given handle // and compute a hash -hash_file_192_3 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { +hash_file_192_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { if !load_at_once { return hash_stream_192_3(os.stream_from_handle(hd)) } else { @@ -444,7 +609,7 @@ hash_file_192_3 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool return hash_bytes_192_3(buf[:]), ok } } - return [24]byte{}, false + return [DIGEST_SIZE_192]byte{}, false } hash_192_3 :: proc { @@ -452,18 +617,20 @@ hash_192_3 :: proc { hash_file_192_3, hash_bytes_192_3, hash_string_192_3, + hash_bytes_to_buffer_192_3, + hash_string_to_buffer_192_3, } // hash_string_192_4 will hash the given input and return the // computed hash -hash_string_192_4 :: proc(data: string) -> [24]byte { +hash_string_192_4 :: proc(data: string) -> [DIGEST_SIZE_192]byte { return hash_bytes_192_4(transmute([]byte)(data)) } // hash_bytes_192_4 will hash the given input and return the // computed hash -hash_bytes_192_4 :: proc(data: []byte) -> [24]byte { - hash: [24]byte +hash_bytes_192_4 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { + hash: [DIGEST_SIZE_192]byte ctx: Haval_Context ctx.hashbitlen = 192 ctx.rounds = 4 @@ -474,10 +641,31 @@ hash_bytes_192_4 :: proc(data: []byte) -> [24]byte { return hash } +// hash_string_to_buffer_192_4 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_192_4 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_192_4(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_192_4 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_192_4 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_192_4 will read the stream in chunks and compute a // hash from its contents -hash_stream_192_4 :: proc(s: io.Stream) -> ([24]byte, bool) { - hash: [24]byte +hash_stream_192_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { + hash: [DIGEST_SIZE_192]byte ctx: Haval_Context ctx.hashbitlen = 192 ctx.rounds = 4 @@ -498,7 +686,7 @@ hash_stream_192_4 :: proc(s: io.Stream) -> ([24]byte, bool) { // hash_file_192_4 will read the file provided by the given handle // and compute a hash -hash_file_192_4 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { +hash_file_192_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { if !load_at_once { return hash_stream_192_4(os.stream_from_handle(hd)) } else { @@ -506,7 +694,7 @@ hash_file_192_4 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool return hash_bytes_192_4(buf[:]), ok } } - return [24]byte{}, false + return [DIGEST_SIZE_192]byte{}, false } hash_192_4 :: proc { @@ -514,18 +702,20 @@ hash_192_4 :: proc { hash_file_192_4, hash_bytes_192_4, hash_string_192_4, + hash_bytes_to_buffer_192_4, + hash_string_to_buffer_192_4, } // hash_string_192_5 will hash the given input and return the // computed hash -hash_string_192_5 :: proc(data: string) -> [24]byte { +hash_string_192_5 :: proc(data: string) -> [DIGEST_SIZE_192]byte { return hash_bytes_192_5(transmute([]byte)(data)) } -// hash_bytes_224_5 will hash the given input and return the +// hash_bytes_2DIGEST_SIZE_192_5 will hash the given input and return the // computed hash -hash_bytes_192_5 :: proc(data: []byte) -> [24]byte { - hash: [24]byte +hash_bytes_192_5 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { + hash: [DIGEST_SIZE_192]byte ctx: Haval_Context ctx.hashbitlen = 192 ctx.rounds = 5 @@ -536,10 +726,31 @@ hash_bytes_192_5 :: proc(data: []byte) -> [24]byte { return hash } +// hash_string_to_buffer_192_5 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_192_5 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_192_5(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_192_5 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_192_5 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 192 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_192_5 will read the stream in chunks and compute a // hash from its contents -hash_stream_192_5 :: proc(s: io.Stream) -> ([24]byte, bool) { - hash: [24]byte +hash_stream_192_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { + hash: [DIGEST_SIZE_192]byte ctx: Haval_Context ctx.hashbitlen = 192 ctx.rounds = 5 @@ -560,7 +771,7 @@ hash_stream_192_5 :: proc(s: io.Stream) -> ([24]byte, bool) { // hash_file_192_5 will read the file provided by the given handle // and compute a hash -hash_file_192_5 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { +hash_file_192_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { if !load_at_once { return hash_stream_192_5(os.stream_from_handle(hd)) } else { @@ -568,7 +779,7 @@ hash_file_192_5 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool return hash_bytes_192_5(buf[:]), ok } } - return [24]byte{}, false + return [DIGEST_SIZE_192]byte{}, false } hash_192_5 :: proc { @@ -576,18 +787,20 @@ hash_192_5 :: proc { hash_file_192_5, hash_bytes_192_5, hash_string_192_5, + hash_bytes_to_buffer_192_5, + hash_string_to_buffer_192_5, } // hash_string_224_3 will hash the given input and return the // computed hash -hash_string_224_3 :: proc(data: string) -> [28]byte { +hash_string_224_3 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224_3(transmute([]byte)(data)) } // hash_bytes_224_3 will hash the given input and return the // computed hash -hash_bytes_224_3 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224_3 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: Haval_Context ctx.hashbitlen = 224 ctx.rounds = 3 @@ -598,10 +811,31 @@ hash_bytes_224_3 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224_3 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224_3 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224_3(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224_3 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224_3 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_224_3 will read the stream in chunks and compute a // hash from its contents -hash_stream_224_3 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: Haval_Context ctx.hashbitlen = 224 ctx.rounds = 3 @@ -622,7 +856,7 @@ hash_stream_224_3 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224_3 will read the file provided by the given handle // and compute a hash -hash_file_224_3 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224_3(os.stream_from_handle(hd)) } else { @@ -630,7 +864,7 @@ hash_file_224_3 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool return hash_bytes_224_3(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224_3 :: proc { @@ -638,18 +872,20 @@ hash_224_3 :: proc { hash_file_224_3, hash_bytes_224_3, hash_string_224_3, + hash_bytes_to_buffer_224_3, + hash_string_to_buffer_224_3, } // hash_string_224_4 will hash the given input and return the // computed hash -hash_string_224_4 :: proc(data: string) -> [28]byte { +hash_string_224_4 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224_4(transmute([]byte)(data)) } // hash_bytes_224_4 will hash the given input and return the // computed hash -hash_bytes_224_4 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224_4 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: Haval_Context ctx.hashbitlen = 224 ctx.rounds = 4 @@ -660,10 +896,31 @@ hash_bytes_224_4 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224_4 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224_4 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224_4(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224_4 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224_4 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_224_4 will read the stream in chunks and compute a // hash from its contents -hash_stream_224_4 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: Haval_Context ctx.hashbitlen = 224 ctx.rounds = 4 @@ -684,7 +941,7 @@ hash_stream_224_4 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224_4 will read the file provided by the given handle // and compute a hash -hash_file_224_4 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224_4(os.stream_from_handle(hd)) } else { @@ -692,7 +949,7 @@ hash_file_224_4 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool return hash_bytes_224_4(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224_4 :: proc { @@ -700,18 +957,20 @@ hash_224_4 :: proc { hash_file_224_4, hash_bytes_224_4, hash_string_224_4, + hash_bytes_to_buffer_224_4, + hash_string_to_buffer_224_4, } // hash_string_224_5 will hash the given input and return the // computed hash -hash_string_224_5 :: proc(data: string) -> [28]byte { +hash_string_224_5 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224_5(transmute([]byte)(data)) } // hash_bytes_224_5 will hash the given input and return the // computed hash -hash_bytes_224_5 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224_5 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: Haval_Context ctx.hashbitlen = 224 ctx.rounds = 5 @@ -722,10 +981,31 @@ hash_bytes_224_5 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224_5 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224_5 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224_5(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224_5 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224_5 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 224 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_224_5 will read the stream in chunks and compute a // hash from its contents -hash_stream_224_5 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: Haval_Context ctx.hashbitlen = 224 ctx.rounds = 5 @@ -746,7 +1026,7 @@ hash_stream_224_5 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224_5 will read the file provided by the given handle // and compute a hash -hash_file_224_5 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224_5(os.stream_from_handle(hd)) } else { @@ -754,7 +1034,7 @@ hash_file_224_5 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool return hash_bytes_224_5(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224_5 :: proc { @@ -762,18 +1042,20 @@ hash_224_5 :: proc { hash_file_224_5, hash_bytes_224_5, hash_string_224_5, + hash_bytes_to_buffer_224_5, + hash_string_to_buffer_224_5, } // hash_string_256_3 will hash the given input and return the // computed hash -hash_string_256_3 :: proc(data: string) -> [32]byte { +hash_string_256_3 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256_3(transmute([]byte)(data)) } // hash_bytes_256_3 will hash the given input and return the // computed hash -hash_bytes_256_3 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256_3 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Haval_Context ctx.hashbitlen = 256 ctx.rounds = 3 @@ -784,10 +1066,31 @@ hash_bytes_256_3 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256_3 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256_3 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256_3(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256_3 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256_3 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 3 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_256_3 will read the stream in chunks and compute a // hash from its contents -hash_stream_256_3 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Haval_Context ctx.hashbitlen = 256 ctx.rounds = 3 @@ -808,7 +1111,7 @@ hash_stream_256_3 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256_3 will read the file provided by the given handle // and compute a hash -hash_file_256_3 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256_3 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256_3(os.stream_from_handle(hd)) } else { @@ -816,7 +1119,7 @@ hash_file_256_3 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool return hash_bytes_256_3(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256_3 :: proc { @@ -824,18 +1127,20 @@ hash_256_3 :: proc { hash_file_256_3, hash_bytes_256_3, hash_string_256_3, + hash_bytes_to_buffer_256_3, + hash_string_to_buffer_256_3, } // hash_string_256_4 will hash the given input and return the // computed hash -hash_string_256_4 :: proc(data: string) -> [32]byte { +hash_string_256_4 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256_4(transmute([]byte)(data)) } // hash_bytes_256_4 will hash the given input and return the // computed hash -hash_bytes_256_4 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256_4 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Haval_Context ctx.hashbitlen = 256 ctx.rounds = 4 @@ -846,10 +1151,31 @@ hash_bytes_256_4 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256_4 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256_4 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256_4(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256_4 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256_4 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 4 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_256_4 will read the stream in chunks and compute a // hash from its contents -hash_stream_256_4 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Haval_Context ctx.hashbitlen = 256 ctx.rounds = 4 @@ -870,7 +1196,7 @@ hash_stream_256_4 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256_4 will read the file provided by the given handle // and compute a hash -hash_file_256_4 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256_4 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256_4(os.stream_from_handle(hd)) } else { @@ -878,7 +1204,7 @@ hash_file_256_4 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool return hash_bytes_256_4(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256_4 :: proc { @@ -886,18 +1212,20 @@ hash_256_4 :: proc { hash_file_256_4, hash_bytes_256_4, hash_string_256_4, + hash_bytes_to_buffer_256_4, + hash_string_to_buffer_256_4, } // hash_string_256_5 will hash the given input and return the // computed hash -hash_string_256_5 :: proc(data: string) -> [32]byte { +hash_string_256_5 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256_5(transmute([]byte)(data)) } // hash_bytes_256_5 will hash the given input and return the // computed hash -hash_bytes_256_5 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256_5 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Haval_Context ctx.hashbitlen = 256 ctx.rounds = 5 @@ -908,10 +1236,32 @@ hash_bytes_256_5 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256_5 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256_5 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256_5(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256_5 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256_5 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Haval_Context + ctx.hashbitlen = 256 + ctx.rounds = 5 + init(&ctx) + ctx.str_len = u32(len(data)) + update(&ctx, data) + final(&ctx, hash) +} + + // hash_stream_256_5 will read the stream in chunks and compute a // hash from its contents -hash_stream_256_5 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Haval_Context ctx.hashbitlen = 256 ctx.rounds = 5 @@ -932,7 +1282,7 @@ hash_stream_256_5 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256_5 will read the file provided by the given handle // and compute a hash -hash_file_256_5 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256_5 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256_5(os.stream_from_handle(hd)) } else { @@ -940,7 +1290,7 @@ hash_file_256_5 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool return hash_bytes_256_5(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256_5 :: proc { @@ -948,6 +1298,8 @@ hash_256_5 :: proc { hash_file_256_5, hash_bytes_256_5, hash_string_256_5, + hash_bytes_to_buffer_256_5, + hash_string_to_buffer_256_5, } /* diff --git a/core/crypto/jh/jh.odin b/core/crypto/jh/jh.odin index f251424d2..4ebc0e5cb 100644 --- a/core/crypto/jh/jh.odin +++ b/core/crypto/jh/jh.odin @@ -17,16 +17,21 @@ import "core:io" High level API */ +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_384 :: 48 +DIGEST_SIZE_512 :: 64 + // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc(data: string) -> [28]byte { +hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: Jh_Context ctx.hashbitlen = 224 init(&ctx) @@ -35,10 +40,29 @@ hash_bytes_224 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: Jh_Context + ctx.hashbitlen = 224 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_224 will read the stream in chunks and compute a // hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: Jh_Context ctx.hashbitlen = 224 init(&ctx) @@ -57,7 +81,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224 will read the file provided by the given handle // and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224(os.stream_from_handle(hd)) } else { @@ -65,7 +89,7 @@ hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) return hash_bytes_224(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { @@ -73,18 +97,20 @@ hash_224 :: proc { hash_file_224, hash_bytes_224, hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Jh_Context ctx.hashbitlen = 256 init(&ctx) @@ -93,10 +119,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Jh_Context + ctx.hashbitlen = 256 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Jh_Context ctx.hashbitlen = 256 init(&ctx) @@ -115,7 +160,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -123,7 +168,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -131,18 +176,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc(data: string) -> [48]byte { +hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc(data: []byte) -> [48]byte { - hash: [48]byte +hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { + hash: [DIGEST_SIZE_384]byte ctx: Jh_Context ctx.hashbitlen = 384 init(&ctx) @@ -151,10 +198,29 @@ hash_bytes_384 :: proc(data: []byte) -> [48]byte { return hash } +// hash_string_to_buffer_384 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_384(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_384 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") + ctx: Jh_Context + ctx.hashbitlen = 384 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_384 will read the stream in chunks and compute a // hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte +hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { + hash: [DIGEST_SIZE_384]byte ctx: Jh_Context ctx.hashbitlen = 384 init(&ctx) @@ -173,7 +239,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { // hash_file_384 will read the file provided by the given handle // and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { +hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { if !load_at_once { return hash_stream_384(os.stream_from_handle(hd)) } else { @@ -181,7 +247,7 @@ hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) return hash_bytes_384(buf[:]), ok } } - return [48]byte{}, false + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { @@ -189,18 +255,20 @@ hash_384 :: proc { hash_file_384, hash_bytes_384, hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: Jh_Context ctx.hashbitlen = 512 init(&ctx) @@ -209,10 +277,29 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: Jh_Context + ctx.hashbitlen = 512 + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: Jh_Context ctx.hashbitlen = 512 init(&ctx) @@ -231,7 +318,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -239,7 +326,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -247,6 +334,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin index 19c4c7dda..f5d4826b1 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/keccak/keccak.odin @@ -21,18 +21,23 @@ import "../_sha3" High level API */ +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_384 :: 48 +DIGEST_SIZE_512 :: 64 + // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc(data: string) -> [28]byte { +hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 28 + ctx.mdlen = DIGEST_SIZE_224 ctx.is_keccak = true _sha3.init(&ctx) _sha3.update(&ctx, data) @@ -40,12 +45,32 @@ hash_bytes_224 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_224 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) +} + // hash_stream_224 will read the stream in chunks and compute a // hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 28 + ctx.mdlen = DIGEST_SIZE_224 ctx.is_keccak = true _sha3.init(&ctx) buf := make([]byte, 512) @@ -63,7 +88,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224 will read the file provided by the given handle // and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224(os.stream_from_handle(hd)) } else { @@ -71,7 +96,7 @@ hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) return hash_bytes_224(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { @@ -79,20 +104,22 @@ hash_224 :: proc { hash_file_224, hash_bytes_224, hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 32 + ctx.mdlen = DIGEST_SIZE_256 ctx.is_keccak = true _sha3.init(&ctx) _sha3.update(&ctx, data) @@ -100,12 +127,32 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 32 + ctx.mdlen = DIGEST_SIZE_256 ctx.is_keccak = true _sha3.init(&ctx) buf := make([]byte, 512) @@ -123,7 +170,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -131,7 +178,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -139,20 +186,22 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc(data: string) -> [48]byte { +hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc(data: []byte) -> [48]byte { - hash: [48]byte +hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { + hash: [DIGEST_SIZE_384]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 48 + ctx.mdlen = DIGEST_SIZE_384 ctx.is_keccak = true _sha3.init(&ctx) _sha3.update(&ctx, data) @@ -160,12 +209,32 @@ hash_bytes_384 :: proc(data: []byte) -> [48]byte { return hash } +// hash_string_to_buffer_384 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_384(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_384 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_384 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) +} + // hash_stream_384 will read the stream in chunks and compute a // hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte +hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { + hash: [DIGEST_SIZE_384]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 48 + ctx.mdlen = DIGEST_SIZE_384 ctx.is_keccak = true _sha3.init(&ctx) buf := make([]byte, 512) @@ -183,7 +252,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { // hash_file_384 will read the file provided by the given handle // and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { +hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { if !load_at_once { return hash_stream_384(os.stream_from_handle(hd)) } else { @@ -191,7 +260,7 @@ hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) return hash_bytes_384(buf[:]), ok } } - return [48]byte{}, false + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { @@ -199,20 +268,22 @@ hash_384 :: proc { hash_file_384, hash_bytes_384, hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 64 + ctx.mdlen = DIGEST_SIZE_512 ctx.is_keccak = true _sha3.init(&ctx) _sha3.update(&ctx, data) @@ -220,12 +291,32 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_512 + ctx.is_keccak = true + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 64 + ctx.mdlen = DIGEST_SIZE_512 ctx.is_keccak = true _sha3.init(&ctx) buf := make([]byte, 512) @@ -243,7 +334,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -251,7 +342,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -259,13 +350,15 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* Low level API */ -Sha3_Context :: _sha3.Sha3_Context +Keccak_Context :: _sha3.Sha3_Context init :: proc(ctx: ^_sha3.Sha3_Context) { ctx.is_keccak = true diff --git a/core/crypto/md2/md2.odin b/core/crypto/md2/md2.odin index 5e027c13c..102c1b8b4 100644 --- a/core/crypto/md2/md2.odin +++ b/core/crypto/md2/md2.odin @@ -17,16 +17,18 @@ import "core:io" High level API */ +DIGEST_SIZE :: 16 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [16]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: Md2_Context // init(&ctx) No-op update(&ctx, data) @@ -34,10 +36,28 @@ hash_bytes :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Md2_Context + // init(&ctx) No-op + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: Md2_Context // init(&ctx) No-op buf := make([]byte, 512) @@ -55,7 +75,7 @@ hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -63,7 +83,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { return hash_bytes(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -71,6 +91,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -86,7 +108,7 @@ update :: proc(ctx: ^Md2_Context, data: []byte) { for i := 0; i < len(data); i += 1 { ctx.data[ctx.datalen] = data[i] ctx.datalen += 1 - if (ctx.datalen == 16) { + if (ctx.datalen == DIGEST_SIZE) { transform(ctx, ctx.data[:]) ctx.datalen = 0 } @@ -94,14 +116,14 @@ update :: proc(ctx: ^Md2_Context, data: []byte) { } final :: proc(ctx: ^Md2_Context, hash: []byte) { - to_pad := byte(16 - ctx.datalen) - for ctx.datalen < 16 { + to_pad := byte(DIGEST_SIZE - ctx.datalen) + for ctx.datalen < DIGEST_SIZE { ctx.data[ctx.datalen] = to_pad ctx.datalen += 1 } transform(ctx, ctx.data[:]) transform(ctx, ctx.checksum[:]) - for i := 0; i < 16; i += 1 { + for i := 0; i < DIGEST_SIZE; i += 1 { hash[i] = ctx.state[i] } } @@ -111,9 +133,9 @@ final :: proc(ctx: ^Md2_Context, hash: []byte) { */ Md2_Context :: struct { - data: [16]byte, - state: [16 * 3]byte, - checksum: [16]byte, + data: [DIGEST_SIZE]byte, + state: [DIGEST_SIZE * 3]byte, + checksum: [DIGEST_SIZE]byte, datalen: int, } @@ -140,20 +162,20 @@ PI_TABLE := [?]byte { transform :: proc(ctx: ^Md2_Context, data: []byte) { j,k,t: byte - for j = 0; j < 16; j += 1 { - ctx.state[j + 16] = data[j] - ctx.state[j + 16 * 2] = (ctx.state[j + 16] ~ ctx.state[j]) + for j = 0; j < DIGEST_SIZE; j += 1 { + ctx.state[j + DIGEST_SIZE] = data[j] + ctx.state[j + DIGEST_SIZE * 2] = (ctx.state[j + DIGEST_SIZE] ~ ctx.state[j]) } t = 0 - for j = 0; j < 16 + 2; j += 1 { - for k = 0; k < 16 * 3; k += 1 { + for j = 0; j < DIGEST_SIZE + 2; j += 1 { + for k = 0; k < DIGEST_SIZE * 3; k += 1 { ctx.state[k] ~= PI_TABLE[t] t = ctx.state[k] } t = (t + j) & 0xff } - t = ctx.checksum[16 - 1] - for j = 0; j < 16; j += 1 { + t = ctx.checksum[DIGEST_SIZE - 1] + for j = 0; j < DIGEST_SIZE; j += 1 { ctx.checksum[j] ~= PI_TABLE[data[j] ~ t] t = ctx.checksum[j] } diff --git a/core/crypto/md4/md4.odin b/core/crypto/md4/md4.odin index 813db578a..d944daa1d 100644 --- a/core/crypto/md4/md4.odin +++ b/core/crypto/md4/md4.odin @@ -21,16 +21,18 @@ import "../util" High level API */ +DIGEST_SIZE :: 16 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [16]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: Md4_Context init(&ctx) update(&ctx, data) @@ -38,10 +40,28 @@ hash_bytes :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Md4_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: Md4_Context init(&ctx) buf := make([]byte, 512) @@ -59,7 +79,7 @@ hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -67,7 +87,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { return hash_bytes(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -75,6 +95,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -171,9 +193,9 @@ HH :: #force_inline proc "contextless"(a, b, c, d, x: u32, s : int) -> u32 { transform :: proc(ctx: ^Md4_Context, data: []byte) { a, b, c, d, i, j: u32 - m: [16]u32 + m: [DIGEST_SIZE]u32 - for i, j = 0, 0; i < 16; i += 1 { + for i, j = 0, 0; i < DIGEST_SIZE; i += 1 { m[i] = u32(data[j]) | (u32(data[j + 1]) << 8) | (u32(data[j + 2]) << 16) | (u32(data[j + 3]) << 24) j += 4 } diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index a41ed16f8..9129e6384 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -20,16 +20,18 @@ import "../util" High level API */ +DIGEST_SIZE :: 16 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [16]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: Md5_Context init(&ctx) update(&ctx, data) @@ -37,10 +39,28 @@ hash_bytes :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Md5_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: Md5_Context init(&ctx) buf := make([]byte, 512) @@ -58,7 +78,7 @@ hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -66,7 +86,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { return hash_bytes(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -74,6 +94,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -176,9 +198,9 @@ II :: #force_inline proc "contextless" (a, b, c, d, m: u32, s: int, t: u32) -> u transform :: proc(ctx: ^Md5_Context, data: []byte) { i, j: u32 - m: [16]u32 + m: [DIGEST_SIZE]u32 - for i, j = 0, 0; i < 16; i+=1 { + for i, j = 0, 0; i < DIGEST_SIZE; i+=1 { m[i] = u32(data[j]) + u32(data[j + 1]) << 8 + u32(data[j + 2]) << 16 + u32(data[j + 3]) << 24 j += 4 } diff --git a/core/crypto/ripemd/ripemd.odin b/core/crypto/ripemd/ripemd.odin index a9a5d1126..c475c4803 100644 --- a/core/crypto/ripemd/ripemd.odin +++ b/core/crypto/ripemd/ripemd.odin @@ -19,16 +19,21 @@ import "../util" High level API */ +DIGEST_SIZE_128 :: 16 +DIGEST_SIZE_160 :: 20 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_320 :: 40 + // hash_string_128 will hash the given input and return the // computed hash -hash_string_128 :: proc(data: string) -> [16]byte { +hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128(transmute([]byte)(data)) } // hash_bytes_128 will hash the given input and return the // computed hash -hash_bytes_128 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: Ripemd128_Context init(&ctx) update(&ctx, data) @@ -36,10 +41,28 @@ hash_bytes_128 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: Ripemd128_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_128 will read the stream in chunks and compute a // hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: Ripemd128_Context init(&ctx) buf := make([]byte, 512) @@ -57,7 +80,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128 will read the file provided by the given handle // and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128(os.stream_from_handle(hd)) } else { @@ -65,7 +88,7 @@ hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) return hash_bytes_128(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128 :: proc { @@ -73,18 +96,20 @@ hash_128 :: proc { hash_file_128, hash_bytes_128, hash_string_128, + hash_bytes_to_buffer_128, + hash_string_to_buffer_128, } // hash_string_160 will hash the given input and return the // computed hash -hash_string_160 :: proc(data: string) -> [20]byte { +hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { return hash_bytes_160(transmute([]byte)(data)) } // hash_bytes_160 will hash the given input and return the // computed hash -hash_bytes_160 :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { + hash: [DIGEST_SIZE_160]byte ctx: Ripemd160_Context init(&ctx) update(&ctx, data) @@ -92,10 +117,28 @@ hash_bytes_160 :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer_160 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_160(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_160 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") + ctx: Ripemd160_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_160 will read the stream in chunks and compute a // hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { + hash: [DIGEST_SIZE_160]byte ctx: Ripemd160_Context init(&ctx) buf := make([]byte, 512) @@ -113,7 +156,7 @@ hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file_160 will read the file provided by the given handle // and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { if !load_at_once { return hash_stream_160(os.stream_from_handle(hd)) } else { @@ -121,7 +164,7 @@ hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) return hash_bytes_160(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE_160]byte{}, false } hash_160 :: proc { @@ -129,18 +172,20 @@ hash_160 :: proc { hash_file_160, hash_bytes_160, hash_string_160, + hash_bytes_to_buffer_160, + hash_string_to_buffer_160, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Ripemd256_Context init(&ctx) update(&ctx, data) @@ -148,10 +193,28 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Ripemd256_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Ripemd256_Context init(&ctx) buf := make([]byte, 512) @@ -169,7 +232,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -177,7 +240,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -185,18 +248,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_320 will hash the given input and return the // computed hash -hash_string_320 :: proc(data: string) -> [40]byte { +hash_string_320 :: proc(data: string) -> [DIGEST_SIZE_320]byte { return hash_bytes_320(transmute([]byte)(data)) } // hash_bytes_320 will hash the given input and return the // computed hash -hash_bytes_320 :: proc(data: []byte) -> [40]byte { - hash: [40]byte +hash_bytes_320 :: proc(data: []byte) -> [DIGEST_SIZE_320]byte { + hash: [DIGEST_SIZE_320]byte ctx: Ripemd320_Context init(&ctx) update(&ctx, data) @@ -204,10 +269,28 @@ hash_bytes_320 :: proc(data: []byte) -> [40]byte { return hash } +// hash_string_to_buffer_320 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_320 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_320(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_320 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_320 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_320, "Size of destination buffer is smaller than the digest size") + ctx: Ripemd320_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_320 will read the stream in chunks and compute a // hash from its contents -hash_stream_320 :: proc(s: io.Stream) -> ([40]byte, bool) { - hash: [40]byte +hash_stream_320 :: proc(s: io.Stream) -> ([DIGEST_SIZE_320]byte, bool) { + hash: [DIGEST_SIZE_320]byte ctx: Ripemd320_Context init(&ctx) buf := make([]byte, 512) @@ -225,7 +308,7 @@ hash_stream_320 :: proc(s: io.Stream) -> ([40]byte, bool) { // hash_file_320 will read the file provided by the given handle // and compute a hash -hash_file_320 :: proc(hd: os.Handle, load_at_once := false) -> ([40]byte, bool) { +hash_file_320 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_320]byte, bool) { if !load_at_once { return hash_stream_320(os.stream_from_handle(hd)) } else { @@ -233,7 +316,7 @@ hash_file_320 :: proc(hd: os.Handle, load_at_once := false) -> ([40]byte, bool) return hash_bytes_320(buf[:]), ok } } - return [40]byte{}, false + return [DIGEST_SIZE_320]byte{}, false } hash_320 :: proc { @@ -241,6 +324,8 @@ hash_320 :: proc { hash_file_320, hash_bytes_320, hash_string_320, + hash_bytes_to_buffer_320, + hash_string_to_buffer_320, } /* diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index 736b207a3..e8df3c7f6 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -19,16 +19,19 @@ import "../util" /* High level API */ + +DIGEST_SIZE :: 20 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [20]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: Sha1_Context init(&ctx) update(&ctx, data) @@ -36,10 +39,28 @@ hash_bytes :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Sha1_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: Sha1_Context init(&ctx) buf := make([]byte, 512) @@ -57,7 +78,7 @@ hash_stream :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -65,7 +86,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { return hash_bytes(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -73,6 +94,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 8b7ccf38a..2178b70b5 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -21,16 +21,21 @@ import "../util" High level API */ +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_384 :: 48 +DIGEST_SIZE_512 :: 64 + // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc(data: string) -> [28]byte { +hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: Sha256_Context ctx.is224 = true init(&ctx) @@ -39,10 +44,29 @@ hash_bytes_224 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: Sha256_Context + ctx.is224 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_224 will read the stream in chunks and compute a // hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: Sha512_Context ctx.is384 = false init(&ctx) @@ -61,7 +85,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224 will read the file provided by the given handle // and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224(os.stream_from_handle(hd)) } else { @@ -69,7 +93,7 @@ hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) return hash_bytes_224(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { @@ -77,18 +101,20 @@ hash_224 :: proc { hash_file_224, hash_bytes_224, hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Sha256_Context ctx.is224 = false init(&ctx) @@ -97,10 +123,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Sha256_Context + ctx.is224 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Sha512_Context ctx.is384 = false init(&ctx) @@ -119,7 +164,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -127,7 +172,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -135,18 +180,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc(data: string) -> [48]byte { +hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc(data: []byte) -> [48]byte { - hash: [48]byte +hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { + hash: [DIGEST_SIZE_384]byte ctx: Sha512_Context ctx.is384 = true init(&ctx) @@ -155,10 +202,29 @@ hash_bytes_384 :: proc(data: []byte) -> [48]byte { return hash } +// hash_string_to_buffer_384 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_384(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_384 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") + ctx: Sha512_Context + ctx.is384 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_384 will read the stream in chunks and compute a // hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte +hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { + hash: [DIGEST_SIZE_384]byte ctx: Sha512_Context ctx.is384 = true init(&ctx) @@ -177,7 +243,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { // hash_file_384 will read the file provided by the given handle // and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { +hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { if !load_at_once { return hash_stream_384(os.stream_from_handle(hd)) } else { @@ -185,7 +251,7 @@ hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) return hash_bytes_384(buf[:]), ok } } - return [48]byte{}, false + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { @@ -193,18 +259,20 @@ hash_384 :: proc { hash_file_384, hash_bytes_384, hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: Sha512_Context ctx.is384 = false init(&ctx) @@ -213,10 +281,29 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: Sha512_Context + ctx.is384 = false + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: Sha512_Context ctx.is384 = false init(&ctx) @@ -235,7 +322,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -243,7 +330,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -251,6 +338,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index 1becf7640..2eceeaff6 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -20,30 +20,54 @@ import "../_sha3" High level API */ +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_384 :: 48 +DIGEST_SIZE_512 :: 64 + // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc(data: string) -> [28]byte { +hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 28 + ctx.mdlen = DIGEST_SIZE_224 _sha3.init(&ctx) _sha3.update(&ctx, data) _sha3.final(&ctx, hash[:]) return hash } +// hash_string_to_buffer_224 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_224 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) +} + // hash_stream_224 will read the stream in chunks and compute a // hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 28 + ctx.mdlen = DIGEST_SIZE_224 _sha3.init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -60,7 +84,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224 will read the file provided by the given handle // and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224(os.stream_from_handle(hd)) } else { @@ -68,7 +92,7 @@ hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) return hash_bytes_224(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { @@ -76,32 +100,53 @@ hash_224 :: proc { hash_file_224, hash_bytes_224, hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 32 + ctx.mdlen = DIGEST_SIZE_256 _sha3.init(&ctx) _sha3.update(&ctx, data) _sha3.final(&ctx, hash[:]) return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 32 + ctx.mdlen = DIGEST_SIZE_256 _sha3.init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -118,7 +163,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -126,7 +171,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -134,32 +179,53 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc(data: string) -> [48]byte { +hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc(data: []byte) -> [48]byte { - hash: [48]byte +hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { + hash: [DIGEST_SIZE_384]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 48 + ctx.mdlen = DIGEST_SIZE_384 _sha3.init(&ctx) _sha3.update(&ctx, data) _sha3.final(&ctx, hash[:]) return hash } +// hash_string_to_buffer_384 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_384(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_384 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_384 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) +} + // hash_stream_384 will read the stream in chunks and compute a // hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte +hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { + hash: [DIGEST_SIZE_384]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 48 + ctx.mdlen = DIGEST_SIZE_384 _sha3.init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -176,7 +242,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { // hash_file_384 will read the file provided by the given handle // and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { +hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { if !load_at_once { return hash_stream_384(os.stream_from_handle(hd)) } else { @@ -184,7 +250,7 @@ hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) return hash_bytes_384(buf[:]), ok } } - return [48]byte{}, false + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { @@ -192,32 +258,53 @@ hash_384 :: proc { hash_file_384, hash_bytes_384, hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 64 + ctx.mdlen = DIGEST_SIZE_512 _sha3.init(&ctx) _sha3.update(&ctx, data) _sha3.final(&ctx, hash[:]) return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_512 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.final(&ctx, hash) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 64 + ctx.mdlen = DIGEST_SIZE_512 _sha3.init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -234,7 +321,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -242,7 +329,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -250,6 +337,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index ff477b1a9..9fdc3ebf1 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -20,18 +20,21 @@ import "../_sha3" High level API */ +DIGEST_SIZE_128 :: 16 +DIGEST_SIZE_256 :: 32 + // hash_string_128 will hash the given input and return the // computed hash -hash_string_128 :: proc(data: string) -> [16]byte { +hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128(transmute([]byte)(data)) } // hash_bytes_128 will hash the given input and return the // computed hash -hash_bytes_128 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 16 + ctx.mdlen = DIGEST_SIZE_128 _sha3.init(&ctx) _sha3.update(&ctx, data) _sha3.shake_xof(&ctx) @@ -39,12 +42,32 @@ hash_bytes_128 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_128 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash) +} + // hash_stream_128 will read the stream in chunks and compute a // hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 16 + ctx.mdlen = DIGEST_SIZE_128 _sha3.init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -62,7 +85,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128 will read the file provided by the given handle // and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128(os.stream_from_handle(hd)) } else { @@ -70,7 +93,7 @@ hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) return hash_bytes_128(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128 :: proc { @@ -78,20 +101,22 @@ hash_128 :: proc { hash_file_128, hash_bytes_128, hash_string_128, + hash_bytes_to_buffer_128, + hash_string_to_buffer_128, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 32 + ctx.mdlen = DIGEST_SIZE_256 _sha3.init(&ctx) _sha3.update(&ctx, data) _sha3.shake_xof(&ctx) @@ -99,12 +124,32 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: _sha3.Sha3_Context + ctx.mdlen = DIGEST_SIZE_256 + _sha3.init(&ctx) + _sha3.update(&ctx, data) + _sha3.shake_xof(&ctx) + _sha3.shake_out(&ctx, hash) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: _sha3.Sha3_Context - ctx.mdlen = 32 + ctx.mdlen = DIGEST_SIZE_256 _sha3.init(&ctx) buf := make([]byte, 512) defer delete(buf) @@ -122,7 +167,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -130,7 +175,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -138,13 +183,15 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } /* Low level API */ -Sha3_Context :: _sha3.Sha3_Context +Shake_Context :: _sha3.Sha3_Context init :: proc(ctx: ^_sha3.Sha3_Context) { _sha3.init(ctx) diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index c72bd4f15..e72973e33 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -15,16 +15,22 @@ import "core:io" import "../util" +/* + High level API +*/ + +DIGEST_SIZE :: 32 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [32]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: Sm3_Context init(&ctx) update(&ctx, data) @@ -32,10 +38,28 @@ hash_bytes :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Sm3_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: Sm3_Context init(&ctx) buf := make([]byte, 512) @@ -53,7 +77,7 @@ hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -61,7 +85,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { return hash_bytes(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -69,6 +93,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* @@ -146,9 +172,6 @@ Sm3_Context :: struct { length: u64, } -BLOCK_SIZE_IN_BYTES :: 64 -BLOCK_SIZE_IN_32 :: 16 - IV := [8]u32 { 0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e, diff --git a/core/crypto/streebog/streebog.odin b/core/crypto/streebog/streebog.odin index b90ef8e86..deb71120d 100644 --- a/core/crypto/streebog/streebog.odin +++ b/core/crypto/streebog/streebog.odin @@ -19,16 +19,19 @@ import "../util" High level API */ +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_512 :: 64 + // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: Streebog_Context ctx.is256 = true init(&ctx) @@ -37,10 +40,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: Streebog_Context + ctx.is256 = true + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: Streebog_Context ctx.is256 = true init(&ctx) @@ -59,7 +81,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -67,7 +89,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -75,18 +97,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: Streebog_Context init(&ctx) update(&ctx, data) @@ -94,10 +118,28 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: Streebog_Context + init(&ctx) + update(&ctx, data) + final(&ctx, hash[:]) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: Streebog_Context init(&ctx) buf := make([]byte, 512) @@ -115,7 +157,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -123,7 +165,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -131,6 +173,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/core/crypto/tiger/tiger.odin b/core/crypto/tiger/tiger.odin index ecd7f5583..4ea80c66c 100644 --- a/core/crypto/tiger/tiger.odin +++ b/core/crypto/tiger/tiger.odin @@ -19,16 +19,20 @@ import "../_tiger" High level API */ +DIGEST_SIZE_128 :: 16 +DIGEST_SIZE_160 :: 20 +DIGEST_SIZE_192 :: 24 + // hash_string_128 will hash the given input and return the // computed hash -hash_string_128 :: proc(data: string) -> [16]byte { +hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128(transmute([]byte)(data)) } // hash_bytes_128 will hash the given input and return the // computed hash -hash_bytes_128 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: _tiger.Tiger_Context ctx.ver = 1 _tiger.init(&ctx) @@ -37,10 +41,29 @@ hash_bytes_128 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash) +} + // hash_stream_128 will read the stream in chunks and compute a // hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: _tiger.Tiger_Context ctx.ver = 1 _tiger.init(&ctx) @@ -59,7 +82,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128 will read the file provided by the given handle // and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128(os.stream_from_handle(hd)) } else { @@ -67,7 +90,7 @@ hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) return hash_bytes_128(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128 :: proc { @@ -75,18 +98,20 @@ hash_128 :: proc { hash_file_128, hash_bytes_128, hash_string_128, + hash_bytes_to_buffer_128, + hash_string_to_buffer_128, } // hash_string_160 will hash the given input and return the // computed hash -hash_string_160 :: proc(data: string) -> [20]byte { +hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { return hash_bytes_160(transmute([]byte)(data)) } // hash_bytes_160 will hash the given input and return the // computed hash -hash_bytes_160 :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { + hash: [DIGEST_SIZE_160]byte ctx: _tiger.Tiger_Context ctx.ver = 1 _tiger.init(&ctx) @@ -95,10 +120,29 @@ hash_bytes_160 :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer_160 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_160(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_160 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash) +} + // hash_stream_160 will read the stream in chunks and compute a // hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { + hash: [DIGEST_SIZE_160]byte ctx: _tiger.Tiger_Context ctx.ver = 1 _tiger.init(&ctx) @@ -117,7 +161,7 @@ hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file_160 will read the file provided by the given handle // and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { if !load_at_once { return hash_stream_160(os.stream_from_handle(hd)) } else { @@ -125,7 +169,7 @@ hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) return hash_bytes_160(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE_160]byte{}, false } hash_160 :: proc { @@ -133,18 +177,20 @@ hash_160 :: proc { hash_file_160, hash_bytes_160, hash_string_160, + hash_bytes_to_buffer_160, + hash_string_to_buffer_160, } // hash_string_192 will hash the given input and return the // computed hash -hash_string_192 :: proc(data: string) -> [24]byte { +hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte { return hash_bytes_192(transmute([]byte)(data)) } // hash_bytes_192 will hash the given input and return the // computed hash -hash_bytes_192 :: proc(data: []byte) -> [24]byte { - hash: [24]byte +hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { + hash: [DIGEST_SIZE_192]byte ctx: _tiger.Tiger_Context ctx.ver = 1 _tiger.init(&ctx) @@ -153,10 +199,29 @@ hash_bytes_192 :: proc(data: []byte) -> [24]byte { return hash } +// hash_string_to_buffer_192 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_192(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_192 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_192 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") + ctx: _tiger.Tiger_Context + ctx.ver = 1 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash) +} + // hash_stream_192 will read the stream in chunks and compute a // hash from its contents -hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { - hash: [24]byte +hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { + hash: [DIGEST_SIZE_192]byte ctx: _tiger.Tiger_Context ctx.ver = 1 _tiger.init(&ctx) @@ -175,7 +240,7 @@ hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { // hash_file_192 will read the file provided by the given handle // and compute a hash -hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { +hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { if !load_at_once { return hash_stream_192(os.stream_from_handle(hd)) } else { @@ -183,7 +248,7 @@ hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) return hash_bytes_192(buf[:]), ok } } - return [24]byte{}, false + return [DIGEST_SIZE_192]byte{}, false } hash_192 :: proc { @@ -191,6 +256,8 @@ hash_192 :: proc { hash_file_192, hash_bytes_192, hash_string_192, + hash_bytes_to_buffer_192, + hash_string_to_buffer_192, } /* diff --git a/core/crypto/tiger2/tiger2.odin b/core/crypto/tiger2/tiger2.odin index a93e19319..84333f344 100644 --- a/core/crypto/tiger2/tiger2.odin +++ b/core/crypto/tiger2/tiger2.odin @@ -19,16 +19,20 @@ import "../_tiger" High level API */ +DIGEST_SIZE_128 :: 16 +DIGEST_SIZE_160 :: 20 +DIGEST_SIZE_192 :: 24 + // hash_string_128 will hash the given input and return the // computed hash -hash_string_128 :: proc(data: string) -> [16]byte { +hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128(transmute([]byte)(data)) } // hash_bytes_128 will hash the given input and return the // computed hash -hash_bytes_128 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: _tiger.Tiger_Context ctx.ver = 2 _tiger.init(&ctx) @@ -37,10 +41,29 @@ hash_bytes_128 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash) +} + // hash_stream_128 will read the stream in chunks and compute a // hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: _tiger.Tiger_Context ctx.ver = 2 _tiger.init(&ctx) @@ -59,7 +82,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128 will read the file provided by the given handle // and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128(os.stream_from_handle(hd)) } else { @@ -67,7 +90,7 @@ hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) return hash_bytes_128(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128 :: proc { @@ -75,18 +98,20 @@ hash_128 :: proc { hash_file_128, hash_bytes_128, hash_string_128, + hash_bytes_to_buffer_128, + hash_string_to_buffer_128, } // hash_string_160 will hash the given input and return the // computed hash -hash_string_160 :: proc(data: string) -> [20]byte { +hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { return hash_bytes_160(transmute([]byte)(data)) } // hash_bytes_160 will hash the given input and return the // computed hash -hash_bytes_160 :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { + hash: [DIGEST_SIZE_160]byte ctx: _tiger.Tiger_Context ctx.ver = 2 _tiger.init(&ctx) @@ -95,10 +120,29 @@ hash_bytes_160 :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer_160 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_160(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_160 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash) +} + // hash_stream_160 will read the stream in chunks and compute a // hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { + hash: [DIGEST_SIZE_160]byte ctx: _tiger.Tiger_Context ctx.ver = 2 _tiger.init(&ctx) @@ -117,7 +161,7 @@ hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file_160 will read the file provided by the given handle // and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { if !load_at_once { return hash_stream_160(os.stream_from_handle(hd)) } else { @@ -125,7 +169,7 @@ hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) return hash_bytes_160(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE_160]byte{}, false } hash_160 :: proc { @@ -133,18 +177,20 @@ hash_160 :: proc { hash_file_160, hash_bytes_160, hash_string_160, + hash_bytes_to_buffer_160, + hash_string_to_buffer_160, } // hash_string_192 will hash the given input and return the // computed hash -hash_string_192 :: proc(data: string) -> [24]byte { +hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte { return hash_bytes_192(transmute([]byte)(data)) } // hash_bytes_192 will hash the given input and return the // computed hash -hash_bytes_192 :: proc(data: []byte) -> [24]byte { - hash: [24]byte +hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { + hash: [DIGEST_SIZE_192]byte ctx: _tiger.Tiger_Context ctx.ver = 2 _tiger.init(&ctx) @@ -153,10 +199,29 @@ hash_bytes_192 :: proc(data: []byte) -> [24]byte { return hash } +// hash_string_to_buffer_192 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_192(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_192 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_192 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") + ctx: _tiger.Tiger_Context + ctx.ver = 2 + _tiger.init(&ctx) + _tiger.update(&ctx, data) + _tiger.final(&ctx, hash) +} + // hash_stream_192 will read the stream in chunks and compute a // hash from its contents -hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { - hash: [24]byte +hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { + hash: [DIGEST_SIZE_192]byte ctx: _tiger.Tiger_Context ctx.ver = 2 _tiger.init(&ctx) @@ -175,7 +240,7 @@ hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { // hash_file_192 will read the file provided by the given handle // and compute a hash -hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { +hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { if !load_at_once { return hash_stream_192(os.stream_from_handle(hd)) } else { @@ -183,7 +248,7 @@ hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) return hash_bytes_192(buf[:]), ok } } - return [24]byte{}, false + return [DIGEST_SIZE_192]byte{}, false } hash_192 :: proc { @@ -191,6 +256,8 @@ hash_192 :: proc { hash_file_192, hash_bytes_192, hash_string_192, + hash_bytes_to_buffer_192, + hash_string_to_buffer_192, } /* diff --git a/core/crypto/whirlpool/whirlpool.odin b/core/crypto/whirlpool/whirlpool.odin index 43ad2a0a5..255f57bc2 100644 --- a/core/crypto/whirlpool/whirlpool.odin +++ b/core/crypto/whirlpool/whirlpool.odin @@ -19,16 +19,18 @@ import "../util" High level API */ +DIGEST_SIZE :: 64 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc(data: string) -> [64]byte { +hash_string :: proc(data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: Whirlpool_Context // init(&ctx) No-op update(&ctx, data) @@ -36,10 +38,28 @@ hash_bytes :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: Whirlpool_Context + // init(&ctx) No-op + update(&ctx, data) + final(&ctx, hash) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: Whirlpool_Context // init(&ctx) No-op buf := make([]byte, 512) @@ -57,7 +77,7 @@ hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -65,7 +85,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { return hash_bytes(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -73,6 +93,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/vendor/botan/README.md b/vendor/botan/README.md index 057aed422..b7d4d01a1 100644 --- a/vendor/botan/README.md +++ b/vendor/botan/README.md @@ -26,9 +26,11 @@ Wrappers for hashing algorithms have been added to match the API within the Odin #### High level API Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_`. -Included in these groups are four procedures. +Included in these groups are six procedures. * `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally * `hash_bytes` - Hash a given byte slice and return the computed hash +* `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally +* `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash * `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it * `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true) @@ -49,6 +51,10 @@ main :: proc() { // Compute the hash, using the high level API computed_hash := md4.hash(input) + // Variant that takes a destination buffer, instead of returning the computed hash + hash := make([]byte, md4.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash + md4.hash(input, hash[:]) + // Compute the hash, using the low level API // @note: Botan's structs are opaque by design, they don't expose any fields ctx: md4.Md4_Context diff --git a/vendor/botan/blake2b/blake2b.odin b/vendor/botan/blake2b/blake2b.odin index efd4f464b..226502e83 100644 --- a/vendor/botan/blake2b/blake2b.odin +++ b/vendor/botan/blake2b/blake2b.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE :: 64 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc "contextless" (data: string) -> [64]byte { +hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_BLAKE2B, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes :: proc "contextless" (data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_BLAKE2B, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_BLAKE2B, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { return hash_bytes(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -76,6 +97,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/vendor/botan/gost/gost.odin b/vendor/botan/gost/gost.odin index 266078c7d..9f081f9cb 100644 --- a/vendor/botan/gost/gost.odin +++ b/vendor/botan/gost/gost.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE :: 32 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc "contextless" (data: string) -> [32]byte { +hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_GOST, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes :: proc "contextless" (data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_GOST, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_GOST, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { return hash_bytes(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -76,6 +97,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/vendor/botan/keccak/keccak.odin b/vendor/botan/keccak/keccak.odin index c2f52bfdc..3316de017 100644 --- a/vendor/botan/keccak/keccak.odin +++ b/vendor/botan/keccak/keccak.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE_512 :: 64 + // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_KECCAK_512, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_KECCAK_512, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_KECCAK_512, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -76,6 +97,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/vendor/botan/md4/md4.odin b/vendor/botan/md4/md4.odin index 47a77c0fb..c8a1ad903 100644 --- a/vendor/botan/md4/md4.odin +++ b/vendor/botan/md4/md4.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE :: 16 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc "contextless" (data: string) -> [16]byte { +hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_MD4, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes :: proc "contextless" (data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_MD4, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_MD4, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { return hash_bytes(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -76,6 +97,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/vendor/botan/md5/md5.odin b/vendor/botan/md5/md5.odin index 15ad1e05a..203f2d092 100644 --- a/vendor/botan/md5/md5.odin +++ b/vendor/botan/md5/md5.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE :: 16 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc "contextless" (data: string) -> [16]byte { +hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_MD5, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes :: proc "contextless" (data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_MD5, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_MD5, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { return hash_bytes(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -76,6 +97,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/vendor/botan/ripemd/ripemd.odin b/vendor/botan/ripemd/ripemd.odin index 66260e520..0a8195a96 100644 --- a/vendor/botan/ripemd/ripemd.odin +++ b/vendor/botan/ripemd/ripemd.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE_160 :: 20 + // hash_string_160 will hash the given input and return the // computed hash -hash_string_160 :: proc(data: string) -> [20]byte { +hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { return hash_bytes_160(transmute([]byte)(data)) } // hash_bytes_160 will hash the given input and return the // computed hash -hash_bytes_160 :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { + hash: [DIGEST_SIZE_160]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_RIPEMD_160, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes_160 :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer_160 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_160(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_160 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_RIPEMD_160, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_160 will read the stream in chunks and compute a // hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { + hash: [DIGEST_SIZE_160]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_RIPEMD_160, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file_160 will read the file provided by the given handle // and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { if !load_at_once { return hash_stream_160(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) return hash_bytes_160(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE_160]byte{}, false } hash_160 :: proc { @@ -76,6 +97,8 @@ hash_160 :: proc { hash_file_160, hash_bytes_160, hash_string_160, + hash_bytes_to_buffer_160, + hash_string_to_buffer_160, } /* diff --git a/vendor/botan/sha1/sha1.odin b/vendor/botan/sha1/sha1.odin index 2eb799cb6..005b01821 100644 --- a/vendor/botan/sha1/sha1.odin +++ b/vendor/botan/sha1/sha1.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE :: 20 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc "contextless" (data: string) -> [20]byte { +hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA1, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes :: proc "contextless" (data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA1, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA1, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { return hash_bytes(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -76,6 +97,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/vendor/botan/sha2/sha2.odin b/vendor/botan/sha2/sha2.odin index cc5cd1d65..f5d6921a8 100644 --- a/vendor/botan/sha2/sha2.odin +++ b/vendor/botan/sha2/sha2.odin @@ -20,16 +20,21 @@ import botan "../bindings" High level API */ +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_384 :: 48 +DIGEST_SIZE_512 :: 64 + // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc(data: string) -> [28]byte { +hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA_224, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +43,29 @@ hash_bytes_224 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA_224, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_224 will read the stream in chunks and compute a // hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA_224, 0) buf := make([]byte, 512) @@ -60,7 +84,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224 will read the file provided by the given handle // and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224(os.stream_from_handle(hd)) } else { @@ -68,7 +92,7 @@ hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) return hash_bytes_224(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { @@ -76,18 +100,20 @@ hash_224 :: proc { hash_file_224, hash_bytes_224, hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA_256, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -96,10 +122,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA_256, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA_256, 0) buf := make([]byte, 512) @@ -118,7 +163,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -126,7 +171,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -134,18 +179,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc(data: string) -> [48]byte { +hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc(data: []byte) -> [48]byte { - hash: [48]byte +hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { + hash: [DIGEST_SIZE_384]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA_384, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -154,10 +201,29 @@ hash_bytes_384 :: proc(data: []byte) -> [48]byte { return hash } +// hash_string_to_buffer_384 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_384(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_384 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA_384, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_384 will read the stream in chunks and compute a // hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte +hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { + hash: [DIGEST_SIZE_384]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA_384, 0) buf := make([]byte, 512) @@ -176,7 +242,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { // hash_file_384 will read the file provided by the given handle // and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { +hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { if !load_at_once { return hash_stream_384(os.stream_from_handle(hd)) } else { @@ -184,7 +250,7 @@ hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) return hash_bytes_384(buf[:]), ok } } - return [48]byte{}, false + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { @@ -192,18 +258,20 @@ hash_384 :: proc { hash_file_384, hash_bytes_384, hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA_512, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -212,10 +280,29 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA_512, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA_512, 0) buf := make([]byte, 512) @@ -234,7 +321,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -242,7 +329,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -250,6 +337,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/vendor/botan/sha3/sha3.odin b/vendor/botan/sha3/sha3.odin index 1211d836a..cf9fa5b2b 100644 --- a/vendor/botan/sha3/sha3.odin +++ b/vendor/botan/sha3/sha3.odin @@ -20,16 +20,21 @@ import botan "../bindings" High level API */ +DIGEST_SIZE_224 :: 28 +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_384 :: 48 +DIGEST_SIZE_512 :: 64 + // hash_string_224 will hash the given input and return the // computed hash -hash_string_224 :: proc(data: string) -> [28]byte { +hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte { return hash_bytes_224(transmute([]byte)(data)) } // hash_bytes_224 will hash the given input and return the // computed hash -hash_bytes_224 :: proc(data: []byte) -> [28]byte { - hash: [28]byte +hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte { + hash: [DIGEST_SIZE_224]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA3_224, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +43,29 @@ hash_bytes_224 :: proc(data: []byte) -> [28]byte { return hash } +// hash_string_to_buffer_224 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_224 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_224(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_224 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_224 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_224, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA3_224, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_224 will read the stream in chunks and compute a // hash from its contents -hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { - hash: [28]byte +hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { + hash: [DIGEST_SIZE_224]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA3_224, 0) buf := make([]byte, 512) @@ -60,7 +84,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([28]byte, bool) { // hash_file_224 will read the file provided by the given handle // and compute a hash -hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) { +hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) { if !load_at_once { return hash_stream_224(os.stream_from_handle(hd)) } else { @@ -68,7 +92,7 @@ hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([28]byte, bool) return hash_bytes_224(buf[:]), ok } } - return [28]byte{}, false + return [DIGEST_SIZE_224]byte{}, false } hash_224 :: proc { @@ -76,18 +100,20 @@ hash_224 :: proc { hash_file_224, hash_bytes_224, hash_string_224, + hash_bytes_to_buffer_224, + hash_string_to_buffer_224, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA3_256, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -96,10 +122,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA3_256, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA3_256, 0) buf := make([]byte, 512) @@ -118,7 +163,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -126,7 +171,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -134,18 +179,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_384 will hash the given input and return the // computed hash -hash_string_384 :: proc(data: string) -> [48]byte { +hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte { return hash_bytes_384(transmute([]byte)(data)) } // hash_bytes_384 will hash the given input and return the // computed hash -hash_bytes_384 :: proc(data: []byte) -> [48]byte { - hash: [48]byte +hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte { + hash: [DIGEST_SIZE_384]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA3_384, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -154,10 +201,29 @@ hash_bytes_384 :: proc(data: []byte) -> [48]byte { return hash } +// hash_string_to_buffer_384 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_384 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_384(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_384 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_384 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_384, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA3_384, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_384 will read the stream in chunks and compute a // hash from its contents -hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { - hash: [48]byte +hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { + hash: [DIGEST_SIZE_384]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA3_384, 0) buf := make([]byte, 512) @@ -176,7 +242,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([48]byte, bool) { // hash_file_384 will read the file provided by the given handle // and compute a hash -hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) { +hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) { if !load_at_once { return hash_stream_384(os.stream_from_handle(hd)) } else { @@ -184,7 +250,7 @@ hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([48]byte, bool) return hash_bytes_384(buf[:]), ok } } - return [48]byte{}, false + return [DIGEST_SIZE_384]byte{}, false } hash_384 :: proc { @@ -192,18 +258,20 @@ hash_384 :: proc { hash_file_384, hash_bytes_384, hash_string_384, + hash_bytes_to_buffer_384, + hash_string_to_buffer_384, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA3_512, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -212,10 +280,29 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHA3_512, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHA3_512, 0) buf := make([]byte, 512) @@ -234,7 +321,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -242,7 +329,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -250,6 +337,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/vendor/botan/shake/shake.odin b/vendor/botan/shake/shake.odin index 82bf7ad15..ac8432f64 100644 --- a/vendor/botan/shake/shake.odin +++ b/vendor/botan/shake/shake.odin @@ -20,16 +20,19 @@ import botan "../bindings" High level API */ +DIGEST_SIZE_128 :: 16 +DIGEST_SIZE_256 :: 32 + // hash_string_128 will hash the given input and return the // computed hash -hash_string_128 :: proc(data: string) -> [16]byte { +hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128(transmute([]byte)(data)) } // hash_bytes_128 will hash the given input and return the // computed hash -hash_bytes_128 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHAKE_128, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +41,29 @@ hash_bytes_128 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHAKE_128, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_128 will read the stream in chunks and compute a // hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHAKE_128, 0) buf := make([]byte, 512) @@ -60,7 +82,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128 will read the file provided by the given handle // and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128(os.stream_from_handle(hd)) } else { @@ -68,7 +90,7 @@ hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) return hash_bytes_128(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128 :: proc { @@ -76,18 +98,20 @@ hash_128 :: proc { hash_file_128, hash_bytes_128, hash_string_128, + hash_bytes_to_buffer_128, + hash_string_to_buffer_128, } // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHAKE_256, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -96,10 +120,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SHAKE_256, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SHAKE_256, 0) buf := make([]byte, 512) @@ -118,7 +161,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -126,7 +169,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -134,6 +177,8 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } /* diff --git a/vendor/botan/skein512/skein512.odin b/vendor/botan/skein512/skein512.odin index dc808edb9..490eeba03 100644 --- a/vendor/botan/skein512/skein512.odin +++ b/vendor/botan/skein512/skein512.odin @@ -22,16 +22,19 @@ import botan "../bindings" High level API */ +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_512 :: 64 + // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SKEIN_512_256, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -40,10 +43,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SKEIN_512_256, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SKEIN_512_256, 0) buf := make([]byte, 512) @@ -62,7 +84,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -70,7 +92,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -78,18 +100,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SKEIN_512_512, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -98,10 +122,29 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SKEIN_512_512, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SKEIN_512_512, 0) buf := make([]byte, 512) @@ -120,7 +163,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -128,7 +171,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -136,6 +179,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } // hash_string_slice will hash the given input and return the @@ -156,6 +201,25 @@ hash_bytes_slice :: proc(data: []byte, bit_size: int, allocator := context.alloc return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_slice :: proc(data: string, hash: []byte, bit_size: int, allocator := context.allocator) { + hash_bytes_to_buffer_slice(transmute([]byte)(data), hash, bit_size, allocator); +} + +// hash_bytes_to_buffer_slice will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_slice :: proc(data, hash: []byte, bit_size: int, allocator := context.allocator) { + assert(len(hash) >= bit_size, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, strings.unsafe_string_to_cstring(fmt.tprintf("Skein-512(%d)", bit_size * 8)), 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_slice will read the stream in chunks and compute a // hash from its contents hash_stream_slice :: proc(s: io.Stream, bit_size: int, allocator := context.allocator) -> ([]byte, bool) { @@ -194,6 +258,8 @@ hash_slice :: proc { hash_file_slice, hash_bytes_slice, hash_string_slice, + hash_bytes_to_buffer_slice, + hash_string_to_buffer_slice, } /* diff --git a/vendor/botan/sm3/sm3.odin b/vendor/botan/sm3/sm3.odin index eada2a5b3..7eb3f1f8d 100644 --- a/vendor/botan/sm3/sm3.odin +++ b/vendor/botan/sm3/sm3.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE :: 32 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc "contextless" (data: string) -> [32]byte { +hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SM3, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes :: proc "contextless" (data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_SM3, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_SM3, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { return hash_bytes(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -76,6 +97,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* diff --git a/vendor/botan/streebog/streebog.odin b/vendor/botan/streebog/streebog.odin index acee1a78a..cbf2047ed 100644 --- a/vendor/botan/streebog/streebog.odin +++ b/vendor/botan/streebog/streebog.odin @@ -20,16 +20,19 @@ import botan "../bindings" High level API */ +DIGEST_SIZE_256 :: 32 +DIGEST_SIZE_512 :: 64 + // hash_string_256 will hash the given input and return the // computed hash -hash_string_256 :: proc(data: string) -> [32]byte { +hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte { return hash_bytes_256(transmute([]byte)(data)) } // hash_bytes_256 will hash the given input and return the // computed hash -hash_bytes_256 :: proc(data: []byte) -> [32]byte { - hash: [32]byte +hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_STREEBOG_256, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +41,29 @@ hash_bytes_256 :: proc(data: []byte) -> [32]byte { return hash } +// hash_string_to_buffer_256 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_256 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_256(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_256 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_256 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_256, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_STREEBOG_256, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_256 will read the stream in chunks and compute a // hash from its contents -hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { - hash: [32]byte +hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { + hash: [DIGEST_SIZE_256]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_STREEBOG_256, 0) buf := make([]byte, 512) @@ -60,7 +82,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([32]byte, bool) { // hash_file_256 will read the file provided by the given handle // and compute a hash -hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) { +hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) { if !load_at_once { return hash_stream_256(os.stream_from_handle(hd)) } else { @@ -68,7 +90,7 @@ hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([32]byte, bool) return hash_bytes_256(buf[:]), ok } } - return [32]byte{}, false + return [DIGEST_SIZE_256]byte{}, false } hash_256 :: proc { @@ -76,18 +98,20 @@ hash_256 :: proc { hash_file_256, hash_bytes_256, hash_string_256, + hash_bytes_to_buffer_256, + hash_string_to_buffer_256, } // hash_string_512 will hash the given input and return the // computed hash -hash_string_512 :: proc(data: string) -> [64]byte { +hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte { return hash_bytes_512(transmute([]byte)(data)) } // hash_bytes_512 will hash the given input and return the // computed hash -hash_bytes_512 :: proc(data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_STREEBOG_512, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -96,10 +120,29 @@ hash_bytes_512 :: proc(data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer_512 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_512 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_512(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_512 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_512 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_512, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_STREEBOG_512, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_512 will read the stream in chunks and compute a // hash from its contents -hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { + hash: [DIGEST_SIZE_512]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_STREEBOG_512, 0) buf := make([]byte, 512) @@ -118,7 +161,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file_512 will read the file provided by the given handle // and compute a hash -hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) { if !load_at_once { return hash_stream_512(os.stream_from_handle(hd)) } else { @@ -126,7 +169,7 @@ hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) return hash_bytes_512(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE_512]byte{}, false } hash_512 :: proc { @@ -134,6 +177,8 @@ hash_512 :: proc { hash_file_512, hash_bytes_512, hash_string_512, + hash_bytes_to_buffer_512, + hash_string_to_buffer_512, } /* diff --git a/vendor/botan/tiger/tiger.odin b/vendor/botan/tiger/tiger.odin index b240457a6..b29602b26 100644 --- a/vendor/botan/tiger/tiger.odin +++ b/vendor/botan/tiger/tiger.odin @@ -20,16 +20,20 @@ import botan "../bindings" High level API */ +DIGEST_SIZE_128 :: 16 +DIGEST_SIZE_160 :: 20 +DIGEST_SIZE_192 :: 24 + // hash_string_128 will hash the given input and return the // computed hash -hash_string_128 :: proc(data: string) -> [16]byte { +hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte { return hash_bytes_128(transmute([]byte)(data)) } // hash_bytes_128 will hash the given input and return the // computed hash -hash_bytes_128 :: proc(data: []byte) -> [16]byte { - hash: [16]byte +hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte { + hash: [DIGEST_SIZE_128]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_TIGER_128, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +42,29 @@ hash_bytes_128 :: proc(data: []byte) -> [16]byte { return hash } +// hash_string_to_buffer_128 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_128 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_128(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_128 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_128 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_128, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_TIGER_128, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_128 will read the stream in chunks and compute a // hash from its contents -hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { - hash: [16]byte +hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { + hash: [DIGEST_SIZE_128]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_TIGER_128, 0) buf := make([]byte, 512) @@ -60,7 +83,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([16]byte, bool) { // hash_file_128 will read the file provided by the given handle // and compute a hash -hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) { +hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) { if !load_at_once { return hash_stream_128(os.stream_from_handle(hd)) } else { @@ -68,7 +91,7 @@ hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([16]byte, bool) return hash_bytes_128(buf[:]), ok } } - return [16]byte{}, false + return [DIGEST_SIZE_128]byte{}, false } hash_128 :: proc { @@ -76,18 +99,20 @@ hash_128 :: proc { hash_file_128, hash_bytes_128, hash_string_128, + hash_bytes_to_buffer_128, + hash_string_to_buffer_128, } // hash_string_160 will hash the given input and return the // computed hash -hash_string_160 :: proc(data: string) -> [20]byte { +hash_string_160 :: proc(data: string) -> [DIGEST_SIZE_160]byte { return hash_bytes_160(transmute([]byte)(data)) } // hash_bytes_160 will hash the given input and return the // computed hash -hash_bytes_160 :: proc(data: []byte) -> [20]byte { - hash: [20]byte +hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte { + hash: [DIGEST_SIZE_160]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_TIGER_160, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -96,10 +121,29 @@ hash_bytes_160 :: proc(data: []byte) -> [20]byte { return hash } +// hash_string_to_buffer_160 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_160 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_160(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_160 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_160 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_160, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_TIGER_160, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_160 will read the stream in chunks and compute a // hash from its contents -hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { - hash: [20]byte +hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { + hash: [DIGEST_SIZE_160]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_TIGER_160, 0) buf := make([]byte, 512) @@ -118,7 +162,7 @@ hash_stream_160 :: proc(s: io.Stream) -> ([20]byte, bool) { // hash_file_160 will read the file provided by the given handle // and compute a hash -hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) { +hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_160]byte, bool) { if !load_at_once { return hash_stream_160(os.stream_from_handle(hd)) } else { @@ -126,7 +170,7 @@ hash_file_160 :: proc(hd: os.Handle, load_at_once := false) -> ([20]byte, bool) return hash_bytes_160(buf[:]), ok } } - return [20]byte{}, false + return [DIGEST_SIZE_160]byte{}, false } hash_160 :: proc { @@ -134,18 +178,20 @@ hash_160 :: proc { hash_file_160, hash_bytes_160, hash_string_160, + hash_bytes_to_buffer_160, + hash_string_to_buffer_160, } // hash_string_192 will hash the given input and return the // computed hash -hash_string_192 :: proc(data: string) -> [24]byte { +hash_string_192 :: proc(data: string) -> [DIGEST_SIZE_192]byte { return hash_bytes_192(transmute([]byte)(data)) } // hash_bytes_192 will hash the given input and return the // computed hash -hash_bytes_192 :: proc(data: []byte) -> [24]byte { - hash: [24]byte +hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte { + hash: [DIGEST_SIZE_192]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_TIGER_192, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -154,10 +200,29 @@ hash_bytes_192 :: proc(data: []byte) -> [24]byte { return hash } +// hash_string_to_buffer_192 will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer_192 :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer_192(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer_192 will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer_192 :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE_192, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_TIGER_192, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream_192 will read the stream in chunks and compute a // hash from its contents -hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { - hash: [24]byte +hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { + hash: [DIGEST_SIZE_192]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_TIGER_192, 0) buf := make([]byte, 512) @@ -176,7 +241,7 @@ hash_stream_192 :: proc(s: io.Stream) -> ([24]byte, bool) { // hash_file_192 will read the file provided by the given handle // and compute a hash -hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) { +hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_192]byte, bool) { if !load_at_once { return hash_stream_192(os.stream_from_handle(hd)) } else { @@ -184,7 +249,7 @@ hash_file_192 :: proc(hd: os.Handle, load_at_once := false) -> ([24]byte, bool) return hash_bytes_192(buf[:]), ok } } - return [24]byte{}, false + return [DIGEST_SIZE_192]byte{}, false } hash_192 :: proc { @@ -192,6 +257,8 @@ hash_192 :: proc { hash_file_192, hash_bytes_192, hash_string_192, + hash_bytes_to_buffer_192, + hash_string_to_buffer_192, } /* diff --git a/vendor/botan/whirlpool/whirlpool.odin b/vendor/botan/whirlpool/whirlpool.odin index 130386ff3..2aff3c8ed 100644 --- a/vendor/botan/whirlpool/whirlpool.odin +++ b/vendor/botan/whirlpool/whirlpool.odin @@ -20,16 +20,18 @@ import botan "../bindings" High level API */ +DIGEST_SIZE :: 64 + // hash_string will hash the given input and return the // computed hash -hash_string :: proc "contextless" (data: string) -> [64]byte { +hash_string :: proc "contextless" (data: string) -> [DIGEST_SIZE]byte { return hash_bytes(transmute([]byte)(data)) } // hash_bytes will hash the given input and return the // computed hash -hash_bytes :: proc "contextless" (data: []byte) -> [64]byte { - hash: [64]byte +hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_WHIRLPOOL, 0) botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) @@ -38,10 +40,29 @@ hash_bytes :: proc "contextless" (data: []byte) -> [64]byte { return hash } +// hash_string_to_buffer will hash the given input and assign the +// computed hash to the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_string_to_buffer :: proc(data: string, hash: []byte) { + hash_bytes_to_buffer(transmute([]byte)(data), hash); +} + +// hash_bytes_to_buffer will hash the given input and write the +// computed hash into the second parameter. +// It requires that the destination buffer is at least as big as the digest size +hash_bytes_to_buffer :: proc(data, hash: []byte) { + assert(len(hash) >= DIGEST_SIZE, "Size of destination buffer is smaller than the digest size") + ctx: botan.hash_t + botan.hash_init(&ctx, botan.HASH_WHIRLPOOL, 0) + botan.hash_update(ctx, len(data) == 0 ? nil : &data[0], uint(len(data))) + botan.hash_final(ctx, &hash[0]) + botan.hash_destroy(ctx) +} + // hash_stream will read the stream in chunks and compute a // hash from its contents -hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { - hash: [64]byte +hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { + hash: [DIGEST_SIZE]byte ctx: botan.hash_t botan.hash_init(&ctx, botan.HASH_WHIRLPOOL, 0) buf := make([]byte, 512) @@ -60,7 +81,7 @@ hash_stream :: proc(s: io.Stream) -> ([64]byte, bool) { // hash_file will read the file provided by the given handle // and compute a hash -hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { +hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) { if !load_at_once { return hash_stream(os.stream_from_handle(hd)) } else { @@ -68,7 +89,7 @@ hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([64]byte, bool) { return hash_bytes(buf[:]), ok } } - return [64]byte{}, false + return [DIGEST_SIZE]byte{}, false } hash :: proc { @@ -76,6 +97,8 @@ hash :: proc { hash_file, hash_bytes, hash_string, + hash_bytes_to_buffer, + hash_string_to_buffer, } /* From bdf66bb1e1096690be66eda90b35c6cfdc8a5cf0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 31 Dec 2021 22:54:12 +0000 Subject: [PATCH 0129/1258] Correct `abs` type behaviour for quaternions --- src/check_builtin.cpp | 13 ++++++++++--- src/types.cpp | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index f93cf9886..dc8c209c9 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1858,7 +1858,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 f64 r = operand->value.value_complex->real; f64 i = operand->value.value_complex->imag; operand->value = exact_value_float(gb_sqrt(r*r + i*i)); - + break; + } + case ExactValue_Quaternion: { + f64 r = operand->value.value_quaternion->real; + f64 i = operand->value.value_quaternion->imag; + f64 j = operand->value.value_quaternion->jmag; + f64 k = operand->value.value_quaternion->kmag; + operand->value = exact_value_float(gb_sqrt(r*r + i*i + j*j + k*k)); break; } default: @@ -1877,10 +1884,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } } - if (is_type_complex(operand->type)) { + if (is_type_complex_or_quaternion(operand->type)) { operand->type = base_complex_elem_type(operand->type); } - GB_ASSERT(!is_type_complex(operand->type)); + GB_ASSERT(!is_type_complex_or_quaternion(operand->type)); break; } diff --git a/src/types.cpp b/src/types.cpp index 2b7ea93dc..f621d4346 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1253,6 +1253,13 @@ bool is_type_quaternion(Type *t) { } return false; } +bool is_type_complex_or_quaternion(Type *t) { + t = core_type(t); + if (t->kind == Type_Basic) { + return (t->Basic.flags & (BasicFlag_Complex|BasicFlag_Quaternion)) != 0; + } + return false; +} bool is_type_f16(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { From 0d7cb02386c765f6f4fe343b463e84c3a7c1d1fc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 31 Dec 2021 23:20:14 +0000 Subject: [PATCH 0130/1258] Fix conversion from float to quaternion --- core/math/linalg/extended.odin | 4 ++-- src/check_expr.cpp | 7 +++++++ src/llvm_backend_expr.cpp | 30 +++++++----------------------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/core/math/linalg/extended.odin b/core/math/linalg/extended.odin index ba64356ce..c2bf5552a 100644 --- a/core/math/linalg/extended.odin +++ b/core/math/linalg/extended.odin @@ -103,10 +103,10 @@ max :: proc{max_single, max_double, max_triple} abs :: proc(a: $T) -> (out: T) where IS_NUMERIC(ELEM_TYPE(T)) { when IS_ARRAY(T) { for i in 0.. Date: Sat, 1 Jan 2022 13:11:53 +0000 Subject: [PATCH 0131/1258] Fix typo in priority_queue.odin and add `default_swap_proc` --- core/container/priority_queue/priority_queue.odin | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/container/priority_queue/priority_queue.odin b/core/container/priority_queue/priority_queue.odin index df26edb1b..2bdb3c777 100644 --- a/core/container/priority_queue/priority_queue.odin +++ b/core/container/priority_queue/priority_queue.odin @@ -11,6 +11,12 @@ Priority_Queue :: struct($T: typeid) { DEFAULT_CAPACITY :: 16 +default_swap_proc :: proc($T: typeid) -> proc(q: []T, i, j: int) { + return proc(q: []T, i, j: int) { + q[i], q[j] = q[j], q[i] + } +} + init :: proc(pq: ^$Q/Priority_Queue($T), less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int), capacity := DEFAULT_CAPACITY, allocator := context.allocator) { if pq.queue.allocator.procedure == nil { pq.queue.allocator = allocator @@ -65,7 +71,7 @@ _shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool { } j, j2 = j1, j1+1 if j1 < n && pq.less(queue[j2], queue[j1]) { - j1 = j2 + j = j2 } if !pq.less(queue[i], queue[j]) { break From 43763ddfda018925ef55fc0f22f2e9ab363a848f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 1 Jan 2022 13:44:37 +0000 Subject: [PATCH 0132/1258] Correct `_shift_down` logic --- core/container/priority_queue/priority_queue.odin | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/core/container/priority_queue/priority_queue.odin b/core/container/priority_queue/priority_queue.odin index 2bdb3c777..e324287f3 100644 --- a/core/container/priority_queue/priority_queue.odin +++ b/core/container/priority_queue/priority_queue.odin @@ -56,24 +56,23 @@ cap :: proc(pq: $Q/Priority_Queue($T)) -> int { _shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool { // O(n log n) - i := i0 - j, j1, j2: int - if 0 > i || i > n { + if 0 > i0 || i0 > n { return false } + i := i0 queue := pq.queue[:] for { j1 := 2*i + 1 - if 0 > j1 || j1 >= n { + if j1 < 0 || j1 >= n { break } - j, j2 = j1, j1+1 - if j1 < n && pq.less(queue[j2], queue[j1]) { + j := j1 + if j2 := j1+1; j2 < n && pq.less(queue[j2], queue[j1]) { j = j2 } - if !pq.less(queue[i], queue[j]) { + if !pq.less(queue[j], queue[i]) { break } @@ -87,7 +86,7 @@ _shift_up :: proc(pq: ^$Q/Priority_Queue($T), j: int) { j := j queue := pq.queue[:] n := builtin.len(queue) - for 0 <= j && j < n { + for 0 <= j { i := (j-1)/2 if i == j || !pq.less(queue[j], queue[i]) { break From f364ac60c290790e7df82c5f6ed9bf79824c223c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 1 Jan 2022 15:31:51 +0000 Subject: [PATCH 0133/1258] Remove the hidden NUL byte past the end from `strings.clone` --- core/strings/strings.odin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 3f703372f..b93c5bcc0 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -6,9 +6,8 @@ import "core:unicode" import "core:unicode/utf8" clone :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> string { - c := make([]byte, len(s)+1, allocator, loc) + c := make([]byte, len(s), allocator, loc) copy(c, s) - c[len(s)] = 0 return string(c[:len(s)]) } From a032a2ef322de150587117396eaf6e5ae7a11768 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 1 Jan 2022 15:33:19 +0000 Subject: [PATCH 0134/1258] Remove the hidden NUL byte past the end from `bytes.clone` --- core/bytes/bytes.odin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/bytes/bytes.odin b/core/bytes/bytes.odin index 1e83b93c8..1bf11e0b0 100644 --- a/core/bytes/bytes.odin +++ b/core/bytes/bytes.odin @@ -5,9 +5,8 @@ import "core:unicode" import "core:unicode/utf8" clone :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> []byte { - c := make([]byte, len(s)+1, allocator, loc) + c := make([]byte, len(s), allocator, loc) copy(c, s) - c[len(s)] = 0 return c[:len(s)] } From a60b9735a2ce49d4d8389db83ed53372b7f6c413 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 1 Jan 2022 15:46:22 +0000 Subject: [PATCH 0135/1258] Add `core:container/queue` --- core/container/queue/queue.odin | 205 ++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 core/container/queue/queue.odin diff --git a/core/container/queue/queue.odin b/core/container/queue/queue.odin new file mode 100644 index 000000000..ff1e85fbd --- /dev/null +++ b/core/container/queue/queue.odin @@ -0,0 +1,205 @@ +package container_queue + +import "core:builtin" +import "core:runtime" + +// Dynamically resizable double-ended queue/ring-buffer +Queue :: struct($T: typeid) { + data: [dynamic]T, + len: uint, + offset: uint, +} + +DEFAULT_CAPACITY :: 16 + +// Procedure to initialize a queue +init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> bool { + if q.data.allocator.procedure == nil { + q.data.allocator = allocator + } + clear(q) + return reserve(q, capacity) +} + +// Procedure to initialize a queue from a fixed backing slice +init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool { + clear(q) + q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{ + data = raw_data(backing), + len = builtin.len(backing), + cap = builtin.len(backing), + allocator = {procedure=runtime.nil_allocator_proc, data=nil}, + } + return true +} + +// Procedure to destroy a queue +destroy :: proc(q: ^$Q/Queue($T)) { + delete(q.data) +} + +// The length of the queue +len :: proc(q: $Q/Queue($T)) -> int { + return int(q.len) +} + +// The current capacity of the queue +cap :: proc(q: $Q/Queue($T)) -> int { + return builtin.len(q.data) +} + +// Remaining space in the queue (cap-len) +space :: proc(q: $Q/Queue($T)) -> int { + return builtin.len(q.data) - int(q.len) +} + +// Reserve enough space for at least the specified capacity +reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> bool { + if uint(capacity) > q.len { + return _grow(q, uint(capacity)) + } + return true +} + + +get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T { + runtime.bounds_check_error_loc(loc, i, builtin.len(q.data)) + + idx := (uint(i)+q.offset)%builtin.len(q.data) + return q.data[idx] +} +set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) { + runtime.bounds_check_error_loc(loc, i, builtin.len(q.data)) + + idx := (uint(i)+q.offset)%builtin.len(q.data) + q.data[idx] = val +} +get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^T { + runtime.bounds_check_error_loc(loc, i, builtin.len(q.data)) + + idx := (uint(i)+q.offset)%builtin.len(q.data) + return &q.data[idx] +} + +// Push an element to the back of the queue +push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool { + if space(q^) == 0 { + _grow(q) or_return + } + q.data[q.len] = elem + q.len += 1 + return true +} + +// Push an element to the front of the queue +push_front :: proc(q: ^$Q/Queue($T), elem: T) -> bool { + if space(q^) == 0 { + _grow(q) or_return + } + q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data) + q.len += 1 + q.data[q.offset] = elem + return true +} + + +// Pop an element from the back of the queue +pop_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) { + assert(condition=q.len > 0, loc=loc) + q.len -= 1 + idx := (q.offset+uint(q.len))%builtin.len(q.data) + elem = q.data[idx] + return +} +// Safely pop an element from the back of the queue +pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { + if q.len > 0 { + q.len -= 1 + idx := (q.offset+uint(q.len))%builtin.len(q.data) + elem = q.data[idx] + ok = true + } + return +} + +// Pop an element from the front of the queue +pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) { + assert(condition=q.len > 0, loc=loc) + elem = q.data[q.offset] + q.len -= 1 + return +} +// Safely pop an element from the front of the queue +pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { + if q.len > 0 { + elem = q.data[q.offset] + q.len -= 1 + ok = true + } + return +} + +// Push multiple elements to the front of the queue +push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> bool { + n := uint(builtin.len(elems)) + if space(q^) < int(n) { + _grow(q, q.len + n) or_return + } + + sz := uint(builtin.len(q.data)) + insert_from := (q.offset + q.len) % sz + insert_to := n + if insert_from + insert_to > sz { + insert_to = sz - insert_from + } + copy(q.data[insert_from:], elems[:insert_to]) + copy(q.data[:insert_from], elems[insert_to:]) + q.len += n + return true +} + +// Consume `n` elements from the front of the queue +consume_front :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) { + assert(condition=int(q.len) >= n, loc=loc) + if n > 0 { + nu := uint(n) + q.offset = (q.offset + nu) % builtin.len(q.data) + q.len -= nu + } +} + +// Consume `n` elements from the back of the queue +consume_back :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) { + assert(condition=int(q.len) >= n, loc=loc) + if n > 0 { + q.len -= uint(n) + } +} + + + +append_elem :: push_back +append_elems :: push_back_elems +push :: proc{push_back, push_back_elems} +append :: proc{push_back, push_back_elems} + + +// Clear the contents of the queue +clear :: proc(q: ^$Q/Queue($T)) { + q.len = 0 + q.offset = 0 +} + + +// Internal growinh procedure +_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> bool { + new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2) + n := uint(builtin.len(q.data)) + builtin.resize(&q.data, int(new_capacity)) or_return + if q.offset + q.len > n { + diff := n - q.offset + copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff]) + q.offset += new_capacity - n + } + return true +} From 50188f03086da716a8f23926ae10be6fd87abab4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 1 Jan 2022 17:13:11 +0000 Subject: [PATCH 0136/1258] Add `sort.map_entries_by_key` `sort.map_entries_by_value` --- core/sort/map.odin | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 core/sort/map.odin diff --git a/core/sort/map.odin b/core/sort/map.odin new file mode 100644 index 000000000..dff2dced3 --- /dev/null +++ b/core/sort/map.odin @@ -0,0 +1,33 @@ +package sort + +import "core:intrinsics" +import "core:runtime" +import "core:slice" + +map_entries_by_key :: proc(m: ^$M/map[$K]$V, loc := #caller_location) where intrinsics.type_is_ordered(K) { + Entry :: struct { + hash: uintptr, + next: int, + key: K, + value: V, + } + + header := runtime.__get_map_header(m) + entries := (^[dynamic]Entry)(&header.m.entries) + slice.sort_by_key(entries[:], proc(e: Entry) -> K { return e.key }) + runtime.__dynamic_map_reset_entries(header, loc) +} + +map_entries_by_value :: proc(m: ^$M/map[$K]$V, loc := #caller_location) where intrinsics.type_is_ordered(V) { + Entry :: struct { + hash: uintptr, + next: int, + key: K, + value: V, + } + + header := runtime.__get_map_header(m) + entries := (^[dynamic]Entry)(&header.m.entries) + slice.sort_by_key(entries[:], proc(e: Entry) -> V { return e.value }) + runtime.__dynamic_map_reset_entries(header, loc) +} \ No newline at end of file From 3cbf9c37193a2852db9ac52b9d9699169318d277 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 2 Jan 2022 14:45:39 +0000 Subject: [PATCH 0137/1258] Fix #1381 --- src/parser.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/parser.cpp b/src/parser.cpp index cbd4d61d5..5bf43cee9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5362,6 +5362,15 @@ isize calc_decl_count(Ast *decl) { count += calc_decl_count(decl->BlockStmt.stmts.data[i]); } break; + case Ast_WhenStmt: + { + isize inner_count = calc_decl_count(decl->WhenStmt.body); + if (decl->WhenStmt.else_stmt) { + inner_count = gb_max(inner_count, calc_decl_count(decl->WhenStmt.else_stmt)); + } + count += inner_count; + } + break; case Ast_ValueDecl: count = decl->ValueDecl.names.count; break; From 65434911489fdb5b9136b3b06b279a07137d7415 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 2 Jan 2022 15:31:47 +0000 Subject: [PATCH 0138/1258] Clean up code for queue (no logic changed) --- src/queue.cpp | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/queue.cpp b/src/queue.cpp index d69a2845c..ee8b1b086 100644 --- a/src/queue.cpp +++ b/src/queue.cpp @@ -71,6 +71,29 @@ void mpmc_destroy(MPMCQueue *q) { } +template +bool mpmc_internal_grow(MPMCQueue *q) { + mutex_lock(&q->mutex); + i32 old_size = q->mask+1; + i32 new_size = old_size*2; + resize_array_raw(&q->nodes, q->allocator, old_size, new_size); + if (q->nodes == nullptr) { + GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size); + mutex_unlock(&q->mutex); + return false; + } + resize_array_raw(&q->indices, q->allocator, old_size, new_size); + if (q->indices == nullptr) { + GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size); + mutex_unlock(&q->mutex); + return false; + } + mpmc_internal_init_indices(q->indices, old_size, new_size); + q->mask = new_size-1; + mutex_unlock(&q->mutex); + return true; +} + template i32 mpmc_enqueue(MPMCQueue *q, T const &data) { GB_ASSERT(q->mask != 0); @@ -78,8 +101,9 @@ i32 mpmc_enqueue(MPMCQueue *q, T const &data) { i32 head_idx = q->head_idx.load(std::memory_order_relaxed); for (;;) { - auto node = &q->nodes[head_idx & q->mask]; - auto node_idx_ptr = &q->indices[head_idx & q->mask]; + i32 index = head_idx & q->mask; + auto node = &q->nodes[index]; + auto node_idx_ptr = &q->indices[index]; i32 node_idx = node_idx_ptr->load(std::memory_order_acquire); i32 diff = node_idx - head_idx; @@ -91,24 +115,9 @@ i32 mpmc_enqueue(MPMCQueue *q, T const &data) { return q->count.fetch_add(1, std::memory_order_release); } } else if (diff < 0) { - mutex_lock(&q->mutex); - i32 old_size = q->mask+1; - i32 new_size = old_size*2; - resize_array_raw(&q->nodes, q->allocator, old_size, new_size); - if (q->nodes == nullptr) { - GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size); - mutex_unlock(&q->mutex); + if (!mpmc_internal_grow(q)) { return -1; } - resize_array_raw(&q->indices, q->allocator, old_size, new_size); - if (q->indices == nullptr) { - GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size); - mutex_unlock(&q->mutex); - return -1; - } - mpmc_internal_init_indices(q->indices, old_size, new_size); - q->mask = new_size-1; - mutex_unlock(&q->mutex); } else { head_idx = q->head_idx.load(std::memory_order_relaxed); } From e4f28de3de7b8bd72c89b87884302bfc7f943b4f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 Jan 2022 12:14:01 +0000 Subject: [PATCH 0139/1258] Fix #1311 --- vendor/microui/microui.odin | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vendor/microui/microui.odin b/vendor/microui/microui.odin index 9d3e01fa0..947f59f40 100644 --- a/vendor/microui/microui.odin +++ b/vendor/microui/microui.odin @@ -1030,9 +1030,7 @@ number_textbox :: proc(ctx: ^Context, value: ^Real, r: Rect, id: Id, fmt_string: if ctx.number_edit_id == id { res := textbox_raw(ctx, ctx.number_edit_buf[:], &ctx.number_edit_len, id, r, {}) if .SUBMIT in res || ctx.focus_id != id { - ok: bool - value^, ok = parse_real(string(ctx.number_edit_buf[:ctx.number_edit_len])) - assert(ok == true) + value^, _ = parse_real(string(ctx.number_edit_buf[:ctx.number_edit_len])) ctx.number_edit_id = 0 } else { return true From 236b08cb4921d5c6000d5029f2936271acb45f29 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 Jan 2022 12:51:32 +0000 Subject: [PATCH 0140/1258] Fix #1356 --- src/check_type.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index b4f30d2f0..282da4d0a 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -922,20 +922,19 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no i64 lower = big_int_to_i64(&i); i64 upper = big_int_to_i64(&j); - bool lower_changed = false; + i64 actual_lower = lower; i64 bits = MAX_BITS; if (type->BitSet.underlying != nullptr) { bits = 8*type_size_of(type->BitSet.underlying); if (lower > 0) { - lower = 0; - lower_changed = true; + actual_lower = 0; } else if (lower < 0) { error(bs->elem, "bit_set does not allow a negative lower bound (%lld) when an underlying type is set", lower); } } - i64 bits_required = upper-lower; + i64 bits_required = upper-actual_lower; switch (be->op.kind) { case Token_Ellipsis: case Token_RangeFull: @@ -959,7 +958,7 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no break; } if (!is_valid) { - if (lower_changed) { + if (actual_lower != lower) { error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required (internal the lower changed was changed 0 as an underlying type was set)", bits, bits_required); } else { error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, bits_required); From e6b8f7e77a419c8ff9e5f7de23fe15bef63264b1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 Jan 2022 12:54:31 +0000 Subject: [PATCH 0141/1258] Fix #1398 --- src/check_expr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 67e2f3bd7..cfffffd9f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7688,6 +7688,14 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } } + if (t->kind == Type_Matrix) { + if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < max_type_count) { + error(node, "Expected %lld values for this matrix literal, got %lld", cast(long long)max_type_count, cast(long long)max); + } + } + } + break; } From 12f459b5fb7904bfa926b5ad3fc5f80c6b5b4193 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 Jan 2022 13:12:39 +0000 Subject: [PATCH 0142/1258] Fix #1344 --- src/check_stmt.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 396388629..c3b8c46ca 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -58,6 +58,30 @@ bool contains_deferred_call(Ast *node) { return false; } +Ast *last_stmt_blocking_in_list(Slice const &stmts) { + for_array(i, stmts) { + Ast *n = stmts[i]; + switch (n->kind) { + case Ast_ReturnStmt: + return n; + case Ast_BranchStmt: + return n; + case Ast_ExprStmt: + if (is_diverging_stmt(n)) { + return n; + } + break; + case Ast_BlockStmt: + n = last_stmt_blocking_in_list(n->BlockStmt.stmts); + if (n != nullptr) { + return n; + } + break; + } + } + return nullptr; +} + void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) { if (stmts.count == 0) { return; @@ -102,6 +126,7 @@ void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) check_stmt(ctx, n, new_flags); if (i+1 < max_non_constant_declaration) { + never_executed_error:; switch (n->kind) { case Ast_ReturnStmt: error(n, "Statements after this 'return' are never executed"); @@ -116,6 +141,13 @@ void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) error(n, "Statements after a diverging procedure call are never executed"); } break; + + case Ast_BlockStmt: + n = last_stmt_blocking_in_list(n->BlockStmt.stmts); + if (n != nullptr) { + goto never_executed_error; + } + break; } } else if (i+1 == max_non_constant_declaration) { if (is_diverging_stmt(n)) { From defc1672c3d1b27c4720f53e95a0e1be0775e5e9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 Jan 2022 13:48:12 +0000 Subject: [PATCH 0143/1258] Revert fix #1344 --- src/check_stmt.cpp | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c3b8c46ca..396388629 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -58,30 +58,6 @@ bool contains_deferred_call(Ast *node) { return false; } -Ast *last_stmt_blocking_in_list(Slice const &stmts) { - for_array(i, stmts) { - Ast *n = stmts[i]; - switch (n->kind) { - case Ast_ReturnStmt: - return n; - case Ast_BranchStmt: - return n; - case Ast_ExprStmt: - if (is_diverging_stmt(n)) { - return n; - } - break; - case Ast_BlockStmt: - n = last_stmt_blocking_in_list(n->BlockStmt.stmts); - if (n != nullptr) { - return n; - } - break; - } - } - return nullptr; -} - void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) { if (stmts.count == 0) { return; @@ -126,7 +102,6 @@ void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) check_stmt(ctx, n, new_flags); if (i+1 < max_non_constant_declaration) { - never_executed_error:; switch (n->kind) { case Ast_ReturnStmt: error(n, "Statements after this 'return' are never executed"); @@ -141,13 +116,6 @@ void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) error(n, "Statements after a diverging procedure call are never executed"); } break; - - case Ast_BlockStmt: - n = last_stmt_blocking_in_list(n->BlockStmt.stmts); - if (n != nullptr) { - goto never_executed_error; - } - break; } } else if (i+1 == max_non_constant_declaration) { if (is_diverging_stmt(n)) { From 38e5e13b3feb4d037fcf0b3df7d335bdb0dda45d Mon Sep 17 00:00:00 2001 From: CiD- Date: Mon, 3 Jan 2022 09:24:39 -0500 Subject: [PATCH 0144/1258] add more Linux syscalls --- core/sys/unix/syscalls_linux.odin | 1497 ++++++++++++++++++++++++++++- 1 file changed, 1481 insertions(+), 16 deletions(-) diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 659eedfbb..25c5ed0a1 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -16,37 +16,1502 @@ import "core:intrinsics" // arm: arch/arm/tools/syscall.tbl when ODIN_ARCH == "amd64" { + SYS_read : uintptr : 0 + SYS_write : uintptr : 1 + SYS_open : uintptr : 2 + SYS_close : uintptr : 3 + SYS_stat : uintptr : 4 + SYS_fstat : uintptr : 5 + SYS_lstat : uintptr : 6 + SYS_poll : uintptr : 7 + SYS_lseek : uintptr : 8 SYS_mmap : uintptr : 9 SYS_mprotect : uintptr : 10 SYS_munmap : uintptr : 11 + SYS_brk : uintptr : 12 + SYS_rt_sigaction : uintptr : 13 + SYS_rt_sigprocmask : uintptr : 14 + SYS_rt_sigreturn : uintptr : 15 + SYS_ioctl : uintptr : 16 + SYS_pread : uintptr : 17 + SYS_pwrite : uintptr : 18 + SYS_readv : uintptr : 19 + SYS_writev : uintptr : 20 + SYS_access : uintptr : 21 + SYS_pipe : uintptr : 22 + SYS_select : uintptr : 23 + SYS_sched_yield : uintptr : 24 + SYS_mremap : uintptr : 25 + SYS_msync : uintptr : 26 + SYS_mincore : uintptr : 27 SYS_madvise : uintptr : 28 - SYS_futex : uintptr : 202 + SYS_shmget : uintptr : 29 + SYS_shmat : uintptr : 30 + SYS_shmctl : uintptr : 31 + SYS_dup : uintptr : 32 + SYS_dup2 : uintptr : 33 + SYS_pause : uintptr : 34 + SYS_nanosleep : uintptr : 35 + SYS_getitimer : uintptr : 36 + SYS_alarm : uintptr : 37 + SYS_setitimer : uintptr : 38 + SYS_getpid : uintptr : 39 + SYS_sendfile : uintptr : 40 + SYS_socket : uintptr : 41 + SYS_connect : uintptr : 42 + SYS_accept : uintptr : 43 + SYS_sendto : uintptr : 44 + SYS_recvfrom : uintptr : 45 + SYS_sendmsg : uintptr : 46 + SYS_recvmsg : uintptr : 47 + SYS_shutdown : uintptr : 48 + SYS_bind : uintptr : 49 + SYS_listen : uintptr : 50 + SYS_getsockname : uintptr : 51 + SYS_getpeername : uintptr : 52 + SYS_socketpair : uintptr : 53 + SYS_setsockopt : uintptr : 54 + SYS_getsockopt : uintptr : 55 + SYS_clone : uintptr : 56 + SYS_fork : uintptr : 57 + SYS_vfork : uintptr : 58 + SYS_execve : uintptr : 59 + SYS_exit : uintptr : 60 + SYS_wait4 : uintptr : 61 + SYS_kill : uintptr : 62 + SYS_uname : uintptr : 63 + SYS_semget : uintptr : 64 + SYS_semop : uintptr : 65 + SYS_semctl : uintptr : 66 + SYS_shmdt : uintptr : 67 + SYS_msgget : uintptr : 68 + SYS_msgsnd : uintptr : 69 + SYS_msgrcv : uintptr : 70 + SYS_msgctl : uintptr : 71 + SYS_fcntl : uintptr : 72 + SYS_flock : uintptr : 73 + SYS_fsync : uintptr : 74 + SYS_fdatasync : uintptr : 75 + SYS_truncate : uintptr : 76 + SYS_ftruncate : uintptr : 77 + SYS_getdents : uintptr : 78 + SYS_getcwd : uintptr : 79 + SYS_chdir : uintptr : 80 + SYS_fchdir : uintptr : 81 + SYS_rename : uintptr : 82 + SYS_mkdir : uintptr : 83 + SYS_rmdir : uintptr : 84 + SYS_creat : uintptr : 85 + SYS_link : uintptr : 86 + SYS_unlink : uintptr : 87 + SYS_symlink : uintptr : 88 + SYS_readlink : uintptr : 89 + SYS_chmod : uintptr : 90 + SYS_fchmod : uintptr : 91 + SYS_chown : uintptr : 92 + SYS_fchown : uintptr : 93 + SYS_lchown : uintptr : 94 + SYS_umask : uintptr : 95 + SYS_gettimeofday : uintptr : 96 + SYS_getrlimit : uintptr : 97 + SYS_getrusage : uintptr : 98 + SYS_sysinfo : uintptr : 99 + SYS_times : uintptr : 100 + SYS_ptrace : uintptr : 101 + SYS_getuid : uintptr : 102 + SYS_syslog : uintptr : 103 + SYS_getgid : uintptr : 104 + SYS_setuid : uintptr : 105 + SYS_setgid : uintptr : 106 + SYS_geteuid : uintptr : 107 + SYS_getegid : uintptr : 108 + SYS_setpgid : uintptr : 109 + SYS_getppid : uintptr : 110 + SYS_getpgrp : uintptr : 111 + SYS_setsid : uintptr : 112 + SYS_setreuid : uintptr : 113 + SYS_setregid : uintptr : 114 + SYS_getgroups : uintptr : 115 + SYS_setgroups : uintptr : 116 + SYS_setresuid : uintptr : 117 + SYS_getresuid : uintptr : 118 + SYS_setresgid : uintptr : 119 + SYS_getresgid : uintptr : 120 + SYS_getpgid : uintptr : 121 + SYS_setfsuid : uintptr : 122 + SYS_setfsgid : uintptr : 123 + SYS_getsid : uintptr : 124 + SYS_capget : uintptr : 125 + SYS_capset : uintptr : 126 + SYS_rt_sigpending : uintptr : 127 + SYS_rt_sigtimedwait : uintptr : 128 + SYS_rt_sigqueueinfo : uintptr : 129 + SYS_rt_sigsuspend : uintptr : 130 + SYS_sigaltstack : uintptr : 131 + SYS_utime : uintptr : 132 + SYS_mknod : uintptr : 133 + SYS_uselib : uintptr : 134 + SYS_personality : uintptr : 135 + SYS_ustat : uintptr : 136 + SYS_statfs : uintptr : 137 + SYS_fstatfs : uintptr : 138 + SYS_sysfs : uintptr : 139 + SYS_getpriority : uintptr : 140 + SYS_setpriority : uintptr : 141 + SYS_sched_setparam : uintptr : 142 + SYS_sched_getparam : uintptr : 143 + SYS_sched_setscheduler : uintptr : 144 + SYS_sched_getscheduler : uintptr : 145 + SYS_sched_get_priority_max : uintptr : 146 + SYS_sched_get_priority_min : uintptr : 147 + SYS_sched_rr_get_interval : uintptr : 148 + SYS_mlock : uintptr : 149 + SYS_munlock : uintptr : 150 + SYS_mlockall : uintptr : 151 + SYS_munlockall : uintptr : 152 + SYS_vhangup : uintptr : 153 + SYS_modify_ldt : uintptr : 154 + SYS_pivot_root : uintptr : 155 + SYS__sysctl : uintptr : 156 + SYS_prctl : uintptr : 157 + SYS_arch_prctl : uintptr : 158 + SYS_adjtimex : uintptr : 159 + SYS_setrlimit : uintptr : 160 + SYS_chroot : uintptr : 161 + SYS_sync : uintptr : 162 + SYS_acct : uintptr : 163 + SYS_settimeofday : uintptr : 164 + SYS_mount : uintptr : 165 + SYS_umount2 : uintptr : 166 + SYS_swapon : uintptr : 167 + SYS_swapoff : uintptr : 168 + SYS_reboot : uintptr : 169 + SYS_sethostname : uintptr : 170 + SYS_setdomainname : uintptr : 171 + SYS_iopl : uintptr : 172 + SYS_ioperm : uintptr : 173 + SYS_create_module : uintptr : 174 + SYS_init_module : uintptr : 175 + SYS_delete_module : uintptr : 176 + SYS_get_kernel_syms : uintptr : 177 + SYS_query_module : uintptr : 178 + SYS_quotactl : uintptr : 179 + SYS_nfsservctl : uintptr : 180 + SYS_getpmsg : uintptr : 181 + SYS_putpmsg : uintptr : 182 + SYS_afs_syscall : uintptr : 183 + SYS_tuxcall : uintptr : 184 + SYS_security : uintptr : 185 SYS_gettid : uintptr : 186 + SYS_readahead : uintptr : 187 + SYS_setxattr : uintptr : 188 + SYS_lsetxattr : uintptr : 189 + SYS_fsetxattr : uintptr : 190 + SYS_getxattr : uintptr : 191 + SYS_lgetxattr : uintptr : 192 + SYS_fgetxattr : uintptr : 193 + SYS_listxattr : uintptr : 194 + SYS_llistxattr : uintptr : 195 + SYS_flistxattr : uintptr : 196 + SYS_removexattr : uintptr : 197 + SYS_lremovexattr : uintptr : 198 + SYS_fremovexattr : uintptr : 199 + SYS_tkill : uintptr : 200 + SYS_time : uintptr : 201 + SYS_futex : uintptr : 202 + SYS_sched_setaffinity : uintptr : 203 + SYS_sched_getaffinity : uintptr : 204 + SYS_set_thread_area : uintptr : 205 + SYS_io_setup : uintptr : 206 + SYS_io_destroy : uintptr : 207 + SYS_io_getevents : uintptr : 208 + SYS_io_submit : uintptr : 209 + SYS_io_cancel : uintptr : 210 + SYS_get_thread_area : uintptr : 211 + SYS_lookup_dcookie : uintptr : 212 + SYS_epoll_create : uintptr : 213 + SYS_epoll_ctl_old : uintptr : 214 + SYS_epoll_wait_old : uintptr : 215 + SYS_remap_file_pages : uintptr : 216 + SYS_getdents64 : uintptr : 217 + SYS_set_tid_address : uintptr : 218 + SYS_restart_syscall : uintptr : 219 + SYS_semtimedop : uintptr : 220 + SYS_fadvise64 : uintptr : 221 + SYS_timer_create : uintptr : 222 + SYS_timer_settime : uintptr : 223 + SYS_timer_gettime : uintptr : 224 + SYS_timer_getoverrun : uintptr : 225 + SYS_timer_delete : uintptr : 226 + SYS_clock_settime : uintptr : 227 + SYS_clock_gettime : uintptr : 228 + SYS_clock_getres : uintptr : 229 + SYS_clock_nanosleep : uintptr : 230 + SYS_exit_group : uintptr : 231 + SYS_epoll_wait : uintptr : 232 + SYS_epoll_ctl : uintptr : 233 + SYS_tgkill : uintptr : 234 + SYS_utimes : uintptr : 235 + SYS_vserver : uintptr : 236 + SYS_mbind : uintptr : 237 + SYS_set_mempolicy : uintptr : 238 + SYS_get_mempolicy : uintptr : 239 + SYS_mq_open : uintptr : 240 + SYS_mq_unlink : uintptr : 241 + SYS_mq_timedsend : uintptr : 242 + SYS_mq_timedreceive : uintptr : 243 + SYS_mq_notify : uintptr : 244 + SYS_mq_getsetattr : uintptr : 245 + SYS_kexec_load : uintptr : 246 + SYS_waitid : uintptr : 247 + SYS_add_key : uintptr : 248 + SYS_request_key : uintptr : 249 + SYS_keyctl : uintptr : 250 + SYS_ioprio_set : uintptr : 251 + SYS_ioprio_get : uintptr : 252 + SYS_inotify_init : uintptr : 253 + SYS_inotify_add_watch : uintptr : 254 + SYS_inotify_rm_watch : uintptr : 255 + SYS_migrate_pages : uintptr : 256 + SYS_openat : uintptr : 257 + SYS_mkdirat : uintptr : 258 + SYS_mknodat : uintptr : 259 + SYS_fchownat : uintptr : 260 + SYS_futimesat : uintptr : 261 + SYS_fstatat : uintptr : 262 + SYS_unlinkat : uintptr : 263 + SYS_renameat : uintptr : 264 + SYS_linkat : uintptr : 265 + SYS_symlinkat : uintptr : 266 + SYS_readlinkat : uintptr : 267 + SYS_fchmodat : uintptr : 268 + SYS_faccessat : uintptr : 269 + SYS_pselect6 : uintptr : 270 + SYS_ppoll : uintptr : 271 + SYS_unshare : uintptr : 272 + SYS_set_robust_list : uintptr : 273 + SYS_get_robust_list : uintptr : 274 + SYS_splice : uintptr : 275 + SYS_tee : uintptr : 276 + SYS_sync_file_range : uintptr : 277 + SYS_vmsplice : uintptr : 278 + SYS_move_pages : uintptr : 279 + SYS_utimensat : uintptr : 280 + SYS_epoll_pwait : uintptr : 281 + SYS_signalfd : uintptr : 282 + SYS_timerfd_create : uintptr : 283 + SYS_eventfd : uintptr : 284 + SYS_fallocate : uintptr : 285 + SYS_timerfd_settime : uintptr : 286 + SYS_timerfd_gettime : uintptr : 287 + SYS_accept4 : uintptr : 288 + SYS_signalfd4 : uintptr : 289 + SYS_eventfd2 : uintptr : 290 + SYS_epoll_create1 : uintptr : 291 + SYS_dup3 : uintptr : 292 + SYS_pipe2 : uintptr : 293 + SYS_inotify_init1 : uintptr : 294 + SYS_preadv : uintptr : 295 + SYS_pwritev : uintptr : 296 + SYS_rt_tgsigqueueinfo : uintptr : 297 + SYS_perf_event_open : uintptr : 298 + SYS_recvmmsg : uintptr : 299 + SYS_fanotify_init : uintptr : 300 + SYS_fanotify_mark : uintptr : 301 + SYS_prlimit64 : uintptr : 302 + SYS_name_to_handle_at : uintptr : 303 + SYS_open_by_handle_at : uintptr : 304 + SYS_clock_adjtime : uintptr : 305 + SYS_syncfs : uintptr : 306 + SYS_sendmmsg : uintptr : 307 + SYS_setns : uintptr : 308 + SYS_getcpu : uintptr : 309 + SYS_process_vm_readv : uintptr : 310 + SYS_process_vm_writev : uintptr : 311 + SYS_kcmp : uintptr : 312 + SYS_finit_module : uintptr : 313 + SYS_sched_setattr : uintptr : 314 + SYS_sched_getattr : uintptr : 315 + SYS_renameat2 : uintptr : 316 + SYS_seccomp : uintptr : 317 SYS_getrandom : uintptr : 318 + SYS_memfd_create : uintptr : 319 + SYS_kexec_file_load : uintptr : 320 + SYS_bpf : uintptr : 321 + SYS_execveat : uintptr : 322 + SYS_userfaultfd : uintptr : 323 + SYS_membarrier : uintptr : 324 + SYS_mlock2 : uintptr : 325 + SYS_copy_file_range : uintptr : 326 + SYS_preadv2 : uintptr : 327 + SYS_pwritev2 : uintptr : 328 + SYS_pkey_mprotect : uintptr : 329 + SYS_pkey_alloc : uintptr : 330 + SYS_pkey_free : uintptr : 331 + SYS_statx : uintptr : 332 + SYS_io_pgetevents : uintptr : 333 + SYS_rseq : uintptr : 334 + SYS_pidfd_send_signal : uintptr : 424 + SYS_io_uring_setup : uintptr : 425 + SYS_io_uring_enter : uintptr : 426 + SYS_io_uring_register : uintptr : 427 + SYS_open_tree : uintptr : 428 + SYS_move_mount : uintptr : 429 + SYS_fsopen : uintptr : 430 + SYS_fsconfig : uintptr : 431 + SYS_fsmount : uintptr : 432 + SYS_fspick : uintptr : 433 + SYS_pidfd_open : uintptr : 434 + SYS_clone3 : uintptr : 435 + SYS_close_range : uintptr : 436 + SYS_openat2 : uintptr : 437 + SYS_pidfd_getfd : uintptr : 438 + SYS_faccessat2 : uintptr : 439 + SYS_process_madvise : uintptr : 440 + SYS_epoll_pwait2 : uintptr : 441 + SYS_mount_setattr : uintptr : 442 + SYS_landlock_create_ruleset : uintptr : 444 + SYS_landlock_add_rule : uintptr : 445 + SYS_landlock_restrict_self : uintptr : 446 + SYS_memfd_secret : uintptr : 447 } else when ODIN_ARCH == "arm64" { - SYS_mmap : uintptr : 222 - SYS_mprotect : uintptr : 226 - SYS_munmap : uintptr : 215 - SYS_madvise : uintptr : 233 + SYS_io_setup : uintptr : 0 + SYS_io_destroy : uintptr : 1 + SYS_io_submit : uintptr : 2 + SYS_io_cancel : uintptr : 3 + SYS_io_getevents : uintptr : 4 + SYS_setxattr : uintptr : 5 + SYS_lsetxattr : uintptr : 6 + SYS_fsetxattr : uintptr : 7 + SYS_getxattr : uintptr : 8 + SYS_lgetxattr : uintptr : 9 + SYS_fgetxattr : uintptr : 10 + SYS_listxattr : uintptr : 11 + SYS_llistxattr : uintptr : 12 + SYS_flistxattr : uintptr : 13 + SYS_removexattr : uintptr : 14 + SYS_lremovexattr : uintptr : 15 + SYS_fremovexattr : uintptr : 16 + SYS_getcwd : uintptr : 17 + SYS_lookup_dcookie : uintptr : 18 + SYS_eventfd2 : uintptr : 19 + SYS_epoll_create1 : uintptr : 20 + SYS_epoll_ctl : uintptr : 21 + SYS_epoll_pwait : uintptr : 22 + SYS_dup : uintptr : 23 + SYS_dup3 : uintptr : 24 + SYS_fcntl : uintptr : 25 + SYS_inotify_init1 : uintptr : 26 + SYS_inotify_add_watch : uintptr : 27 + SYS_inotify_rm_watch : uintptr : 28 + SYS_ioctl : uintptr : 29 + SYS_ioprio_set : uintptr : 30 + SYS_ioprio_get : uintptr : 31 + SYS_flock : uintptr : 32 + SYS_mknodat : uintptr : 33 + SYS_mkdirat : uintptr : 34 + SYS_unlinkat : uintptr : 35 + SYS_symlinkat : uintptr : 36 + SYS_linkat : uintptr : 37 + SYS_renameat : uintptr : 38 + SYS_umount2 : uintptr : 39 + SYS_mount : uintptr : 40 + SYS_pivot_root : uintptr : 41 + SYS_nfsservctl : uintptr : 42 + SYS_statfs : uintptr : 43 + SYS_fstatfs : uintptr : 44 + SYS_truncate : uintptr : 45 + SYS_ftruncate : uintptr : 46 + SYS_fallocate : uintptr : 47 + SYS_faccessat : uintptr : 48 + SYS_chdir : uintptr : 49 + SYS_fchdir : uintptr : 50 + SYS_chroot : uintptr : 51 + SYS_fchmod : uintptr : 52 + SYS_fchmodat : uintptr : 53 + SYS_fchownat : uintptr : 54 + SYS_fchown : uintptr : 55 + SYS_openat : uintptr : 56 + SYS_close : uintptr : 57 + SYS_vhangup : uintptr : 58 + SYS_pipe2 : uintptr : 59 + SYS_quotactl : uintptr : 60 + SYS_getdents64 : uintptr : 61 + SYS_lseek : uintptr : 62 + SYS_read : uintptr : 63 + SYS_write : uintptr : 64 + SYS_readv : uintptr : 65 + SYS_writev : uintptr : 66 + SYS_pread64 : uintptr : 67 + SYS_pwrite64 : uintptr : 68 + SYS_preadv : uintptr : 69 + SYS_pwritev : uintptr : 70 + SYS_sendfile : uintptr : 71 + SYS_pselect6 : uintptr : 72 + SYS_ppoll : uintptr : 73 + SYS_signalfd4 : uintptr : 74 + SYS_vmsplice : uintptr : 75 + SYS_splice : uintptr : 76 + SYS_tee : uintptr : 77 + SYS_readlinkat : uintptr : 78 + SYS_fstatat : uintptr : 79 + SYS_fstat : uintptr : 80 + SYS_sync : uintptr : 81 + SYS_fsync : uintptr : 82 + SYS_fdatasync : uintptr : 83 + SYS_sync_file_range : uintptr : 84 + SYS_timerfd_create : uintptr : 85 + SYS_timerfd_settime : uintptr : 86 + SYS_timerfd_gettime : uintptr : 87 + SYS_utimensat : uintptr : 88 + SYS_acct : uintptr : 89 + SYS_capget : uintptr : 90 + SYS_capset : uintptr : 91 + SYS_personality : uintptr : 92 + SYS_exit : uintptr : 93 + SYS_exit_group : uintptr : 94 + SYS_waitid : uintptr : 95 + SYS_set_tid_address : uintptr : 96 + SYS_unshare : uintptr : 97 SYS_futex : uintptr : 98 + SYS_set_robust_list : uintptr : 99 + SYS_get_robust_list : uintptr : 100 + SYS_nanosleep : uintptr : 101 + SYS_getitimer : uintptr : 102 + SYS_setitimer : uintptr : 103 + SYS_kexec_load : uintptr : 104 + SYS_init_module : uintptr : 105 + SYS_delete_module : uintptr : 106 + SYS_timer_create : uintptr : 107 + SYS_timer_gettime : uintptr : 108 + SYS_timer_getoverrun : uintptr : 109 + SYS_timer_settime : uintptr : 110 + SYS_timer_delete : uintptr : 111 + SYS_clock_settime : uintptr : 112 + SYS_clock_gettime : uintptr : 113 + SYS_clock_getres : uintptr : 114 + SYS_clock_nanosleep : uintptr : 115 + SYS_syslog : uintptr : 116 + SYS_ptrace : uintptr : 117 + SYS_sched_setparam : uintptr : 118 + SYS_sched_setscheduler : uintptr : 119 + SYS_sched_getscheduler : uintptr : 120 + SYS_sched_getparam : uintptr : 121 + SYS_sched_setaffinity : uintptr : 122 + SYS_sched_getaffinity : uintptr : 123 + SYS_sched_yield : uintptr : 124 + SYS_sched_get_priority_max : uintptr : 125 + SYS_sched_get_priority_min : uintptr : 126 + SYS_sched_rr_get_interval : uintptr : 127 + SYS_restart_syscall : uintptr : 128 + SYS_kill : uintptr : 129 + SYS_tkill : uintptr : 130 + SYS_tgkill : uintptr : 131 + SYS_sigaltstack : uintptr : 132 + SYS_rt_sigsuspend : uintptr : 133 + SYS_rt_sigaction : uintptr : 134 + SYS_rt_sigprocmask : uintptr : 135 + SYS_rt_sigpending : uintptr : 136 + SYS_rt_sigtimedwait : uintptr : 137 + SYS_rt_sigqueueinfo : uintptr : 138 + SYS_rt_sigreturn : uintptr : 139 + SYS_setpriority : uintptr : 140 + SYS_getpriority : uintptr : 141 + SYS_reboot : uintptr : 142 + SYS_setregid : uintptr : 143 + SYS_setgid : uintptr : 144 + SYS_setreuid : uintptr : 145 + SYS_setuid : uintptr : 146 + SYS_setresuid : uintptr : 147 + SYS_getresuid : uintptr : 148 + SYS_setresgid : uintptr : 149 + SYS_getresgid : uintptr : 150 + SYS_setfsuid : uintptr : 151 + SYS_setfsgid : uintptr : 152 + SYS_times : uintptr : 153 + SYS_setpgid : uintptr : 154 + SYS_getpgid : uintptr : 155 + SYS_getsid : uintptr : 156 + SYS_setsid : uintptr : 157 + SYS_getgroups : uintptr : 158 + SYS_setgroups : uintptr : 159 + SYS_uname : uintptr : 160 + SYS_sethostname : uintptr : 161 + SYS_setdomainname : uintptr : 162 + SYS_getrlimit : uintptr : 163 + SYS_setrlimit : uintptr : 164 + SYS_getrusage : uintptr : 165 + SYS_umask : uintptr : 166 + SYS_prctl : uintptr : 167 + SYS_getcpu : uintptr : 168 + SYS_gettimeofday : uintptr : 169 + SYS_settimeofday : uintptr : 170 + SYS_adjtimex : uintptr : 171 + SYS_getpid : uintptr : 172 + SYS_getppid : uintptr : 173 + SYS_getuid : uintptr : 174 + SYS_geteuid : uintptr : 175 + SYS_getgid : uintptr : 176 + SYS_getegid : uintptr : 177 SYS_gettid : uintptr : 178 + SYS_sysinfo : uintptr : 179 + SYS_mq_open : uintptr : 180 + SYS_mq_unlink : uintptr : 181 + SYS_mq_timedsend : uintptr : 182 + SYS_mq_timedreceive : uintptr : 183 + SYS_mq_notify : uintptr : 184 + SYS_mq_getsetattr : uintptr : 185 + SYS_msgget : uintptr : 186 + SYS_msgctl : uintptr : 187 + SYS_msgrcv : uintptr : 188 + SYS_msgsnd : uintptr : 189 + SYS_semget : uintptr : 190 + SYS_semctl : uintptr : 191 + SYS_semtimedop : uintptr : 192 + SYS_semop : uintptr : 193 + SYS_shmget : uintptr : 194 + SYS_shmctl : uintptr : 195 + SYS_shmat : uintptr : 196 + SYS_shmdt : uintptr : 197 + SYS_socket : uintptr : 198 + SYS_socketpair : uintptr : 199 + SYS_bind : uintptr : 200 + SYS_listen : uintptr : 201 + SYS_accept : uintptr : 202 + SYS_connect : uintptr : 203 + SYS_getsockname : uintptr : 204 + SYS_getpeername : uintptr : 205 + SYS_sendto : uintptr : 206 + SYS_recvfrom : uintptr : 207 + SYS_setsockopt : uintptr : 208 + SYS_getsockopt : uintptr : 209 + SYS_shutdown : uintptr : 210 + SYS_sendmsg : uintptr : 211 + SYS_recvmsg : uintptr : 212 + SYS_readahead : uintptr : 213 + SYS_brk : uintptr : 214 + SYS_munmap : uintptr : 215 + SYS_mremap : uintptr : 216 + SYS_add_key : uintptr : 217 + SYS_request_key : uintptr : 218 + SYS_keyctl : uintptr : 219 + SYS_clone : uintptr : 220 + SYS_execve : uintptr : 221 + SYS_mmap : uintptr : 222 + SYS_fadvise64 : uintptr : 223 + SYS_swapon : uintptr : 224 + SYS_swapoff : uintptr : 225 + SYS_mprotect : uintptr : 226 + SYS_msync : uintptr : 227 + SYS_mlock : uintptr : 228 + SYS_munlock : uintptr : 229 + SYS_mlockall : uintptr : 230 + SYS_munlockall : uintptr : 231 + SYS_mincore : uintptr : 232 + SYS_madvise : uintptr : 233 + SYS_remap_file_pages : uintptr : 234 + SYS_mbind : uintptr : 235 + SYS_get_mempolicy : uintptr : 236 + SYS_set_mempolicy : uintptr : 237 + SYS_migrate_pages : uintptr : 238 + SYS_move_pages : uintptr : 239 + SYS_rt_tgsigqueueinfo : uintptr : 240 + SYS_perf_event_open : uintptr : 241 + SYS_accept4 : uintptr : 242 + SYS_recvmmsg : uintptr : 243 + SYS_arch_specific_syscall : uintptr : 244 + SYS_wait4 : uintptr : 260 + SYS_prlimit64 : uintptr : 261 + SYS_fanotify_init : uintptr : 262 + SYS_fanotify_mark : uintptr : 263 + SYS_clock_adjtime : uintptr : 266 + SYS_syncfs : uintptr : 267 + SYS_setns : uintptr : 268 + SYS_sendmmsg : uintptr : 269 + SYS_process_vm_readv : uintptr : 270 + SYS_process_vm_writev : uintptr : 271 + SYS_kcmp : uintptr : 272 + SYS_finit_module : uintptr : 273 + SYS_sched_setattr : uintptr : 274 + SYS_sched_getattr : uintptr : 275 + SYS_renameat2 : uintptr : 276 + SYS_seccomp : uintptr : 277 SYS_getrandom : uintptr : 278 + SYS_memfd_create : uintptr : 279 + SYS_bpf : uintptr : 280 + SYS_execveat : uintptr : 281 + SYS_userfaultfd : uintptr : 282 + SYS_membarrier : uintptr : 283 + SYS_mlock2 : uintptr : 284 + SYS_copy_file_range : uintptr : 285 + SYS_preadv2 : uintptr : 286 + SYS_pwritev2 : uintptr : 287 + SYS_pkey_mprotect : uintptr : 288 + SYS_pkey_alloc : uintptr : 289 + SYS_pkey_free : uintptr : 290 + SYS_statx : uintptr : 291 + SYS_io_pgetevents : uintptr : 292 + SYS_rseq : uintptr : 293 + SYS_kexec_file_load : uintptr : 294 + SYS_pidfd_send_signal : uintptr : 424 + SYS_io_uring_setup : uintptr : 425 + SYS_io_uring_enter : uintptr : 426 + SYS_io_uring_register : uintptr : 427 + SYS_open_tree : uintptr : 428 + SYS_move_mount : uintptr : 429 + SYS_fsopen : uintptr : 430 + SYS_fsconfig : uintptr : 431 + SYS_fsmount : uintptr : 432 + SYS_fspick : uintptr : 433 + SYS_pidfd_open : uintptr : 434 + SYS_clone3 : uintptr : 435 + SYS_close_range : uintptr : 436 + SYS_openat2 : uintptr : 437 + SYS_pidfd_getfd : uintptr : 438 + SYS_faccessat2 : uintptr : 439 + SYS_process_madvise : uintptr : 440 + SYS_epoll_pwait2 : uintptr : 441 + SYS_mount_setattr : uintptr : 442 + SYS_landlock_create_ruleset : uintptr : 444 + SYS_landlock_add_rule : uintptr : 445 + SYS_landlock_restrict_self : uintptr : 446 } else when ODIN_ARCH == "386" { - SYS_mmap : uintptr : 192 // 90 is "sys_old_mmap", we want mmap2 - SYS_mprotect : uintptr : 125 + SYS_restart_syscall : uintptr : 0 + SYS_exit : uintptr : 1 + SYS_fork : uintptr : 2 + SYS_read : uintptr : 3 + SYS_write : uintptr : 4 + SYS_open : uintptr : 5 + SYS_close : uintptr : 6 + SYS_waitpid : uintptr : 7 + SYS_creat : uintptr : 8 + SYS_link : uintptr : 9 + SYS_unlink : uintptr : 10 + SYS_execve : uintptr : 11 + SYS_chdir : uintptr : 12 + SYS_time : uintptr : 13 + SYS_mknod : uintptr : 14 + SYS_chmod : uintptr : 15 + SYS_lchown : uintptr : 16 + SYS_break : uintptr : 17 + SYS_oldstat : uintptr : 18 + SYS_lseek : uintptr : 19 + SYS_getpid : uintptr : 20 + SYS_mount : uintptr : 21 + SYS_umount : uintptr : 22 + SYS_setuid : uintptr : 23 + SYS_getuid : uintptr : 24 + SYS_stime : uintptr : 25 + SYS_ptrace : uintptr : 26 + SYS_alarm : uintptr : 27 + SYS_oldfstat : uintptr : 28 + SYS_pause : uintptr : 29 + SYS_utime : uintptr : 30 + SYS_stty : uintptr : 31 + SYS_gtty : uintptr : 32 + SYS_access : uintptr : 33 + SYS_nice : uintptr : 34 + SYS_ftime : uintptr : 35 + SYS_sync : uintptr : 36 + SYS_kill : uintptr : 37 + SYS_rename : uintptr : 38 + SYS_mkdir : uintptr : 39 + SYS_rmdir : uintptr : 40 + SYS_dup : uintptr : 41 + SYS_pipe : uintptr : 42 + SYS_times : uintptr : 43 + SYS_prof : uintptr : 44 + SYS_brk : uintptr : 45 + SYS_setgid : uintptr : 46 + SYS_getgid : uintptr : 47 + SYS_signal : uintptr : 48 + SYS_geteuid : uintptr : 49 + SYS_getegid : uintptr : 50 + SYS_acct : uintptr : 51 + SYS_umount2 : uintptr : 52 + SYS_lock : uintptr : 53 + SYS_ioctl : uintptr : 54 + SYS_fcntl : uintptr : 55 + SYS_mpx : uintptr : 56 + SYS_setpgid : uintptr : 57 + SYS_ulimit : uintptr : 58 + SYS_oldolduname : uintptr : 59 + SYS_umask : uintptr : 60 + SYS_chroot : uintptr : 61 + SYS_ustat : uintptr : 62 + SYS_dup2 : uintptr : 63 + SYS_getppid : uintptr : 64 + SYS_getpgrp : uintptr : 65 + SYS_setsid : uintptr : 66 + SYS_sigaction : uintptr : 67 + SYS_sgetmask : uintptr : 68 + SYS_ssetmask : uintptr : 69 + SYS_setreuid : uintptr : 70 + SYS_setregid : uintptr : 71 + SYS_sigsuspend : uintptr : 72 + SYS_sigpending : uintptr : 73 + SYS_sethostname : uintptr : 74 + SYS_setrlimit : uintptr : 75 + SYS_getrlimit : uintptr : 76 + SYS_getrusage : uintptr : 77 + SYS_gettimeofday : uintptr : 78 + SYS_settimeofday : uintptr : 79 + SYS_getgroups : uintptr : 80 + SYS_setgroups : uintptr : 81 + SYS_select : uintptr : 82 + SYS_symlink : uintptr : 83 + SYS_oldlstat : uintptr : 84 + SYS_readlink : uintptr : 85 + SYS_uselib : uintptr : 86 + SYS_swapon : uintptr : 87 + SYS_reboot : uintptr : 88 + SYS_readdir : uintptr : 89 + SYS_old_mmap : uintptr : 90 // 90 is "sys_old_mmap", we want mmap2 SYS_munmap : uintptr : 91 - SYS_madvise : uintptr : 219 - SYS_futex : uintptr : 240 - SYS_gettid : uintptr : 224 - SYS_getrandom : uintptr : 355 -} else when ODIN_ARCH == "arm" { - SYS_mmap : uintptr : 192 // 90 is "sys_old_mmap", we want mmap2 + SYS_truncate : uintptr : 92 + SYS_ftruncate : uintptr : 93 + SYS_fchmod : uintptr : 94 + SYS_fchown : uintptr : 95 + SYS_getpriority : uintptr : 96 + SYS_setpriority : uintptr : 97 + SYS_profil : uintptr : 98 + SYS_statfs : uintptr : 99 + SYS_fstatfs : uintptr : 100 + SYS_ioperm : uintptr : 101 + SYS_socketcall : uintptr : 102 + SYS_syslog : uintptr : 103 + SYS_setitimer : uintptr : 104 + SYS_getitimer : uintptr : 105 + SYS_stat : uintptr : 106 + SYS_lstat : uintptr : 107 + SYS_fstat : uintptr : 108 + SYS_olduname : uintptr : 109 + SYS_iopl : uintptr : 110 + SYS_vhangup : uintptr : 111 + SYS_idle : uintptr : 112 + SYS_vm86old : uintptr : 113 + SYS_wait4 : uintptr : 114 + SYS_swapoff : uintptr : 115 + SYS_sysinfo : uintptr : 116 + SYS_ipc : uintptr : 117 + SYS_fsync : uintptr : 118 + SYS_sigreturn : uintptr : 119 + SYS_clone : uintptr : 120 + SYS_setdomainname : uintptr : 121 + SYS_uname : uintptr : 122 + SYS_modify_ldt : uintptr : 123 + SYS_adjtimex : uintptr : 124 SYS_mprotect : uintptr : 125 - SYS_munmap: uintptr : 91 - SYS_madvise: uintptr : 220 + SYS_sigprocmask : uintptr : 126 + SYS_create_module : uintptr : 127 + SYS_init_module : uintptr : 128 + SYS_delete_module : uintptr : 129 + SYS_get_kernel_syms : uintptr : 130 + SYS_quotactl : uintptr : 131 + SYS_getpgid : uintptr : 132 + SYS_fchdir : uintptr : 133 + SYS_bdflush : uintptr : 134 + SYS_sysfs : uintptr : 135 + SYS_personality : uintptr : 136 + SYS_afs_syscall : uintptr : 137 + SYS_setfsuid : uintptr : 138 + SYS_setfsgid : uintptr : 139 + SYS__llseek : uintptr : 140 + SYS_getdents : uintptr : 141 + SYS__newselect : uintptr : 142 + SYS_flock : uintptr : 143 + SYS_msync : uintptr : 144 + SYS_readv : uintptr : 145 + SYS_writev : uintptr : 146 + SYS_getsid : uintptr : 147 + SYS_fdatasync : uintptr : 148 + SYS__sysctl : uintptr : 149 + SYS_mlock : uintptr : 150 + SYS_munlock : uintptr : 151 + SYS_mlockall : uintptr : 152 + SYS_munlockall : uintptr : 153 + SYS_sched_setparam : uintptr : 154 + SYS_sched_getparam : uintptr : 155 + SYS_sched_setscheduler : uintptr : 156 + SYS_sched_getscheduler : uintptr : 157 + SYS_sched_yield : uintptr : 158 + SYS_sched_get_priority_max : uintptr : 159 + SYS_sched_get_priority_min : uintptr : 160 + SYS_sched_rr_get_interval : uintptr : 161 + SYS_nanosleep : uintptr : 162 + SYS_mremap : uintptr : 163 + SYS_setresuid : uintptr : 164 + SYS_getresuid : uintptr : 165 + SYS_vm86 : uintptr : 166 + SYS_query_module : uintptr : 167 + SYS_poll : uintptr : 168 + SYS_nfsservctl : uintptr : 169 + SYS_setresgid : uintptr : 170 + SYS_getresgid : uintptr : 171 + SYS_prctl : uintptr : 172 + SYS_rt_sigreturn : uintptr : 173 + SYS_rt_sigaction : uintptr : 174 + SYS_rt_sigprocmask : uintptr : 175 + SYS_rt_sigpending : uintptr : 176 + SYS_rt_sigtimedwait : uintptr : 177 + SYS_rt_sigqueueinfo : uintptr : 178 + SYS_rt_sigsuspend : uintptr : 179 + SYS_pread64 : uintptr : 180 + SYS_pwrite64 : uintptr : 181 + SYS_chown : uintptr : 182 + SYS_getcwd : uintptr : 183 + SYS_capget : uintptr : 184 + SYS_capset : uintptr : 185 + SYS_sigaltstack : uintptr : 186 + SYS_sendfile : uintptr : 187 + SYS_getpmsg : uintptr : 188 + SYS_putpmsg : uintptr : 189 + SYS_vfork : uintptr : 190 + SYS_ugetrlimit : uintptr : 191 + SYS_mmap : uintptr : 192 // actually mmap2 + SYS_truncate64 : uintptr : 193 + SYS_ftruncate64 : uintptr : 194 + SYS_stat64 : uintptr : 195 + SYS_lstat64 : uintptr : 196 + SYS_fstat64 : uintptr : 197 + SYS_lchown32 : uintptr : 198 + SYS_getuid32 : uintptr : 199 + SYS_getgid32 : uintptr : 200 + SYS_geteuid32 : uintptr : 201 + SYS_getegid32 : uintptr : 202 + SYS_setreuid32 : uintptr : 203 + SYS_setregid32 : uintptr : 204 + SYS_getgroups32 : uintptr : 205 + SYS_setgroups32 : uintptr : 206 + SYS_fchown32 : uintptr : 207 + SYS_setresuid32 : uintptr : 208 + SYS_getresuid32 : uintptr : 209 + SYS_setresgid32 : uintptr : 210 + SYS_getresgid32 : uintptr : 211 + SYS_chown32 : uintptr : 212 + SYS_setuid32 : uintptr : 213 + SYS_setgid32 : uintptr : 214 + SYS_setfsuid32 : uintptr : 215 + SYS_setfsgid32 : uintptr : 216 + SYS_pivot_root : uintptr : 217 + SYS_mincore : uintptr : 218 + SYS_madvise : uintptr : 219 + SYS_getdents64 : uintptr : 220 + SYS_fcntl64 : uintptr : 221 + SYS_gettid : uintptr : 224 + SYS_readahead : uintptr : 225 + SYS_setxattr : uintptr : 226 + SYS_lsetxattr : uintptr : 227 + SYS_fsetxattr : uintptr : 228 + SYS_getxattr : uintptr : 229 + SYS_lgetxattr : uintptr : 230 + SYS_fgetxattr : uintptr : 231 + SYS_listxattr : uintptr : 232 + SYS_llistxattr : uintptr : 233 + SYS_flistxattr : uintptr : 234 + SYS_removexattr : uintptr : 235 + SYS_lremovexattr : uintptr : 236 + SYS_fremovexattr : uintptr : 237 + SYS_tkill : uintptr : 238 + SYS_sendfile64 : uintptr : 239 SYS_futex : uintptr : 240 - SYS_gettid : uintptr: 224 + SYS_sched_setaffinity : uintptr : 241 + SYS_sched_getaffinity : uintptr : 242 + SYS_set_thread_area : uintptr : 243 + SYS_get_thread_area : uintptr : 244 + SYS_io_setup : uintptr : 245 + SYS_io_destroy : uintptr : 246 + SYS_io_getevents : uintptr : 247 + SYS_io_submit : uintptr : 248 + SYS_io_cancel : uintptr : 249 + SYS_fadvise64 : uintptr : 250 + SYS_exit_group : uintptr : 252 + SYS_lookup_dcookie : uintptr : 253 + SYS_epoll_create : uintptr : 254 + SYS_epoll_ctl : uintptr : 255 + SYS_epoll_wait : uintptr : 256 + SYS_remap_file_pages : uintptr : 257 + SYS_set_tid_address : uintptr : 258 + SYS_timer_create : uintptr : 259 + SYS_timer_settime : uintptr : 260 + SYS_timer_gettime : uintptr : 261 + SYS_timer_getoverrun : uintptr : 262 + SYS_timer_delete : uintptr : 263 + SYS_clock_settime : uintptr : 264 + SYS_clock_gettime : uintptr : 265 + SYS_clock_getres : uintptr : 266 + SYS_clock_nanosleep : uintptr : 267 + SYS_statfs64 : uintptr : 268 + SYS_fstatfs64 : uintptr : 269 + SYS_tgkill : uintptr : 270 + SYS_utimes : uintptr : 271 + SYS_fadvise64_64 : uintptr : 272 + SYS_vserver : uintptr : 273 + SYS_mbind : uintptr : 274 + SYS_get_mempolicy : uintptr : 275 + SYS_set_mempolicy : uintptr : 276 + SYS_mq_open : uintptr : 277 + SYS_mq_unlink : uintptr : 278 + SYS_mq_timedsend : uintptr : 279 + SYS_mq_timedreceive : uintptr : 280 + SYS_mq_notify : uintptr : 281 + SYS_mq_getsetattr : uintptr : 282 + SYS_kexec_load : uintptr : 283 + SYS_waitid : uintptr : 284 + SYS_add_key : uintptr : 286 + SYS_request_key : uintptr : 287 + SYS_keyctl : uintptr : 288 + SYS_ioprio_set : uintptr : 289 + SYS_ioprio_get : uintptr : 290 + SYS_inotify_init : uintptr : 291 + SYS_inotify_add_watch : uintptr : 292 + SYS_inotify_rm_watch : uintptr : 293 + SYS_migrate_pages : uintptr : 294 + SYS_openat : uintptr : 295 + SYS_mkdirat : uintptr : 296 + SYS_mknodat : uintptr : 297 + SYS_fchownat : uintptr : 298 + SYS_futimesat : uintptr : 299 + SYS_fstatat64 : uintptr : 300 + SYS_unlinkat : uintptr : 301 + SYS_renameat : uintptr : 302 + SYS_linkat : uintptr : 303 + SYS_symlinkat : uintptr : 304 + SYS_readlinkat : uintptr : 305 + SYS_fchmodat : uintptr : 306 + SYS_faccessat : uintptr : 307 + SYS_pselect6 : uintptr : 308 + SYS_ppoll : uintptr : 309 + SYS_unshare : uintptr : 310 + SYS_set_robust_list : uintptr : 311 + SYS_get_robust_list : uintptr : 312 + SYS_splice : uintptr : 313 + SYS_sync_file_range : uintptr : 314 + SYS_tee : uintptr : 315 + SYS_vmsplice : uintptr : 316 + SYS_move_pages : uintptr : 317 + SYS_getcpu : uintptr : 318 + SYS_epoll_pwait : uintptr : 319 + SYS_utimensat : uintptr : 320 + SYS_signalfd : uintptr : 321 + SYS_timerfd_create : uintptr : 322 + SYS_eventfd : uintptr : 323 + SYS_fallocate : uintptr : 324 + SYS_timerfd_settime : uintptr : 325 + SYS_timerfd_gettime : uintptr : 326 + SYS_signalfd4 : uintptr : 327 + SYS_eventfd2 : uintptr : 328 + SYS_epoll_create1 : uintptr : 329 + SYS_dup3 : uintptr : 330 + SYS_pipe2 : uintptr : 331 + SYS_inotify_init1 : uintptr : 332 + SYS_preadv : uintptr : 333 + SYS_pwritev : uintptr : 334 + SYS_rt_tgsigqueueinfo : uintptr : 335 + SYS_perf_event_open : uintptr : 336 + SYS_recvmmsg : uintptr : 337 + SYS_fanotify_init : uintptr : 338 + SYS_fanotify_mark : uintptr : 339 + SYS_prlimit64 : uintptr : 340 + SYS_name_to_handle_at : uintptr : 341 + SYS_open_by_handle_at : uintptr : 342 + SYS_clock_adjtime : uintptr : 343 + SYS_syncfs : uintptr : 344 + SYS_sendmmsg : uintptr : 345 + SYS_setns : uintptr : 346 + SYS_process_vm_readv : uintptr : 347 + SYS_process_vm_writev : uintptr : 348 + SYS_kcmp : uintptr : 349 + SYS_finit_module : uintptr : 350 + SYS_sched_setattr : uintptr : 351 + SYS_sched_getattr : uintptr : 352 + SYS_renameat2 : uintptr : 353 + SYS_seccomp : uintptr : 354 + SYS_getrandom : uintptr : 355 + SYS_memfd_create : uintptr : 356 + SYS_bpf : uintptr : 357 + SYS_execveat : uintptr : 358 + SYS_socket : uintptr : 359 + SYS_socketpair : uintptr : 360 + SYS_bind : uintptr : 361 + SYS_connect : uintptr : 362 + SYS_listen : uintptr : 363 + SYS_accept4 : uintptr : 364 + SYS_getsockopt : uintptr : 365 + SYS_setsockopt : uintptr : 366 + SYS_getsockname : uintptr : 367 + SYS_getpeername : uintptr : 368 + SYS_sendto : uintptr : 369 + SYS_sendmsg : uintptr : 370 + SYS_recvfrom : uintptr : 371 + SYS_recvmsg : uintptr : 372 + SYS_shutdown : uintptr : 373 + SYS_userfaultfd : uintptr : 374 + SYS_membarrier : uintptr : 375 + SYS_mlock2 : uintptr : 376 + SYS_copy_file_range : uintptr : 377 + SYS_preadv2 : uintptr : 378 + SYS_pwritev2 : uintptr : 379 + SYS_pkey_mprotect : uintptr : 380 + SYS_pkey_alloc : uintptr : 381 + SYS_pkey_free : uintptr : 382 + SYS_statx : uintptr : 383 + SYS_arch_prctl : uintptr : 384 + SYS_io_pgetevents : uintptr : 385 + SYS_rseq : uintptr : 386 + SYS_semget : uintptr : 393 + SYS_semctl : uintptr : 394 + SYS_shmget : uintptr : 395 + SYS_shmctl : uintptr : 396 + SYS_shmat : uintptr : 397 + SYS_shmdt : uintptr : 398 + SYS_msgget : uintptr : 399 + SYS_msgsnd : uintptr : 400 + SYS_msgrcv : uintptr : 401 + SYS_msgctl : uintptr : 402 + SYS_clock_gettime64 : uintptr : 403 + SYS_clock_settime64 : uintptr : 404 + SYS_clock_adjtime64 : uintptr : 405 + SYS_clock_getres_time64 : uintptr : 406 + SYS_clock_nanosleep_time64 : uintptr : 407 + SYS_timer_gettime64 : uintptr : 408 + SYS_timer_settime64 : uintptr : 409 + SYS_timerfd_gettime64 : uintptr : 410 + SYS_timerfd_settime64 : uintptr : 411 + SYS_utimensat_time64 : uintptr : 412 + SYS_pselect6_time64 : uintptr : 413 + SYS_ppoll_time64 : uintptr : 414 + SYS_io_pgetevents_time64 : uintptr : 416 + SYS_recvmmsg_time64 : uintptr : 417 + SYS_mq_timedsend_time64 : uintptr : 418 + SYS_mq_timedreceive_time64 : uintptr : 419 + SYS_semtimedop_time64 : uintptr : 420 + SYS_rt_sigtimedwait_time64 : uintptr : 421 + SYS_futex_time64 : uintptr : 422 + SYS_sched_rr_get_interval_time64 : uintptr : 423 + SYS_pidfd_send_signal : uintptr : 424 + SYS_io_uring_setup : uintptr : 425 + SYS_io_uring_enter : uintptr : 426 + SYS_io_uring_register : uintptr : 427 + SYS_open_tree : uintptr : 428 + SYS_move_mount : uintptr : 429 + SYS_fsopen : uintptr : 430 + SYS_fsconfig : uintptr : 431 + SYS_fsmount : uintptr : 432 + SYS_fspick : uintptr : 433 + SYS_pidfd_open : uintptr : 434 + SYS_clone3 : uintptr : 435 + SYS_close_range : uintptr : 436 + SYS_openat2 : uintptr : 437 + SYS_pidfd_getfd : uintptr : 438 + SYS_faccessat2 : uintptr : 439 + SYS_process_madvise : uintptr : 440 + SYS_epoll_pwait2 : uintptr : 441 + SYS_mount_setattr : uintptr : 442 + SYS_landlock_create_ruleset : uintptr : 444 + SYS_landlock_add_rule : uintptr : 445 + SYS_landlock_restrict_self : uintptr : 446 + SYS_memfd_secret : uintptr : 447 +} else when ODIN_ARCH == "arm" { + SYS_restart_syscall : uintptr : 0 + SYS_exit : uintptr : 1 + SYS_fork : uintptr : 2 + SYS_read : uintptr : 3 + SYS_write : uintptr : 4 + SYS_open : uintptr : 5 + SYS_close : uintptr : 6 + SYS_creat : uintptr : 8 + SYS_link : uintptr : 9 + SYS_unlink : uintptr : 10 + SYS_execve : uintptr : 11 + SYS_chdir : uintptr : 12 + SYS_mknod : uintptr : 14 + SYS_chmod : uintptr : 15 + SYS_lchown : uintptr : 16 + SYS_lseek : uintptr : 19 + SYS_getpid : uintptr : 20 + SYS_mount : uintptr : 21 + SYS_setuid : uintptr : 23 + SYS_getuid : uintptr : 24 + SYS_ptrace : uintptr : 26 + SYS_pause : uintptr : 29 + SYS_access : uintptr : 33 + SYS_nice : uintptr : 34 + SYS_sync : uintptr : 36 + SYS_kill : uintptr : 37 + SYS_rename : uintptr : 38 + SYS_mkdir : uintptr : 39 + SYS_rmdir : uintptr : 40 + SYS_dup : uintptr : 41 + SYS_pipe : uintptr : 42 + SYS_times : uintptr : 43 + SYS_brk : uintptr : 45 + SYS_setgid : uintptr : 46 + SYS_getgid : uintptr : 47 + SYS_geteuid : uintptr : 49 + SYS_getegid : uintptr : 50 + SYS_acct : uintptr : 51 + SYS_umount2 : uintptr : 52 + SYS_ioctl : uintptr : 54 + SYS_fcntl : uintptr : 55 + SYS_setpgid : uintptr : 57 + SYS_umask : uintptr : 60 + SYS_chroot : uintptr : 61 + SYS_ustat : uintptr : 62 + SYS_dup2 : uintptr : 63 + SYS_getppid : uintptr : 64 + SYS_getpgrp : uintptr : 65 + SYS_setsid : uintptr : 66 + SYS_sigaction : uintptr : 67 + SYS_setreuid : uintptr : 70 + SYS_setregid : uintptr : 71 + SYS_sigsuspend : uintptr : 72 + SYS_sigpending : uintptr : 73 + SYS_sethostname : uintptr : 74 + SYS_setrlimit : uintptr : 75 + SYS_getrusage : uintptr : 77 + SYS_gettimeofday : uintptr : 78 + SYS_settimeofday : uintptr : 79 + SYS_getgroups : uintptr : 80 + SYS_setgroups : uintptr : 81 + SYS_symlink : uintptr : 83 + SYS_readlink : uintptr : 85 + SYS_uselib : uintptr : 86 + SYS_swapon : uintptr : 87 + SYS_reboot : uintptr : 88 + SYS_munmap : uintptr : 91 + SYS_truncate : uintptr : 92 + SYS_ftruncate : uintptr : 93 + SYS_fchmod : uintptr : 94 + SYS_fchown : uintptr : 95 + SYS_getpriority : uintptr : 96 + SYS_setpriority : uintptr : 97 + SYS_statfs : uintptr : 99 + SYS_fstatfs : uintptr : 100 + SYS_syslog : uintptr : 103 + SYS_setitimer : uintptr : 104 + SYS_getitimer : uintptr : 105 + SYS_stat : uintptr : 106 + SYS_lstat : uintptr : 107 + SYS_fstat : uintptr : 108 + SYS_vhangup : uintptr : 111 + SYS_wait4 : uintptr : 114 + SYS_swapoff : uintptr : 115 + SYS_sysinfo : uintptr : 116 + SYS_fsync : uintptr : 118 + SYS_sigreturn : uintptr : 119 + SYS_clone : uintptr : 120 + SYS_setdomainname : uintptr : 121 + SYS_uname : uintptr : 122 + SYS_adjtimex : uintptr : 124 + SYS_mprotect : uintptr : 125 + SYS_sigprocmask : uintptr : 126 + SYS_init_module : uintptr : 128 + SYS_delete_module : uintptr : 129 + SYS_quotactl : uintptr : 131 + SYS_getpgid : uintptr : 132 + SYS_fchdir : uintptr : 133 + SYS_bdflush : uintptr : 134 + SYS_sysfs : uintptr : 135 + SYS_personality : uintptr : 136 + SYS_setfsuid : uintptr : 138 + SYS_setfsgid : uintptr : 139 + SYS__llseek : uintptr : 140 + SYS_getdents : uintptr : 141 + SYS__newselect : uintptr : 142 + SYS_flock : uintptr : 143 + SYS_msync : uintptr : 144 + SYS_readv : uintptr : 145 + SYS_writev : uintptr : 146 + SYS_getsid : uintptr : 147 + SYS_fdatasync : uintptr : 148 + SYS__sysctl : uintptr : 149 + SYS_mlock : uintptr : 150 + SYS_munlock : uintptr : 151 + SYS_mlockall : uintptr : 152 + SYS_munlockall : uintptr : 153 + SYS_sched_setparam : uintptr : 154 + SYS_sched_getparam : uintptr : 155 + SYS_sched_setscheduler : uintptr : 156 + SYS_sched_getscheduler : uintptr : 157 + SYS_sched_yield : uintptr : 158 + SYS_sched_get_priority_max : uintptr : 159 + SYS_sched_get_priority_min : uintptr : 160 + SYS_sched_rr_get_interval : uintptr : 161 + SYS_nanosleep : uintptr : 162 + SYS_mremap : uintptr : 163 + SYS_setresuid : uintptr : 164 + SYS_getresuid : uintptr : 165 + SYS_poll : uintptr : 168 + SYS_nfsservctl : uintptr : 169 + SYS_setresgid : uintptr : 170 + SYS_getresgid : uintptr : 171 + SYS_prctl : uintptr : 172 + SYS_rt_sigreturn : uintptr : 173 + SYS_rt_sigaction : uintptr : 174 + SYS_rt_sigprocmask : uintptr : 175 + SYS_rt_sigpending : uintptr : 176 + SYS_rt_sigtimedwait : uintptr : 177 + SYS_rt_sigqueueinfo : uintptr : 178 + SYS_rt_sigsuspend : uintptr : 179 + SYS_pread64 : uintptr : 180 + SYS_pwrite64 : uintptr : 181 + SYS_chown : uintptr : 182 + SYS_getcwd : uintptr : 183 + SYS_capget : uintptr : 184 + SYS_capset : uintptr : 185 + SYS_sigaltstack : uintptr : 186 + SYS_sendfile : uintptr : 187 + SYS_vfork : uintptr : 190 + SYS_ugetrlimit : uintptr : 191 + SYS_mmap : uintptr : 192 // actually mmap2 + SYS_truncate64 : uintptr : 193 + SYS_ftruncate64 : uintptr : 194 + SYS_stat64 : uintptr : 195 + SYS_lstat64 : uintptr : 196 + SYS_fstat64 : uintptr : 197 + SYS_lchown32 : uintptr : 198 + SYS_getuid32 : uintptr : 199 + SYS_getgid32 : uintptr : 200 + SYS_geteuid32 : uintptr : 201 + SYS_getegid32 : uintptr : 202 + SYS_setreuid32 : uintptr : 203 + SYS_setregid32 : uintptr : 204 + SYS_getgroups32 : uintptr : 205 + SYS_setgroups32 : uintptr : 206 + SYS_fchown32 : uintptr : 207 + SYS_setresuid32 : uintptr : 208 + SYS_getresuid32 : uintptr : 209 + SYS_setresgid32 : uintptr : 210 + SYS_getresgid32 : uintptr : 211 + SYS_chown32 : uintptr : 212 + SYS_setuid32 : uintptr : 213 + SYS_setgid32 : uintptr : 214 + SYS_setfsuid32 : uintptr : 215 + SYS_setfsgid32 : uintptr : 216 + SYS_getdents64 : uintptr : 217 + SYS_pivot_root : uintptr : 218 + SYS_mincore : uintptr : 219 + SYS_madvise : uintptr : 220 + SYS_fcntl64 : uintptr : 221 + SYS_gettid : uintptr : 224 + SYS_readahead : uintptr : 225 + SYS_setxattr : uintptr : 226 + SYS_lsetxattr : uintptr : 227 + SYS_fsetxattr : uintptr : 228 + SYS_getxattr : uintptr : 229 + SYS_lgetxattr : uintptr : 230 + SYS_fgetxattr : uintptr : 231 + SYS_listxattr : uintptr : 232 + SYS_llistxattr : uintptr : 233 + SYS_flistxattr : uintptr : 234 + SYS_removexattr : uintptr : 235 + SYS_lremovexattr : uintptr : 236 + SYS_fremovexattr : uintptr : 237 + SYS_tkill : uintptr : 238 + SYS_sendfile64 : uintptr : 239 + SYS_futex : uintptr : 240 + SYS_sched_setaffinity : uintptr : 241 + SYS_sched_getaffinity : uintptr : 242 + SYS_io_setup : uintptr : 243 + SYS_io_destroy : uintptr : 244 + SYS_io_getevents : uintptr : 245 + SYS_io_submit : uintptr : 246 + SYS_io_cancel : uintptr : 247 + SYS_exit_group : uintptr : 248 + SYS_lookup_dcookie : uintptr : 249 + SYS_epoll_create : uintptr : 250 + SYS_epoll_ctl : uintptr : 251 + SYS_epoll_wait : uintptr : 252 + SYS_remap_file_pages : uintptr : 253 + SYS_set_tid_address : uintptr : 256 + SYS_timer_create : uintptr : 257 + SYS_timer_settime : uintptr : 258 + SYS_timer_gettime : uintptr : 259 + SYS_timer_getoverrun : uintptr : 260 + SYS_timer_delete : uintptr : 261 + SYS_clock_settime : uintptr : 262 + SYS_clock_gettime : uintptr : 263 + SYS_clock_getres : uintptr : 264 + SYS_clock_nanosleep : uintptr : 265 + SYS_statfs64 : uintptr : 266 + SYS_fstatfs64 : uintptr : 267 + SYS_tgkill : uintptr : 268 + SYS_utimes : uintptr : 269 + SYS_fadvise64_64 : uintptr : 270 + SYS_pciconfig_iobase : uintptr : 271 + SYS_pciconfig_read : uintptr : 272 + SYS_pciconfig_write : uintptr : 273 + SYS_mq_open : uintptr : 274 + SYS_mq_unlink : uintptr : 275 + SYS_mq_timedsend : uintptr : 276 + SYS_mq_timedreceive : uintptr : 277 + SYS_mq_notify : uintptr : 278 + SYS_mq_getsetattr : uintptr : 279 + SYS_waitid : uintptr : 280 + SYS_socket : uintptr : 281 + SYS_bind : uintptr : 282 + SYS_connect : uintptr : 283 + SYS_listen : uintptr : 284 + SYS_accept : uintptr : 285 + SYS_getsockname : uintptr : 286 + SYS_getpeername : uintptr : 287 + SYS_socketpair : uintptr : 288 + SYS_send : uintptr : 289 + SYS_sendto : uintptr : 290 + SYS_recv : uintptr : 291 + SYS_recvfrom : uintptr : 292 + SYS_shutdown : uintptr : 293 + SYS_setsockopt : uintptr : 294 + SYS_getsockopt : uintptr : 295 + SYS_sendmsg : uintptr : 296 + SYS_recvmsg : uintptr : 297 + SYS_semop : uintptr : 298 + SYS_semget : uintptr : 299 + SYS_semctl : uintptr : 300 + SYS_msgsnd : uintptr : 301 + SYS_msgrcv : uintptr : 302 + SYS_msgget : uintptr : 303 + SYS_msgctl : uintptr : 304 + SYS_shmat : uintptr : 305 + SYS_shmdt : uintptr : 306 + SYS_shmget : uintptr : 307 + SYS_shmctl : uintptr : 308 + SYS_add_key : uintptr : 309 + SYS_request_key : uintptr : 310 + SYS_keyctl : uintptr : 311 + SYS_semtimedop : uintptr : 312 + SYS_vserver : uintptr : 313 + SYS_ioprio_set : uintptr : 314 + SYS_ioprio_get : uintptr : 315 + SYS_inotify_init : uintptr : 316 + SYS_inotify_add_watch : uintptr : 317 + SYS_inotify_rm_watch : uintptr : 318 + SYS_mbind : uintptr : 319 + SYS_get_mempolicy : uintptr : 320 + SYS_set_mempolicy : uintptr : 321 + SYS_openat : uintptr : 322 + SYS_mkdirat : uintptr : 323 + SYS_mknodat : uintptr : 324 + SYS_fchownat : uintptr : 325 + SYS_futimesat : uintptr : 326 + SYS_fstatat64 : uintptr : 327 + SYS_unlinkat : uintptr : 328 + SYS_renameat : uintptr : 329 + SYS_linkat : uintptr : 330 + SYS_symlinkat : uintptr : 331 + SYS_readlinkat : uintptr : 332 + SYS_fchmodat : uintptr : 333 + SYS_faccessat : uintptr : 334 + SYS_pselect6 : uintptr : 335 + SYS_ppoll : uintptr : 336 + SYS_unshare : uintptr : 337 + SYS_set_robust_list : uintptr : 338 + SYS_get_robust_list : uintptr : 339 + SYS_splice : uintptr : 340 + SYS_sync_file_range : uintptr : 341 + SYS_tee : uintptr : 342 + SYS_vmsplice : uintptr : 343 + SYS_move_pages : uintptr : 344 + SYS_getcpu : uintptr : 345 + SYS_epoll_pwait : uintptr : 346 + SYS_kexec_load : uintptr : 347 + SYS_utimensat : uintptr : 348 + SYS_signalfd : uintptr : 349 + SYS_timerfd_create : uintptr : 350 + SYS_eventfd : uintptr : 351 + SYS_fallocate : uintptr : 352 + SYS_timerfd_settime : uintptr : 353 + SYS_timerfd_gettime : uintptr : 354 + SYS_signalfd4 : uintptr : 355 + SYS_eventfd2 : uintptr : 356 + SYS_epoll_create1 : uintptr : 357 + SYS_dup3 : uintptr : 358 + SYS_pipe2 : uintptr : 359 + SYS_inotify_init1 : uintptr : 360 + SYS_preadv : uintptr : 361 + SYS_pwritev : uintptr : 362 + SYS_rt_tgsigqueueinfo : uintptr : 363 + SYS_perf_event_open : uintptr : 364 + SYS_recvmmsg : uintptr : 365 + SYS_accept4 : uintptr : 366 + SYS_fanotify_init : uintptr : 367 + SYS_fanotify_mark : uintptr : 368 + SYS_prlimit64 : uintptr : 369 + SYS_name_to_handle_at : uintptr : 370 + SYS_open_by_handle_at : uintptr : 371 + SYS_clock_adjtime : uintptr : 372 + SYS_syncfs : uintptr : 373 + SYS_sendmmsg : uintptr : 374 + SYS_setns : uintptr : 375 + SYS_process_vm_readv : uintptr : 376 + SYS_process_vm_writev : uintptr : 377 + SYS_kcmp : uintptr : 378 + SYS_finit_module : uintptr : 379 + SYS_sched_setattr : uintptr : 380 + SYS_sched_getattr : uintptr : 381 + SYS_renameat2 : uintptr : 382 + SYS_seccomp : uintptr : 383 SYS_getrandom : uintptr : 384 + SYS_memfd_create : uintptr : 385 + SYS_bpf : uintptr : 386 + SYS_execveat : uintptr : 387 + SYS_userfaultfd : uintptr : 388 + SYS_membarrier : uintptr : 389 + SYS_mlock2 : uintptr : 390 + SYS_copy_file_range : uintptr : 391 + SYS_preadv2 : uintptr : 392 + SYS_pwritev2 : uintptr : 393 + SYS_pkey_mprotect : uintptr : 394 + SYS_pkey_alloc : uintptr : 395 + SYS_pkey_free : uintptr : 396 + SYS_statx : uintptr : 397 + SYS_rseq : uintptr : 398 + SYS_io_pgetevents : uintptr : 399 + SYS_migrate_pages : uintptr : 400 + SYS_kexec_file_load : uintptr : 401 + SYS_clock_gettime64 : uintptr : 403 + SYS_clock_settime64 : uintptr : 404 + SYS_clock_adjtime64 : uintptr : 405 + SYS_clock_getres_time64 : uintptr : 406 + SYS_clock_nanosleep_time64 : uintptr : 407 + SYS_timer_gettime64 : uintptr : 408 + SYS_timer_settime64 : uintptr : 409 + SYS_timerfd_gettime64 : uintptr : 410 + SYS_timerfd_settime64 : uintptr : 411 + SYS_utimensat_time64 : uintptr : 412 + SYS_pselect6_time64 : uintptr : 413 + SYS_ppoll_time64 : uintptr : 414 + SYS_io_pgetevents_time64 : uintptr : 416 + SYS_recvmmsg_time64 : uintptr : 417 + SYS_mq_timedsend_time64 : uintptr : 418 + SYS_mq_timedreceive_time64 : uintptr : 419 + SYS_semtimedop_time64 : uintptr : 420 + SYS_rt_sigtimedwait_time64 : uintptr : 421 + SYS_futex_time64 : uintptr : 422 + SYS_sched_rr_get_interval_time64 : uintptr : 423 + SYS_pidfd_send_signal : uintptr : 424 + SYS_io_uring_setup : uintptr : 425 + SYS_io_uring_enter : uintptr : 426 + SYS_io_uring_register : uintptr : 427 + SYS_open_tree : uintptr : 428 + SYS_move_mount : uintptr : 429 + SYS_fsopen : uintptr : 430 + SYS_fsconfig : uintptr : 431 + SYS_fsmount : uintptr : 432 + SYS_fspick : uintptr : 433 + SYS_pidfd_open : uintptr : 434 + SYS_clone3 : uintptr : 435 + SYS_close_range : uintptr : 436 + SYS_openat2 : uintptr : 437 + SYS_pidfd_getfd : uintptr : 438 + SYS_faccessat2 : uintptr : 439 + SYS_process_madvise : uintptr : 440 + SYS_epoll_pwait2 : uintptr : 441 + SYS_mount_setattr : uintptr : 442 + SYS_landlock_create_ruleset : uintptr : 444 + SYS_landlock_add_rule : uintptr : 445 + SYS_landlock_restrict_self : uintptr : 446 } else { #panic("Unsupported architecture") } From 68e5f57e278ea7a3404508783daf2cc299a202e2 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Mon, 3 Jan 2022 20:34:57 +0100 Subject: [PATCH 0145/1258] Fixes open system call (Thanks TIM!) --- core/os/os_darwin.odin | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index d40c80aeb..d882dcbbd 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -296,6 +296,8 @@ foreign libc { @(link_name="readdir_r$INODE64") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- @(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int --- + @(link_name="fchmod") _unix_fchmod :: proc(fildes: Handle, mode: u16) -> c.int ---; + @(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr --- @(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr --- @(link_name="free") _unix_free :: proc(ptr: rawptr) --- @@ -305,6 +307,8 @@ foreign libc { @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + @(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---; + @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } @@ -319,16 +323,35 @@ get_last_error :: proc() -> int { return __error()^ } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { +get_last_error_string :: proc() -> string { + return cast(string)_darwin_string_error(cast(c.int)get_last_error()); +} + +open :: proc(path: string, flags: int = O_RDWR|O_CREATE, mode: int = 0) -> (Handle, Errno) { cstr := strings.clone_to_cstring(path) handle := _unix_open(cstr, i32(flags), u16(mode)) delete(cstr) if handle == -1 { return INVALID_HANDLE, 1 } + +when ODIN_OS == "darwin" && ODIN_ARCH == "arm64" { + if mode != 0 { + err := fchmod(handle, cast(u16)mode) + if err != 0 { + _unix_close(handle) + return INVALID_HANDLE, 1 + } + } +} + return handle, 0 } +fchmod :: proc(fildes: Handle, mode: u16) -> Errno { + return cast(Errno)_unix_fchmod(fildes, mode) +} + close :: proc(fd: Handle) { _unix_close(fd) } From 8ff6f955715f70f4d369f8c52c8fc5e5c1658cc0 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Mon, 3 Jan 2022 20:40:56 +0100 Subject: [PATCH 0146/1258] Removes the default create flag --- core/os/os_darwin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index d882dcbbd..b32453a5d 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -327,7 +327,7 @@ get_last_error_string :: proc() -> string { return cast(string)_darwin_string_error(cast(c.int)get_last_error()); } -open :: proc(path: string, flags: int = O_RDWR|O_CREATE, mode: int = 0) -> (Handle, Errno) { +open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) { cstr := strings.clone_to_cstring(path) handle := _unix_open(cstr, i32(flags), u16(mode)) delete(cstr) From f818d0feb1fe0bb421ba27060ea6ff812bf67117 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 Jan 2022 19:43:22 +0000 Subject: [PATCH 0147/1258] Fix #1344 --- src/llvm_backend_stmt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 016e464b8..20b444058 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -2188,6 +2188,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { lb_emit_defer_stmts(p, lbDeferExit_Branch, block); } lb_emit_jump(p, block); + lb_start_block(p, lb_create_block(p, "unreachable")); case_end; } } From f15bb0b424d854e4ba84c14046b56d7b8357eb94 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 3 Jan 2022 19:45:27 +0000 Subject: [PATCH 0148/1258] Fix quaternion casting --- core/math/linalg/glsl/linalg_glsl.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/math/linalg/glsl/linalg_glsl.odin b/core/math/linalg/glsl/linalg_glsl.odin index 3b4976452..053182794 100644 --- a/core/math/linalg/glsl/linalg_glsl.odin +++ b/core/math/linalg/glsl/linalg_glsl.odin @@ -1597,7 +1597,7 @@ quatNlerp :: proc "c" (a, b: quat, t: f32) -> (c: quat) { c.y = a.y + (b.y-a.y)*t c.z = a.z + (b.z-a.z)*t c.w = a.w + (b.w-a.w)*t - return c/builtin.abs(c) + return c/quat(builtin.abs(c)) } quatSlerp :: proc "c" (x, y: quat, t: f32) -> (q: quat) { @@ -1699,7 +1699,7 @@ dquatNlerp :: proc "c" (a, b: dquat, t: f64) -> (c: dquat) { c.y = a.y + (b.y-a.y)*t c.z = a.z + (b.z-a.z)*t c.w = a.w + (b.w-a.w)*t - return c/builtin.abs(c) + return c/dquat(builtin.abs(c)) } dquatSlerp :: proc "c" (x, y: dquat, t: f64) -> (q: dquat) { From 17613185e79b324948c14257f64c388c8e2a52fb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 4 Jan 2022 11:44:34 +0000 Subject: [PATCH 0149/1258] Support struct field tags in odin doc format --- core/odin/doc-format/doc_format.odin | 4 +++- src/docs_format.cpp | 3 ++- src/docs_writer.cpp | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index c80be2489..83cd89ca2 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -11,7 +11,7 @@ String :: distinct Array(byte) Version_Type_Major :: 0 Version_Type_Minor :: 2 -Version_Type_Patch :: 1 +Version_Type_Patch :: 2 Version_Type :: struct { major, minor, patch: u8, @@ -242,6 +242,8 @@ Type :: struct { polymorphic_params: Type_Index, // Used By: .Struct, .Union where_clauses: Array(String), + // Used By: .Struct + tags: Array(String), } Type_Flags_Basic :: distinct bit_set[Type_Flag_Basic; u32le] diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 1c3af6257..5cfac4817 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -15,7 +15,7 @@ struct OdinDocVersionType { #define OdinDocVersionType_Major 0 #define OdinDocVersionType_Minor 2 -#define OdinDocVersionType_Patch 1 +#define OdinDocVersionType_Patch 2 struct OdinDocHeaderBase { u8 magic[8]; @@ -137,6 +137,7 @@ struct OdinDocType { OdinDocArray entities; OdinDocTypeIndex polmorphic_params; OdinDocArray where_clauses; + OdinDocArray tags; // struct field tags }; struct OdinDocAttribute { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index e8e8892ec..56ad0561e 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -598,6 +598,15 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { } doc_type.where_clauses = odin_doc_where_clauses(w, st->where_clauses); } + + auto tags = array_make(heap_allocator(), type->Struct.fields.count); + defer (array_free(&tags)); + + for_array(i, type->Struct.fields) { + tags[i] = odin_doc_write_string(w, type->Struct.tags[i]); + } + + doc_type.tags = odin_write_slice(w, tags.data, tags.count); } break; case Type_Union: From 72862ce30d55891f1b04d3aadd085d7822f1b960 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 4 Jan 2022 11:48:18 +0000 Subject: [PATCH 0150/1258] Fix minor typo in c/frontend/preprocess --- core/c/frontend/preprocessor/preprocess.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/c/frontend/preprocessor/preprocess.odin b/core/c/frontend/preprocessor/preprocess.odin index 62b4183bc..9651cc81c 100644 --- a/core/c/frontend/preprocessor/preprocess.odin +++ b/core/c/frontend/preprocessor/preprocess.odin @@ -956,7 +956,7 @@ substitute_token :: proc(cpp: ^Preprocessor, tok: ^Token, args: ^Macro_Arg) -> ^ continue } - if tok.lit == "__VA__OPT__" && tok.next.lit == "(" { + if tok.lit == "__VA_OPT__" && tok.next.lit == "(" { opt_arg := read_macro_arg_one(cpp, &tok, tok.next.next, true) if has_varargs(args) { for t := opt_arg.tok; t.kind != .EOF; t = t.next { From 8c9597b24bc7397143b1a9039362be1c7ae53aeb Mon Sep 17 00:00:00 2001 From: Tyler Erickson Date: Tue, 4 Jan 2022 16:45:16 -0800 Subject: [PATCH 0151/1258] add schar to core:c and core:c/libc --- core/c/c.odin | 2 ++ core/c/libc/types.odin | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/c/c.odin b/core/c/c.odin index d135fa93c..139d9920a 100644 --- a/core/c/c.odin +++ b/core/c/c.odin @@ -3,6 +3,8 @@ package c import builtin "core:builtin" char :: builtin.u8 // assuming -funsigned-char + +schar :: builtin.i8 short :: builtin.i16 int :: builtin.i32 long :: builtin.i32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.i64 diff --git a/core/c/libc/types.odin b/core/c/libc/types.odin index 7199cf57b..a49e52fb6 100644 --- a/core/c/libc/types.odin +++ b/core/c/libc/types.odin @@ -3,6 +3,8 @@ package libc import "core:c" char :: c.char // assuming -funsigned-char + +schar :: c.schar short :: c.short int :: c.int long :: c.long From 7a14acaa01d37ca02597bf40df00f7d62903a291 Mon Sep 17 00:00:00 2001 From: Platin21 Date: Wed, 5 Jan 2022 16:49:58 +0100 Subject: [PATCH 0152/1258] Fixes syscall intrinsic on macOS they use a slightly different section + register for the id --- src/llvm_backend_proc.cpp | 59 ++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 84fddd9e2..50aa5f6db 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2058,26 +2058,47 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, break; case TargetArch_arm64: { - GB_ASSERT(arg_count <= 7); - - char asm_string[] = "svc #0"; - gbString constraints = gb_string_make(heap_allocator(), "={x0}"); - for (unsigned i = 0; i < arg_count; i++) { - constraints = gb_string_appendc(constraints, ",{"); - static char const *regs[] = { - "x8", - "x0", - "x1", - "x2", - "x3", - "x4", - "x5", - }; - constraints = gb_string_appendc(constraints, regs[i]); - constraints = gb_string_appendc(constraints, "}"); - } + GB_ASSERT(arg_count <= 7); + + if(build_context.metrics.os == TargetOs_darwin) { + char asm_string[] = "svc #0x80"; + gbString constraints = gb_string_make(heap_allocator(), "={x0}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "x16", + "x0", + "x1", + "x2", + "x3", + "x4", + "x5", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } - inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } else { + char asm_string[] = "svc #0"; + gbString constraints = gb_string_make(heap_allocator(), "={x0}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "x8", + "x0", + "x1", + "x2", + "x3", + "x4", + "x5", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } + + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } } break; default: From 566a7508990632726a181b12459538b9898bc72e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 7 Jan 2022 06:12:00 +0100 Subject: [PATCH 0153/1258] Fix unused imports. --- core/sort/map.odin | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/sort/map.odin b/core/sort/map.odin index dff2dced3..32f5e09a2 100644 --- a/core/sort/map.odin +++ b/core/sort/map.odin @@ -4,6 +4,9 @@ import "core:intrinsics" import "core:runtime" import "core:slice" +_ :: runtime +_ :: slice + map_entries_by_key :: proc(m: ^$M/map[$K]$V, loc := #caller_location) where intrinsics.type_is_ordered(K) { Entry :: struct { hash: uintptr, From 773cfac449a1a4a46795cc3345245fbd98b32cbe Mon Sep 17 00:00:00 2001 From: Naboris Date: Sat, 8 Jan 2022 09:39:26 +0100 Subject: [PATCH 0154/1258] fix typo --- core/unicode/utf16/utf16.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/unicode/utf16/utf16.odin b/core/unicode/utf16/utf16.odin index 2e349640e..6bdd6558a 100644 --- a/core/unicode/utf16/utf16.odin +++ b/core/unicode/utf16/utf16.odin @@ -117,9 +117,9 @@ decode_to_utf8 :: proc(d: []byte, s: []u16) -> (n: int) { switch c := s[i]; { case c < _surr1, _surr3 <= c: r = rune(c) - case _surr1 <= r && r < _surr2 && i+1 < len(s) && + case _surr1 <= c && c < _surr2 && i+1 < len(s) && _surr2 <= s[i+1] && s[i+1] < _surr3: - r = decode_surrogate_pair(rune(r), rune(s[i+1])) + r = decode_surrogate_pair(rune(c), rune(s[i+1])) i += 1 } From 1cff72ad6240e2ea211a0d3c4867a6671364e4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Bog=C3=B3cki?= Date: Sun, 9 Jan 2022 22:43:12 +0800 Subject: [PATCH 0155/1258] Fix link to Odin blog --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b1d0a39a1..5b8c25492 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ The official Odin Language specification. ### Articles -#### [The Odin Blog](https://odin-lang.org/blog) +#### [The Odin Blog](https://odin-lang.org/news/) The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests. From af612bc7e9ee96a73d4f766340249385979dd3c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 10 Jan 2022 11:32:27 +0000 Subject: [PATCH 0156/1258] Update matrix types to be the native Odin `matrix` types --- core/math/linalg/general.odin | 73 +- core/math/linalg/specific.odin | 1063 ++++++++--------- .../linalg/specific_euler_angles_f16.odin | 1042 ++++++++-------- .../linalg/specific_euler_angles_f32.odin | 1042 ++++++++-------- .../linalg/specific_euler_angles_f64.odin | 1042 ++++++++-------- core/math/linalg/swizzle.odin | 5 + 6 files changed, 2103 insertions(+), 2164 deletions(-) diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index 6c594945f..b0572c0d3 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -1,6 +1,7 @@ package linalg import "core:math" +import "core:builtin" import "core:intrinsics" // Generic @@ -60,14 +61,7 @@ quaternion256_dot :: proc(a, b: $T/quaternion256) -> (c: f64) { dot :: proc{scalar_dot, vector_dot, quaternion64_dot, quaternion128_dot, quaternion256_dot} inner_product :: dot -outer_product :: proc(a: $A/[$M]$E, b: $B/[$N]E) -> (out: [M][N]E) where IS_NUMERIC(E) #no_bounds_check { - for i in 0.. Q where IS_QUATERNION(Q) { return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0) @@ -163,65 +157,28 @@ identity :: proc($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check { return m } -trace :: proc(m: $T/[$N][N]$E) -> (tr: E) { - for i in 0.. (m: (T when N == M else [M][N]E)) #no_bounds_check { - for j in 0.. (c: M) +matrix_mul :: proc(a, b: $M/matrix[$N, N]$E) -> (c: M) where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check { - for i in 0.. (c: M) +matrix_comp_mul :: proc(a, b: $M/matrix[$I, $J]$E) -> (c: M) where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check { - for j in 0.. (c: [K][I]E) +matrix_mul_differ :: proc(a: $A/matrix[$I, $J]$E, b: $B/matrix[J, $K]E) -> (c: matrix[I, K]E) where !IS_ARRAY(E), IS_NUMERIC(E), I != K #no_bounds_check { - for k in 0.. (c: B) +matrix_mul_vector :: proc(a: $A/matrix[$I, $J]$E, b: $B/[J]E) -> (c: B) where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check { - for i in 0.. Q where IS_QUATERNION(Q) { @@ -270,8 +227,8 @@ mul :: proc{ vector_to_ptr :: proc(v: ^$V/[$N]$E) -> ^E where IS_NUMERIC(E), N > 0 #no_bounds_check { return &v[0] } -matrix_to_ptr :: proc(m: ^$A/[$I][$J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check { - return &m[0][0] +matrix_to_ptr :: proc(m: ^$A/matrix[$I, $J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check { + return &m[0, 0] } to_ptr :: proc{vector_to_ptr, matrix_to_ptr} @@ -357,6 +314,6 @@ to_uint :: #force_inline proc(v: $A/[$N]$T) -> [N]uint { return array_cast(v, ui to_complex32 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex32 { return array_cast(v, complex32) } to_complex64 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex64 { return array_cast(v, complex64) } to_complex128 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex128 { return array_cast(v, complex128) } -to_quaternion64 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion64 { return array_cast(v, quaternion64) } +to_quaternion64 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion64 { return array_cast(v, quaternion64) } to_quaternion128 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion128 { return array_cast(v, quaternion128) } to_quaternion256 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion256 { return array_cast(v, quaternion256) } diff --git a/core/math/linalg/specific.odin b/core/math/linalg/specific.odin index 5cb68e3a8..cb007bd91 100644 --- a/core/math/linalg/specific.odin +++ b/core/math/linalg/specific.odin @@ -1,5 +1,6 @@ package linalg +import "core:builtin" import "core:math" F16_EPSILON :: 1e-3 @@ -10,25 +11,25 @@ Vector2f16 :: distinct [2]f16 Vector3f16 :: distinct [3]f16 Vector4f16 :: distinct [4]f16 -Matrix1x1f16 :: distinct [1][1]f16 -Matrix1x2f16 :: distinct [1][2]f16 -Matrix1x3f16 :: distinct [1][3]f16 -Matrix1x4f16 :: distinct [1][4]f16 +Matrix1x1f16 :: distinct matrix[1, 1]f16 +Matrix1x2f16 :: distinct matrix[1, 2]f16 +Matrix1x3f16 :: distinct matrix[1, 3]f16 +Matrix1x4f16 :: distinct matrix[1, 4]f16 -Matrix2x1f16 :: distinct [2][1]f16 -Matrix2x2f16 :: distinct [2][2]f16 -Matrix2x3f16 :: distinct [2][3]f16 -Matrix2x4f16 :: distinct [2][4]f16 +Matrix2x1f16 :: distinct matrix[2, 1]f16 +Matrix2x2f16 :: distinct matrix[2, 2]f16 +Matrix2x3f16 :: distinct matrix[2, 3]f16 +Matrix2x4f16 :: distinct matrix[2, 4]f16 -Matrix3x1f16 :: distinct [3][1]f16 -Matrix3x2f16 :: distinct [3][2]f16 -Matrix3x3f16 :: distinct [3][3]f16 -Matrix3x4f16 :: distinct [3][4]f16 +Matrix3x1f16 :: distinct matrix[3, 1]f16 +Matrix3x2f16 :: distinct matrix[3, 2]f16 +Matrix3x3f16 :: distinct matrix[3, 3]f16 +Matrix3x4f16 :: distinct matrix[3, 4]f16 -Matrix4x1f16 :: distinct [4][1]f16 -Matrix4x2f16 :: distinct [4][2]f16 -Matrix4x3f16 :: distinct [4][3]f16 -Matrix4x4f16 :: distinct [4][4]f16 +Matrix4x1f16 :: distinct matrix[4, 1]f16 +Matrix4x2f16 :: distinct matrix[4, 2]f16 +Matrix4x3f16 :: distinct matrix[4, 3]f16 +Matrix4x4f16 :: distinct matrix[4, 4]f16 Matrix1f16 :: Matrix1x1f16 Matrix2f16 :: Matrix2x2f16 @@ -39,25 +40,25 @@ Vector2f32 :: distinct [2]f32 Vector3f32 :: distinct [3]f32 Vector4f32 :: distinct [4]f32 -Matrix1x1f32 :: distinct [1][1]f32 -Matrix1x2f32 :: distinct [1][2]f32 -Matrix1x3f32 :: distinct [1][3]f32 -Matrix1x4f32 :: distinct [1][4]f32 +Matrix1x1f32 :: distinct matrix[1, 1]f32 +Matrix1x2f32 :: distinct matrix[1, 2]f32 +Matrix1x3f32 :: distinct matrix[1, 3]f32 +Matrix1x4f32 :: distinct matrix[1, 4]f32 -Matrix2x1f32 :: distinct [2][1]f32 -Matrix2x2f32 :: distinct [2][2]f32 -Matrix2x3f32 :: distinct [2][3]f32 -Matrix2x4f32 :: distinct [2][4]f32 +Matrix2x1f32 :: distinct matrix[2, 1]f32 +Matrix2x2f32 :: distinct matrix[2, 2]f32 +Matrix2x3f32 :: distinct matrix[2, 3]f32 +Matrix2x4f32 :: distinct matrix[2, 4]f32 -Matrix3x1f32 :: distinct [3][1]f32 -Matrix3x2f32 :: distinct [3][2]f32 -Matrix3x3f32 :: distinct [3][3]f32 -Matrix3x4f32 :: distinct [3][4]f32 +Matrix3x1f32 :: distinct matrix[3, 1]f32 +Matrix3x2f32 :: distinct matrix[3, 2]f32 +Matrix3x3f32 :: distinct matrix[3, 3]f32 +Matrix3x4f32 :: distinct matrix[3, 4]f32 -Matrix4x1f32 :: distinct [4][1]f32 -Matrix4x2f32 :: distinct [4][2]f32 -Matrix4x3f32 :: distinct [4][3]f32 -Matrix4x4f32 :: distinct [4][4]f32 +Matrix4x1f32 :: distinct matrix[4, 1]f32 +Matrix4x2f32 :: distinct matrix[4, 2]f32 +Matrix4x3f32 :: distinct matrix[4, 3]f32 +Matrix4x4f32 :: distinct matrix[4, 4]f32 Matrix1f32 :: Matrix1x1f32 Matrix2f32 :: Matrix2x2f32 @@ -68,25 +69,25 @@ Vector2f64 :: distinct [2]f64 Vector3f64 :: distinct [3]f64 Vector4f64 :: distinct [4]f64 -Matrix1x1f64 :: distinct [1][1]f64 -Matrix1x2f64 :: distinct [1][2]f64 -Matrix1x3f64 :: distinct [1][3]f64 -Matrix1x4f64 :: distinct [1][4]f64 +Matrix1x1f64 :: distinct matrix[1, 1]f64 +Matrix1x2f64 :: distinct matrix[1, 2]f64 +Matrix1x3f64 :: distinct matrix[1, 3]f64 +Matrix1x4f64 :: distinct matrix[1, 4]f64 -Matrix2x1f64 :: distinct [2][1]f64 -Matrix2x2f64 :: distinct [2][2]f64 -Matrix2x3f64 :: distinct [2][3]f64 -Matrix2x4f64 :: distinct [2][4]f64 +Matrix2x1f64 :: distinct matrix[2, 1]f64 +Matrix2x2f64 :: distinct matrix[2, 2]f64 +Matrix2x3f64 :: distinct matrix[2, 3]f64 +Matrix2x4f64 :: distinct matrix[2, 4]f64 -Matrix3x1f64 :: distinct [3][1]f64 -Matrix3x2f64 :: distinct [3][2]f64 -Matrix3x3f64 :: distinct [3][3]f64 -Matrix3x4f64 :: distinct [3][4]f64 +Matrix3x1f64 :: distinct matrix[3, 1]f64 +Matrix3x2f64 :: distinct matrix[3, 2]f64 +Matrix3x3f64 :: distinct matrix[3, 3]f64 +Matrix3x4f64 :: distinct matrix[3, 4]f64 -Matrix4x1f64 :: distinct [4][1]f64 -Matrix4x2f64 :: distinct [4][2]f64 -Matrix4x3f64 :: distinct [4][3]f64 -Matrix4x4f64 :: distinct [4][4]f64 +Matrix4x1f64 :: distinct matrix[4, 1]f64 +Matrix4x2f64 :: distinct matrix[4, 2]f64 +Matrix4x3f64 :: distinct matrix[4, 3]f64 +Matrix4x4f64 :: distinct matrix[4, 4]f64 Matrix1f64 :: Matrix1x1f64 Matrix2f64 :: Matrix2x2f64 @@ -97,20 +98,20 @@ Quaternionf16 :: distinct quaternion64 Quaternionf32 :: distinct quaternion128 Quaternionf64 :: distinct quaternion256 -MATRIX1F16_IDENTITY :: Matrix1f16{{1}} -MATRIX2F16_IDENTITY :: Matrix2f16{{1, 0}, {0, 1}} -MATRIX3F16_IDENTITY :: Matrix3f16{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}} -MATRIX4F16_IDENTITY :: Matrix4f16{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}} +MATRIX1F16_IDENTITY :: Matrix1f16(1) +MATRIX2F16_IDENTITY :: Matrix2f16(1) +MATRIX3F16_IDENTITY :: Matrix3f16(1) +MATRIX4F16_IDENTITY :: Matrix4f16(1) -MATRIX1F32_IDENTITY :: Matrix1f32{{1}} -MATRIX2F32_IDENTITY :: Matrix2f32{{1, 0}, {0, 1}} -MATRIX3F32_IDENTITY :: Matrix3f32{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}} -MATRIX4F32_IDENTITY :: Matrix4f32{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}} +MATRIX1F32_IDENTITY :: Matrix1f32(1) +MATRIX2F32_IDENTITY :: Matrix2f32(1) +MATRIX3F32_IDENTITY :: Matrix3f32(1) +MATRIX4F32_IDENTITY :: Matrix4f32(1) -MATRIX1F64_IDENTITY :: Matrix1f64{{1}} -MATRIX2F64_IDENTITY :: Matrix2f64{{1, 0}, {0, 1}} -MATRIX3F64_IDENTITY :: Matrix3f64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}} -MATRIX4F64_IDENTITY :: Matrix4f64{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}} +MATRIX1F64_IDENTITY :: Matrix1f64(1) +MATRIX2F64_IDENTITY :: Matrix2f64(1) +MATRIX3F64_IDENTITY :: Matrix3f64(1) +MATRIX4F64_IDENTITY :: Matrix4f64(1) QUATERNIONF16_IDENTITY :: Quaternionf16(1) QUATERNIONF32_IDENTITY :: Quaternionf32(1) @@ -558,9 +559,9 @@ quaternion_from_forward_and_up_f16 :: proc(forward, up: Vector3f16) -> Quaternio s := normalize(cross(f, up)) u := cross(s, f) m := Matrix3f16{ - {+s.x, +u.x, -f.x}, - {+s.y, +u.y, -f.y}, - {+s.z, +u.z, -f.z}, + +s.x, +s.y, +s.z, + +u.x, +u.y, +u.z, + -f.x, -f.y, -f.z, } tr := trace(m) @@ -571,26 +572,26 @@ quaternion_from_forward_and_up_f16 :: proc(forward, up: Vector3f16) -> Quaternio case tr > 0: S := 2 * math.sqrt(1 + tr) q.w = 0.25 * S - q.x = (m[2][1] - m[1][2]) / S - q.y = (m[0][2] - m[2][0]) / S - q.z = (m[1][0] - m[0][1]) / S - case (m[0][0] > m[1][1]) && (m[0][0] > m[2][2]): - S := 2 * math.sqrt(1 + m[0][0] - m[1][1] - m[2][2]) - q.w = (m[2][1] - m[1][2]) / S + q.x = (m[1, 2] - m[2, 1]) / S + q.y = (m[2, 0] - m[0, 2]) / S + q.z = (m[0, 1] - m[1, 0]) / S + case (m[0, 0] > m[1, 1]) && (m[0, 0] > m[2, 2]): + S := 2 * math.sqrt(1 + m[0, 0] - m[1, 1] - m[2, 2]) + q.w = (m[1, 2] - m[2, 1]) / S q.x = 0.25 * S - q.y = (m[0][1] + m[1][0]) / S - q.z = (m[0][2] + m[2][0]) / S - case m[1][1] > m[2][2]: - S := 2 * math.sqrt(1 + m[1][1] - m[0][0] - m[2][2]) - q.w = (m[0][2] - m[2][0]) / S - q.x = (m[0][1] + m[1][0]) / S + q.y = (m[1, 0] + m[0, 1]) / S + q.z = (m[2, 0] + m[0, 2]) / S + case m[1, 1] > m[2, 2]: + S := 2 * math.sqrt(1 + m[1, 1] - m[0, 0] - m[2, 2]) + q.w = (m[2, 0] - m[0, 2]) / S + q.x = (m[1, 0] + m[0, 1]) / S q.y = 0.25 * S - q.z = (m[1][2] + m[2][1]) / S + q.z = (m[2, 1] + m[1, 2]) / S case: - S := 2 * math.sqrt(1 + m[2][2] - m[0][0] - m[1][1]) - q.w = (m[1][0] - m[0][1]) / S - q.x = (m[0][2] - m[2][0]) / S - q.y = (m[1][2] + m[2][1]) / S + S := 2 * math.sqrt(1 + m[2, 2] - m[0, 0] - m[1, 1]) + q.w = (m[0, 1] - m[1, 0]) / S + q.x = (m[2, 0] - m[0, 2]) / S + q.y = (m[2, 1] + m[1, 2]) / S q.z = 0.25 * S } @@ -601,9 +602,9 @@ quaternion_from_forward_and_up_f32 :: proc(forward, up: Vector3f32) -> Quaternio s := normalize(cross(f, up)) u := cross(s, f) m := Matrix3f32{ - {+s.x, +u.x, -f.x}, - {+s.y, +u.y, -f.y}, - {+s.z, +u.z, -f.z}, + +s.x, +s.y, +s.z, + +u.x, +u.y, +u.z, + -f.x, -f.y, -f.z, } tr := trace(m) @@ -614,26 +615,26 @@ quaternion_from_forward_and_up_f32 :: proc(forward, up: Vector3f32) -> Quaternio case tr > 0: S := 2 * math.sqrt(1 + tr) q.w = 0.25 * S - q.x = (m[2][1] - m[1][2]) / S - q.y = (m[0][2] - m[2][0]) / S - q.z = (m[1][0] - m[0][1]) / S - case (m[0][0] > m[1][1]) && (m[0][0] > m[2][2]): - S := 2 * math.sqrt(1 + m[0][0] - m[1][1] - m[2][2]) - q.w = (m[2][1] - m[1][2]) / S + q.x = (m[1, 2] - m[2, 1]) / S + q.y = (m[2, 0] - m[0, 2]) / S + q.z = (m[0, 1] - m[1, 0]) / S + case (m[0, 0] > m[1, 1]) && (m[0, 0] > m[2, 2]): + S := 2 * math.sqrt(1 + m[0, 0] - m[1, 1] - m[2, 2]) + q.w = (m[1, 2] - m[2, 1]) / S q.x = 0.25 * S - q.y = (m[0][1] + m[1][0]) / S - q.z = (m[0][2] + m[2][0]) / S - case m[1][1] > m[2][2]: - S := 2 * math.sqrt(1 + m[1][1] - m[0][0] - m[2][2]) - q.w = (m[0][2] - m[2][0]) / S - q.x = (m[0][1] + m[1][0]) / S + q.y = (m[1, 0] + m[0, 1]) / S + q.z = (m[2, 0] + m[0, 2]) / S + case m[1, 1] > m[2, 2]: + S := 2 * math.sqrt(1 + m[1, 1] - m[0, 0] - m[2, 2]) + q.w = (m[2, 0] - m[0, 2]) / S + q.x = (m[1, 0] + m[0, 1]) / S q.y = 0.25 * S - q.z = (m[1][2] + m[2][1]) / S + q.z = (m[2, 1] + m[1, 2]) / S case: - S := 2 * math.sqrt(1 + m[2][2] - m[0][0] - m[1][1]) - q.w = (m[1][0] - m[0][1]) / S - q.x = (m[0][2] - m[2][0]) / S - q.y = (m[1][2] + m[2][1]) / S + S := 2 * math.sqrt(1 + m[2, 2] - m[0, 0] - m[1, 1]) + q.w = (m[0, 1] - m[1, 0]) / S + q.x = (m[2, 0] - m[0, 2]) / S + q.y = (m[2, 1] + m[1, 2]) / S q.z = 0.25 * S } @@ -644,9 +645,9 @@ quaternion_from_forward_and_up_f64 :: proc(forward, up: Vector3f64) -> Quaternio s := normalize(cross(f, up)) u := cross(s, f) m := Matrix3f64{ - {+s.x, +u.x, -f.x}, - {+s.y, +u.y, -f.y}, - {+s.z, +u.z, -f.z}, + +s.x, +s.y, +s.z, + +u.x, +u.y, +u.z, + -f.x, -f.y, -f.z, } tr := trace(m) @@ -657,26 +658,26 @@ quaternion_from_forward_and_up_f64 :: proc(forward, up: Vector3f64) -> Quaternio case tr > 0: S := 2 * math.sqrt(1 + tr) q.w = 0.25 * S - q.x = (m[2][1] - m[1][2]) / S - q.y = (m[0][2] - m[2][0]) / S - q.z = (m[1][0] - m[0][1]) / S - case (m[0][0] > m[1][1]) && (m[0][0] > m[2][2]): - S := 2 * math.sqrt(1 + m[0][0] - m[1][1] - m[2][2]) - q.w = (m[2][1] - m[1][2]) / S + q.x = (m[1, 2] - m[2, 1]) / S + q.y = (m[2, 0] - m[0, 2]) / S + q.z = (m[0, 1] - m[1, 0]) / S + case (m[0, 0] > m[1, 1]) && (m[0, 0] > m[2, 2]): + S := 2 * math.sqrt(1 + m[0, 0] - m[1, 1] - m[2, 2]) + q.w = (m[1, 2] - m[2, 1]) / S q.x = 0.25 * S - q.y = (m[0][1] + m[1][0]) / S - q.z = (m[0][2] + m[2][0]) / S - case m[1][1] > m[2][2]: - S := 2 * math.sqrt(1 + m[1][1] - m[0][0] - m[2][2]) - q.w = (m[0][2] - m[2][0]) / S - q.x = (m[0][1] + m[1][0]) / S + q.y = (m[1, 0] + m[0, 1]) / S + q.z = (m[2, 0] + m[0, 2]) / S + case m[1, 1] > m[2, 2]: + S := 2 * math.sqrt(1 + m[1, 1] - m[0, 0] - m[2, 2]) + q.w = (m[2, 0] - m[0, 2]) / S + q.x = (m[1, 0] + m[0, 1]) / S q.y = 0.25 * S - q.z = (m[1][2] + m[2][1]) / S + q.z = (m[2, 1] + m[1, 2]) / S case: - S := 2 * math.sqrt(1 + m[2][2] - m[0][0] - m[1][1]) - q.w = (m[1][0] - m[0][1]) / S - q.x = (m[0][2] - m[2][0]) / S - q.y = (m[1][2] + m[2][1]) / S + S := 2 * math.sqrt(1 + m[2, 2] - m[0, 0] - m[1, 1]) + q.w = (m[0, 1] - m[1, 0]) / S + q.x = (m[2, 0] - m[0, 2]) / S + q.y = (m[2, 1] + m[1, 2]) / S q.z = 0.25 * S } @@ -842,23 +843,23 @@ quaternion_squad :: proc{ quaternion_from_matrix4_f16 :: proc(m: Matrix4f16) -> (q: Quaternionf16) { m3: Matrix3f16 = --- - m3[0][0], m3[0][1], m3[0][2] = m[0][0], m[0][1], m[0][2] - m3[1][0], m3[1][1], m3[1][2] = m[1][0], m[1][1], m[1][2] - m3[2][0], m3[2][1], m3[2][2] = m[2][0], m[2][1], m[2][2] + m3[0, 0], m3[1, 0], m3[2, 0] = m[0, 0], m[1, 0], m[2, 0] + m3[0, 1], m3[1, 1], m3[2, 1] = m[0, 1], m[1, 1], m[2, 1] + m3[0, 2], m3[1, 2], m3[2, 2] = m[0, 2], m[1, 2], m[2, 2] return quaternion_from_matrix3(m3) } quaternion_from_matrix4_f32 :: proc(m: Matrix4f32) -> (q: Quaternionf32) { m3: Matrix3f32 = --- - m3[0][0], m3[0][1], m3[0][2] = m[0][0], m[0][1], m[0][2] - m3[1][0], m3[1][1], m3[1][2] = m[1][0], m[1][1], m[1][2] - m3[2][0], m3[2][1], m3[2][2] = m[2][0], m[2][1], m[2][2] + m3[0, 0], m3[1, 0], m3[2, 0] = m[0, 0], m[1, 0], m[2, 0] + m3[0, 1], m3[1, 1], m3[2, 1] = m[0, 1], m[1, 1], m[2, 1] + m3[0, 2], m3[1, 2], m3[2, 2] = m[0, 2], m[1, 2], m[2, 2] return quaternion_from_matrix3(m3) } quaternion_from_matrix4_f64 :: proc(m: Matrix4f64) -> (q: Quaternionf64) { m3: Matrix3f64 = --- - m3[0][0], m3[0][1], m3[0][2] = m[0][0], m[0][1], m[0][2] - m3[1][0], m3[1][1], m3[1][2] = m[1][0], m[1][1], m[1][2] - m3[2][0], m3[2][1], m3[2][2] = m[2][0], m[2][1], m[2][2] + m3[0, 0], m3[1, 0], m3[2, 0] = m[0, 0], m[1, 0], m[2, 0] + m3[0, 1], m3[1, 1], m3[2, 1] = m[0, 1], m[1, 1], m[2, 1] + m3[0, 2], m3[1, 2], m3[2, 2] = m[0, 2], m[1, 2], m[2, 2] return quaternion_from_matrix3(m3) } quaternion_from_matrix4 :: proc{ @@ -869,10 +870,10 @@ quaternion_from_matrix4 :: proc{ quaternion_from_matrix3_f16 :: proc(m: Matrix3f16) -> (q: Quaternionf16) { - four_x_squared_minus_1 := m[0][0] - m[1][1] - m[2][2] - four_y_squared_minus_1 := m[1][1] - m[0][0] - m[2][2] - four_z_squared_minus_1 := m[2][2] - m[0][0] - m[1][1] - four_w_squared_minus_1 := m[0][0] + m[1][1] + m[2][2] + four_x_squared_minus_1 := m[0, 0] - m[1, 1] - m[2, 2] + four_y_squared_minus_1 := m[1, 1] - m[0, 0] - m[2, 2] + four_z_squared_minus_1 := m[2, 2] - m[0, 0] - m[1, 1] + four_w_squared_minus_1 := m[0, 0] + m[1, 1] + m[2, 2] biggest_index := 0 four_biggest_squared_minus_1 := four_w_squared_minus_1 @@ -896,32 +897,32 @@ quaternion_from_matrix3_f16 :: proc(m: Matrix3f16) -> (q: Quaternionf16) { switch biggest_index { case 0: q.w = biggest_val - q.x = (m[1][2] - m[2][1]) * mult - q.y = (m[2][0] - m[0][2]) * mult - q.z = (m[0][1] - m[1][0]) * mult + q.x = (m[2, 1] - m[1, 2]) * mult + q.y = (m[0, 2] - m[2, 0]) * mult + q.z = (m[1, 0] - m[0, 1]) * mult case 1: - q.w = (m[1][2] - m[2][1]) * mult + q.w = (m[2, 1] - m[1, 2]) * mult q.x = biggest_val - q.y = (m[0][1] + m[1][0]) * mult - q.z = (m[2][0] + m[0][2]) * mult + q.y = (m[1, 0] + m[0, 1]) * mult + q.z = (m[0, 2] + m[2, 0]) * mult case 2: - q.w = (m[2][0] - m[0][2]) * mult - q.x = (m[0][1] + m[1][0]) * mult + q.w = (m[0, 2] - m[2, 0]) * mult + q.x = (m[1, 0] + m[0, 1]) * mult q.y = biggest_val - q.z = (m[1][2] + m[2][1]) * mult + q.z = (m[2, 1] + m[1, 2]) * mult case 3: - q.w = (m[0][1] - m[1][0]) * mult - q.x = (m[2][0] + m[0][2]) * mult - q.y = (m[1][2] + m[2][1]) * mult + q.w = (m[1, 0] - m[0, 1]) * mult + q.x = (m[0, 2] + m[2, 0]) * mult + q.y = (m[2, 1] + m[1, 2]) * mult q.z = biggest_val } return } quaternion_from_matrix3_f32 :: proc(m: Matrix3f32) -> (q: Quaternionf32) { - four_x_squared_minus_1 := m[0][0] - m[1][1] - m[2][2] - four_y_squared_minus_1 := m[1][1] - m[0][0] - m[2][2] - four_z_squared_minus_1 := m[2][2] - m[0][0] - m[1][1] - four_w_squared_minus_1 := m[0][0] + m[1][1] + m[2][2] + four_x_squared_minus_1 := m[0, 0] - m[1, 1] - m[2, 2] + four_y_squared_minus_1 := m[1, 1] - m[0, 0] - m[2, 2] + four_z_squared_minus_1 := m[2, 2] - m[0, 0] - m[1, 1] + four_w_squared_minus_1 := m[0, 0] + m[1, 1] + m[2, 2] biggest_index := 0 four_biggest_squared_minus_1 := four_w_squared_minus_1 @@ -945,32 +946,32 @@ quaternion_from_matrix3_f32 :: proc(m: Matrix3f32) -> (q: Quaternionf32) { switch biggest_index { case 0: q.w = biggest_val - q.x = (m[1][2] - m[2][1]) * mult - q.y = (m[2][0] - m[0][2]) * mult - q.z = (m[0][1] - m[1][0]) * mult + q.x = (m[2, 1] - m[1, 2]) * mult + q.y = (m[0, 2] - m[2, 0]) * mult + q.z = (m[1, 0] - m[0, 1]) * mult case 1: - q.w = (m[1][2] - m[2][1]) * mult + q.w = (m[2, 1] - m[1, 2]) * mult q.x = biggest_val - q.y = (m[0][1] + m[1][0]) * mult - q.z = (m[2][0] + m[0][2]) * mult + q.y = (m[1, 0] + m[0, 1]) * mult + q.z = (m[0, 2] + m[2, 0]) * mult case 2: - q.w = (m[2][0] - m[0][2]) * mult - q.x = (m[0][1] + m[1][0]) * mult + q.w = (m[0, 2] - m[2, 0]) * mult + q.x = (m[1, 0] + m[0, 1]) * mult q.y = biggest_val - q.z = (m[1][2] + m[2][1]) * mult + q.z = (m[2, 1] + m[1, 2]) * mult case 3: - q.w = (m[0][1] - m[1][0]) * mult - q.x = (m[2][0] + m[0][2]) * mult - q.y = (m[1][2] + m[2][1]) * mult + q.w = (m[1, 0] - m[0, 1]) * mult + q.x = (m[0, 2] + m[2, 0]) * mult + q.y = (m[2, 1] + m[1, 2]) * mult q.z = biggest_val } return } quaternion_from_matrix3_f64 :: proc(m: Matrix3f64) -> (q: Quaternionf64) { - four_x_squared_minus_1 := m[0][0] - m[1][1] - m[2][2] - four_y_squared_minus_1 := m[1][1] - m[0][0] - m[2][2] - four_z_squared_minus_1 := m[2][2] - m[0][0] - m[1][1] - four_w_squared_minus_1 := m[0][0] + m[1][1] + m[2][2] + four_x_squared_minus_1 := m[0, 0] - m[1, 1] - m[2, 2] + four_y_squared_minus_1 := m[1, 1] - m[0, 0] - m[2, 2] + four_z_squared_minus_1 := m[2, 2] - m[0, 0] - m[1, 1] + four_w_squared_minus_1 := m[0, 0] + m[1, 1] + m[2, 2] biggest_index := 0 four_biggest_squared_minus_1 := four_w_squared_minus_1 @@ -994,23 +995,23 @@ quaternion_from_matrix3_f64 :: proc(m: Matrix3f64) -> (q: Quaternionf64) { switch biggest_index { case 0: q.w = biggest_val - q.x = (m[1][2] - m[2][1]) * mult - q.y = (m[2][0] - m[0][2]) * mult - q.z = (m[0][1] - m[1][0]) * mult + q.x = (m[2, 1] - m[1, 2]) * mult + q.y = (m[0, 2] - m[2, 0]) * mult + q.z = (m[1, 0] - m[0, 1]) * mult case 1: - q.w = (m[1][2] - m[2][1]) * mult + q.w = (m[2, 1] - m[1, 2]) * mult q.x = biggest_val - q.y = (m[0][1] + m[1][0]) * mult - q.z = (m[2][0] + m[0][2]) * mult + q.y = (m[1, 0] + m[0, 1]) * mult + q.z = (m[0, 2] + m[2, 0]) * mult case 2: - q.w = (m[2][0] - m[0][2]) * mult - q.x = (m[0][1] + m[1][0]) * mult + q.w = (m[0, 2] - m[2, 0]) * mult + q.x = (m[1, 0] + m[0, 1]) * mult q.y = biggest_val - q.z = (m[1][2] + m[2][1]) * mult + q.z = (m[2, 1] + m[1, 2]) * mult case 3: - q.w = (m[0][1] - m[1][0]) * mult - q.x = (m[2][0] + m[0][2]) * mult - q.y = (m[1][2] + m[2][1]) * mult + q.w = (m[1, 0] - m[0, 1]) * mult + q.x = (m[0, 2] + m[2, 0]) * mult + q.y = (m[2, 1] + m[1, 2]) * mult q.z = biggest_val } return @@ -1093,30 +1094,30 @@ quaternion_between_two_vector3 :: proc{ matrix2_inverse_transpose_f16 :: proc(m: Matrix2f16) -> (c: Matrix2f16) { - d := m[0][0]*m[1][1] - m[1][0]*m[0][1] + d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] id := 1.0/d - c[0][0] = +m[1][1] * id - c[0][1] = -m[0][1] * id - c[1][0] = -m[1][0] * id - c[1][1] = +m[0][0] * id + c[0, 0] = +m[1, 1] * id + c[1, 0] = -m[1, 0] * id + c[0, 1] = -m[0, 1] * id + c[1, 1] = +m[0, 0] * id return c } matrix2_inverse_transpose_f32 :: proc(m: Matrix2f32) -> (c: Matrix2f32) { - d := m[0][0]*m[1][1] - m[1][0]*m[0][1] + d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] id := 1.0/d - c[0][0] = +m[1][1] * id - c[0][1] = -m[0][1] * id - c[1][0] = -m[1][0] * id - c[1][1] = +m[0][0] * id + c[0, 0] = +m[1, 1] * id + c[1, 0] = -m[1, 0] * id + c[0, 1] = -m[0, 1] * id + c[1, 1] = +m[0, 0] * id return c } matrix2_inverse_transpose_f64 :: proc(m: Matrix2f64) -> (c: Matrix2f64) { - d := m[0][0]*m[1][1] - m[1][0]*m[0][1] + d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] id := 1.0/d - c[0][0] = +m[1][1] * id - c[0][1] = -m[0][1] * id - c[1][0] = -m[1][0] * id - c[1][1] = +m[0][0] * id + c[0, 0] = +m[1, 1] * id + c[1, 0] = -m[1, 0] * id + c[0, 1] = -m[0, 1] * id + c[1, 1] = +m[0, 0] * id return c } matrix2_inverse_transpose :: proc{ @@ -1127,13 +1128,13 @@ matrix2_inverse_transpose :: proc{ matrix2_determinant_f16 :: proc(m: Matrix2f16) -> f16 { - return m[0][0]*m[1][1] - m[1][0]*m[0][1] + return m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] } matrix2_determinant_f32 :: proc(m: Matrix2f32) -> f32 { - return m[0][0]*m[1][1] - m[1][0]*m[0][1] + return m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] } matrix2_determinant_f64 :: proc(m: Matrix2f64) -> f64 { - return m[0][0]*m[1][1] - m[1][0]*m[0][1] + return m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] } matrix2_determinant :: proc{ matrix2_determinant_f16, @@ -1143,30 +1144,30 @@ matrix2_determinant :: proc{ matrix2_inverse_f16 :: proc(m: Matrix2f16) -> (c: Matrix2f16) { - d := m[0][0]*m[1][1] - m[1][0]*m[0][1] + d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] id := 1.0/d - c[0][0] = +m[1][1] * id - c[1][0] = -m[0][1] * id - c[0][1] = -m[1][0] * id - c[1][1] = +m[0][0] * id + c[0, 0] = +m[1, 1] * id + c[0, 1] = -m[1, 0] * id + c[1, 0] = -m[0, 1] * id + c[1, 1] = +m[0, 0] * id return c } matrix2_inverse_f32 :: proc(m: Matrix2f32) -> (c: Matrix2f32) { - d := m[0][0]*m[1][1] - m[1][0]*m[0][1] + d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] id := 1.0/d - c[0][0] = +m[1][1] * id - c[1][0] = -m[0][1] * id - c[0][1] = -m[1][0] * id - c[1][1] = +m[0][0] * id + c[0, 0] = +m[1, 1] * id + c[0, 1] = -m[1, 0] * id + c[1, 0] = -m[0, 1] * id + c[1, 1] = +m[0, 0] * id return c } matrix2_inverse_f64 :: proc(m: Matrix2f64) -> (c: Matrix2f64) { - d := m[0][0]*m[1][1] - m[1][0]*m[0][1] + d := m[0, 0]*m[1, 1] - m[0, 1]*m[1, 0] id := 1.0/d - c[0][0] = +m[1][1] * id - c[1][0] = -m[0][1] * id - c[0][1] = -m[1][0] * id - c[1][1] = +m[0][0] * id + c[0, 0] = +m[1, 1] * id + c[0, 1] = -m[1, 0] * id + c[1, 0] = -m[0, 1] * id + c[1, 1] = +m[0, 0] * id return c } matrix2_inverse :: proc{ @@ -1177,24 +1178,24 @@ matrix2_inverse :: proc{ matrix2_adjoint_f16 :: proc(m: Matrix2f16) -> (c: Matrix2f16) { - c[0][0] = +m[1][1] - c[0][1] = -m[1][0] - c[1][0] = -m[0][1] - c[1][1] = +m[0][0] + c[0, 0] = +m[1, 1] + c[1, 0] = -m[0, 1] + c[0, 1] = -m[1, 0] + c[1, 1] = +m[0, 0] return c } matrix2_adjoint_f32 :: proc(m: Matrix2f32) -> (c: Matrix2f32) { - c[0][0] = +m[1][1] - c[0][1] = -m[1][0] - c[1][0] = -m[0][1] - c[1][1] = +m[0][0] + c[0, 0] = +m[1, 1] + c[1, 0] = -m[0, 1] + c[0, 1] = -m[1, 0] + c[1, 1] = +m[0, 0] return c } matrix2_adjoint_f64 :: proc(m: Matrix2f64) -> (c: Matrix2f64) { - c[0][0] = +m[1][1] - c[0][1] = -m[1][0] - c[1][0] = -m[0][1] - c[1][1] = +m[0][0] + c[0, 0] = +m[1, 1] + c[1, 0] = -m[0, 1] + c[0, 1] = -m[1, 0] + c[1, 1] = +m[0, 0] return c } matrix2_adjoint :: proc{ @@ -1215,17 +1216,17 @@ matrix3_from_quaternion_f16 :: proc(q: Quaternionf16) -> (m: Matrix3f16) { qwy := q.w * q.y qwz := q.w * q.z - m[0][0] = 1 - 2 * (qyy + qzz) - m[0][1] = 2 * (qxy + qwz) - m[0][2] = 2 * (qxz - qwy) + m[0, 0] = 1 - 2 * (qyy + qzz) + m[1, 0] = 2 * (qxy + qwz) + m[2, 0] = 2 * (qxz - qwy) - m[1][0] = 2 * (qxy - qwz) - m[1][1] = 1 - 2 * (qxx + qzz) - m[1][2] = 2 * (qyz + qwx) + m[0, 1] = 2 * (qxy - qwz) + m[1, 1] = 1 - 2 * (qxx + qzz) + m[2, 1] = 2 * (qyz + qwx) - m[2][0] = 2 * (qxz + qwy) - m[2][1] = 2 * (qyz - qwx) - m[2][2] = 1 - 2 * (qxx + qyy) + m[0, 2] = 2 * (qxz + qwy) + m[1, 2] = 2 * (qyz - qwx) + m[2, 2] = 1 - 2 * (qxx + qyy) return m } matrix3_from_quaternion_f32 :: proc(q: Quaternionf32) -> (m: Matrix3f32) { @@ -1239,17 +1240,17 @@ matrix3_from_quaternion_f32 :: proc(q: Quaternionf32) -> (m: Matrix3f32) { qwy := q.w * q.y qwz := q.w * q.z - m[0][0] = 1 - 2 * (qyy + qzz) - m[0][1] = 2 * (qxy + qwz) - m[0][2] = 2 * (qxz - qwy) + m[0, 0] = 1 - 2 * (qyy + qzz) + m[1, 0] = 2 * (qxy + qwz) + m[2, 0] = 2 * (qxz - qwy) - m[1][0] = 2 * (qxy - qwz) - m[1][1] = 1 - 2 * (qxx + qzz) - m[1][2] = 2 * (qyz + qwx) + m[0, 1] = 2 * (qxy - qwz) + m[1, 1] = 1 - 2 * (qxx + qzz) + m[2, 1] = 2 * (qyz + qwx) - m[2][0] = 2 * (qxz + qwy) - m[2][1] = 2 * (qyz - qwx) - m[2][2] = 1 - 2 * (qxx + qyy) + m[0, 2] = 2 * (qxz + qwy) + m[1, 2] = 2 * (qyz - qwx) + m[2, 2] = 1 - 2 * (qxx + qyy) return m } matrix3_from_quaternion_f64 :: proc(q: Quaternionf64) -> (m: Matrix3f64) { @@ -1263,17 +1264,17 @@ matrix3_from_quaternion_f64 :: proc(q: Quaternionf64) -> (m: Matrix3f64) { qwy := q.w * q.y qwz := q.w * q.z - m[0][0] = 1 - 2 * (qyy + qzz) - m[0][1] = 2 * (qxy + qwz) - m[0][2] = 2 * (qxz - qwy) + m[0, 0] = 1 - 2 * (qyy + qzz) + m[1, 0] = 2 * (qxy + qwz) + m[2, 0] = 2 * (qxz - qwy) - m[1][0] = 2 * (qxy - qwz) - m[1][1] = 1 - 2 * (qxx + qzz) - m[1][2] = 2 * (qyz + qwx) + m[0, 1] = 2 * (qxy - qwz) + m[1, 1] = 1 - 2 * (qxx + qzz) + m[2, 1] = 2 * (qyz + qwx) - m[2][0] = 2 * (qxz + qwy) - m[2][1] = 2 * (qyz - qwx) - m[2][2] = 1 - 2 * (qxx + qyy) + m[0, 2] = 2 * (qxz + qwy) + m[1, 2] = 2 * (qyz - qwx) + m[2, 2] = 1 - 2 * (qxx + qyy) return m } matrix3_from_quaternion :: proc{ @@ -1300,21 +1301,21 @@ matrix3_inverse :: proc{ matrix3_determinant_f16 :: proc(m: Matrix3f16) -> f16 { - a := +m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) - b := -m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) - c := +m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]) + a := +m[0, 0] * (m[1, 1] * m[2, 2] - m[1, 2] * m[2, 1]) + b := -m[0, 1] * (m[1, 0] * m[2, 2] - m[1, 2] * m[2, 0]) + c := +m[0, 2] * (m[1, 0] * m[2, 1] - m[1, 1] * m[2, 0]) return a + b + c } matrix3_determinant_f32 :: proc(m: Matrix3f32) -> f32 { - a := +m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) - b := -m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) - c := +m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]) + a := +m[0, 0] * (m[1, 1] * m[2, 2] - m[1, 2] * m[2, 1]) + b := -m[0, 1] * (m[1, 0] * m[2, 2] - m[1, 2] * m[2, 0]) + c := +m[0, 2] * (m[1, 0] * m[2, 1] - m[1, 1] * m[2, 0]) return a + b + c } matrix3_determinant_f64 :: proc(m: Matrix3f64) -> f64 { - a := +m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) - b := -m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) - c := +m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]) + a := +m[0, 0] * (m[1, 1] * m[2, 2] - m[1, 2] * m[2, 1]) + b := -m[0, 1] * (m[1, 0] * m[2, 2] - m[1, 2] * m[2, 0]) + c := +m[0, 2] * (m[1, 0] * m[2, 1] - m[1, 1] * m[2, 0]) return a + b + c } matrix3_determinant :: proc{ @@ -1325,39 +1326,39 @@ matrix3_determinant :: proc{ matrix3_adjoint_f16 :: proc(m: Matrix3f16) -> (adjoint: Matrix3f16) { - adjoint[0][0] = +(m[1][1] * m[2][2] - m[1][2] * m[2][1]) - adjoint[1][0] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]) - adjoint[2][0] = +(m[0][1] * m[1][2] - m[0][2] * m[1][1]) - adjoint[0][1] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]) - adjoint[1][1] = +(m[0][0] * m[2][2] - m[0][2] * m[2][0]) - adjoint[2][1] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]) - adjoint[0][2] = +(m[1][0] * m[2][1] - m[1][1] * m[2][0]) - adjoint[1][2] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]) - adjoint[2][2] = +(m[0][0] * m[1][1] - m[0][1] * m[1][0]) + adjoint[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + adjoint[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + adjoint[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + adjoint[1, 0] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + adjoint[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + adjoint[1, 2] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + adjoint[2, 0] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + adjoint[2, 1] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + adjoint[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) return adjoint } matrix3_adjoint_f32 :: proc(m: Matrix3f32) -> (adjoint: Matrix3f32) { - adjoint[0][0] = +(m[1][1] * m[2][2] - m[1][2] * m[2][1]) - adjoint[1][0] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]) - adjoint[2][0] = +(m[0][1] * m[1][2] - m[0][2] * m[1][1]) - adjoint[0][1] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]) - adjoint[1][1] = +(m[0][0] * m[2][2] - m[0][2] * m[2][0]) - adjoint[2][1] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]) - adjoint[0][2] = +(m[1][0] * m[2][1] - m[1][1] * m[2][0]) - adjoint[1][2] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]) - adjoint[2][2] = +(m[0][0] * m[1][1] - m[0][1] * m[1][0]) + adjoint[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + adjoint[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + adjoint[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + adjoint[1, 0] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + adjoint[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + adjoint[1, 2] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + adjoint[2, 0] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + adjoint[2, 1] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + adjoint[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) return adjoint } matrix3_adjoint_f64 :: proc(m: Matrix3f64) -> (adjoint: Matrix3f64) { - adjoint[0][0] = +(m[1][1] * m[2][2] - m[1][2] * m[2][1]) - adjoint[1][0] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]) - adjoint[2][0] = +(m[0][1] * m[1][2] - m[0][2] * m[1][1]) - adjoint[0][1] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]) - adjoint[1][1] = +(m[0][0] * m[2][2] - m[0][2] * m[2][0]) - adjoint[2][1] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]) - adjoint[0][2] = +(m[1][0] * m[2][1] - m[1][1] * m[2][0]) - adjoint[1][2] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]) - adjoint[2][2] = +(m[0][0] * m[1][1] - m[0][1] * m[1][0]) + adjoint[0, 0] = +(m[1, 1] * m[2, 2] - m[2, 1] * m[1, 2]) + adjoint[0, 1] = -(m[1, 0] * m[2, 2] - m[2, 0] * m[1, 2]) + adjoint[0, 2] = +(m[1, 0] * m[2, 1] - m[2, 0] * m[1, 1]) + adjoint[1, 0] = -(m[0, 1] * m[2, 2] - m[2, 1] * m[0, 2]) + adjoint[1, 1] = +(m[0, 0] * m[2, 2] - m[2, 0] * m[0, 2]) + adjoint[1, 2] = -(m[0, 0] * m[2, 1] - m[2, 0] * m[0, 1]) + adjoint[2, 0] = +(m[0, 1] * m[1, 2] - m[1, 1] * m[0, 2]) + adjoint[2, 1] = -(m[0, 0] * m[1, 2] - m[1, 0] * m[0, 2]) + adjoint[2, 2] = +(m[0, 0] * m[1, 1] - m[1, 0] * m[0, 1]) return adjoint } matrix3_adjoint :: proc{ @@ -1369,37 +1370,13 @@ matrix3_adjoint :: proc{ matrix3_inverse_transpose_f16 :: proc(m: Matrix3f16) -> (inverse_transpose: Matrix3f16) { - adjoint := matrix3_adjoint(m) - determinant := matrix3_determinant(m) - inv_determinant := 1.0 / determinant - for i in 0..<3 { - for j in 0..<3 { - inverse_transpose[i][j] = adjoint[i][j] * inv_determinant - } - } - return + return builtin.inverse_transpose(m) } matrix3_inverse_transpose_f32 :: proc(m: Matrix3f32) -> (inverse_transpose: Matrix3f32) { - adjoint := matrix3_adjoint(m) - determinant := matrix3_determinant(m) - inv_determinant := 1.0 / determinant - for i in 0..<3 { - for j in 0..<3 { - inverse_transpose[i][j] = adjoint[i][j] * inv_determinant - } - } - return + return builtin.inverse_transpose(m) } matrix3_inverse_transpose_f64 :: proc(m: Matrix3f64) -> (inverse_transpose: Matrix3f64) { - adjoint := matrix3_adjoint(m) - determinant := matrix3_determinant(m) - inv_determinant := 1.0 / determinant - for i in 0..<3 { - for j in 0..<3 { - inverse_transpose[i][j] = adjoint[i][j] * inv_determinant - } - } - return + return builtin.inverse_transpose(m) } matrix3_inverse_transpose :: proc{ matrix3_inverse_transpose_f16, @@ -1409,21 +1386,21 @@ matrix3_inverse_transpose :: proc{ matrix3_scale_f16 :: proc(s: Vector3f16) -> (m: Matrix3f16) { - m[0][0] = s[0] - m[1][1] = s[1] - m[2][2] = s[2] + m[0, 0] = s[0] + m[1, 1] = s[1] + m[2, 2] = s[2] return m } matrix3_scale_f32 :: proc(s: Vector3f32) -> (m: Matrix3f32) { - m[0][0] = s[0] - m[1][1] = s[1] - m[2][2] = s[2] + m[0, 0] = s[0] + m[1, 1] = s[1] + m[2, 2] = s[2] return m } matrix3_scale_f64 :: proc(s: Vector3f64) -> (m: Matrix3f64) { - m[0][0] = s[0] - m[1][1] = s[1] - m[2][2] = s[2] + m[0, 0] = s[0] + m[1, 1] = s[1] + m[2, 2] = s[2] return m } matrix3_scale :: proc{ @@ -1440,17 +1417,17 @@ matrix3_rotate_f16 :: proc(angle_radians: f16, v: Vector3f16) -> (rot: Matrix3f1 a := normalize(v) t := a * (1-c) - rot[0][0] = c + t[0]*a[0] - rot[0][1] = 0 + t[0]*a[1] + s*a[2] - rot[0][2] = 0 + t[0]*a[2] - s*a[1] + rot[0, 0] = c + t[0]*a[0] + rot[1, 0] = 0 + t[0]*a[1] + s*a[2] + rot[2, 0] = 0 + t[0]*a[2] - s*a[1] - rot[1][0] = 0 + t[1]*a[0] - s*a[2] - rot[1][1] = c + t[1]*a[1] - rot[1][2] = 0 + t[1]*a[2] + s*a[0] + rot[0, 1] = 0 + t[1]*a[0] - s*a[2] + rot[1, 1] = c + t[1]*a[1] + rot[2, 1] = 0 + t[1]*a[2] + s*a[0] - rot[2][0] = 0 + t[2]*a[0] + s*a[1] - rot[2][1] = 0 + t[2]*a[1] - s*a[0] - rot[2][2] = c + t[2]*a[2] + rot[0, 2] = 0 + t[2]*a[0] + s*a[1] + rot[1, 2] = 0 + t[2]*a[1] - s*a[0] + rot[2, 2] = c + t[2]*a[2] return rot } @@ -1461,17 +1438,17 @@ matrix3_rotate_f32 :: proc(angle_radians: f32, v: Vector3f32) -> (rot: Matrix3f3 a := normalize(v) t := a * (1-c) - rot[0][0] = c + t[0]*a[0] - rot[0][1] = 0 + t[0]*a[1] + s*a[2] - rot[0][2] = 0 + t[0]*a[2] - s*a[1] + rot[0, 0] = c + t[0]*a[0] + rot[1, 0] = 0 + t[0]*a[1] + s*a[2] + rot[2, 0] = 0 + t[0]*a[2] - s*a[1] - rot[1][0] = 0 + t[1]*a[0] - s*a[2] - rot[1][1] = c + t[1]*a[1] - rot[1][2] = 0 + t[1]*a[2] + s*a[0] + rot[0, 1] = 0 + t[1]*a[0] - s*a[2] + rot[1, 1] = c + t[1]*a[1] + rot[2, 1] = 0 + t[1]*a[2] + s*a[0] - rot[2][0] = 0 + t[2]*a[0] + s*a[1] - rot[2][1] = 0 + t[2]*a[1] - s*a[0] - rot[2][2] = c + t[2]*a[2] + rot[0, 2] = 0 + t[2]*a[0] + s*a[1] + rot[1, 2] = 0 + t[2]*a[1] - s*a[0] + rot[2, 2] = c + t[2]*a[2] return rot } @@ -1482,17 +1459,17 @@ matrix3_rotate_f64 :: proc(angle_radians: f64, v: Vector3f64) -> (rot: Matrix3f6 a := normalize(v) t := a * (1-c) - rot[0][0] = c + t[0]*a[0] - rot[0][1] = 0 + t[0]*a[1] + s*a[2] - rot[0][2] = 0 + t[0]*a[2] - s*a[1] + rot[0, 0] = c + t[0]*a[0] + rot[1, 0] = 0 + t[0]*a[1] + s*a[2] + rot[2, 0] = 0 + t[0]*a[2] - s*a[1] - rot[1][0] = 0 + t[1]*a[0] - s*a[2] - rot[1][1] = c + t[1]*a[1] - rot[1][2] = 0 + t[1]*a[2] + s*a[0] + rot[0, 1] = 0 + t[1]*a[0] - s*a[2] + rot[1, 1] = c + t[1]*a[1] + rot[2, 1] = 0 + t[1]*a[2] + s*a[0] - rot[2][0] = 0 + t[2]*a[0] + s*a[1] - rot[2][1] = 0 + t[2]*a[1] - s*a[0] - rot[2][2] = c + t[2]*a[2] + rot[0, 2] = 0 + t[2]*a[0] + s*a[1] + rot[1, 2] = 0 + t[2]*a[1] - s*a[0] + rot[2, 2] = c + t[2]*a[2] return rot } @@ -1508,9 +1485,9 @@ matrix3_look_at_f16 :: proc(eye, centre, up: Vector3f16) -> Matrix3f16 { s := normalize(cross(f, up)) u := cross(s, f) return Matrix3f16{ - {+s.x, +u.x, -f.x}, - {+s.y, +u.y, -f.y}, - {+s.z, +u.z, -f.z}, + +s.x, +s.y, +s.z, + +u.x, +u.y, +u.z, + -f.x, -f.y, -f.z, } } matrix3_look_at_f32 :: proc(eye, centre, up: Vector3f32) -> Matrix3f32 { @@ -1518,9 +1495,9 @@ matrix3_look_at_f32 :: proc(eye, centre, up: Vector3f32) -> Matrix3f32 { s := normalize(cross(f, up)) u := cross(s, f) return Matrix3f32{ - {+s.x, +u.x, -f.x}, - {+s.y, +u.y, -f.y}, - {+s.z, +u.z, -f.z}, + +s.x, +s.y, +s.z, + +u.x, +u.y, +u.z, + -f.x, -f.y, -f.z, } } matrix3_look_at_f64 :: proc(eye, centre, up: Vector3f64) -> Matrix3f64 { @@ -1528,9 +1505,9 @@ matrix3_look_at_f64 :: proc(eye, centre, up: Vector3f64) -> Matrix3f64 { s := normalize(cross(f, up)) u := cross(s, f) return Matrix3f64{ - {+s.x, +u.x, -f.x}, - {+s.y, +u.y, -f.y}, - {+s.z, +u.z, -f.z}, + +s.x, +s.y, +s.z, + +u.x, +u.y, +u.z, + -f.x, -f.y, -f.z, } } matrix3_look_at :: proc{ @@ -1551,19 +1528,19 @@ matrix4_from_quaternion_f16 :: proc(q: Quaternionf16) -> (m: Matrix4f16) { qwy := q.w * q.y qwz := q.w * q.z - m[0][0] = 1 - 2 * (qyy + qzz) - m[0][1] = 2 * (qxy + qwz) - m[0][2] = 2 * (qxz - qwy) + m[0, 0] = 1 - 2 * (qyy + qzz) + m[1, 0] = 2 * (qxy + qwz) + m[2, 0] = 2 * (qxz - qwy) - m[1][0] = 2 * (qxy - qwz) - m[1][1] = 1 - 2 * (qxx + qzz) - m[1][2] = 2 * (qyz + qwx) + m[0, 1] = 2 * (qxy - qwz) + m[1, 1] = 1 - 2 * (qxx + qzz) + m[2, 1] = 2 * (qyz + qwx) - m[2][0] = 2 * (qxz + qwy) - m[2][1] = 2 * (qyz - qwx) - m[2][2] = 1 - 2 * (qxx + qyy) + m[0, 2] = 2 * (qxz + qwy) + m[1, 2] = 2 * (qyz - qwx) + m[2, 2] = 1 - 2 * (qxx + qyy) - m[3][3] = 1 + m[3, 3] = 1 return m } @@ -1578,19 +1555,19 @@ matrix4_from_quaternion_f32 :: proc(q: Quaternionf32) -> (m: Matrix4f32) { qwy := q.w * q.y qwz := q.w * q.z - m[0][0] = 1 - 2 * (qyy + qzz) - m[0][1] = 2 * (qxy + qwz) - m[0][2] = 2 * (qxz - qwy) + m[0, 0] = 1 - 2 * (qyy + qzz) + m[1, 0] = 2 * (qxy + qwz) + m[2, 0] = 2 * (qxz - qwy) - m[1][0] = 2 * (qxy - qwz) - m[1][1] = 1 - 2 * (qxx + qzz) - m[1][2] = 2 * (qyz + qwx) + m[0, 1] = 2 * (qxy - qwz) + m[1, 1] = 1 - 2 * (qxx + qzz) + m[2, 1] = 2 * (qyz + qwx) - m[2][0] = 2 * (qxz + qwy) - m[2][1] = 2 * (qyz - qwx) - m[2][2] = 1 - 2 * (qxx + qyy) + m[0, 2] = 2 * (qxz + qwy) + m[1, 2] = 2 * (qyz - qwx) + m[2, 2] = 1 - 2 * (qxx + qyy) - m[3][3] = 1 + m[3, 3] = 1 return m } @@ -1605,19 +1582,19 @@ matrix4_from_quaternion_f64 :: proc(q: Quaternionf64) -> (m: Matrix4f64) { qwy := q.w * q.y qwz := q.w * q.z - m[0][0] = 1 - 2 * (qyy + qzz) - m[0][1] = 2 * (qxy + qwz) - m[0][2] = 2 * (qxz - qwy) + m[0, 0] = 1 - 2 * (qyy + qzz) + m[1, 0] = 2 * (qxy + qwz) + m[2, 0] = 2 * (qxz - qwy) - m[1][0] = 2 * (qxy - qwz) - m[1][1] = 1 - 2 * (qxx + qzz) - m[1][2] = 2 * (qyz + qwx) + m[0, 1] = 2 * (qxy - qwz) + m[1, 1] = 1 - 2 * (qxx + qzz) + m[2, 1] = 2 * (qyz + qwx) - m[2][0] = 2 * (qxz + qwy) - m[2][1] = 2 * (qyz - qwx) - m[2][2] = 1 - 2 * (qxx + qyy) + m[0, 2] = 2 * (qxz + qwy) + m[1, 2] = 2 * (qyz - qwx) + m[2, 2] = 1 - 2 * (qxx + qyy) - m[3][3] = 1 + m[3, 3] = 1 return m } @@ -1992,10 +1969,10 @@ matrix4_look_at_f16 :: proc(eye, centre, up: Vector3f16, flip_z_axis := true) -> fe := dot(f, eye) return { - {+s.x, +u.x, -f.x, 0}, - {+s.y, +u.y, -f.y, 0}, - {+s.z, +u.z, -f.z, 0}, - {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + +s.x, +s.y, +s.z, -dot(s, eye), + +u.x, +u.y, +u.z, -dot(u, eye), + -f.x, -f.y, -f.z, +fe if flip_z_axis else -fe, + 0, 0, 0, 1, } } matrix4_look_at_f32 :: proc(eye, centre, up: Vector3f32, flip_z_axis := true) -> (m: Matrix4f32) { @@ -2006,10 +1983,10 @@ matrix4_look_at_f32 :: proc(eye, centre, up: Vector3f32, flip_z_axis := true) -> fe := dot(f, eye) return { - {+s.x, +u.x, -f.x, 0}, - {+s.y, +u.y, -f.y, 0}, - {+s.z, +u.z, -f.z, 0}, - {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + +s.x, +s.y, +s.z, -dot(s, eye), + +u.x, +u.y, +u.z, -dot(u, eye), + -f.x, -f.y, -f.z, +fe if flip_z_axis else -fe, + 0, 0, 0, 1, } } matrix4_look_at_f64 :: proc(eye, centre, up: Vector3f64, flip_z_axis := true) -> (m: Matrix4f64) { @@ -2020,10 +1997,10 @@ matrix4_look_at_f64 :: proc(eye, centre, up: Vector3f64, flip_z_axis := true) -> fe := dot(f, eye) return { - {+s.x, +u.x, -f.x, 0}, - {+s.y, +u.y, -f.y, 0}, - {+s.z, +u.z, -f.z, 0}, - {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + +s.x, +s.y, +s.z, -dot(s, eye), + +u.x, +u.y, +u.z, -dot(u, eye), + -f.x, -f.y, -f.z, +fe if flip_z_axis else -fe, + 0, 0, 0, 1, } } matrix4_look_at :: proc{ @@ -2041,10 +2018,10 @@ matrix4_look_at_from_fru_f16 :: proc(eye, f, r, u: Vector3f16, flip_z_axis := tr fe := dot(f, eye) return { - {+s.x, +u.x, -f.x, 0}, - {+s.y, +u.y, -f.y, 0}, - {+s.z, +u.z, -f.z, 0}, - {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + +s.x, +s.y, +s.z, -dot(s, eye), + +u.x, +u.y, +u.z, -dot(u, eye), + -f.x, -f.y, -f.z, +fe if flip_z_axis else -fe, + 0, 0, 0, 1, } } matrix4_look_at_from_fru_f32 :: proc(eye, f, r, u: Vector3f32, flip_z_axis := true) -> (m: Matrix4f32) { @@ -2055,10 +2032,10 @@ matrix4_look_at_from_fru_f32 :: proc(eye, f, r, u: Vector3f32, flip_z_axis := tr fe := dot(f, eye) return { - {+s.x, +u.x, -f.x, 0}, - {+s.y, +u.y, -f.y, 0}, - {+s.z, +u.z, -f.z, 0}, - {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + +s.x, +s.y, +s.z, -dot(s, eye), + +u.x, +u.y, +u.z, -dot(u, eye), + -f.x, -f.y, -f.z, +fe if flip_z_axis else -fe, + 0, 0, 0, 1, } } matrix4_look_at_from_fru_f64 :: proc(eye, f, r, u: Vector3f64, flip_z_axis := true) -> (m: Matrix4f64) { @@ -2069,10 +2046,10 @@ matrix4_look_at_from_fru_f64 :: proc(eye, f, r, u: Vector3f64, flip_z_axis := tr fe := dot(f, eye) return { - {+s.x, +u.x, -f.x, 0}, - {+s.y, +u.y, -f.y, 0}, - {+s.z, +u.z, -f.z, 0}, - {-dot(s, eye), -dot(u, eye), +fe if flip_z_axis else -fe, 1}, + +s.x, +s.y, +s.z, -dot(s, eye), + +u.x, +u.y, +u.z, -dot(u, eye), + -f.x, -f.y, -f.z, +fe if flip_z_axis else -fe, + 0, 0, 0, 1, } } matrix4_look_at_from_fru :: proc{ @@ -2084,11 +2061,11 @@ matrix4_look_at_from_fru :: proc{ matrix4_perspective_f16 :: proc(fovy, aspect, near, far: f16, flip_z_axis := true) -> (m: Matrix4f16) { tan_half_fovy := math.tan(0.5 * fovy) - m[0][0] = 1 / (aspect*tan_half_fovy) - m[1][1] = 1 / (tan_half_fovy) - m[2][2] = +(far + near) / (far - near) - m[2][3] = +1 - m[3][2] = -2*far*near / (far - near) + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = +(far + near) / (far - near) + m[3, 2] = +1 + m[2, 3] = -2*far*near / (far - near) if flip_z_axis { m[2] = -m[2] @@ -2098,11 +2075,11 @@ matrix4_perspective_f16 :: proc(fovy, aspect, near, far: f16, flip_z_axis := tru } matrix4_perspective_f32 :: proc(fovy, aspect, near, far: f32, flip_z_axis := true) -> (m: Matrix4f32) { tan_half_fovy := math.tan(0.5 * fovy) - m[0][0] = 1 / (aspect*tan_half_fovy) - m[1][1] = 1 / (tan_half_fovy) - m[2][2] = +(far + near) / (far - near) - m[2][3] = +1 - m[3][2] = -2*far*near / (far - near) + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = +(far + near) / (far - near) + m[3, 2] = +1 + m[2, 3] = -2*far*near / (far - near) if flip_z_axis { m[2] = -m[2] @@ -2112,11 +2089,11 @@ matrix4_perspective_f32 :: proc(fovy, aspect, near, far: f32, flip_z_axis := tru } matrix4_perspective_f64 :: proc(fovy, aspect, near, far: f64, flip_z_axis := true) -> (m: Matrix4f64) { tan_half_fovy := math.tan(0.5 * fovy) - m[0][0] = 1 / (aspect*tan_half_fovy) - m[1][1] = 1 / (tan_half_fovy) - m[2][2] = +(far + near) / (far - near) - m[2][3] = +1 - m[3][2] = -2*far*near / (far - near) + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = +(far + near) / (far - near) + m[3, 2] = +1 + m[2, 3] = -2*far*near / (far - near) if flip_z_axis { m[2] = -m[2] @@ -2133,13 +2110,13 @@ matrix4_perspective :: proc{ matrix_ortho3d_f16 :: proc(left, right, bottom, top, near, far: f16, flip_z_axis := true) -> (m: Matrix4f16) { - m[0][0] = +2 / (right - left) - m[1][1] = +2 / (top - bottom) - m[2][2] = +2 / (far - near) - m[3][0] = -(right + left) / (right - left) - m[3][1] = -(top + bottom) / (top - bottom) - m[3][2] = -(far + near) / (far- near) - m[3][3] = 1 + m[0, 0] = +2 / (right - left) + m[1, 1] = +2 / (top - bottom) + m[2, 2] = +2 / (far - near) + m[0, 3] = -(right + left) / (right - left) + m[1, 3] = -(top + bottom) / (top - bottom) + m[2, 3] = -(far + near) / (far- near) + m[3, 3] = 1 if flip_z_axis { m[2] = -m[2] @@ -2148,13 +2125,13 @@ matrix_ortho3d_f16 :: proc(left, right, bottom, top, near, far: f16, flip_z_axis return } matrix_ortho3d_f32 :: proc(left, right, bottom, top, near, far: f32, flip_z_axis := true) -> (m: Matrix4f32) { - m[0][0] = +2 / (right - left) - m[1][1] = +2 / (top - bottom) - m[2][2] = +2 / (far - near) - m[3][0] = -(right + left) / (right - left) - m[3][1] = -(top + bottom) / (top - bottom) - m[3][2] = -(far + near) / (far- near) - m[3][3] = 1 + m[0, 0] = +2 / (right - left) + m[1, 1] = +2 / (top - bottom) + m[2, 2] = +2 / (far - near) + m[0, 3] = -(right + left) / (right - left) + m[1, 3] = -(top + bottom) / (top - bottom) + m[2, 3] = -(far + near) / (far- near) + m[3, 3] = 1 if flip_z_axis { m[2] = -m[2] @@ -2163,13 +2140,13 @@ matrix_ortho3d_f32 :: proc(left, right, bottom, top, near, far: f32, flip_z_axis return } matrix_ortho3d_f64 :: proc(left, right, bottom, top, near, far: f64, flip_z_axis := true) -> (m: Matrix4f64) { - m[0][0] = +2 / (right - left) - m[1][1] = +2 / (top - bottom) - m[2][2] = +2 / (far - near) - m[3][0] = -(right + left) / (right - left) - m[3][1] = -(top + bottom) / (top - bottom) - m[3][2] = -(far + near) / (far- near) - m[3][3] = 1 + m[0, 0] = +2 / (right - left) + m[1, 1] = +2 / (top - bottom) + m[2, 2] = +2 / (far - near) + m[0, 3] = -(right + left) / (right - left) + m[1, 3] = -(top + bottom) / (top - bottom) + m[2, 3] = -(far + near) / (far- near) + m[3, 3] = 1 if flip_z_axis { m[2] = -m[2] @@ -2187,11 +2164,11 @@ matrix_ortho3d :: proc{ matrix4_infinite_perspective_f16 :: proc(fovy, aspect, near: f16, flip_z_axis := true) -> (m: Matrix4f16) { tan_half_fovy := math.tan(0.5 * fovy) - m[0][0] = 1 / (aspect*tan_half_fovy) - m[1][1] = 1 / (tan_half_fovy) - m[2][2] = +1 - m[2][3] = +1 - m[3][2] = -2*near + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = +1 + m[3, 2] = +1 + m[2, 3] = -2*near if flip_z_axis { m[2] = -m[2] @@ -2201,11 +2178,11 @@ matrix4_infinite_perspective_f16 :: proc(fovy, aspect, near: f16, flip_z_axis := } matrix4_infinite_perspective_f32 :: proc(fovy, aspect, near: f32, flip_z_axis := true) -> (m: Matrix4f32) { tan_half_fovy := math.tan(0.5 * fovy) - m[0][0] = 1 / (aspect*tan_half_fovy) - m[1][1] = 1 / (tan_half_fovy) - m[2][2] = +1 - m[2][3] = +1 - m[3][2] = -2*near + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = +1 + m[3, 2] = +1 + m[2, 3] = -2*near if flip_z_axis { m[2] = -m[2] @@ -2215,11 +2192,11 @@ matrix4_infinite_perspective_f32 :: proc(fovy, aspect, near: f32, flip_z_axis := } matrix4_infinite_perspective_f64 :: proc(fovy, aspect, near: f64, flip_z_axis := true) -> (m: Matrix4f64) { tan_half_fovy := math.tan(0.5 * fovy) - m[0][0] = 1 / (aspect*tan_half_fovy) - m[1][1] = 1 / (tan_half_fovy) - m[2][2] = +1 - m[2][3] = +1 - m[3][2] = -2*near + m[0, 0] = 1 / (aspect*tan_half_fovy) + m[1, 1] = 1 / (tan_half_fovy) + m[2, 2] = +1 + m[3, 2] = +1 + m[2, 3] = -2*near if flip_z_axis { m[2] = -m[2] @@ -2236,18 +2213,18 @@ matrix4_infinite_perspective :: proc{ matrix2_from_scalar_f16 :: proc(f: f16) -> (m: Matrix2f16) { - m[0][0], m[0][1] = f, 0 - m[1][0], m[1][1] = 0, f + m[0, 0], m[1, 0] = f, 0 + m[0, 1], m[1, 1] = 0, f return } matrix2_from_scalar_f32 :: proc(f: f32) -> (m: Matrix2f32) { - m[0][0], m[0][1] = f, 0 - m[1][0], m[1][1] = 0, f + m[0, 0], m[1, 0] = f, 0 + m[0, 1], m[1, 1] = 0, f return } matrix2_from_scalar_f64 :: proc(f: f64) -> (m: Matrix2f64) { - m[0][0], m[0][1] = f, 0 - m[1][0], m[1][1] = 0, f + m[0, 0], m[1, 0] = f, 0 + m[0, 1], m[1, 1] = 0, f return } matrix2_from_scalar :: proc{ @@ -2258,21 +2235,21 @@ matrix2_from_scalar :: proc{ matrix3_from_scalar_f16 :: proc(f: f16) -> (m: Matrix3f16) { - m[0][0], m[0][1], m[0][2] = f, 0, 0 - m[1][0], m[1][1], m[1][2] = 0, f, 0 - m[2][0], m[2][1], m[2][2] = 0, 0, f + m[0, 0], m[1, 0], m[2, 0] = f, 0, 0 + m[0, 1], m[1, 1], m[2, 1] = 0, f, 0 + m[0, 2], m[1, 2], m[2, 2] = 0, 0, f return } matrix3_from_scalar_f32 :: proc(f: f32) -> (m: Matrix3f32) { - m[0][0], m[0][1], m[0][2] = f, 0, 0 - m[1][0], m[1][1], m[1][2] = 0, f, 0 - m[2][0], m[2][1], m[2][2] = 0, 0, f + m[0, 0], m[1, 0], m[2, 0] = f, 0, 0 + m[0, 1], m[1, 1], m[2, 1] = 0, f, 0 + m[0, 2], m[1, 2], m[2, 2] = 0, 0, f return } matrix3_from_scalar_f64 :: proc(f: f64) -> (m: Matrix3f64) { - m[0][0], m[0][1], m[0][2] = f, 0, 0 - m[1][0], m[1][1], m[1][2] = 0, f, 0 - m[2][0], m[2][1], m[2][2] = 0, 0, f + m[0, 0], m[1, 0], m[2, 0] = f, 0, 0 + m[0, 1], m[1, 1], m[2, 1] = 0, f, 0 + m[0, 2], m[1, 2], m[2, 2] = 0, 0, f return } matrix3_from_scalar :: proc{ @@ -2283,24 +2260,24 @@ matrix3_from_scalar :: proc{ matrix4_from_scalar_f16 :: proc(f: f16) -> (m: Matrix4f16) { - m[0][0], m[0][1], m[0][2], m[0][3] = f, 0, 0, 0 - m[1][0], m[1][1], m[1][2], m[1][3] = 0, f, 0, 0 - m[2][0], m[2][1], m[2][2], m[2][3] = 0, 0, f, 0 - m[3][0], m[3][1], m[3][2], m[3][3] = 0, 0, 0, f + m[0, 0], m[1, 0], m[2, 0], m[3, 0] = f, 0, 0, 0 + m[0, 1], m[1, 1], m[2, 1], m[3, 1] = 0, f, 0, 0 + m[0, 2], m[1, 2], m[2, 2], m[3, 2] = 0, 0, f, 0 + m[0, 3], m[1, 3], m[2, 3], m[3, 3] = 0, 0, 0, f return } matrix4_from_scalar_f32 :: proc(f: f32) -> (m: Matrix4f32) { - m[0][0], m[0][1], m[0][2], m[0][3] = f, 0, 0, 0 - m[1][0], m[1][1], m[1][2], m[1][3] = 0, f, 0, 0 - m[2][0], m[2][1], m[2][2], m[2][3] = 0, 0, f, 0 - m[3][0], m[3][1], m[3][2], m[3][3] = 0, 0, 0, f + m[0, 0], m[1, 0], m[2, 0], m[3, 0] = f, 0, 0, 0 + m[0, 1], m[1, 1], m[2, 1], m[3, 1] = 0, f, 0, 0 + m[0, 2], m[1, 2], m[2, 2], m[3, 2] = 0, 0, f, 0 + m[0, 3], m[1, 3], m[2, 3], m[3, 3] = 0, 0, 0, f return } matrix4_from_scalar_f64 :: proc(f: f64) -> (m: Matrix4f64) { - m[0][0], m[0][1], m[0][2], m[0][3] = f, 0, 0, 0 - m[1][0], m[1][1], m[1][2], m[1][3] = 0, f, 0, 0 - m[2][0], m[2][1], m[2][2], m[2][3] = 0, 0, f, 0 - m[3][0], m[3][1], m[3][2], m[3][3] = 0, 0, 0, f + m[0, 0], m[1, 0], m[2, 0], m[3, 0] = f, 0, 0, 0 + m[0, 1], m[1, 1], m[2, 1], m[3, 1] = 0, f, 0, 0 + m[0, 2], m[1, 2], m[2, 2], m[3, 2] = 0, 0, f, 0 + m[0, 3], m[1, 3], m[2, 3], m[3, 3] = 0, 0, 0, f return } matrix4_from_scalar :: proc{ @@ -2311,18 +2288,18 @@ matrix4_from_scalar :: proc{ matrix2_from_matrix3_f16 :: proc(m: Matrix3f16) -> (r: Matrix2f16) { - r[0][0], r[0][1] = m[0][0], m[0][1] - r[1][0], r[1][1] = m[1][0], m[1][1] + r[0, 0], r[1, 0] = m[0, 0], m[1, 0] + r[0, 1], r[1, 1] = m[0, 1], m[1, 1] return } matrix2_from_matrix3_f32 :: proc(m: Matrix3f32) -> (r: Matrix2f32) { - r[0][0], r[0][1] = m[0][0], m[0][1] - r[1][0], r[1][1] = m[1][0], m[1][1] + r[0, 0], r[1, 0] = m[0, 0], m[1, 0] + r[0, 1], r[1, 1] = m[0, 1], m[1, 1] return } matrix2_from_matrix3_f64 :: proc(m: Matrix3f64) -> (r: Matrix2f64) { - r[0][0], r[0][1] = m[0][0], m[0][1] - r[1][0], r[1][1] = m[1][0], m[1][1] + r[0, 0], r[1, 0] = m[0, 0], m[1, 0] + r[0, 1], r[1, 1] = m[0, 1], m[1, 1] return } matrix2_from_matrix3 :: proc{ @@ -2333,18 +2310,18 @@ matrix2_from_matrix3 :: proc{ matrix2_from_matrix4_f16 :: proc(m: Matrix4f16) -> (r: Matrix2f16) { - r[0][0], r[0][1] = m[0][0], m[0][1] - r[1][0], r[1][1] = m[1][0], m[1][1] + r[0, 0], r[1, 0] = m[0, 0], m[1, 0] + r[0, 1], r[1, 1] = m[0, 1], m[1, 1] return } matrix2_from_matrix4_f32 :: proc(m: Matrix4f32) -> (r: Matrix2f32) { - r[0][0], r[0][1] = m[0][0], m[0][1] - r[1][0], r[1][1] = m[1][0], m[1][1] + r[0, 0], r[1, 0] = m[0, 0], m[1, 0] + r[0, 1], r[1, 1] = m[0, 1], m[1, 1] return } matrix2_from_matrix4_f64 :: proc(m: Matrix4f64) -> (r: Matrix2f64) { - r[0][0], r[0][1] = m[0][0], m[0][1] - r[1][0], r[1][1] = m[1][0], m[1][1] + r[0, 0], r[1, 0] = m[0, 0], m[1, 0] + r[0, 1], r[1, 1] = m[0, 1], m[1, 1] return } matrix2_from_matrix4 :: proc{ @@ -2355,21 +2332,21 @@ matrix2_from_matrix4 :: proc{ matrix3_from_matrix2_f16 :: proc(m: Matrix2f16) -> (r: Matrix3f16) { - r[0][0], r[0][1], r[0][2] = m[0][0], m[0][1], 0 - r[1][0], r[1][1], r[1][2] = m[1][0], m[1][1], 0 - r[2][0], r[2][1], r[2][2] = 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0] = m[0, 0], m[1, 0], 0 + r[0, 1], r[1, 1], r[2, 1] = m[0, 1], m[1, 1], 0 + r[0, 2], r[1, 2], r[2, 2] = 0, 0, 1 return } matrix3_from_matrix2_f32 :: proc(m: Matrix2f32) -> (r: Matrix3f32) { - r[0][0], r[0][1], r[0][2] = m[0][0], m[0][1], 0 - r[1][0], r[1][1], r[1][2] = m[1][0], m[1][1], 0 - r[2][0], r[2][1], r[2][2] = 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0] = m[0, 0], m[1, 0], 0 + r[0, 1], r[1, 1], r[2, 1] = m[0, 1], m[1, 1], 0 + r[0, 2], r[1, 2], r[2, 2] = 0, 0, 1 return } matrix3_from_matrix2_f64 :: proc(m: Matrix2f64) -> (r: Matrix3f64) { - r[0][0], r[0][1], r[0][2] = m[0][0], m[0][1], 0 - r[1][0], r[1][1], r[1][2] = m[1][0], m[1][1], 0 - r[2][0], r[2][1], r[2][2] = 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0] = m[0, 0], m[1, 0], 0 + r[0, 1], r[1, 1], r[2, 1] = m[0, 1], m[1, 1], 0 + r[0, 2], r[1, 2], r[2, 2] = 0, 0, 1 return } matrix3_from_matrix2 :: proc{ @@ -2380,21 +2357,21 @@ matrix3_from_matrix2 :: proc{ matrix3_from_matrix4_f16 :: proc(m: Matrix4f16) -> (r: Matrix3f16) { - r[0][0], r[0][1], r[0][2] = m[0][0], m[0][1], m[0][2] - r[1][0], r[1][1], r[1][2] = m[1][0], m[1][1], m[1][2] - r[2][0], r[2][1], r[2][2] = m[2][0], m[2][1], m[2][2] + r[0, 0], r[1, 0], r[2, 0] = m[0, 0], m[1, 0], m[2, 0] + r[0, 1], r[1, 1], r[2, 1] = m[0, 1], m[1, 1], m[2, 1] + r[0, 2], r[1, 2], r[2, 2] = m[0, 2], m[1, 2], m[2, 2] return } matrix3_from_matrix4_f32 :: proc(m: Matrix4f32) -> (r: Matrix3f32) { - r[0][0], r[0][1], r[0][2] = m[0][0], m[0][1], m[0][2] - r[1][0], r[1][1], r[1][2] = m[1][0], m[1][1], m[1][2] - r[2][0], r[2][1], r[2][2] = m[2][0], m[2][1], m[2][2] + r[0, 0], r[1, 0], r[2, 0] = m[0, 0], m[1, 0], m[2, 0] + r[0, 1], r[1, 1], r[2, 1] = m[0, 1], m[1, 1], m[2, 1] + r[0, 2], r[1, 2], r[2, 2] = m[0, 2], m[1, 2], m[2, 2] return } matrix3_from_matrix4_f64 :: proc(m: Matrix4f64) -> (r: Matrix3f64) { - r[0][0], r[0][1], r[0][2] = m[0][0], m[0][1], m[0][2] - r[1][0], r[1][1], r[1][2] = m[1][0], m[1][1], m[1][2] - r[2][0], r[2][1], r[2][2] = m[2][0], m[2][1], m[2][2] + r[0, 0], r[1, 0], r[2, 0] = m[0, 0], m[1, 0], m[2, 0] + r[0, 1], r[1, 1], r[2, 1] = m[0, 1], m[1, 1], m[2, 1] + r[0, 2], r[1, 2], r[2, 2] = m[0, 2], m[1, 2], m[2, 2] return } matrix3_from_matrix4 :: proc{ @@ -2405,24 +2382,24 @@ matrix3_from_matrix4 :: proc{ matrix4_from_matrix2_f16 :: proc(m: Matrix2f16) -> (r: Matrix4f16) { - r[0][0], r[0][1], r[0][2], r[0][3] = m[0][0], m[0][1], 0, 0 - r[1][0], r[1][1], r[1][2], r[1][3] = m[1][0], m[1][1], 0, 0 - r[2][0], r[2][1], r[2][2], r[2][3] = 0, 0, 1, 0 - r[3][0], r[3][1], r[3][2], r[3][3] = 0, 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0], r[3, 0] = m[0, 0], m[1, 0], 0, 0 + r[0, 1], r[1, 1], r[2, 1], r[3, 1] = m[0, 1], m[1, 1], 0, 0 + r[0, 2], r[1, 2], r[2, 2], r[3, 2] = 0, 0, 1, 0 + r[0, 3], r[1, 3], r[2, 3], r[3, 3] = 0, 0, 0, 1 return } matrix4_from_matrix2_f32 :: proc(m: Matrix2f32) -> (r: Matrix4f32) { - r[0][0], r[0][1], r[0][2], r[0][3] = m[0][0], m[0][1], 0, 0 - r[1][0], r[1][1], r[1][2], r[1][3] = m[1][0], m[1][1], 0, 0 - r[2][0], r[2][1], r[2][2], r[2][3] = 0, 0, 1, 0 - r[3][0], r[3][1], r[3][2], r[3][3] = 0, 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0], r[3, 0] = m[0, 0], m[1, 0], 0, 0 + r[0, 1], r[1, 1], r[2, 1], r[3, 1] = m[0, 1], m[1, 1], 0, 0 + r[0, 2], r[1, 2], r[2, 2], r[3, 2] = 0, 0, 1, 0 + r[0, 3], r[1, 3], r[2, 3], r[3, 3] = 0, 0, 0, 1 return } matrix4_from_matrix2_f64 :: proc(m: Matrix2f64) -> (r: Matrix4f64) { - r[0][0], r[0][1], r[0][2], r[0][3] = m[0][0], m[0][1], 0, 0 - r[1][0], r[1][1], r[1][2], r[1][3] = m[1][0], m[1][1], 0, 0 - r[2][0], r[2][1], r[2][2], r[2][3] = 0, 0, 1, 0 - r[3][0], r[3][1], r[3][2], r[3][3] = 0, 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0], r[3, 0] = m[0, 0], m[1, 0], 0, 0 + r[0, 1], r[1, 1], r[2, 1], r[3, 1] = m[0, 1], m[1, 1], 0, 0 + r[0, 2], r[1, 2], r[2, 2], r[3, 2] = 0, 0, 1, 0 + r[0, 3], r[1, 3], r[2, 3], r[3, 3] = 0, 0, 0, 1 return } matrix4_from_matrix2 :: proc{ @@ -2433,24 +2410,24 @@ matrix4_from_matrix2 :: proc{ matrix4_from_matrix3_f16 :: proc(m: Matrix3f16) -> (r: Matrix4f16) { - r[0][0], r[0][1], r[0][2], r[0][3] = m[0][0], m[0][1], m[0][2], 0 - r[1][0], r[1][1], r[1][2], r[1][3] = m[1][0], m[1][1], m[1][2], 0 - r[2][0], r[2][1], r[2][2], r[2][3] = m[2][0], m[2][1], m[2][2], 0 - r[3][0], r[3][1], r[3][2], r[3][3] = 0, 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0], r[3, 0] = m[0, 0], m[1, 0], m[2, 0], 0 + r[0, 1], r[1, 1], r[2, 1], r[3, 1] = m[0, 1], m[1, 1], m[2, 1], 0 + r[0, 2], r[1, 2], r[2, 2], r[3, 2] = m[0, 2], m[1, 2], m[2, 2], 0 + r[0, 3], r[1, 3], r[2, 3], r[3, 3] = 0, 0, 0, 1 return } matrix4_from_matrix3_f32 :: proc(m: Matrix3f32) -> (r: Matrix4f32) { - r[0][0], r[0][1], r[0][2], r[0][3] = m[0][0], m[0][1], m[0][2], 0 - r[1][0], r[1][1], r[1][2], r[1][3] = m[1][0], m[1][1], m[1][2], 0 - r[2][0], r[2][1], r[2][2], r[2][3] = m[2][0], m[2][1], m[2][2], 0 - r[3][0], r[3][1], r[3][2], r[3][3] = 0, 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0], r[3, 0] = m[0, 0], m[1, 0], m[2, 0], 0 + r[0, 1], r[1, 1], r[2, 1], r[3, 1] = m[0, 1], m[1, 1], m[2, 1], 0 + r[0, 2], r[1, 2], r[2, 2], r[3, 2] = m[0, 2], m[1, 2], m[2, 2], 0 + r[0, 3], r[1, 3], r[2, 3], r[3, 3] = 0, 0, 0, 1 return } matrix4_from_matrix3_f64 :: proc(m: Matrix3f64) -> (r: Matrix4f64) { - r[0][0], r[0][1], r[0][2], r[0][3] = m[0][0], m[0][1], m[0][2], 0 - r[1][0], r[1][1], r[1][2], r[1][3] = m[1][0], m[1][1], m[1][2], 0 - r[2][0], r[2][1], r[2][2], r[2][3] = m[2][0], m[2][1], m[2][2], 0 - r[3][0], r[3][1], r[3][2], r[3][3] = 0, 0, 0, 1 + r[0, 0], r[1, 0], r[2, 0], r[3, 0] = m[0, 0], m[1, 0], m[2, 0], 0 + r[0, 1], r[1, 1], r[2, 1], r[3, 1] = m[0, 1], m[1, 1], m[2, 1], 0 + r[0, 2], r[1, 2], r[2, 2], r[3, 2] = m[0, 2], m[1, 2], m[2, 2], 0 + r[0, 3], r[1, 3], r[2, 3], r[3, 3] = 0, 0, 0, 1 return } matrix4_from_matrix3 :: proc{ diff --git a/core/math/linalg/specific_euler_angles_f16.odin b/core/math/linalg/specific_euler_angles_f16.odin index d0fb1beb3..9e21c7f97 100644 --- a/core/math/linalg/specific_euler_angles_f16.odin +++ b/core/math/linalg/specific_euler_angles_f16.odin @@ -212,29 +212,29 @@ euler_angles_zxy_from_quaternion_f16 :: proc(q: Quaternionf16) -> (t1, t2, t3: f matrix3_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix3f16) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x return } matrix3_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix3f16) { cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y return } matrix3_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix3f16) { cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 return } @@ -242,31 +242,31 @@ matrix3_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix3f16) { matrix3_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x: f16) -> (m: Matrix3f16) { cos_x := math.cos(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x return } matrix3_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y: f16) -> (m: Matrix3f16) { cos_y := math.cos(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y return } matrix3_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z: f16) -> (m: Matrix3f16) { cos_z := math.cos(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 return } @@ -274,14 +274,14 @@ matrix3_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z: matrix3_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix3f16) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[1][0] = -sin_x * - sin_y - m[2][0] = -cos_x * - sin_y - m[1][1] = cos_x - m[2][1] = sin_x - m[0][2] = sin_y - m[1][2] = -sin_x * cos_y - m[2][2] = cos_x * cos_y + m[0, 0] = cos_y + m[0, 1] = -sin_x * - sin_y + m[0, 2] = -cos_x * - sin_y + m[1, 1] = cos_x + m[1, 2] = sin_x + m[2, 0] = sin_y + m[2, 1] = -sin_x * cos_y + m[2, 2] = cos_x * cos_y return } @@ -289,14 +289,14 @@ matrix3_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix3f1 matrix3_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix3f16) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[2][0] = -sin_y - m[0][1] = sin_y*sin_x - m[1][1] = cos_x - m[2][1] = cos_y*sin_x - m[0][2] = sin_y*cos_x - m[1][2] = -sin_x - m[2][2] = cos_y*cos_x + m[0, 0] = cos_y + m[0, 2] = -sin_y + m[1, 0] = sin_y*sin_x + m[1, 1] = cos_x + m[1, 2] = cos_y*sin_x + m[2, 0] = sin_y*cos_x + m[2, 1] = -sin_x + m[2, 2] = cos_y*cos_x return } @@ -322,15 +322,15 @@ matrix3_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { s2 := math.sin(-t2) s3 := math.sin(-t3) - m[0][0] = c2 * c3 - m[0][1] =-c1 * s3 + s1 * s2 * c3 - m[0][2] = s1 * s3 + c1 * s2 * c3 - m[1][0] = c2 * s3 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] =-s1 * c3 + c1 * s2 * s3 - m[2][0] =-s2 - m[2][1] = s1 * c2 - m[2][2] = c1 * c2 + m[0, 0] = c2 * c3 + m[1, 0] =-c1 * s3 + s1 * s2 * c3 + m[2, 0] = s1 * s3 + c1 * s2 * c3 + m[0, 1] = c2 * s3 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] =-s1 * c3 + c1 * s2 * s3 + m[0, 2] =-s2 + m[1, 2] = s1 * c2 + m[2, 2] = c1 * c2 return } @@ -342,15 +342,15 @@ matrix3_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp return } @@ -362,15 +362,15 @@ matrix3_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = c1 * s2 - m[0][2] = s1 * s2 - m[1][0] =-c3 * s2 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c1 * s3 + c2 * c3 * s1 - m[2][0] = s2 * s3 - m[2][1] =-c3 * s1 - c1 * c2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 + m[0, 0] = c2 + m[1, 0] = c1 * s2 + m[2, 0] = s1 * s2 + m[0, 1] =-c3 * s2 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c1 * s3 + c2 * c3 * s1 + m[0, 2] = s2 * s3 + m[1, 2] =-c3 * s1 - c1 * c2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 return } @@ -382,15 +382,15 @@ matrix3_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = s1 * s2 - m[0][2] =-c1 * s2 - m[1][0] = s2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = c3 * s1 + c1 * c2 * s3 - m[2][0] = c3 * s2 - m[2][1] =-c1 * s3 - c2 * c3 * s1 - m[2][2] = c1 * c2 * c3 - s1 * s3 + m[0, 0] = c2 + m[1, 0] = s1 * s2 + m[2, 0] =-c1 * s2 + m[0, 1] = s2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = c3 * s1 + c1 * c2 * s3 + m[0, 2] = c3 * s2 + m[1, 2] =-c1 * s3 - c2 * c3 * s1 + m[2, 2] = c1 * c2 * c3 - s1 * s3 return } @@ -402,15 +402,15 @@ matrix3_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = s2* s3 - m[0][2] =-c3 * s1 - c1 * c2 * s3 - m[1][0] = s1 * s2 - m[1][1] = c2 - m[1][2] = c1 * s2 - m[2][0] = c1 * s3 + c2 * c3 * s1 - m[2][1] =-c3 * s2 - m[2][2] = c1 * c2 * c3 - s1 * s3 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = s2* s3 + m[2, 0] =-c3 * s1 - c1 * c2 * s3 + m[0, 1] = s1 * s2 + m[1, 1] = c2 + m[2, 1] = c1 * s2 + m[0, 2] = c1 * s3 + c2 * c3 * s1 + m[1, 2] =-c3 * s2 + m[2, 2] = c1 * c2 * c3 - s1 * s3 return } @@ -422,15 +422,15 @@ matrix3_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c3 * s2 - m[0][2] =-c1 * s3 - c2 * c3 * s1 - m[1][0] =-c1 * s2 - m[1][1] = c2 - m[1][2] = s1 * s2 - m[2][0] = c3 * s1 + c1 * c2 * s3 - m[2][1] = s2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c3 * s2 + m[2, 0] =-c1 * s3 - c2 * c3 * s1 + m[0, 1] =-c1 * s2 + m[1, 1] = c2 + m[2, 1] = s1 * s2 + m[0, 2] = c3 * s1 + c1 * c2 * s3 + m[1, 2] = s2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 return } @@ -442,15 +442,15 @@ matrix3_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c1 * s3 + c2 * c3 * s1 - m[0][2] =-c3 * s2 - m[1][0] =-c3 * s1 - c1 * c2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = s2 * s3 - m[2][0] = c1 * s2 - m[2][1] = s1 * s2 - m[2][2] = c2 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c1 * s3 + c2 * c3 * s1 + m[2, 0] =-c3 * s2 + m[0, 1] =-c3 * s1 - c1 * c2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = s2 * s3 + m[0, 2] = c1 * s2 + m[1, 2] = s1 * s2 + m[2, 2] = c2 return } @@ -462,15 +462,15 @@ matrix3_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = c3 * s1 + c1 * c2 * s3 - m[0][2] = s2 *s3 - m[1][0] =-c1 * s3 - c2 * c3 * s1 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c3 * s2 - m[2][0] = s1 * s2 - m[2][1] =-c1 * s2 - m[2][2] = c2 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = c3 * s1 + c1 * c2 * s3 + m[2, 0] = s2 *s3 + m[0, 1] =-c1 * s3 - c2 * c3 * s1 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c3 * s2 + m[0, 2] = s1 * s2 + m[1, 2] =-c1 * s2 + m[2, 2] = c2 return } @@ -483,15 +483,15 @@ matrix3_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 * c3 - m[0][1] = s1 * s3 + c1 * c3 * s2 - m[0][2] = c3 * s1 * s2 - c1 * s3 - m[1][0] =-s2 - m[1][1] = c1 * c2 - m[1][2] = c2 * s1 - m[2][0] = c2 * s3 - m[2][1] = c1 * s2 * s3 - c3 * s1 - m[2][2] = c1 * c3 + s1 * s2 *s3 + m[0, 0] = c2 * c3 + m[1, 0] = s1 * s3 + c1 * c3 * s2 + m[2, 0] = c3 * s1 * s2 - c1 * s3 + m[0, 1] =-s2 + m[1, 1] = c1 * c2 + m[2, 1] = c2 * s1 + m[0, 2] = c2 * s3 + m[1, 2] = c1 * s2 * s3 - c3 * s1 + m[2, 2] = c1 * c3 + s1 * s2 *s3 return } @@ -503,15 +503,15 @@ matrix3_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = s2 - m[0][2] =-c2 * s1 - m[1][0] = s1 * s3 - c1 * c3 * s2 - m[1][1] = c2 * c3 - m[1][2] = c1 * s3 + c3 * s1 * s2 - m[2][0] = c3 * s1 + c1 * s2 * s3 - m[2][1] =-c2 * s3 - m[2][2] = c1 * c3 - s1 * s2 * s3 + m[0, 0] = c1 * c2 + m[1, 0] = s2 + m[2, 0] =-c2 * s1 + m[0, 1] = s1 * s3 - c1 * c3 * s2 + m[1, 1] = c2 * c3 + m[2, 1] = c1 * s3 + c3 * s1 * s2 + m[0, 2] = c3 * s1 + c1 * s2 * s3 + m[1, 2] =-c2 * s3 + m[2, 2] = c1 * c3 - s1 * s2 * s3 return } @@ -523,15 +523,15 @@ matrix3_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = c2 * s1 - m[0][2] =-s2 - m[1][0] = c1 * s2 * s3 - c3 * s1 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] = c2 * s3 - m[2][0] = s1 * s3 + c1 * c3 * s2 - m[2][1] = c3 * s1 * s2 - c1 * s3 - m[2][2] = c2 * c3 + m[0, 0] = c1 * c2 + m[1, 0] = c2 * s1 + m[2, 0] =-s2 + m[0, 1] = c1 * s2 * s3 - c3 * s1 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] = c2 * s3 + m[0, 2] = s1 * s3 + c1 * c3 * s2 + m[1, 2] = c3 * s1 * s2 - c1 * s3 + m[2, 2] = c2 * c3 return } @@ -543,15 +543,15 @@ matrix3_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix3f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - s1 * s2 * s3 - m[0][1] = c3 * s1 + c1 * s2 * s3 - m[0][2] =-c2 * s3 - m[1][0] =-c2 * s1 - m[1][1] = c1 * c2 - m[1][2] = s2 - m[2][0] = c1 * s3 + c3 * s1 * s2 - m[2][1] = s1 * s3 - c1 * c3 * s2 - m[2][2] = c2 * c3 + m[0, 0] = c1 * c3 - s1 * s2 * s3 + m[1, 0] = c3 * s1 + c1 * s2 * s3 + m[2, 0] =-c2 * s3 + m[0, 1] =-c2 * s1 + m[1, 1] = c1 * c2 + m[2, 1] = s2 + m[0, 2] = c1 * s3 + c3 * s1 * s2 + m[1, 2] = s1 * s3 - c1 * c3 * s2 + m[2, 2] = c2 * c3 return } @@ -564,25 +564,25 @@ matrix3_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix3f16 cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp return m } euler_angles_xyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[2][1], m[2][2]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[1][0]*m[1][0]) - T2 := math.atan2(-m[2][0], C2) + T1 := math.atan2(m[1, 2], m[2, 2]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) + T2 := math.atan2(-m[0, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][2] - C1*m[0][1], C1*m[1][1] - S1*m[1][2]) + T3 := math.atan2(S1*m[2, 0] - C1*m[1, 0], C1*m[1, 1] - S1*m[2, 1]) t1 = -T1 t2 = -T2 t3 = -T3 @@ -590,12 +590,12 @@ euler_angles_xyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_yxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[2][0], m[2][2]) - C2 := math.sqrt(m[0][1]*m[0][1] + m[1][1]*m[1][1]) - T2 := math.atan2(-m[2][1], C2) + T1 := math.atan2(m[0, 2], m[2, 2]) + C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) + T2 := math.atan2(-m[1, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][2] - C1*m[1][0], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(S1*m[2, 1] - C1*m[0, 1], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -603,12 +603,12 @@ euler_angles_yxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_xzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[0][2], m[0][1]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[2, 0], m[1, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[1][2] - S1*m[1][1], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(C1*m[2, 1] - S1*m[1, 1], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -616,12 +616,12 @@ euler_angles_xzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_xyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[0][1], -m[0][2]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[1, 0], -m[2, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[2][1] - S1*m[2][2], C1*m[1][1] + S1*m[1][2]) + T3 := math.atan2(-C1*m[1, 2] - S1*m[2, 2], C1*m[1, 1] + S1*m[2, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -629,12 +629,12 @@ euler_angles_xyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_yxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[1][0], m[1][2]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[0, 1], m[2, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] - S1*m[2][2], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(C1*m[0, 2] - S1*m[2, 2], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -642,24 +642,24 @@ euler_angles_yxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_yzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[1][2], -m[1][0]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[2, 1], -m[0, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-S1*m[0][0] - C1*m[0][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(-S1*m[0, 0] - C1*m[2, 0], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 return } euler_angles_zyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[2][1], m[2][0]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[1, 2], m[0, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[0][1] - S1*m[0][0], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(C1*m[1, 0] - S1*m[0, 0], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -667,12 +667,12 @@ euler_angles_zyz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_zxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[2][0], -m[2][1]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[0, 2], -m[1, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[1][0] - S1*m[1][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(-C1*m[0, 1] - S1*m[1, 1], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -680,12 +680,12 @@ euler_angles_zxz_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_xzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[1][2], m[1][1]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[2][0]*m[2][0]) - T2 := math.atan2(-m[1][0], C2) + T1 := math.atan2(m[2, 1], m[1, 1]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) + T2 := math.atan2(-m[0, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][1] - C1*m[0][2], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(S1*m[1, 0] - C1*m[2, 0], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -693,12 +693,12 @@ euler_angles_xzy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_yzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(-m[0][2], m[0][0]) - C2 := math.sqrt(m[1][1]*m[1][1] + m[2][1]*m[2][1]) - T2 := math.atan2(m[0][1], C2) + T1 := math.atan2(-m[2, 0], m[0, 0]) + C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) + T2 := math.atan2(m[1, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][0] + C1*m[1][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(S1*m[0, 1] + C1*m[2, 1], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -706,12 +706,12 @@ euler_angles_yzx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_zyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[0][1], m[0][0]) - C2 := math.sqrt(m[1][2]*m[1][2] + m[2][2]*m[2][2]) - T2 := math.atan2(-m[0][2], C2) + T1 := math.atan2(m[1, 0], m[0, 0]) + C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) + T2 := math.atan2(-m[2, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[2][0] - C1*m[2][1], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(S1*m[0, 2] - C1*m[1, 2], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -719,12 +719,12 @@ euler_angles_zyx_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { } euler_angles_zxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(-m[1][0], m[1][1]) - C2 := math.sqrt(m[0][2]*m[0][2] + m[2][2]*m[2][2]) - T2 := math.atan2(m[1][2], C2) + T1 := math.atan2(-m[0, 1], m[1, 1]) + C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) + T2 := math.atan2(m[2, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] + S1*m[2][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(C1*m[0, 2] + S1*m[1, 2], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -737,32 +737,32 @@ euler_angles_zxy_from_matrix3_f16 :: proc(m: Matrix3f16) -> (t1, t2, t3: f16) { matrix4_from_euler_angle_x_f16 :: proc(angle_x: f16) -> (m: Matrix4f16) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x - m[3][3] = 1 + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x + m[3, 3] = 1 return } matrix4_from_euler_angle_y_f16 :: proc(angle_y: f16) -> (m: Matrix4f16) { cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y - m[3][3] = 1 + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y + m[3, 3] = 1 return } matrix4_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix4f16) { cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 - m[3][3] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 + m[3, 3] = 1 return } @@ -770,34 +770,34 @@ matrix4_from_euler_angle_z_f16 :: proc(angle_z: f16) -> (m: Matrix4f16) { matrix4_from_derived_euler_angle_x_f16 :: proc(angle_x: f16, angular_velocity_x: f16) -> (m: Matrix4f16) { cos_x := math.cos(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x - m[3][3] = 1 + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x + m[3, 3] = 1 return } matrix4_from_derived_euler_angle_y_f16 :: proc(angle_y: f16, angular_velocity_y: f16) -> (m: Matrix4f16) { cos_y := math.cos(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y - m[3][3] = 1 + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y + m[3, 3] = 1 return } matrix4_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z: f16) -> (m: Matrix4f16) { cos_z := math.cos(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 - m[3][3] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 + m[3, 3] = 1 return } @@ -805,15 +805,15 @@ matrix4_from_derived_euler_angle_z_f16 :: proc(angle_z: f16, angular_velocity_z: matrix4_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix4f16) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[1][0] = -sin_x * - sin_y - m[2][0] = -cos_x * - sin_y - m[1][1] = cos_x - m[2][1] = sin_x - m[0][2] = sin_y - m[1][2] = -sin_x * cos_y - m[2][2] = cos_x * cos_y - m[3][3] = 1 + m[0, 0] = cos_y + m[0, 1] = -sin_x * - sin_y + m[0, 2] = -cos_x * - sin_y + m[1, 1] = cos_x + m[1, 2] = sin_x + m[2, 0] = sin_y + m[2, 1] = -sin_x * cos_y + m[2, 2] = cos_x * cos_y + m[3, 3] = 1 return } @@ -821,15 +821,15 @@ matrix4_from_euler_angles_xy_f16 :: proc(angle_x, angle_y: f16) -> (m: Matrix4f1 matrix4_from_euler_angles_yx_f16 :: proc(angle_y, angle_x: f16) -> (m: Matrix4f16) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[2][0] = -sin_y - m[0][1] = sin_y*sin_x - m[1][1] = cos_x - m[2][1] = cos_y*sin_x - m[0][2] = sin_y*cos_x - m[1][2] = -sin_x - m[2][2] = cos_y*cos_x - m[3][3] = 1 + m[0, 0] = cos_y + m[0, 2] = -sin_y + m[1, 0] = sin_y*sin_x + m[1, 1] = cos_x + m[1, 2] = cos_y*sin_x + m[2, 0] = sin_y*cos_x + m[2, 1] = -sin_x + m[2, 2] = cos_y*cos_x + m[3, 3] = 1 return } @@ -855,22 +855,22 @@ matrix4_from_euler_angles_xyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { s2 := math.sin(-t2) s3 := math.sin(-t3) - m[0][0] = c2 * c3 - m[0][1] =-c1 * s3 + s1 * s2 * c3 - m[0][2] = s1 * s3 + c1 * s2 * c3 - m[0][3] = 0 - m[1][0] = c2 * s3 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] =-s1 * c3 + c1 * s2 * s3 - m[1][3] = 0 - m[2][0] =-s2 - m[2][1] = s1 * c2 - m[2][2] = c1 * c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 * c3 + m[1, 0] =-c1 * s3 + s1 * s2 * c3 + m[2, 0] = s1 * s3 + c1 * s2 * c3 + m[3, 0] = 0 + m[0, 1] = c2 * s3 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] =-s1 * c3 + c1 * s2 * s3 + m[3, 1] = 0 + m[0, 2] =-s2 + m[1, 2] = s1 * c2 + m[2, 2] = c1 * c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -882,22 +882,22 @@ matrix4_from_euler_angles_yxz_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[0][3] = 0 - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[1][3] = 0 - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[3, 0] = 0 + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[3, 1] = 0 + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -909,22 +909,22 @@ matrix4_from_euler_angles_xzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = c1 * s2 - m[0][2] = s1 * s2 - m[0][3] = 0 - m[1][0] =-c3 * s2 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c1 * s3 + c2 * c3 * s1 - m[1][3] = 0 - m[2][0] = s2 * s3 - m[2][1] =-c3 * s1 - c1 * c2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 + m[1, 0] = c1 * s2 + m[2, 0] = s1 * s2 + m[3, 0] = 0 + m[0, 1] =-c3 * s2 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c1 * s3 + c2 * c3 * s1 + m[3, 1] = 0 + m[0, 2] = s2 * s3 + m[1, 2] =-c3 * s1 - c1 * c2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -936,22 +936,22 @@ matrix4_from_euler_angles_xyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = s1 * s2 - m[0][2] =-c1 * s2 - m[0][3] = 0 - m[1][0] = s2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = c3 * s1 + c1 * c2 * s3 - m[1][3] = 0 - m[2][0] = c3 * s2 - m[2][1] =-c1 * s3 - c2 * c3 * s1 - m[2][2] = c1 * c2 * c3 - s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 + m[1, 0] = s1 * s2 + m[2, 0] =-c1 * s2 + m[3, 0] = 0 + m[0, 1] = s2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = c3 * s1 + c1 * c2 * s3 + m[3, 1] = 0 + m[0, 2] = c3 * s2 + m[1, 2] =-c1 * s3 - c2 * c3 * s1 + m[2, 2] = c1 * c2 * c3 - s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -963,22 +963,22 @@ matrix4_from_euler_angles_yxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = s2* s3 - m[0][2] =-c3 * s1 - c1 * c2 * s3 - m[0][3] = 0 - m[1][0] = s1 * s2 - m[1][1] = c2 - m[1][2] = c1 * s2 - m[1][3] = 0 - m[2][0] = c1 * s3 + c2 * c3 * s1 - m[2][1] =-c3 * s2 - m[2][2] = c1 * c2 * c3 - s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = s2* s3 + m[2, 0] =-c3 * s1 - c1 * c2 * s3 + m[3, 0] = 0 + m[0, 1] = s1 * s2 + m[1, 1] = c2 + m[2, 1] = c1 * s2 + m[3, 1] = 0 + m[0, 2] = c1 * s3 + c2 * c3 * s1 + m[1, 2] =-c3 * s2 + m[2, 2] = c1 * c2 * c3 - s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -990,22 +990,22 @@ matrix4_from_euler_angles_yzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c3 * s2 - m[0][2] =-c1 * s3 - c2 * c3 * s1 - m[0][3] = 0 - m[1][0] =-c1 * s2 - m[1][1] = c2 - m[1][2] = s1 * s2 - m[1][3] = 0 - m[2][0] = c3 * s1 + c1 * c2 * s3 - m[2][1] = s2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c3 * s2 + m[2, 0] =-c1 * s3 - c2 * c3 * s1 + m[3, 0] = 0 + m[0, 1] =-c1 * s2 + m[1, 1] = c2 + m[2, 1] = s1 * s2 + m[3, 1] = 0 + m[0, 2] = c3 * s1 + c1 * c2 * s3 + m[1, 2] = s2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1017,22 +1017,22 @@ matrix4_from_euler_angles_zyz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c1 * s3 + c2 * c3 * s1 - m[0][2] =-c3 * s2 - m[0][3] = 0 - m[1][0] =-c3 * s1 - c1 * c2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = s2 * s3 - m[1][3] = 0 - m[2][0] = c1 * s2 - m[2][1] = s1 * s2 - m[2][2] = c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c1 * s3 + c2 * c3 * s1 + m[2, 0] =-c3 * s2 + m[3, 0] = 0 + m[0, 1] =-c3 * s1 - c1 * c2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = s2 * s3 + m[3, 1] = 0 + m[0, 2] = c1 * s2 + m[1, 2] = s1 * s2 + m[2, 2] = c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1044,22 +1044,22 @@ matrix4_from_euler_angles_zxz_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = c3 * s1 + c1 * c2 * s3 - m[0][2] = s2 *s3 - m[0][3] = 0 - m[1][0] =-c1 * s3 - c2 * c3 * s1 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c3 * s2 - m[1][3] = 0 - m[2][0] = s1 * s2 - m[2][1] =-c1 * s2 - m[2][2] = c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = c3 * s1 + c1 * c2 * s3 + m[2, 0] = s2 *s3 + m[3, 0] = 0 + m[0, 1] =-c1 * s3 - c2 * c3 * s1 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c3 * s2 + m[3, 1] = 0 + m[0, 2] = s1 * s2 + m[1, 2] =-c1 * s2 + m[2, 2] = c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1072,22 +1072,22 @@ matrix4_from_euler_angles_xzy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 * c3 - m[0][1] = s1 * s3 + c1 * c3 * s2 - m[0][2] = c3 * s1 * s2 - c1 * s3 - m[0][3] = 0 - m[1][0] =-s2 - m[1][1] = c1 * c2 - m[1][2] = c2 * s1 - m[1][3] = 0 - m[2][0] = c2 * s3 - m[2][1] = c1 * s2 * s3 - c3 * s1 - m[2][2] = c1 * c3 + s1 * s2 *s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 * c3 + m[1, 0] = s1 * s3 + c1 * c3 * s2 + m[2, 0] = c3 * s1 * s2 - c1 * s3 + m[3, 0] = 0 + m[0, 1] =-s2 + m[1, 1] = c1 * c2 + m[2, 1] = c2 * s1 + m[3, 1] = 0 + m[0, 2] = c2 * s3 + m[1, 2] = c1 * s2 * s3 - c3 * s1 + m[2, 2] = c1 * c3 + s1 * s2 *s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1099,22 +1099,22 @@ matrix4_from_euler_angles_yzx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = s2 - m[0][2] =-c2 * s1 - m[0][3] = 0 - m[1][0] = s1 * s3 - c1 * c3 * s2 - m[1][1] = c2 * c3 - m[1][2] = c1 * s3 + c3 * s1 * s2 - m[1][3] = 0 - m[2][0] = c3 * s1 + c1 * s2 * s3 - m[2][1] =-c2 * s3 - m[2][2] = c1 * c3 - s1 * s2 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 + m[1, 0] = s2 + m[2, 0] =-c2 * s1 + m[3, 0] = 0 + m[0, 1] = s1 * s3 - c1 * c3 * s2 + m[1, 1] = c2 * c3 + m[2, 1] = c1 * s3 + c3 * s1 * s2 + m[3, 1] = 0 + m[0, 2] = c3 * s1 + c1 * s2 * s3 + m[1, 2] =-c2 * s3 + m[2, 2] = c1 * c3 - s1 * s2 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1126,22 +1126,22 @@ matrix4_from_euler_angles_zyx_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = c2 * s1 - m[0][2] =-s2 - m[0][3] = 0 - m[1][0] = c1 * s2 * s3 - c3 * s1 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] = c2 * s3 - m[1][3] = 0 - m[2][0] = s1 * s3 + c1 * c3 * s2 - m[2][1] = c3 * s1 * s2 - c1 * s3 - m[2][2] = c2 * c3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 + m[1, 0] = c2 * s1 + m[2, 0] =-s2 + m[3, 0] = 0 + m[0, 1] = c1 * s2 * s3 - c3 * s1 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] = c2 * s3 + m[3, 1] = 0 + m[0, 2] = s1 * s3 + c1 * c3 * s2 + m[1, 2] = c3 * s1 * s2 - c1 * s3 + m[2, 2] = c2 * c3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1153,22 +1153,22 @@ matrix4_from_euler_angles_zxy_f16 :: proc(t1, t2, t3: f16) -> (m: Matrix4f16) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - s1 * s2 * s3 - m[0][1] = c3 * s1 + c1 * s2 * s3 - m[0][2] =-c2 * s3 - m[0][3] = 0 - m[1][0] =-c2 * s1 - m[1][1] = c1 * c2 - m[1][2] = s2 - m[1][3] = 0 - m[2][0] = c1 * s3 + c3 * s1 * s2 - m[2][1] = s1 * s3 - c1 * c3 * s2 - m[2][2] = c2 * c3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - s1 * s2 * s3 + m[1, 0] = c3 * s1 + c1 * s2 * s3 + m[2, 0] =-c2 * s3 + m[3, 0] = 0 + m[0, 1] =-c2 * s1 + m[1, 1] = c1 * c2 + m[2, 1] = s2 + m[3, 1] = 0 + m[0, 2] = c1 * s3 + c3 * s1 * s2 + m[1, 2] = s1 * s3 - c1 * c3 * s2 + m[2, 2] = c2 * c3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1181,32 +1181,32 @@ matrix4_from_yaw_pitch_roll_f16 :: proc(yaw, pitch, roll: f16) -> (m: Matrix4f16 cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[0][3] = 0 - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[1][3] = 0 - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[3, 0] = 0 + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[3, 1] = 0 + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return m } euler_angles_xyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[2][1], m[2][2]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[1][0]*m[1][0]) - T2 := math.atan2(-m[2][0], C2) + T1 := math.atan2(m[1, 2], m[2, 2]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) + T2 := math.atan2(-m[0, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][2] - C1*m[0][1], C1*m[1][1] - S1*m[1][2]) + T3 := math.atan2(S1*m[2, 0] - C1*m[1, 0], C1*m[1, 1] - S1*m[2, 1]) t1 = -T1 t2 = -T2 t3 = -T3 @@ -1214,12 +1214,12 @@ euler_angles_xyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_yxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[2][0], m[2][2]) - C2 := math.sqrt(m[0][1]*m[0][1] + m[1][1]*m[1][1]) - T2 := math.atan2(-m[2][1], C2) + T1 := math.atan2(m[0, 2], m[2, 2]) + C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) + T2 := math.atan2(-m[1, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][2] - C1*m[1][0], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(S1*m[2, 1] - C1*m[0, 1], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1227,12 +1227,12 @@ euler_angles_yxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_xzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[0][2], m[0][1]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[2, 0], m[1, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[1][2] - S1*m[1][1], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(C1*m[2, 1] - S1*m[1, 1], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1240,12 +1240,12 @@ euler_angles_xzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_xyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[0][1], -m[0][2]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[1, 0], -m[2, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[2][1] - S1*m[2][2], C1*m[1][1] + S1*m[1][2]) + T3 := math.atan2(-C1*m[1, 2] - S1*m[2, 2], C1*m[1, 1] + S1*m[2, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1253,12 +1253,12 @@ euler_angles_xyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_yxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[1][0], m[1][2]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[0, 1], m[2, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] - S1*m[2][2], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(C1*m[0, 2] - S1*m[2, 2], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1266,24 +1266,24 @@ euler_angles_yxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_yzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[1][2], -m[1][0]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[2, 1], -m[0, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-S1*m[0][0] - C1*m[0][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(-S1*m[0, 0] - C1*m[2, 0], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 return } euler_angles_zyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[2][1], m[2][0]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[1, 2], m[0, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[0][1] - S1*m[0][0], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(C1*m[1, 0] - S1*m[0, 0], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1291,12 +1291,12 @@ euler_angles_zyz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_zxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[2][0], -m[2][1]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[0, 2], -m[1, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[1][0] - S1*m[1][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(-C1*m[0, 1] - S1*m[1, 1], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1304,12 +1304,12 @@ euler_angles_zxz_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_xzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[1][2], m[1][1]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[2][0]*m[2][0]) - T2 := math.atan2(-m[1][0], C2) + T1 := math.atan2(m[2, 1], m[1, 1]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) + T2 := math.atan2(-m[0, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][1] - C1*m[0][2], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(S1*m[1, 0] - C1*m[2, 0], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1317,12 +1317,12 @@ euler_angles_xzy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_yzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(-m[0][2], m[0][0]) - C2 := math.sqrt(m[1][1]*m[1][1] + m[2][1]*m[2][1]) - T2 := math.atan2(m[0][1], C2) + T1 := math.atan2(-m[2, 0], m[0, 0]) + C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) + T2 := math.atan2(m[1, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][0] + C1*m[1][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(S1*m[0, 1] + C1*m[2, 1], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1330,12 +1330,12 @@ euler_angles_yzx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_zyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(m[0][1], m[0][0]) - C2 := math.sqrt(m[1][2]*m[1][2] + m[2][2]*m[2][2]) - T2 := math.atan2(-m[0][2], C2) + T1 := math.atan2(m[1, 0], m[0, 0]) + C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) + T2 := math.atan2(-m[2, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[2][0] - C1*m[2][1], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(S1*m[0, 2] - C1*m[1, 2], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1343,12 +1343,12 @@ euler_angles_zyx_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { } euler_angles_zxy_from_matrix4_f16 :: proc(m: Matrix4f16) -> (t1, t2, t3: f16) { - T1 := math.atan2(-m[1][0], m[1][1]) - C2 := math.sqrt(m[0][2]*m[0][2] + m[2][2]*m[2][2]) - T2 := math.atan2(m[1][2], C2) + T1 := math.atan2(-m[0, 1], m[1, 1]) + C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) + T2 := math.atan2(m[2, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] + S1*m[2][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(C1*m[0, 2] + S1*m[1, 2], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 diff --git a/core/math/linalg/specific_euler_angles_f32.odin b/core/math/linalg/specific_euler_angles_f32.odin index 6ae1b0fa0..80e19ce85 100644 --- a/core/math/linalg/specific_euler_angles_f32.odin +++ b/core/math/linalg/specific_euler_angles_f32.odin @@ -212,29 +212,29 @@ euler_angles_zxy_from_quaternion_f32 :: proc(q: Quaternionf32) -> (t1, t2, t3: f matrix3_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix3f32) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x return } matrix3_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix3f32) { cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y return } matrix3_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix3f32) { cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 return } @@ -242,31 +242,31 @@ matrix3_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix3f32) { matrix3_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x: f32) -> (m: Matrix3f32) { cos_x := math.cos(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x return } matrix3_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y: f32) -> (m: Matrix3f32) { cos_y := math.cos(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y return } matrix3_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z: f32) -> (m: Matrix3f32) { cos_z := math.cos(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 return } @@ -274,14 +274,14 @@ matrix3_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z: matrix3_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix3f32) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[1][0] = -sin_x * - sin_y - m[2][0] = -cos_x * - sin_y - m[1][1] = cos_x - m[2][1] = sin_x - m[0][2] = sin_y - m[1][2] = -sin_x * cos_y - m[2][2] = cos_x * cos_y + m[0, 0] = cos_y + m[0, 1] = -sin_x * - sin_y + m[0, 2] = -cos_x * - sin_y + m[1, 1] = cos_x + m[1, 2] = sin_x + m[2, 0] = sin_y + m[2, 1] = -sin_x * cos_y + m[2, 2] = cos_x * cos_y return } @@ -289,14 +289,14 @@ matrix3_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix3f3 matrix3_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix3f32) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[2][0] = -sin_y - m[0][1] = sin_y*sin_x - m[1][1] = cos_x - m[2][1] = cos_y*sin_x - m[0][2] = sin_y*cos_x - m[1][2] = -sin_x - m[2][2] = cos_y*cos_x + m[0, 0] = cos_y + m[0, 2] = -sin_y + m[1, 0] = sin_y*sin_x + m[1, 1] = cos_x + m[1, 2] = cos_y*sin_x + m[2, 0] = sin_y*cos_x + m[2, 1] = -sin_x + m[2, 2] = cos_y*cos_x return } @@ -322,15 +322,15 @@ matrix3_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { s2 := math.sin(-t2) s3 := math.sin(-t3) - m[0][0] = c2 * c3 - m[0][1] =-c1 * s3 + s1 * s2 * c3 - m[0][2] = s1 * s3 + c1 * s2 * c3 - m[1][0] = c2 * s3 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] =-s1 * c3 + c1 * s2 * s3 - m[2][0] =-s2 - m[2][1] = s1 * c2 - m[2][2] = c1 * c2 + m[0, 0] = c2 * c3 + m[1, 0] =-c1 * s3 + s1 * s2 * c3 + m[2, 0] = s1 * s3 + c1 * s2 * c3 + m[0, 1] = c2 * s3 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] =-s1 * c3 + c1 * s2 * s3 + m[0, 2] =-s2 + m[1, 2] = s1 * c2 + m[2, 2] = c1 * c2 return } @@ -342,15 +342,15 @@ matrix3_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp return } @@ -362,15 +362,15 @@ matrix3_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = c1 * s2 - m[0][2] = s1 * s2 - m[1][0] =-c3 * s2 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c1 * s3 + c2 * c3 * s1 - m[2][0] = s2 * s3 - m[2][1] =-c3 * s1 - c1 * c2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 + m[0, 0] = c2 + m[1, 0] = c1 * s2 + m[2, 0] = s1 * s2 + m[0, 1] =-c3 * s2 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c1 * s3 + c2 * c3 * s1 + m[0, 2] = s2 * s3 + m[1, 2] =-c3 * s1 - c1 * c2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 return } @@ -382,15 +382,15 @@ matrix3_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = s1 * s2 - m[0][2] =-c1 * s2 - m[1][0] = s2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = c3 * s1 + c1 * c2 * s3 - m[2][0] = c3 * s2 - m[2][1] =-c1 * s3 - c2 * c3 * s1 - m[2][2] = c1 * c2 * c3 - s1 * s3 + m[0, 0] = c2 + m[1, 0] = s1 * s2 + m[2, 0] =-c1 * s2 + m[0, 1] = s2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = c3 * s1 + c1 * c2 * s3 + m[0, 2] = c3 * s2 + m[1, 2] =-c1 * s3 - c2 * c3 * s1 + m[2, 2] = c1 * c2 * c3 - s1 * s3 return } @@ -402,15 +402,15 @@ matrix3_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = s2* s3 - m[0][2] =-c3 * s1 - c1 * c2 * s3 - m[1][0] = s1 * s2 - m[1][1] = c2 - m[1][2] = c1 * s2 - m[2][0] = c1 * s3 + c2 * c3 * s1 - m[2][1] =-c3 * s2 - m[2][2] = c1 * c2 * c3 - s1 * s3 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = s2* s3 + m[2, 0] =-c3 * s1 - c1 * c2 * s3 + m[0, 1] = s1 * s2 + m[1, 1] = c2 + m[2, 1] = c1 * s2 + m[0, 2] = c1 * s3 + c2 * c3 * s1 + m[1, 2] =-c3 * s2 + m[2, 2] = c1 * c2 * c3 - s1 * s3 return } @@ -422,15 +422,15 @@ matrix3_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c3 * s2 - m[0][2] =-c1 * s3 - c2 * c3 * s1 - m[1][0] =-c1 * s2 - m[1][1] = c2 - m[1][2] = s1 * s2 - m[2][0] = c3 * s1 + c1 * c2 * s3 - m[2][1] = s2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c3 * s2 + m[2, 0] =-c1 * s3 - c2 * c3 * s1 + m[0, 1] =-c1 * s2 + m[1, 1] = c2 + m[2, 1] = s1 * s2 + m[0, 2] = c3 * s1 + c1 * c2 * s3 + m[1, 2] = s2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 return } @@ -442,15 +442,15 @@ matrix3_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c1 * s3 + c2 * c3 * s1 - m[0][2] =-c3 * s2 - m[1][0] =-c3 * s1 - c1 * c2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = s2 * s3 - m[2][0] = c1 * s2 - m[2][1] = s1 * s2 - m[2][2] = c2 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c1 * s3 + c2 * c3 * s1 + m[2, 0] =-c3 * s2 + m[0, 1] =-c3 * s1 - c1 * c2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = s2 * s3 + m[0, 2] = c1 * s2 + m[1, 2] = s1 * s2 + m[2, 2] = c2 return } @@ -462,15 +462,15 @@ matrix3_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = c3 * s1 + c1 * c2 * s3 - m[0][2] = s2 *s3 - m[1][0] =-c1 * s3 - c2 * c3 * s1 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c3 * s2 - m[2][0] = s1 * s2 - m[2][1] =-c1 * s2 - m[2][2] = c2 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = c3 * s1 + c1 * c2 * s3 + m[2, 0] = s2 *s3 + m[0, 1] =-c1 * s3 - c2 * c3 * s1 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c3 * s2 + m[0, 2] = s1 * s2 + m[1, 2] =-c1 * s2 + m[2, 2] = c2 return } @@ -483,15 +483,15 @@ matrix3_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 * c3 - m[0][1] = s1 * s3 + c1 * c3 * s2 - m[0][2] = c3 * s1 * s2 - c1 * s3 - m[1][0] =-s2 - m[1][1] = c1 * c2 - m[1][2] = c2 * s1 - m[2][0] = c2 * s3 - m[2][1] = c1 * s2 * s3 - c3 * s1 - m[2][2] = c1 * c3 + s1 * s2 *s3 + m[0, 0] = c2 * c3 + m[1, 0] = s1 * s3 + c1 * c3 * s2 + m[2, 0] = c3 * s1 * s2 - c1 * s3 + m[0, 1] =-s2 + m[1, 1] = c1 * c2 + m[2, 1] = c2 * s1 + m[0, 2] = c2 * s3 + m[1, 2] = c1 * s2 * s3 - c3 * s1 + m[2, 2] = c1 * c3 + s1 * s2 *s3 return } @@ -503,15 +503,15 @@ matrix3_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = s2 - m[0][2] =-c2 * s1 - m[1][0] = s1 * s3 - c1 * c3 * s2 - m[1][1] = c2 * c3 - m[1][2] = c1 * s3 + c3 * s1 * s2 - m[2][0] = c3 * s1 + c1 * s2 * s3 - m[2][1] =-c2 * s3 - m[2][2] = c1 * c3 - s1 * s2 * s3 + m[0, 0] = c1 * c2 + m[1, 0] = s2 + m[2, 0] =-c2 * s1 + m[0, 1] = s1 * s3 - c1 * c3 * s2 + m[1, 1] = c2 * c3 + m[2, 1] = c1 * s3 + c3 * s1 * s2 + m[0, 2] = c3 * s1 + c1 * s2 * s3 + m[1, 2] =-c2 * s3 + m[2, 2] = c1 * c3 - s1 * s2 * s3 return } @@ -523,15 +523,15 @@ matrix3_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = c2 * s1 - m[0][2] =-s2 - m[1][0] = c1 * s2 * s3 - c3 * s1 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] = c2 * s3 - m[2][0] = s1 * s3 + c1 * c3 * s2 - m[2][1] = c3 * s1 * s2 - c1 * s3 - m[2][2] = c2 * c3 + m[0, 0] = c1 * c2 + m[1, 0] = c2 * s1 + m[2, 0] =-s2 + m[0, 1] = c1 * s2 * s3 - c3 * s1 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] = c2 * s3 + m[0, 2] = s1 * s3 + c1 * c3 * s2 + m[1, 2] = c3 * s1 * s2 - c1 * s3 + m[2, 2] = c2 * c3 return } @@ -543,15 +543,15 @@ matrix3_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix3f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - s1 * s2 * s3 - m[0][1] = c3 * s1 + c1 * s2 * s3 - m[0][2] =-c2 * s3 - m[1][0] =-c2 * s1 - m[1][1] = c1 * c2 - m[1][2] = s2 - m[2][0] = c1 * s3 + c3 * s1 * s2 - m[2][1] = s1 * s3 - c1 * c3 * s2 - m[2][2] = c2 * c3 + m[0, 0] = c1 * c3 - s1 * s2 * s3 + m[1, 0] = c3 * s1 + c1 * s2 * s3 + m[2, 0] =-c2 * s3 + m[0, 1] =-c2 * s1 + m[1, 1] = c1 * c2 + m[2, 1] = s2 + m[0, 2] = c1 * s3 + c3 * s1 * s2 + m[1, 2] = s1 * s3 - c1 * c3 * s2 + m[2, 2] = c2 * c3 return } @@ -564,25 +564,25 @@ matrix3_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix3f32 cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp return m } euler_angles_xyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[2][1], m[2][2]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[1][0]*m[1][0]) - T2 := math.atan2(-m[2][0], C2) + T1 := math.atan2(m[1, 2], m[2, 2]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) + T2 := math.atan2(-m[0, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][2] - C1*m[0][1], C1*m[1][1] - S1*m[1][2]) + T3 := math.atan2(S1*m[2, 0] - C1*m[1, 0], C1*m[1, 1] - S1*m[2, 1]) t1 = -T1 t2 = -T2 t3 = -T3 @@ -590,12 +590,12 @@ euler_angles_xyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_yxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[2][0], m[2][2]) - C2 := math.sqrt(m[0][1]*m[0][1] + m[1][1]*m[1][1]) - T2 := math.atan2(-m[2][1], C2) + T1 := math.atan2(m[0, 2], m[2, 2]) + C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) + T2 := math.atan2(-m[1, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][2] - C1*m[1][0], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(S1*m[2, 1] - C1*m[0, 1], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -603,12 +603,12 @@ euler_angles_yxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_xzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[0][2], m[0][1]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[2, 0], m[1, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[1][2] - S1*m[1][1], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(C1*m[2, 1] - S1*m[1, 1], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -616,12 +616,12 @@ euler_angles_xzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_xyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[0][1], -m[0][2]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[1, 0], -m[2, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[2][1] - S1*m[2][2], C1*m[1][1] + S1*m[1][2]) + T3 := math.atan2(-C1*m[1, 2] - S1*m[2, 2], C1*m[1, 1] + S1*m[2, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -629,12 +629,12 @@ euler_angles_xyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_yxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[1][0], m[1][2]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[0, 1], m[2, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] - S1*m[2][2], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(C1*m[0, 2] - S1*m[2, 2], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -642,24 +642,24 @@ euler_angles_yxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_yzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[1][2], -m[1][0]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[2, 1], -m[0, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-S1*m[0][0] - C1*m[0][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(-S1*m[0, 0] - C1*m[2, 0], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 return } euler_angles_zyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[2][1], m[2][0]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[1, 2], m[0, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[0][1] - S1*m[0][0], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(C1*m[1, 0] - S1*m[0, 0], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -667,12 +667,12 @@ euler_angles_zyz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_zxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[2][0], -m[2][1]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[0, 2], -m[1, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[1][0] - S1*m[1][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(-C1*m[0, 1] - S1*m[1, 1], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -680,12 +680,12 @@ euler_angles_zxz_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_xzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[1][2], m[1][1]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[2][0]*m[2][0]) - T2 := math.atan2(-m[1][0], C2) + T1 := math.atan2(m[2, 1], m[1, 1]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) + T2 := math.atan2(-m[0, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][1] - C1*m[0][2], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(S1*m[1, 0] - C1*m[2, 0], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -693,12 +693,12 @@ euler_angles_xzy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_yzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(-m[0][2], m[0][0]) - C2 := math.sqrt(m[1][1]*m[1][1] + m[2][1]*m[2][1]) - T2 := math.atan2(m[0][1], C2) + T1 := math.atan2(-m[2, 0], m[0, 0]) + C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) + T2 := math.atan2(m[1, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][0] + C1*m[1][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(S1*m[0, 1] + C1*m[2, 1], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -706,12 +706,12 @@ euler_angles_yzx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_zyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[0][1], m[0][0]) - C2 := math.sqrt(m[1][2]*m[1][2] + m[2][2]*m[2][2]) - T2 := math.atan2(-m[0][2], C2) + T1 := math.atan2(m[1, 0], m[0, 0]) + C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) + T2 := math.atan2(-m[2, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[2][0] - C1*m[2][1], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(S1*m[0, 2] - C1*m[1, 2], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -719,12 +719,12 @@ euler_angles_zyx_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { } euler_angles_zxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(-m[1][0], m[1][1]) - C2 := math.sqrt(m[0][2]*m[0][2] + m[2][2]*m[2][2]) - T2 := math.atan2(m[1][2], C2) + T1 := math.atan2(-m[0, 1], m[1, 1]) + C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) + T2 := math.atan2(m[2, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] + S1*m[2][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(C1*m[0, 2] + S1*m[1, 2], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -737,32 +737,32 @@ euler_angles_zxy_from_matrix3_f32 :: proc(m: Matrix3f32) -> (t1, t2, t3: f32) { matrix4_from_euler_angle_x_f32 :: proc(angle_x: f32) -> (m: Matrix4f32) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x - m[3][3] = 1 + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x + m[3, 3] = 1 return } matrix4_from_euler_angle_y_f32 :: proc(angle_y: f32) -> (m: Matrix4f32) { cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y - m[3][3] = 1 + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y + m[3, 3] = 1 return } matrix4_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix4f32) { cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 - m[3][3] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 + m[3, 3] = 1 return } @@ -770,34 +770,34 @@ matrix4_from_euler_angle_z_f32 :: proc(angle_z: f32) -> (m: Matrix4f32) { matrix4_from_derived_euler_angle_x_f32 :: proc(angle_x: f32, angular_velocity_x: f32) -> (m: Matrix4f32) { cos_x := math.cos(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x - m[3][3] = 1 + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x + m[3, 3] = 1 return } matrix4_from_derived_euler_angle_y_f32 :: proc(angle_y: f32, angular_velocity_y: f32) -> (m: Matrix4f32) { cos_y := math.cos(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y - m[3][3] = 1 + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y + m[3, 3] = 1 return } matrix4_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z: f32) -> (m: Matrix4f32) { cos_z := math.cos(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 - m[3][3] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 + m[3, 3] = 1 return } @@ -805,15 +805,15 @@ matrix4_from_derived_euler_angle_z_f32 :: proc(angle_z: f32, angular_velocity_z: matrix4_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix4f32) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[1][0] = -sin_x * - sin_y - m[2][0] = -cos_x * - sin_y - m[1][1] = cos_x - m[2][1] = sin_x - m[0][2] = sin_y - m[1][2] = -sin_x * cos_y - m[2][2] = cos_x * cos_y - m[3][3] = 1 + m[0, 0] = cos_y + m[0, 1] = -sin_x * - sin_y + m[0, 2] = -cos_x * - sin_y + m[1, 1] = cos_x + m[1, 2] = sin_x + m[2, 0] = sin_y + m[2, 1] = -sin_x * cos_y + m[2, 2] = cos_x * cos_y + m[3, 3] = 1 return } @@ -821,15 +821,15 @@ matrix4_from_euler_angles_xy_f32 :: proc(angle_x, angle_y: f32) -> (m: Matrix4f3 matrix4_from_euler_angles_yx_f32 :: proc(angle_y, angle_x: f32) -> (m: Matrix4f32) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[2][0] = -sin_y - m[0][1] = sin_y*sin_x - m[1][1] = cos_x - m[2][1] = cos_y*sin_x - m[0][2] = sin_y*cos_x - m[1][2] = -sin_x - m[2][2] = cos_y*cos_x - m[3][3] = 1 + m[0, 0] = cos_y + m[0, 2] = -sin_y + m[1, 0] = sin_y*sin_x + m[1, 1] = cos_x + m[1, 2] = cos_y*sin_x + m[2, 0] = sin_y*cos_x + m[2, 1] = -sin_x + m[2, 2] = cos_y*cos_x + m[3, 3] = 1 return } @@ -855,22 +855,22 @@ matrix4_from_euler_angles_xyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { s2 := math.sin(-t2) s3 := math.sin(-t3) - m[0][0] = c2 * c3 - m[0][1] =-c1 * s3 + s1 * s2 * c3 - m[0][2] = s1 * s3 + c1 * s2 * c3 - m[0][3] = 0 - m[1][0] = c2 * s3 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] =-s1 * c3 + c1 * s2 * s3 - m[1][3] = 0 - m[2][0] =-s2 - m[2][1] = s1 * c2 - m[2][2] = c1 * c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 * c3 + m[1, 0] =-c1 * s3 + s1 * s2 * c3 + m[2, 0] = s1 * s3 + c1 * s2 * c3 + m[3, 0] = 0 + m[0, 1] = c2 * s3 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] =-s1 * c3 + c1 * s2 * s3 + m[3, 1] = 0 + m[0, 2] =-s2 + m[1, 2] = s1 * c2 + m[2, 2] = c1 * c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -882,22 +882,22 @@ matrix4_from_euler_angles_yxz_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[0][3] = 0 - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[1][3] = 0 - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[3, 0] = 0 + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[3, 1] = 0 + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -909,22 +909,22 @@ matrix4_from_euler_angles_xzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = c1 * s2 - m[0][2] = s1 * s2 - m[0][3] = 0 - m[1][0] =-c3 * s2 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c1 * s3 + c2 * c3 * s1 - m[1][3] = 0 - m[2][0] = s2 * s3 - m[2][1] =-c3 * s1 - c1 * c2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 + m[1, 0] = c1 * s2 + m[2, 0] = s1 * s2 + m[3, 0] = 0 + m[0, 1] =-c3 * s2 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c1 * s3 + c2 * c3 * s1 + m[3, 1] = 0 + m[0, 2] = s2 * s3 + m[1, 2] =-c3 * s1 - c1 * c2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -936,22 +936,22 @@ matrix4_from_euler_angles_xyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = s1 * s2 - m[0][2] =-c1 * s2 - m[0][3] = 0 - m[1][0] = s2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = c3 * s1 + c1 * c2 * s3 - m[1][3] = 0 - m[2][0] = c3 * s2 - m[2][1] =-c1 * s3 - c2 * c3 * s1 - m[2][2] = c1 * c2 * c3 - s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 + m[1, 0] = s1 * s2 + m[2, 0] =-c1 * s2 + m[3, 0] = 0 + m[0, 1] = s2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = c3 * s1 + c1 * c2 * s3 + m[3, 1] = 0 + m[0, 2] = c3 * s2 + m[1, 2] =-c1 * s3 - c2 * c3 * s1 + m[2, 2] = c1 * c2 * c3 - s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -963,22 +963,22 @@ matrix4_from_euler_angles_yxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = s2* s3 - m[0][2] =-c3 * s1 - c1 * c2 * s3 - m[0][3] = 0 - m[1][0] = s1 * s2 - m[1][1] = c2 - m[1][2] = c1 * s2 - m[1][3] = 0 - m[2][0] = c1 * s3 + c2 * c3 * s1 - m[2][1] =-c3 * s2 - m[2][2] = c1 * c2 * c3 - s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = s2* s3 + m[2, 0] =-c3 * s1 - c1 * c2 * s3 + m[3, 0] = 0 + m[0, 1] = s1 * s2 + m[1, 1] = c2 + m[2, 1] = c1 * s2 + m[3, 1] = 0 + m[0, 2] = c1 * s3 + c2 * c3 * s1 + m[1, 2] =-c3 * s2 + m[2, 2] = c1 * c2 * c3 - s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -990,22 +990,22 @@ matrix4_from_euler_angles_yzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c3 * s2 - m[0][2] =-c1 * s3 - c2 * c3 * s1 - m[0][3] = 0 - m[1][0] =-c1 * s2 - m[1][1] = c2 - m[1][2] = s1 * s2 - m[1][3] = 0 - m[2][0] = c3 * s1 + c1 * c2 * s3 - m[2][1] = s2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c3 * s2 + m[2, 0] =-c1 * s3 - c2 * c3 * s1 + m[3, 0] = 0 + m[0, 1] =-c1 * s2 + m[1, 1] = c2 + m[2, 1] = s1 * s2 + m[3, 1] = 0 + m[0, 2] = c3 * s1 + c1 * c2 * s3 + m[1, 2] = s2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1017,22 +1017,22 @@ matrix4_from_euler_angles_zyz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c1 * s3 + c2 * c3 * s1 - m[0][2] =-c3 * s2 - m[0][3] = 0 - m[1][0] =-c3 * s1 - c1 * c2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = s2 * s3 - m[1][3] = 0 - m[2][0] = c1 * s2 - m[2][1] = s1 * s2 - m[2][2] = c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c1 * s3 + c2 * c3 * s1 + m[2, 0] =-c3 * s2 + m[3, 0] = 0 + m[0, 1] =-c3 * s1 - c1 * c2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = s2 * s3 + m[3, 1] = 0 + m[0, 2] = c1 * s2 + m[1, 2] = s1 * s2 + m[2, 2] = c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1044,22 +1044,22 @@ matrix4_from_euler_angles_zxz_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = c3 * s1 + c1 * c2 * s3 - m[0][2] = s2 *s3 - m[0][3] = 0 - m[1][0] =-c1 * s3 - c2 * c3 * s1 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c3 * s2 - m[1][3] = 0 - m[2][0] = s1 * s2 - m[2][1] =-c1 * s2 - m[2][2] = c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = c3 * s1 + c1 * c2 * s3 + m[2, 0] = s2 *s3 + m[3, 0] = 0 + m[0, 1] =-c1 * s3 - c2 * c3 * s1 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c3 * s2 + m[3, 1] = 0 + m[0, 2] = s1 * s2 + m[1, 2] =-c1 * s2 + m[2, 2] = c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1072,22 +1072,22 @@ matrix4_from_euler_angles_xzy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 * c3 - m[0][1] = s1 * s3 + c1 * c3 * s2 - m[0][2] = c3 * s1 * s2 - c1 * s3 - m[0][3] = 0 - m[1][0] =-s2 - m[1][1] = c1 * c2 - m[1][2] = c2 * s1 - m[1][3] = 0 - m[2][0] = c2 * s3 - m[2][1] = c1 * s2 * s3 - c3 * s1 - m[2][2] = c1 * c3 + s1 * s2 *s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 * c3 + m[1, 0] = s1 * s3 + c1 * c3 * s2 + m[2, 0] = c3 * s1 * s2 - c1 * s3 + m[3, 0] = 0 + m[0, 1] =-s2 + m[1, 1] = c1 * c2 + m[2, 1] = c2 * s1 + m[3, 1] = 0 + m[0, 2] = c2 * s3 + m[1, 2] = c1 * s2 * s3 - c3 * s1 + m[2, 2] = c1 * c3 + s1 * s2 *s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1099,22 +1099,22 @@ matrix4_from_euler_angles_yzx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = s2 - m[0][2] =-c2 * s1 - m[0][3] = 0 - m[1][0] = s1 * s3 - c1 * c3 * s2 - m[1][1] = c2 * c3 - m[1][2] = c1 * s3 + c3 * s1 * s2 - m[1][3] = 0 - m[2][0] = c3 * s1 + c1 * s2 * s3 - m[2][1] =-c2 * s3 - m[2][2] = c1 * c3 - s1 * s2 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 + m[1, 0] = s2 + m[2, 0] =-c2 * s1 + m[3, 0] = 0 + m[0, 1] = s1 * s3 - c1 * c3 * s2 + m[1, 1] = c2 * c3 + m[2, 1] = c1 * s3 + c3 * s1 * s2 + m[3, 1] = 0 + m[0, 2] = c3 * s1 + c1 * s2 * s3 + m[1, 2] =-c2 * s3 + m[2, 2] = c1 * c3 - s1 * s2 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1126,22 +1126,22 @@ matrix4_from_euler_angles_zyx_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = c2 * s1 - m[0][2] =-s2 - m[0][3] = 0 - m[1][0] = c1 * s2 * s3 - c3 * s1 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] = c2 * s3 - m[1][3] = 0 - m[2][0] = s1 * s3 + c1 * c3 * s2 - m[2][1] = c3 * s1 * s2 - c1 * s3 - m[2][2] = c2 * c3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 + m[1, 0] = c2 * s1 + m[2, 0] =-s2 + m[3, 0] = 0 + m[0, 1] = c1 * s2 * s3 - c3 * s1 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] = c2 * s3 + m[3, 1] = 0 + m[0, 2] = s1 * s3 + c1 * c3 * s2 + m[1, 2] = c3 * s1 * s2 - c1 * s3 + m[2, 2] = c2 * c3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1153,22 +1153,22 @@ matrix4_from_euler_angles_zxy_f32 :: proc(t1, t2, t3: f32) -> (m: Matrix4f32) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - s1 * s2 * s3 - m[0][1] = c3 * s1 + c1 * s2 * s3 - m[0][2] =-c2 * s3 - m[0][3] = 0 - m[1][0] =-c2 * s1 - m[1][1] = c1 * c2 - m[1][2] = s2 - m[1][3] = 0 - m[2][0] = c1 * s3 + c3 * s1 * s2 - m[2][1] = s1 * s3 - c1 * c3 * s2 - m[2][2] = c2 * c3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - s1 * s2 * s3 + m[1, 0] = c3 * s1 + c1 * s2 * s3 + m[2, 0] =-c2 * s3 + m[3, 0] = 0 + m[0, 1] =-c2 * s1 + m[1, 1] = c1 * c2 + m[2, 1] = s2 + m[3, 1] = 0 + m[0, 2] = c1 * s3 + c3 * s1 * s2 + m[1, 2] = s1 * s3 - c1 * c3 * s2 + m[2, 2] = c2 * c3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1181,32 +1181,32 @@ matrix4_from_yaw_pitch_roll_f32 :: proc(yaw, pitch, roll: f32) -> (m: Matrix4f32 cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[0][3] = 0 - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[1][3] = 0 - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[3, 0] = 0 + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[3, 1] = 0 + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return m } euler_angles_xyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[2][1], m[2][2]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[1][0]*m[1][0]) - T2 := math.atan2(-m[2][0], C2) + T1 := math.atan2(m[1, 2], m[2, 2]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) + T2 := math.atan2(-m[0, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][2] - C1*m[0][1], C1*m[1][1] - S1*m[1][2]) + T3 := math.atan2(S1*m[2, 0] - C1*m[1, 0], C1*m[1, 1] - S1*m[2, 1]) t1 = -T1 t2 = -T2 t3 = -T3 @@ -1214,12 +1214,12 @@ euler_angles_xyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_yxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[2][0], m[2][2]) - C2 := math.sqrt(m[0][1]*m[0][1] + m[1][1]*m[1][1]) - T2 := math.atan2(-m[2][1], C2) + T1 := math.atan2(m[0, 2], m[2, 2]) + C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) + T2 := math.atan2(-m[1, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][2] - C1*m[1][0], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(S1*m[2, 1] - C1*m[0, 1], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1227,12 +1227,12 @@ euler_angles_yxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_xzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[0][2], m[0][1]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[2, 0], m[1, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[1][2] - S1*m[1][1], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(C1*m[2, 1] - S1*m[1, 1], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1240,12 +1240,12 @@ euler_angles_xzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_xyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[0][1], -m[0][2]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[1, 0], -m[2, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[2][1] - S1*m[2][2], C1*m[1][1] + S1*m[1][2]) + T3 := math.atan2(-C1*m[1, 2] - S1*m[2, 2], C1*m[1, 1] + S1*m[2, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1253,12 +1253,12 @@ euler_angles_xyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_yxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[1][0], m[1][2]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[0, 1], m[2, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] - S1*m[2][2], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(C1*m[0, 2] - S1*m[2, 2], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1266,24 +1266,24 @@ euler_angles_yxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_yzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[1][2], -m[1][0]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[2, 1], -m[0, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-S1*m[0][0] - C1*m[0][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(-S1*m[0, 0] - C1*m[2, 0], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 return } euler_angles_zyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[2][1], m[2][0]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[1, 2], m[0, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[0][1] - S1*m[0][0], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(C1*m[1, 0] - S1*m[0, 0], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1291,12 +1291,12 @@ euler_angles_zyz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_zxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[2][0], -m[2][1]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[0, 2], -m[1, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[1][0] - S1*m[1][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(-C1*m[0, 1] - S1*m[1, 1], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1304,12 +1304,12 @@ euler_angles_zxz_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_xzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[1][2], m[1][1]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[2][0]*m[2][0]) - T2 := math.atan2(-m[1][0], C2) + T1 := math.atan2(m[2, 1], m[1, 1]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) + T2 := math.atan2(-m[0, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][1] - C1*m[0][2], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(S1*m[1, 0] - C1*m[2, 0], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1317,12 +1317,12 @@ euler_angles_xzy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_yzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(-m[0][2], m[0][0]) - C2 := math.sqrt(m[1][1]*m[1][1] + m[2][1]*m[2][1]) - T2 := math.atan2(m[0][1], C2) + T1 := math.atan2(-m[2, 0], m[0, 0]) + C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) + T2 := math.atan2(m[1, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][0] + C1*m[1][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(S1*m[0, 1] + C1*m[2, 1], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1330,12 +1330,12 @@ euler_angles_yzx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_zyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(m[0][1], m[0][0]) - C2 := math.sqrt(m[1][2]*m[1][2] + m[2][2]*m[2][2]) - T2 := math.atan2(-m[0][2], C2) + T1 := math.atan2(m[1, 0], m[0, 0]) + C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) + T2 := math.atan2(-m[2, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[2][0] - C1*m[2][1], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(S1*m[0, 2] - C1*m[1, 2], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1343,12 +1343,12 @@ euler_angles_zyx_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { } euler_angles_zxy_from_matrix4_f32 :: proc(m: Matrix4f32) -> (t1, t2, t3: f32) { - T1 := math.atan2(-m[1][0], m[1][1]) - C2 := math.sqrt(m[0][2]*m[0][2] + m[2][2]*m[2][2]) - T2 := math.atan2(m[1][2], C2) + T1 := math.atan2(-m[0, 1], m[1, 1]) + C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) + T2 := math.atan2(m[2, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] + S1*m[2][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(C1*m[0, 2] + S1*m[1, 2], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 diff --git a/core/math/linalg/specific_euler_angles_f64.odin b/core/math/linalg/specific_euler_angles_f64.odin index efaddd651..2f8f758b0 100644 --- a/core/math/linalg/specific_euler_angles_f64.odin +++ b/core/math/linalg/specific_euler_angles_f64.odin @@ -212,29 +212,29 @@ euler_angles_zxy_from_quaternion_f64 :: proc(q: Quaternionf64) -> (t1, t2, t3: f matrix3_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix3f64) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x return } matrix3_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix3f64) { cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y return } matrix3_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix3f64) { cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 return } @@ -242,31 +242,31 @@ matrix3_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix3f64) { matrix3_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x: f64) -> (m: Matrix3f64) { cos_x := math.cos(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x return } matrix3_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y: f64) -> (m: Matrix3f64) { cos_y := math.cos(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y return } matrix3_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z: f64) -> (m: Matrix3f64) { cos_z := math.cos(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 return } @@ -274,14 +274,14 @@ matrix3_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z: matrix3_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix3f64) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[1][0] = -sin_x * - sin_y - m[2][0] = -cos_x * - sin_y - m[1][1] = cos_x - m[2][1] = sin_x - m[0][2] = sin_y - m[1][2] = -sin_x * cos_y - m[2][2] = cos_x * cos_y + m[0, 0] = cos_y + m[0, 1] = -sin_x * - sin_y + m[0, 2] = -cos_x * - sin_y + m[1, 1] = cos_x + m[1, 2] = sin_x + m[2, 0] = sin_y + m[2, 1] = -sin_x * cos_y + m[2, 2] = cos_x * cos_y return } @@ -289,14 +289,14 @@ matrix3_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix3f6 matrix3_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix3f64) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[2][0] = -sin_y - m[0][1] = sin_y*sin_x - m[1][1] = cos_x - m[2][1] = cos_y*sin_x - m[0][2] = sin_y*cos_x - m[1][2] = -sin_x - m[2][2] = cos_y*cos_x + m[0, 0] = cos_y + m[0, 2] = -sin_y + m[1, 0] = sin_y*sin_x + m[1, 1] = cos_x + m[1, 2] = cos_y*sin_x + m[2, 0] = sin_y*cos_x + m[2, 1] = -sin_x + m[2, 2] = cos_y*cos_x return } @@ -322,15 +322,15 @@ matrix3_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { s2 := math.sin(-t2) s3 := math.sin(-t3) - m[0][0] = c2 * c3 - m[0][1] =-c1 * s3 + s1 * s2 * c3 - m[0][2] = s1 * s3 + c1 * s2 * c3 - m[1][0] = c2 * s3 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] =-s1 * c3 + c1 * s2 * s3 - m[2][0] =-s2 - m[2][1] = s1 * c2 - m[2][2] = c1 * c2 + m[0, 0] = c2 * c3 + m[1, 0] =-c1 * s3 + s1 * s2 * c3 + m[2, 0] = s1 * s3 + c1 * s2 * c3 + m[0, 1] = c2 * s3 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] =-s1 * c3 + c1 * s2 * s3 + m[0, 2] =-s2 + m[1, 2] = s1 * c2 + m[2, 2] = c1 * c2 return } @@ -342,15 +342,15 @@ matrix3_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp return } @@ -362,15 +362,15 @@ matrix3_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = c1 * s2 - m[0][2] = s1 * s2 - m[1][0] =-c3 * s2 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c1 * s3 + c2 * c3 * s1 - m[2][0] = s2 * s3 - m[2][1] =-c3 * s1 - c1 * c2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 + m[0, 0] = c2 + m[1, 0] = c1 * s2 + m[2, 0] = s1 * s2 + m[0, 1] =-c3 * s2 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c1 * s3 + c2 * c3 * s1 + m[0, 2] = s2 * s3 + m[1, 2] =-c3 * s1 - c1 * c2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 return } @@ -382,15 +382,15 @@ matrix3_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = s1 * s2 - m[0][2] =-c1 * s2 - m[1][0] = s2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = c3 * s1 + c1 * c2 * s3 - m[2][0] = c3 * s2 - m[2][1] =-c1 * s3 - c2 * c3 * s1 - m[2][2] = c1 * c2 * c3 - s1 * s3 + m[0, 0] = c2 + m[1, 0] = s1 * s2 + m[2, 0] =-c1 * s2 + m[0, 1] = s2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = c3 * s1 + c1 * c2 * s3 + m[0, 2] = c3 * s2 + m[1, 2] =-c1 * s3 - c2 * c3 * s1 + m[2, 2] = c1 * c2 * c3 - s1 * s3 return } @@ -402,15 +402,15 @@ matrix3_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = s2* s3 - m[0][2] =-c3 * s1 - c1 * c2 * s3 - m[1][0] = s1 * s2 - m[1][1] = c2 - m[1][2] = c1 * s2 - m[2][0] = c1 * s3 + c2 * c3 * s1 - m[2][1] =-c3 * s2 - m[2][2] = c1 * c2 * c3 - s1 * s3 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = s2* s3 + m[2, 0] =-c3 * s1 - c1 * c2 * s3 + m[0, 1] = s1 * s2 + m[1, 1] = c2 + m[2, 1] = c1 * s2 + m[0, 2] = c1 * s3 + c2 * c3 * s1 + m[1, 2] =-c3 * s2 + m[2, 2] = c1 * c2 * c3 - s1 * s3 return } @@ -422,15 +422,15 @@ matrix3_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c3 * s2 - m[0][2] =-c1 * s3 - c2 * c3 * s1 - m[1][0] =-c1 * s2 - m[1][1] = c2 - m[1][2] = s1 * s2 - m[2][0] = c3 * s1 + c1 * c2 * s3 - m[2][1] = s2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c3 * s2 + m[2, 0] =-c1 * s3 - c2 * c3 * s1 + m[0, 1] =-c1 * s2 + m[1, 1] = c2 + m[2, 1] = s1 * s2 + m[0, 2] = c3 * s1 + c1 * c2 * s3 + m[1, 2] = s2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 return } @@ -442,15 +442,15 @@ matrix3_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c1 * s3 + c2 * c3 * s1 - m[0][2] =-c3 * s2 - m[1][0] =-c3 * s1 - c1 * c2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = s2 * s3 - m[2][0] = c1 * s2 - m[2][1] = s1 * s2 - m[2][2] = c2 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c1 * s3 + c2 * c3 * s1 + m[2, 0] =-c3 * s2 + m[0, 1] =-c3 * s1 - c1 * c2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = s2 * s3 + m[0, 2] = c1 * s2 + m[1, 2] = s1 * s2 + m[2, 2] = c2 return } @@ -462,15 +462,15 @@ matrix3_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = c3 * s1 + c1 * c2 * s3 - m[0][2] = s2 *s3 - m[1][0] =-c1 * s3 - c2 * c3 * s1 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c3 * s2 - m[2][0] = s1 * s2 - m[2][1] =-c1 * s2 - m[2][2] = c2 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = c3 * s1 + c1 * c2 * s3 + m[2, 0] = s2 *s3 + m[0, 1] =-c1 * s3 - c2 * c3 * s1 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c3 * s2 + m[0, 2] = s1 * s2 + m[1, 2] =-c1 * s2 + m[2, 2] = c2 return } @@ -483,15 +483,15 @@ matrix3_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 * c3 - m[0][1] = s1 * s3 + c1 * c3 * s2 - m[0][2] = c3 * s1 * s2 - c1 * s3 - m[1][0] =-s2 - m[1][1] = c1 * c2 - m[1][2] = c2 * s1 - m[2][0] = c2 * s3 - m[2][1] = c1 * s2 * s3 - c3 * s1 - m[2][2] = c1 * c3 + s1 * s2 *s3 + m[0, 0] = c2 * c3 + m[1, 0] = s1 * s3 + c1 * c3 * s2 + m[2, 0] = c3 * s1 * s2 - c1 * s3 + m[0, 1] =-s2 + m[1, 1] = c1 * c2 + m[2, 1] = c2 * s1 + m[0, 2] = c2 * s3 + m[1, 2] = c1 * s2 * s3 - c3 * s1 + m[2, 2] = c1 * c3 + s1 * s2 *s3 return } @@ -503,15 +503,15 @@ matrix3_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = s2 - m[0][2] =-c2 * s1 - m[1][0] = s1 * s3 - c1 * c3 * s2 - m[1][1] = c2 * c3 - m[1][2] = c1 * s3 + c3 * s1 * s2 - m[2][0] = c3 * s1 + c1 * s2 * s3 - m[2][1] =-c2 * s3 - m[2][2] = c1 * c3 - s1 * s2 * s3 + m[0, 0] = c1 * c2 + m[1, 0] = s2 + m[2, 0] =-c2 * s1 + m[0, 1] = s1 * s3 - c1 * c3 * s2 + m[1, 1] = c2 * c3 + m[2, 1] = c1 * s3 + c3 * s1 * s2 + m[0, 2] = c3 * s1 + c1 * s2 * s3 + m[1, 2] =-c2 * s3 + m[2, 2] = c1 * c3 - s1 * s2 * s3 return } @@ -523,15 +523,15 @@ matrix3_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = c2 * s1 - m[0][2] =-s2 - m[1][0] = c1 * s2 * s3 - c3 * s1 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] = c2 * s3 - m[2][0] = s1 * s3 + c1 * c3 * s2 - m[2][1] = c3 * s1 * s2 - c1 * s3 - m[2][2] = c2 * c3 + m[0, 0] = c1 * c2 + m[1, 0] = c2 * s1 + m[2, 0] =-s2 + m[0, 1] = c1 * s2 * s3 - c3 * s1 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] = c2 * s3 + m[0, 2] = s1 * s3 + c1 * c3 * s2 + m[1, 2] = c3 * s1 * s2 - c1 * s3 + m[2, 2] = c2 * c3 return } @@ -543,15 +543,15 @@ matrix3_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix3f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - s1 * s2 * s3 - m[0][1] = c3 * s1 + c1 * s2 * s3 - m[0][2] =-c2 * s3 - m[1][0] =-c2 * s1 - m[1][1] = c1 * c2 - m[1][2] = s2 - m[2][0] = c1 * s3 + c3 * s1 * s2 - m[2][1] = s1 * s3 - c1 * c3 * s2 - m[2][2] = c2 * c3 + m[0, 0] = c1 * c3 - s1 * s2 * s3 + m[1, 0] = c3 * s1 + c1 * s2 * s3 + m[2, 0] =-c2 * s3 + m[0, 1] =-c2 * s1 + m[1, 1] = c1 * c2 + m[2, 1] = s2 + m[0, 2] = c1 * s3 + c3 * s1 * s2 + m[1, 2] = s1 * s3 - c1 * c3 * s2 + m[2, 2] = c2 * c3 return } @@ -564,25 +564,25 @@ matrix3_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix3f64 cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp return m } euler_angles_xyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[2][1], m[2][2]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[1][0]*m[1][0]) - T2 := math.atan2(-m[2][0], C2) + T1 := math.atan2(m[1, 2], m[2, 2]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) + T2 := math.atan2(-m[0, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][2] - C1*m[0][1], C1*m[1][1] - S1*m[1][2]) + T3 := math.atan2(S1*m[2, 0] - C1*m[1, 0], C1*m[1, 1] - S1*m[2, 1]) t1 = -T1 t2 = -T2 t3 = -T3 @@ -590,12 +590,12 @@ euler_angles_xyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_yxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[2][0], m[2][2]) - C2 := math.sqrt(m[0][1]*m[0][1] + m[1][1]*m[1][1]) - T2 := math.atan2(-m[2][1], C2) + T1 := math.atan2(m[0, 2], m[2, 2]) + C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) + T2 := math.atan2(-m[1, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][2] - C1*m[1][0], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(S1*m[2, 1] - C1*m[0, 1], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -603,12 +603,12 @@ euler_angles_yxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_xzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[0][2], m[0][1]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[2, 0], m[1, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[1][2] - S1*m[1][1], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(C1*m[2, 1] - S1*m[1, 1], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -616,12 +616,12 @@ euler_angles_xzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_xyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[0][1], -m[0][2]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[1, 0], -m[2, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[2][1] - S1*m[2][2], C1*m[1][1] + S1*m[1][2]) + T3 := math.atan2(-C1*m[1, 2] - S1*m[2, 2], C1*m[1, 1] + S1*m[2, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -629,12 +629,12 @@ euler_angles_xyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_yxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[1][0], m[1][2]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[0, 1], m[2, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] - S1*m[2][2], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(C1*m[0, 2] - S1*m[2, 2], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -642,24 +642,24 @@ euler_angles_yxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_yzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[1][2], -m[1][0]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[2, 1], -m[0, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-S1*m[0][0] - C1*m[0][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(-S1*m[0, 0] - C1*m[2, 0], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 return } euler_angles_zyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[2][1], m[2][0]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[1, 2], m[0, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[0][1] - S1*m[0][0], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(C1*m[1, 0] - S1*m[0, 0], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -667,12 +667,12 @@ euler_angles_zyz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_zxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[2][0], -m[2][1]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[0, 2], -m[1, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[1][0] - S1*m[1][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(-C1*m[0, 1] - S1*m[1, 1], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -680,12 +680,12 @@ euler_angles_zxz_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_xzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[1][2], m[1][1]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[2][0]*m[2][0]) - T2 := math.atan2(-m[1][0], C2) + T1 := math.atan2(m[2, 1], m[1, 1]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) + T2 := math.atan2(-m[0, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][1] - C1*m[0][2], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(S1*m[1, 0] - C1*m[2, 0], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -693,12 +693,12 @@ euler_angles_xzy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_yzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(-m[0][2], m[0][0]) - C2 := math.sqrt(m[1][1]*m[1][1] + m[2][1]*m[2][1]) - T2 := math.atan2(m[0][1], C2) + T1 := math.atan2(-m[2, 0], m[0, 0]) + C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) + T2 := math.atan2(m[1, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][0] + C1*m[1][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(S1*m[0, 1] + C1*m[2, 1], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -706,12 +706,12 @@ euler_angles_yzx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_zyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[0][1], m[0][0]) - C2 := math.sqrt(m[1][2]*m[1][2] + m[2][2]*m[2][2]) - T2 := math.atan2(-m[0][2], C2) + T1 := math.atan2(m[1, 0], m[0, 0]) + C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) + T2 := math.atan2(-m[2, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[2][0] - C1*m[2][1], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(S1*m[0, 2] - C1*m[1, 2], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -719,12 +719,12 @@ euler_angles_zyx_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { } euler_angles_zxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(-m[1][0], m[1][1]) - C2 := math.sqrt(m[0][2]*m[0][2] + m[2][2]*m[2][2]) - T2 := math.atan2(m[1][2], C2) + T1 := math.atan2(-m[0, 1], m[1, 1]) + C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) + T2 := math.atan2(m[2, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] + S1*m[2][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(C1*m[0, 2] + S1*m[1, 2], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -737,32 +737,32 @@ euler_angles_zxy_from_matrix3_f64 :: proc(m: Matrix3f64) -> (t1, t2, t3: f64) { matrix4_from_euler_angle_x_f64 :: proc(angle_x: f64) -> (m: Matrix4f64) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x - m[3][3] = 1 + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x + m[3, 3] = 1 return } matrix4_from_euler_angle_y_f64 :: proc(angle_y: f64) -> (m: Matrix4f64) { cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y - m[3][3] = 1 + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y + m[3, 3] = 1 return } matrix4_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix4f64) { cos_z, sin_z := math.cos(angle_z), math.sin(angle_z) - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 - m[3][3] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 + m[3, 3] = 1 return } @@ -770,34 +770,34 @@ matrix4_from_euler_angle_z_f64 :: proc(angle_z: f64) -> (m: Matrix4f64) { matrix4_from_derived_euler_angle_x_f64 :: proc(angle_x: f64, angular_velocity_x: f64) -> (m: Matrix4f64) { cos_x := math.cos(angle_x) * angular_velocity_x sin_x := math.sin(angle_x) * angular_velocity_x - m[0][0] = 1 - m[1][1] = +cos_x - m[2][1] = +sin_x - m[1][2] = -sin_x - m[2][2] = +cos_x - m[3][3] = 1 + m[0, 0] = 1 + m[1, 1] = +cos_x + m[1, 2] = +sin_x + m[2, 1] = -sin_x + m[2, 2] = +cos_x + m[3, 3] = 1 return } matrix4_from_derived_euler_angle_y_f64 :: proc(angle_y: f64, angular_velocity_y: f64) -> (m: Matrix4f64) { cos_y := math.cos(angle_y) * angular_velocity_y sin_y := math.sin(angle_y) * angular_velocity_y - m[0][0] = +cos_y - m[2][0] = -sin_y - m[1][1] = 1 - m[0][2] = +sin_y - m[2][2] = +cos_y - m[3][3] = 1 + m[0, 0] = +cos_y + m[0, 2] = -sin_y + m[1, 1] = 1 + m[2, 0] = +sin_y + m[2, 2] = +cos_y + m[3, 3] = 1 return } matrix4_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z: f64) -> (m: Matrix4f64) { cos_z := math.cos(angle_z) * angular_velocity_z sin_z := math.sin(angle_z) * angular_velocity_z - m[0][0] = +cos_z - m[1][0] = +sin_z - m[1][1] = +cos_z - m[0][1] = -sin_z - m[2][2] = 1 - m[3][3] = 1 + m[0, 0] = +cos_z + m[0, 1] = +sin_z + m[1, 1] = +cos_z + m[1, 0] = -sin_z + m[2, 2] = 1 + m[3, 3] = 1 return } @@ -805,15 +805,15 @@ matrix4_from_derived_euler_angle_z_f64 :: proc(angle_z: f64, angular_velocity_z: matrix4_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix4f64) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[1][0] = -sin_x * - sin_y - m[2][0] = -cos_x * - sin_y - m[1][1] = cos_x - m[2][1] = sin_x - m[0][2] = sin_y - m[1][2] = -sin_x * cos_y - m[2][2] = cos_x * cos_y - m[3][3] = 1 + m[0, 0] = cos_y + m[0, 1] = -sin_x * - sin_y + m[0, 2] = -cos_x * - sin_y + m[1, 1] = cos_x + m[1, 2] = sin_x + m[2, 0] = sin_y + m[2, 1] = -sin_x * cos_y + m[2, 2] = cos_x * cos_y + m[3, 3] = 1 return } @@ -821,15 +821,15 @@ matrix4_from_euler_angles_xy_f64 :: proc(angle_x, angle_y: f64) -> (m: Matrix4f6 matrix4_from_euler_angles_yx_f64 :: proc(angle_y, angle_x: f64) -> (m: Matrix4f64) { cos_x, sin_x := math.cos(angle_x), math.sin(angle_x) cos_y, sin_y := math.cos(angle_y), math.sin(angle_y) - m[0][0] = cos_y - m[2][0] = -sin_y - m[0][1] = sin_y*sin_x - m[1][1] = cos_x - m[2][1] = cos_y*sin_x - m[0][2] = sin_y*cos_x - m[1][2] = -sin_x - m[2][2] = cos_y*cos_x - m[3][3] = 1 + m[0, 0] = cos_y + m[0, 2] = -sin_y + m[1, 0] = sin_y*sin_x + m[1, 1] = cos_x + m[1, 2] = cos_y*sin_x + m[2, 0] = sin_y*cos_x + m[2, 1] = -sin_x + m[2, 2] = cos_y*cos_x + m[3, 3] = 1 return } @@ -855,22 +855,22 @@ matrix4_from_euler_angles_xyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { s2 := math.sin(-t2) s3 := math.sin(-t3) - m[0][0] = c2 * c3 - m[0][1] =-c1 * s3 + s1 * s2 * c3 - m[0][2] = s1 * s3 + c1 * s2 * c3 - m[0][3] = 0 - m[1][0] = c2 * s3 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] =-s1 * c3 + c1 * s2 * s3 - m[1][3] = 0 - m[2][0] =-s2 - m[2][1] = s1 * c2 - m[2][2] = c1 * c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 * c3 + m[1, 0] =-c1 * s3 + s1 * s2 * c3 + m[2, 0] = s1 * s3 + c1 * s2 * c3 + m[3, 0] = 0 + m[0, 1] = c2 * s3 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] =-s1 * c3 + c1 * s2 * s3 + m[3, 1] = 0 + m[0, 2] =-s2 + m[1, 2] = s1 * c2 + m[2, 2] = c1 * c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -882,22 +882,22 @@ matrix4_from_euler_angles_yxz_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[0][3] = 0 - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[1][3] = 0 - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[3, 0] = 0 + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[3, 1] = 0 + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -909,22 +909,22 @@ matrix4_from_euler_angles_xzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = c1 * s2 - m[0][2] = s1 * s2 - m[0][3] = 0 - m[1][0] =-c3 * s2 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c1 * s3 + c2 * c3 * s1 - m[1][3] = 0 - m[2][0] = s2 * s3 - m[2][1] =-c3 * s1 - c1 * c2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 + m[1, 0] = c1 * s2 + m[2, 0] = s1 * s2 + m[3, 0] = 0 + m[0, 1] =-c3 * s2 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c1 * s3 + c2 * c3 * s1 + m[3, 1] = 0 + m[0, 2] = s2 * s3 + m[1, 2] =-c3 * s1 - c1 * c2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -936,22 +936,22 @@ matrix4_from_euler_angles_xyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 - m[0][1] = s1 * s2 - m[0][2] =-c1 * s2 - m[0][3] = 0 - m[1][0] = s2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = c3 * s1 + c1 * c2 * s3 - m[1][3] = 0 - m[2][0] = c3 * s2 - m[2][1] =-c1 * s3 - c2 * c3 * s1 - m[2][2] = c1 * c2 * c3 - s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 + m[1, 0] = s1 * s2 + m[2, 0] =-c1 * s2 + m[3, 0] = 0 + m[0, 1] = s2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = c3 * s1 + c1 * c2 * s3 + m[3, 1] = 0 + m[0, 2] = c3 * s2 + m[1, 2] =-c1 * s3 - c2 * c3 * s1 + m[2, 2] = c1 * c2 * c3 - s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -963,22 +963,22 @@ matrix4_from_euler_angles_yxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = s2* s3 - m[0][2] =-c3 * s1 - c1 * c2 * s3 - m[0][3] = 0 - m[1][0] = s1 * s2 - m[1][1] = c2 - m[1][2] = c1 * s2 - m[1][3] = 0 - m[2][0] = c1 * s3 + c2 * c3 * s1 - m[2][1] =-c3 * s2 - m[2][2] = c1 * c2 * c3 - s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = s2* s3 + m[2, 0] =-c3 * s1 - c1 * c2 * s3 + m[3, 0] = 0 + m[0, 1] = s1 * s2 + m[1, 1] = c2 + m[2, 1] = c1 * s2 + m[3, 1] = 0 + m[0, 2] = c1 * s3 + c2 * c3 * s1 + m[1, 2] =-c3 * s2 + m[2, 2] = c1 * c2 * c3 - s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -990,22 +990,22 @@ matrix4_from_euler_angles_yzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c3 * s2 - m[0][2] =-c1 * s3 - c2 * c3 * s1 - m[0][3] = 0 - m[1][0] =-c1 * s2 - m[1][1] = c2 - m[1][2] = s1 * s2 - m[1][3] = 0 - m[2][0] = c3 * s1 + c1 * c2 * s3 - m[2][1] = s2 * s3 - m[2][2] = c1 * c3 - c2 * s1 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c3 * s2 + m[2, 0] =-c1 * s3 - c2 * c3 * s1 + m[3, 0] = 0 + m[0, 1] =-c1 * s2 + m[1, 1] = c2 + m[2, 1] = s1 * s2 + m[3, 1] = 0 + m[0, 2] = c3 * s1 + c1 * c2 * s3 + m[1, 2] = s2 * s3 + m[2, 2] = c1 * c3 - c2 * s1 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1017,22 +1017,22 @@ matrix4_from_euler_angles_zyz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 * c3 - s1 * s3 - m[0][1] = c1 * s3 + c2 * c3 * s1 - m[0][2] =-c3 * s2 - m[0][3] = 0 - m[1][0] =-c3 * s1 - c1 * c2 * s3 - m[1][1] = c1 * c3 - c2 * s1 * s3 - m[1][2] = s2 * s3 - m[1][3] = 0 - m[2][0] = c1 * s2 - m[2][1] = s1 * s2 - m[2][2] = c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 * c3 - s1 * s3 + m[1, 0] = c1 * s3 + c2 * c3 * s1 + m[2, 0] =-c3 * s2 + m[3, 0] = 0 + m[0, 1] =-c3 * s1 - c1 * c2 * s3 + m[1, 1] = c1 * c3 - c2 * s1 * s3 + m[2, 1] = s2 * s3 + m[3, 1] = 0 + m[0, 2] = c1 * s2 + m[1, 2] = s1 * s2 + m[2, 2] = c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1044,22 +1044,22 @@ matrix4_from_euler_angles_zxz_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - c2 * s1 * s3 - m[0][1] = c3 * s1 + c1 * c2 * s3 - m[0][2] = s2 *s3 - m[0][3] = 0 - m[1][0] =-c1 * s3 - c2 * c3 * s1 - m[1][1] = c1 * c2 * c3 - s1 * s3 - m[1][2] = c3 * s2 - m[1][3] = 0 - m[2][0] = s1 * s2 - m[2][1] =-c1 * s2 - m[2][2] = c2 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - c2 * s1 * s3 + m[1, 0] = c3 * s1 + c1 * c2 * s3 + m[2, 0] = s2 *s3 + m[3, 0] = 0 + m[0, 1] =-c1 * s3 - c2 * c3 * s1 + m[1, 1] = c1 * c2 * c3 - s1 * s3 + m[2, 1] = c3 * s2 + m[3, 1] = 0 + m[0, 2] = s1 * s2 + m[1, 2] =-c1 * s2 + m[2, 2] = c2 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1072,22 +1072,22 @@ matrix4_from_euler_angles_xzy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c2 * c3 - m[0][1] = s1 * s3 + c1 * c3 * s2 - m[0][2] = c3 * s1 * s2 - c1 * s3 - m[0][3] = 0 - m[1][0] =-s2 - m[1][1] = c1 * c2 - m[1][2] = c2 * s1 - m[1][3] = 0 - m[2][0] = c2 * s3 - m[2][1] = c1 * s2 * s3 - c3 * s1 - m[2][2] = c1 * c3 + s1 * s2 *s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c2 * c3 + m[1, 0] = s1 * s3 + c1 * c3 * s2 + m[2, 0] = c3 * s1 * s2 - c1 * s3 + m[3, 0] = 0 + m[0, 1] =-s2 + m[1, 1] = c1 * c2 + m[2, 1] = c2 * s1 + m[3, 1] = 0 + m[0, 2] = c2 * s3 + m[1, 2] = c1 * s2 * s3 - c3 * s1 + m[2, 2] = c1 * c3 + s1 * s2 *s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1099,22 +1099,22 @@ matrix4_from_euler_angles_yzx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = s2 - m[0][2] =-c2 * s1 - m[0][3] = 0 - m[1][0] = s1 * s3 - c1 * c3 * s2 - m[1][1] = c2 * c3 - m[1][2] = c1 * s3 + c3 * s1 * s2 - m[1][3] = 0 - m[2][0] = c3 * s1 + c1 * s2 * s3 - m[2][1] =-c2 * s3 - m[2][2] = c1 * c3 - s1 * s2 * s3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 + m[1, 0] = s2 + m[2, 0] =-c2 * s1 + m[3, 0] = 0 + m[0, 1] = s1 * s3 - c1 * c3 * s2 + m[1, 1] = c2 * c3 + m[2, 1] = c1 * s3 + c3 * s1 * s2 + m[3, 1] = 0 + m[0, 2] = c3 * s1 + c1 * s2 * s3 + m[1, 2] =-c2 * s3 + m[2, 2] = c1 * c3 - s1 * s2 * s3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1126,22 +1126,22 @@ matrix4_from_euler_angles_zyx_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c2 - m[0][1] = c2 * s1 - m[0][2] =-s2 - m[0][3] = 0 - m[1][0] = c1 * s2 * s3 - c3 * s1 - m[1][1] = c1 * c3 + s1 * s2 * s3 - m[1][2] = c2 * s3 - m[1][3] = 0 - m[2][0] = s1 * s3 + c1 * c3 * s2 - m[2][1] = c3 * s1 * s2 - c1 * s3 - m[2][2] = c2 * c3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c2 + m[1, 0] = c2 * s1 + m[2, 0] =-s2 + m[3, 0] = 0 + m[0, 1] = c1 * s2 * s3 - c3 * s1 + m[1, 1] = c1 * c3 + s1 * s2 * s3 + m[2, 1] = c2 * s3 + m[3, 1] = 0 + m[0, 2] = s1 * s3 + c1 * c3 * s2 + m[1, 2] = c3 * s1 * s2 - c1 * s3 + m[2, 2] = c2 * c3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1153,22 +1153,22 @@ matrix4_from_euler_angles_zxy_f64 :: proc(t1, t2, t3: f64) -> (m: Matrix4f64) { c3 := math.cos(t3) s3 := math.sin(t3) - m[0][0] = c1 * c3 - s1 * s2 * s3 - m[0][1] = c3 * s1 + c1 * s2 * s3 - m[0][2] =-c2 * s3 - m[0][3] = 0 - m[1][0] =-c2 * s1 - m[1][1] = c1 * c2 - m[1][2] = s2 - m[1][3] = 0 - m[2][0] = c1 * s3 + c3 * s1 * s2 - m[2][1] = s1 * s3 - c1 * c3 * s2 - m[2][2] = c2 * c3 - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = c1 * c3 - s1 * s2 * s3 + m[1, 0] = c3 * s1 + c1 * s2 * s3 + m[2, 0] =-c2 * s3 + m[3, 0] = 0 + m[0, 1] =-c2 * s1 + m[1, 1] = c1 * c2 + m[2, 1] = s2 + m[3, 1] = 0 + m[0, 2] = c1 * s3 + c3 * s1 * s2 + m[1, 2] = s1 * s3 - c1 * c3 * s2 + m[2, 2] = c2 * c3 + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return } @@ -1181,32 +1181,32 @@ matrix4_from_yaw_pitch_roll_f64 :: proc(yaw, pitch, roll: f64) -> (m: Matrix4f64 cb := math.cos(roll) sb := math.sin(roll) - m[0][0] = ch * cb + sh * sp * sb - m[0][1] = sb * cp - m[0][2] = -sh * cb + ch * sp * sb - m[0][3] = 0 - m[1][0] = -ch * sb + sh * sp * cb - m[1][1] = cb * cp - m[1][2] = sb * sh + ch * sp * cb - m[1][3] = 0 - m[2][0] = sh * cp - m[2][1] = -sp - m[2][2] = ch * cp - m[2][3] = 0 - m[3][0] = 0 - m[3][1] = 0 - m[3][2] = 0 - m[3][3] = 1 + m[0, 0] = ch * cb + sh * sp * sb + m[1, 0] = sb * cp + m[2, 0] = -sh * cb + ch * sp * sb + m[3, 0] = 0 + m[0, 1] = -ch * sb + sh * sp * cb + m[1, 1] = cb * cp + m[2, 1] = sb * sh + ch * sp * cb + m[3, 1] = 0 + m[0, 2] = sh * cp + m[1, 2] = -sp + m[2, 2] = ch * cp + m[3, 2] = 0 + m[0, 3] = 0 + m[1, 3] = 0 + m[2, 3] = 0 + m[3, 3] = 1 return m } euler_angles_xyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[2][1], m[2][2]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[1][0]*m[1][0]) - T2 := math.atan2(-m[2][0], C2) + T1 := math.atan2(m[1, 2], m[2, 2]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 1]*m[0, 1]) + T2 := math.atan2(-m[0, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][2] - C1*m[0][1], C1*m[1][1] - S1*m[1][2]) + T3 := math.atan2(S1*m[2, 0] - C1*m[1, 0], C1*m[1, 1] - S1*m[2, 1]) t1 = -T1 t2 = -T2 t3 = -T3 @@ -1214,12 +1214,12 @@ euler_angles_xyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_yxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[2][0], m[2][2]) - C2 := math.sqrt(m[0][1]*m[0][1] + m[1][1]*m[1][1]) - T2 := math.atan2(-m[2][1], C2) + T1 := math.atan2(m[0, 2], m[2, 2]) + C2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 1]*m[1, 1]) + T2 := math.atan2(-m[1, 2], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][2] - C1*m[1][0], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(S1*m[2, 1] - C1*m[0, 1], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1227,12 +1227,12 @@ euler_angles_yxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_xzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[0][2], m[0][1]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[2, 0], m[1, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[1][2] - S1*m[1][1], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(C1*m[2, 1] - S1*m[1, 1], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1240,12 +1240,12 @@ euler_angles_xzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_xyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[0][1], -m[0][2]) - S2 := math.sqrt(m[1][0]*m[1][0] + m[2][0]*m[2][0]) - T2 := math.atan2(S2, m[0][0]) + T1 := math.atan2(m[1, 0], -m[2, 0]) + S2 := math.sqrt(m[0, 1]*m[0, 1] + m[0, 2]*m[0, 2]) + T2 := math.atan2(S2, m[0, 0]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[2][1] - S1*m[2][2], C1*m[1][1] + S1*m[1][2]) + T3 := math.atan2(-C1*m[1, 2] - S1*m[2, 2], C1*m[1, 1] + S1*m[2, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1253,12 +1253,12 @@ euler_angles_xyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_yxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[1][0], m[1][2]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[0, 1], m[2, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] - S1*m[2][2], C1*m[0][0] - S1*m[0][2]) + T3 := math.atan2(C1*m[0, 2] - S1*m[2, 2], C1*m[0, 0] - S1*m[2, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1266,24 +1266,24 @@ euler_angles_yxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_yzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[1][2], -m[1][0]) - S2 := math.sqrt(m[0][1]*m[0][1] + m[2][1]*m[2][1]) - T2 := math.atan2(S2, m[1][1]) + T1 := math.atan2(m[2, 1], -m[0, 1]) + S2 := math.sqrt(m[1, 0]*m[1, 0] + m[1, 2]*m[1, 2]) + T2 := math.atan2(S2, m[1, 1]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-S1*m[0][0] - C1*m[0][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(-S1*m[0, 0] - C1*m[2, 0], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 return } euler_angles_zyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[2][1], m[2][0]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[1, 2], m[0, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[0][1] - S1*m[0][0], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(C1*m[1, 0] - S1*m[0, 0], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1291,12 +1291,12 @@ euler_angles_zyz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_zxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[2][0], -m[2][1]) - S2 := math.sqrt(m[0][2]*m[0][2] + m[1][2]*m[1][2]) - T2 := math.atan2(S2, m[2][2]) + T1 := math.atan2(m[0, 2], -m[1, 2]) + S2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 1]*m[2, 1]) + T2 := math.atan2(S2, m[2, 2]) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(-C1*m[1][0] - S1*m[1][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(-C1*m[0, 1] - S1*m[1, 1], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 @@ -1304,12 +1304,12 @@ euler_angles_zxz_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_xzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[1][2], m[1][1]) - C2 := math.sqrt(m[0][0]*m[0][0] + m[2][0]*m[2][0]) - T2 := math.atan2(-m[1][0], C2) + T1 := math.atan2(m[2, 1], m[1, 1]) + C2 := math.sqrt(m[0, 0]*m[0, 0] + m[0, 2]*m[0, 2]) + T2 := math.atan2(-m[0, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[0][1] - C1*m[0][2], C1*m[2][2] - S1*m[2][1]) + T3 := math.atan2(S1*m[1, 0] - C1*m[2, 0], C1*m[2, 2] - S1*m[1, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1317,12 +1317,12 @@ euler_angles_xzy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_yzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(-m[0][2], m[0][0]) - C2 := math.sqrt(m[1][1]*m[1][1] + m[2][1]*m[2][1]) - T2 := math.atan2(m[0][1], C2) + T1 := math.atan2(-m[2, 0], m[0, 0]) + C2 := math.sqrt(m[1, 1]*m[1, 1] + m[1, 2]*m[1, 2]) + T2 := math.atan2(m[1, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[1][0] + C1*m[1][2], S1*m[2][0] + C1*m[2][2]) + T3 := math.atan2(S1*m[0, 1] + C1*m[2, 1], S1*m[0, 2] + C1*m[2, 2]) t1 = T1 t2 = T2 t3 = T3 @@ -1330,12 +1330,12 @@ euler_angles_yzx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_zyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(m[0][1], m[0][0]) - C2 := math.sqrt(m[1][2]*m[1][2] + m[2][2]*m[2][2]) - T2 := math.atan2(-m[0][2], C2) + T1 := math.atan2(m[1, 0], m[0, 0]) + C2 := math.sqrt(m[2, 1]*m[2, 1] + m[2, 2]*m[2, 2]) + T2 := math.atan2(-m[2, 0], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(S1*m[2][0] - C1*m[2][1], C1*m[1][1] - S1*m[1][0]) + T3 := math.atan2(S1*m[0, 2] - C1*m[1, 2], C1*m[1, 1] - S1*m[0, 1]) t1 = T1 t2 = T2 t3 = T3 @@ -1343,12 +1343,12 @@ euler_angles_zyx_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { } euler_angles_zxy_from_matrix4_f64 :: proc(m: Matrix4f64) -> (t1, t2, t3: f64) { - T1 := math.atan2(-m[1][0], m[1][1]) - C2 := math.sqrt(m[0][2]*m[0][2] + m[2][2]*m[2][2]) - T2 := math.atan2(m[1][2], C2) + T1 := math.atan2(-m[0, 1], m[1, 1]) + C2 := math.sqrt(m[2, 0]*m[2, 0] + m[2, 2]*m[2, 2]) + T2 := math.atan2(m[2, 1], C2) S1 := math.sin(T1) C1 := math.cos(T1) - T3 := math.atan2(C1*m[2][0] + S1*m[2][1], C1*m[0][0] + S1*m[0][1]) + T3 := math.atan2(C1*m[0, 2] + S1*m[1, 2], C1*m[0, 0] + S1*m[1, 0]) t1 = T1 t2 = T2 t3 = T3 diff --git a/core/math/linalg/swizzle.odin b/core/math/linalg/swizzle.odin index f035a5276..ada4aebcf 100644 --- a/core/math/linalg/swizzle.odin +++ b/core/math/linalg/swizzle.odin @@ -1,5 +1,10 @@ package linalg +/* + These procedures are to allow for swizzling with non-compile (runtime) known components +*/ + + Scalar_Components :: enum u8 { x = 0, r = 0, From 80bd1eb615ba83727a57173a391ae2bb710f6533 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 10 Jan 2022 12:19:49 +0000 Subject: [PATCH 0157/1258] Fix polymorphic matrix element with a minor hack --- core/math/linalg/general.odin | 8 ++++---- src/check_type.cpp | 11 +++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index b0572c0d3..9f22fa45e 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -287,10 +287,10 @@ array_cast :: proc(v: $A/[$N]$T, $Elem_Type: typeid) -> (w: [N]Elem_Type) #no_bo return } -matrix_cast :: proc(v: $A/[$M][$N]$T, $Elem_Type: typeid) -> (w: [M][N]Elem_Type) #no_bounds_check { - for i in 0.. (w: matrix[M, N]Elem_Type) #no_bounds_check { + for j in 0..elem); + if (e && e->kind == Entity_TypeName && e->TypeName.is_type_alias) { + // HACK TODO(bill): This is to allow polymorphic parameters for matrix elements + // proc($T: typeid) -> matrix[2, 2]T + // + // THIS IS NEEDS TO BE FIXED AND NOT USE THIS HACK + goto type_assign; + } + } gbString s = type_to_string(elem); error(column.expr, "Matrix elements types are limited to integers, floats, and complex, got %s", s); gb_string_free(s); } +type_assign:; *type = alloc_type_matrix(elem, row_count, column_count, generic_row, generic_column); From cb1080d56c7a5d26f344a41ea6553bf154509072 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 10 Jan 2022 13:31:34 +0000 Subject: [PATCH 0158/1258] Fix `check_procedure_bodies` to allow multiple threads caused by a typo --- src/checker.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/checker.cpp b/src/checker.cpp index 667146eda..c270e8210 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4941,7 +4941,6 @@ void check_procedure_bodies(Checker *c) { if (!build_context.threaded_checker) { worker_count = 0; } - worker_count = 0; if (worker_count == 0) { auto *this_queue = &c->procs_to_check_queue; From 6f3e450c502a8d05653ffcd98c74e2e933a34d1d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 10 Jan 2022 14:03:36 +0000 Subject: [PATCH 0159/1258] Move error handling code to a separate file --- src/error.cpp | 411 +++++++++++++++++++++++++++++++++++++++++++++ src/tokenizer.cpp | 415 +--------------------------------------------- 2 files changed, 413 insertions(+), 413 deletions(-) create mode 100644 src/error.cpp diff --git a/src/error.cpp b/src/error.cpp new file mode 100644 index 000000000..1496b4775 --- /dev/null +++ b/src/error.cpp @@ -0,0 +1,411 @@ +struct ErrorCollector { + TokenPos prev; + std::atomic count; + std::atomic warning_count; + std::atomic in_block; + BlockingMutex mutex; + BlockingMutex error_out_mutex; + BlockingMutex string_mutex; + RecursiveMutex block_mutex; + + Array error_buffer; + Array errors; +}; + +gb_global ErrorCollector global_error_collector; + +#define MAX_ERROR_COLLECTOR_COUNT (36) + + +bool any_errors(void) { + return global_error_collector.count.load() != 0; +} + +void init_global_error_collector(void) { + mutex_init(&global_error_collector.mutex); + mutex_init(&global_error_collector.block_mutex); + mutex_init(&global_error_collector.error_out_mutex); + mutex_init(&global_error_collector.string_mutex); + array_init(&global_error_collector.errors, heap_allocator()); + array_init(&global_error_collector.error_buffer, heap_allocator()); + array_init(&global_file_path_strings, heap_allocator(), 1, 4096); + array_init(&global_files, heap_allocator(), 1, 4096); +} + + +bool set_file_path_string(i32 index, String const &path) { + bool ok = false; + GB_ASSERT(index >= 0); + mutex_lock(&global_error_collector.string_mutex); + + if (index >= global_file_path_strings.count) { + array_resize(&global_file_path_strings, index+1); + } + String prev = global_file_path_strings[index]; + if (prev.len == 0) { + global_file_path_strings[index] = path; + ok = true; + } + + mutex_unlock(&global_error_collector.string_mutex); + return ok; +} + +bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) { + bool ok = false; + GB_ASSERT(index >= 0); + mutex_lock(&global_error_collector.string_mutex); + + if (index >= global_files.count) { + array_resize(&global_files, index+1); + } + AstFile *prev = global_files[index]; + if (prev == nullptr) { + global_files[index] = file; + ok = true; + } + + mutex_unlock(&global_error_collector.string_mutex); + return ok; +} + +String get_file_path_string(i32 index) { + GB_ASSERT(index >= 0); + mutex_lock(&global_error_collector.string_mutex); + + String path = {}; + if (index < global_file_path_strings.count) { + path = global_file_path_strings[index]; + } + + mutex_unlock(&global_error_collector.string_mutex); + return path; +} + +AstFile *thread_safe_get_ast_file_from_id(i32 index) { + GB_ASSERT(index >= 0); + mutex_lock(&global_error_collector.string_mutex); + + AstFile *file = nullptr; + if (index < global_files.count) { + file = global_files[index]; + } + + mutex_unlock(&global_error_collector.string_mutex); + return file; +} + + + +void begin_error_block(void) { + mutex_lock(&global_error_collector.block_mutex); + global_error_collector.in_block.store(true); +} + +void end_error_block(void) { + if (global_error_collector.error_buffer.count > 0) { + isize n = global_error_collector.error_buffer.count; + u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1); + gb_memmove(text, global_error_collector.error_buffer.data, n); + text[n] = 0; + String s = {text, n}; + array_add(&global_error_collector.errors, s); + global_error_collector.error_buffer.count = 0; + } + + global_error_collector.in_block.store(false); + mutex_unlock(&global_error_collector.block_mutex); +} + +#define ERROR_BLOCK() begin_error_block(); defer (end_error_block()) + + +#define ERROR_OUT_PROC(name) void name(char const *fmt, va_list va) +typedef ERROR_OUT_PROC(ErrorOutProc); + +ERROR_OUT_PROC(default_error_out_va) { + gbFile *f = gb_file_get_standard(gbFileStandard_Error); + + char buf[4096] = {}; + isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va); + isize n = len-1; + if (global_error_collector.in_block) { + isize cap = global_error_collector.error_buffer.count + n; + array_reserve(&global_error_collector.error_buffer, cap); + u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count; + gb_memmove(data, buf, n); + global_error_collector.error_buffer.count += n; + } else { + mutex_lock(&global_error_collector.error_out_mutex); + { + u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1); + gb_memmove(text, buf, n); + text[n] = 0; + array_add(&global_error_collector.errors, make_string(text, n)); + } + mutex_unlock(&global_error_collector.error_out_mutex); + + } + gb_file_write(f, buf, n); +} + + +ErrorOutProc *error_out_va = default_error_out_va; + +// NOTE: defined in build_settings.cpp +bool global_warnings_as_errors(void); +bool global_ignore_warnings(void); +bool show_error_line(void); +gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); + +void error_out(char const *fmt, ...) { + va_list va; + va_start(va, fmt); + error_out_va(fmt, va); + va_end(va); +} + + +bool show_error_on_line(TokenPos const &pos, TokenPos end) { + if (!show_error_line()) { + return false; + } + + i32 offset = 0; + gbString the_line = get_file_line_as_string(pos, &offset); + defer (gb_string_free(the_line)); + + if (the_line != nullptr) { + String line = make_string(cast(u8 const *)the_line, gb_string_length(the_line)); + + // TODO(bill): This assumes ASCII + + enum { + MAX_LINE_LENGTH = 76, + MAX_TAB_WIDTH = 8, + ELLIPSIS_PADDING = 8 + }; + + error_out("\n\t"); + if (line.len+MAX_TAB_WIDTH+ELLIPSIS_PADDING > MAX_LINE_LENGTH) { + i32 const half_width = MAX_LINE_LENGTH/2; + i32 left = cast(i32)(offset); + i32 right = cast(i32)(line.len - offset); + left = gb_min(left, half_width); + right = gb_min(right, half_width); + + line.text += offset-left; + line.len -= offset+right-left; + + line = string_trim_whitespace(line); + + offset = left + ELLIPSIS_PADDING/2; + + error_out("... %.*s ...", LIT(line)); + } else { + error_out("%.*s", LIT(line)); + } + error_out("\n\t"); + + for (i32 i = 0; i < offset; i++) { + error_out(" "); + } + error_out("^"); + if (end.file_id == pos.file_id) { + if (end.line > pos.line) { + for (i32 i = offset; i < line.len; i++) { + error_out("~"); + } + } else if (end.line == pos.line && end.column > pos.column) { + i32 length = gb_min(end.offset - pos.offset, cast(i32)(line.len-offset)); + for (i32 i = 1; i < length-1; i++) { + error_out("~"); + } + if (length > 1) { + error_out("^"); + } + } + } + + error_out("\n\n"); + return true; + } + return false; +} + +void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { + global_error_collector.count.fetch_add(1); + + mutex_lock(&global_error_collector.mutex); + // NOTE(bill): Duplicate error, skip it + if (pos.line == 0) { + error_out("Error: %s\n", gb_bprintf_va(fmt, va)); + } else if (global_error_collector.prev != pos) { + global_error_collector.prev = pos; + error_out("%s %s\n", + token_pos_to_string(pos), + gb_bprintf_va(fmt, va)); + show_error_on_line(pos, end); + } + mutex_unlock(&global_error_collector.mutex); + if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { + gb_exit(1); + } +} + +void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { + if (global_warnings_as_errors()) { + error_va(pos, end, fmt, va); + return; + } + global_error_collector.warning_count.fetch_add(1); + mutex_lock(&global_error_collector.mutex); + if (!global_ignore_warnings()) { + // NOTE(bill): Duplicate error, skip it + if (pos.line == 0) { + error_out("Warning: %s\n", gb_bprintf_va(fmt, va)); + } else if (global_error_collector.prev != pos) { + global_error_collector.prev = pos; + error_out("%s Warning: %s\n", + token_pos_to_string(pos), + gb_bprintf_va(fmt, va)); + show_error_on_line(pos, end); + } + } + mutex_unlock(&global_error_collector.mutex); +} + + +void error_line_va(char const *fmt, va_list va) { + error_out_va(fmt, va); +} + +void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) { + mutex_lock(&global_error_collector.mutex); + global_error_collector.count++; + // NOTE(bill): Duplicate error, skip it + if (pos.line == 0) { + error_out("Error: %s", gb_bprintf_va(fmt, va)); + } else if (global_error_collector.prev != pos) { + global_error_collector.prev = pos; + error_out("%s %s", + token_pos_to_string(pos), + gb_bprintf_va(fmt, va)); + } + mutex_unlock(&global_error_collector.mutex); + if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { + gb_exit(1); + } +} + + +void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { + mutex_lock(&global_error_collector.mutex); + global_error_collector.count++; + // NOTE(bill): Duplicate error, skip it + if (global_error_collector.prev != pos) { + global_error_collector.prev = pos; + error_out("%s Syntax Error: %s\n", + token_pos_to_string(pos), + gb_bprintf_va(fmt, va)); + show_error_on_line(pos, end); + } else if (pos.line == 0) { + error_out("Syntax Error: %s\n", gb_bprintf_va(fmt, va)); + } + + mutex_unlock(&global_error_collector.mutex); + if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { + gb_exit(1); + } +} + +void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { + if (global_warnings_as_errors()) { + syntax_error_va(pos, end, fmt, va); + return; + } + mutex_lock(&global_error_collector.mutex); + global_error_collector.warning_count++; + if (!global_ignore_warnings()) { + // NOTE(bill): Duplicate error, skip it + if (global_error_collector.prev != pos) { + global_error_collector.prev = pos; + error_out("%s Syntax Warning: %s\n", + token_pos_to_string(pos), + gb_bprintf_va(fmt, va)); + show_error_on_line(pos, end); + } else if (pos.line == 0) { + error_out("Warning: %s\n", gb_bprintf_va(fmt, va)); + } + } + mutex_unlock(&global_error_collector.mutex); +} + + + +void warning(Token const &token, char const *fmt, ...) { + va_list va; + va_start(va, fmt); + warning_va(token.pos, {}, fmt, va); + va_end(va); +} + +void error(Token const &token, char const *fmt, ...) { + va_list va; + va_start(va, fmt); + error_va(token.pos, {}, fmt, va); + va_end(va); +} + +void error(TokenPos pos, char const *fmt, ...) { + va_list va; + va_start(va, fmt); + Token token = {}; + token.pos = pos; + error_va(pos, {}, fmt, va); + va_end(va); +} + +void error_line(char const *fmt, ...) { + va_list va; + va_start(va, fmt); + error_line_va(fmt, va); + va_end(va); +} + + +void syntax_error(Token const &token, char const *fmt, ...) { + va_list va; + va_start(va, fmt); + syntax_error_va(token.pos, {}, fmt, va); + va_end(va); +} + +void syntax_error(TokenPos pos, char const *fmt, ...) { + va_list va; + va_start(va, fmt); + syntax_error_va(pos, {}, fmt, va); + va_end(va); +} + +void syntax_warning(Token const &token, char const *fmt, ...) { + va_list va; + va_start(va, fmt); + syntax_warning_va(token.pos, {}, fmt, va); + va_end(va); +} + + +void compiler_error(char const *fmt, ...) { + va_list va; + + va_start(va, fmt); + gb_printf_err("Internal Compiler Error: %s\n", + gb_bprintf_va(fmt, va)); + va_end(va); + gb_exit(1); +} + + + + diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 624aea2aa..20815fd16 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -264,419 +264,6 @@ bool token_is_newline(Token const &tok) { return tok.kind == Token_Semicolon && tok.string == "\n"; } - -struct ErrorCollector { - TokenPos prev; - std::atomic count; - std::atomic warning_count; - std::atomic in_block; - BlockingMutex mutex; - BlockingMutex error_out_mutex; - BlockingMutex string_mutex; - RecursiveMutex block_mutex; - - Array error_buffer; - Array errors; -}; - -gb_global ErrorCollector global_error_collector; - -#define MAX_ERROR_COLLECTOR_COUNT (36) - - -bool any_errors(void) { - return global_error_collector.count.load() != 0; -} - -void init_global_error_collector(void) { - mutex_init(&global_error_collector.mutex); - mutex_init(&global_error_collector.block_mutex); - mutex_init(&global_error_collector.error_out_mutex); - mutex_init(&global_error_collector.string_mutex); - array_init(&global_error_collector.errors, heap_allocator()); - array_init(&global_error_collector.error_buffer, heap_allocator()); - array_init(&global_file_path_strings, heap_allocator(), 1, 4096); - array_init(&global_files, heap_allocator(), 1, 4096); -} - - -bool set_file_path_string(i32 index, String const &path) { - bool ok = false; - GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.string_mutex); - - if (index >= global_file_path_strings.count) { - array_resize(&global_file_path_strings, index+1); - } - String prev = global_file_path_strings[index]; - if (prev.len == 0) { - global_file_path_strings[index] = path; - ok = true; - } - - mutex_unlock(&global_error_collector.string_mutex); - return ok; -} - -bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) { - bool ok = false; - GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.string_mutex); - - if (index >= global_files.count) { - array_resize(&global_files, index+1); - } - AstFile *prev = global_files[index]; - if (prev == nullptr) { - global_files[index] = file; - ok = true; - } - - mutex_unlock(&global_error_collector.string_mutex); - return ok; -} - -String get_file_path_string(i32 index) { - GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.string_mutex); - - String path = {}; - if (index < global_file_path_strings.count) { - path = global_file_path_strings[index]; - } - - mutex_unlock(&global_error_collector.string_mutex); - return path; -} - -AstFile *thread_safe_get_ast_file_from_id(i32 index) { - GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.string_mutex); - - AstFile *file = nullptr; - if (index < global_files.count) { - file = global_files[index]; - } - - mutex_unlock(&global_error_collector.string_mutex); - return file; -} - - - -void begin_error_block(void) { - mutex_lock(&global_error_collector.block_mutex); - global_error_collector.in_block.store(true); -} - -void end_error_block(void) { - if (global_error_collector.error_buffer.count > 0) { - isize n = global_error_collector.error_buffer.count; - u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1); - gb_memmove(text, global_error_collector.error_buffer.data, n); - text[n] = 0; - String s = {text, n}; - array_add(&global_error_collector.errors, s); - global_error_collector.error_buffer.count = 0; - } - - global_error_collector.in_block.store(false); - mutex_unlock(&global_error_collector.block_mutex); -} - -#define ERROR_BLOCK() begin_error_block(); defer (end_error_block()) - - -#define ERROR_OUT_PROC(name) void name(char const *fmt, va_list va) -typedef ERROR_OUT_PROC(ErrorOutProc); - -ERROR_OUT_PROC(default_error_out_va) { - gbFile *f = gb_file_get_standard(gbFileStandard_Error); - - char buf[4096] = {}; - isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va); - isize n = len-1; - if (global_error_collector.in_block) { - isize cap = global_error_collector.error_buffer.count + n; - array_reserve(&global_error_collector.error_buffer, cap); - u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count; - gb_memmove(data, buf, n); - global_error_collector.error_buffer.count += n; - } else { - mutex_lock(&global_error_collector.error_out_mutex); - { - u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1); - gb_memmove(text, buf, n); - text[n] = 0; - array_add(&global_error_collector.errors, make_string(text, n)); - } - mutex_unlock(&global_error_collector.error_out_mutex); - - } - gb_file_write(f, buf, n); -} - - -ErrorOutProc *error_out_va = default_error_out_va; - -// NOTE: defined in build_settings.cpp -bool global_warnings_as_errors(void); -bool global_ignore_warnings(void); -bool show_error_line(void); -gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); - -void error_out(char const *fmt, ...) { - va_list va; - va_start(va, fmt); - error_out_va(fmt, va); - va_end(va); -} - - -bool show_error_on_line(TokenPos const &pos, TokenPos end) { - if (!show_error_line()) { - return false; - } - - i32 offset = 0; - gbString the_line = get_file_line_as_string(pos, &offset); - defer (gb_string_free(the_line)); - - if (the_line != nullptr) { - String line = make_string(cast(u8 const *)the_line, gb_string_length(the_line)); - - // TODO(bill): This assumes ASCII - - enum { - MAX_LINE_LENGTH = 76, - MAX_TAB_WIDTH = 8, - ELLIPSIS_PADDING = 8 - }; - - error_out("\n\t"); - if (line.len+MAX_TAB_WIDTH+ELLIPSIS_PADDING > MAX_LINE_LENGTH) { - i32 const half_width = MAX_LINE_LENGTH/2; - i32 left = cast(i32)(offset); - i32 right = cast(i32)(line.len - offset); - left = gb_min(left, half_width); - right = gb_min(right, half_width); - - line.text += offset-left; - line.len -= offset+right-left; - - line = string_trim_whitespace(line); - - offset = left + ELLIPSIS_PADDING/2; - - error_out("... %.*s ...", LIT(line)); - } else { - error_out("%.*s", LIT(line)); - } - error_out("\n\t"); - - for (i32 i = 0; i < offset; i++) { - error_out(" "); - } - error_out("^"); - if (end.file_id == pos.file_id) { - if (end.line > pos.line) { - for (i32 i = offset; i < line.len; i++) { - error_out("~"); - } - } else if (end.line == pos.line && end.column > pos.column) { - i32 length = gb_min(end.offset - pos.offset, cast(i32)(line.len-offset)); - for (i32 i = 1; i < length-1; i++) { - error_out("~"); - } - if (length > 1) { - error_out("^"); - } - } - } - - error_out("\n\n"); - return true; - } - return false; -} - -void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { - global_error_collector.count.fetch_add(1); - - mutex_lock(&global_error_collector.mutex); - // NOTE(bill): Duplicate error, skip it - if (pos.line == 0) { - error_out("Error: %s\n", gb_bprintf_va(fmt, va)); - } else if (global_error_collector.prev != pos) { - global_error_collector.prev = pos; - error_out("%s %s\n", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); - show_error_on_line(pos, end); - } - mutex_unlock(&global_error_collector.mutex); - if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { - gb_exit(1); - } -} - -void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { - if (global_warnings_as_errors()) { - error_va(pos, end, fmt, va); - return; - } - global_error_collector.warning_count.fetch_add(1); - mutex_lock(&global_error_collector.mutex); - if (!global_ignore_warnings()) { - // NOTE(bill): Duplicate error, skip it - if (pos.line == 0) { - error_out("Warning: %s\n", gb_bprintf_va(fmt, va)); - } else if (global_error_collector.prev != pos) { - global_error_collector.prev = pos; - error_out("%s Warning: %s\n", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); - show_error_on_line(pos, end); - } - } - mutex_unlock(&global_error_collector.mutex); -} - - -void error_line_va(char const *fmt, va_list va) { - error_out_va(fmt, va); -} - -void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) { - mutex_lock(&global_error_collector.mutex); - global_error_collector.count++; - // NOTE(bill): Duplicate error, skip it - if (pos.line == 0) { - error_out("Error: %s", gb_bprintf_va(fmt, va)); - } else if (global_error_collector.prev != pos) { - global_error_collector.prev = pos; - error_out("%s %s", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); - } - mutex_unlock(&global_error_collector.mutex); - if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { - gb_exit(1); - } -} - - -void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { - mutex_lock(&global_error_collector.mutex); - global_error_collector.count++; - // NOTE(bill): Duplicate error, skip it - if (global_error_collector.prev != pos) { - global_error_collector.prev = pos; - error_out("%s Syntax Error: %s\n", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); - show_error_on_line(pos, end); - } else if (pos.line == 0) { - error_out("Syntax Error: %s\n", gb_bprintf_va(fmt, va)); - } - - mutex_unlock(&global_error_collector.mutex); - if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { - gb_exit(1); - } -} - -void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { - if (global_warnings_as_errors()) { - syntax_error_va(pos, end, fmt, va); - return; - } - mutex_lock(&global_error_collector.mutex); - global_error_collector.warning_count++; - if (!global_ignore_warnings()) { - // NOTE(bill): Duplicate error, skip it - if (global_error_collector.prev != pos) { - global_error_collector.prev = pos; - error_out("%s Syntax Warning: %s\n", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); - show_error_on_line(pos, end); - } else if (pos.line == 0) { - error_out("Warning: %s\n", gb_bprintf_va(fmt, va)); - } - } - mutex_unlock(&global_error_collector.mutex); -} - - - -void warning(Token const &token, char const *fmt, ...) { - va_list va; - va_start(va, fmt); - warning_va(token.pos, {}, fmt, va); - va_end(va); -} - -void error(Token const &token, char const *fmt, ...) { - va_list va; - va_start(va, fmt); - error_va(token.pos, {}, fmt, va); - va_end(va); -} - -void error(TokenPos pos, char const *fmt, ...) { - va_list va; - va_start(va, fmt); - Token token = {}; - token.pos = pos; - error_va(pos, {}, fmt, va); - va_end(va); -} - -void error_line(char const *fmt, ...) { - va_list va; - va_start(va, fmt); - error_line_va(fmt, va); - va_end(va); -} - - -void syntax_error(Token const &token, char const *fmt, ...) { - va_list va; - va_start(va, fmt); - syntax_error_va(token.pos, {}, fmt, va); - va_end(va); -} - -void syntax_error(TokenPos pos, char const *fmt, ...) { - va_list va; - va_start(va, fmt); - syntax_error_va(pos, {}, fmt, va); - va_end(va); -} - -void syntax_warning(Token const &token, char const *fmt, ...) { - va_list va; - va_start(va, fmt); - syntax_warning_va(token.pos, {}, fmt, va); - va_end(va); -} - - -void compiler_error(char const *fmt, ...) { - va_list va; - - va_start(va, fmt); - gb_printf_err("Internal Compiler Error: %s\n", - gb_bprintf_va(fmt, va)); - va_end(va); - gb_exit(1); -} - - - - - gb_inline bool token_is_literal(TokenKind t) { return gb_is_between(t, Token__LiteralBegin+1, Token__LiteralEnd-1); } @@ -695,6 +282,8 @@ gb_inline bool token_is_shift(TokenKind t) { gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); } +#include "error.cpp" + enum TokenizerInitError { TokenizerInit_None, From 7cc265e14ce3ec08a5908d31441000bdcb4ac645 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 10 Jan 2022 14:50:28 +0000 Subject: [PATCH 0160/1258] Add mutex guards for signature scopes --- src/array.cpp | 4 ++++ src/check_decl.cpp | 2 +- src/check_expr.cpp | 2 ++ src/check_stmt.cpp | 2 +- src/checker.cpp | 2 +- src/common_memory.cpp | 36 +++++++++++++++++++++++++----------- src/threading.cpp | 34 ++++++++++++++++++++++++++++++++++ 7 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/array.cpp b/src/array.cpp index c41125c6d..ac3727978 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -77,15 +77,19 @@ template Slice slice_from_array(Array const &a); template Slice slice_make(gbAllocator const &allocator, isize count) { + GB_ASSERT(count >= 0); Slice s = {}; s.data = gb_alloc_array(allocator, T, count); + GB_ASSERT(s.data != nullptr); s.count = count; return s; } template void slice_init(Slice *s, gbAllocator const &allocator, isize count) { + GB_ASSERT(count >= 0); s->data = gb_alloc_array(allocator, T, count); + GB_ASSERT(s->data != nullptr); s->count = count; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 42f68203c..55ad67abf 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1286,7 +1286,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty using_entities.allocator = heap_allocator(); defer (array_free(&using_entities)); - { + MUTEX_GUARD_BLOCK(ctx->scope->mutex) { if (type->Proc.param_count > 0) { TypeTuple *params = &type->Proc.params->Tuple; for_array(i, params->variables) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cfffffd9f..1162cefee 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4021,10 +4021,12 @@ void check_did_you_mean_scope(String const &name, Scope *scope) { DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.entries.count, name); defer (did_you_mean_destroy(&d)); + mutex_lock(&scope->mutex); for_array(i, scope->elements.entries) { Entity *e = scope->elements.entries[i].value; did_you_mean_append(&d, e->token.string); } + mutex_unlock(&scope->mutex); check_did_you_mean_print(&d); } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 396388629..94b7561c7 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -607,7 +607,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b case Entity_ImportName: { Scope *scope = e->ImportName.scope; - for_array(i, scope->elements.entries) { + MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) { String name = scope->elements.entries[i].key.string; Entity *decl = scope->elements.entries[i].value; if (!is_entity_exported(decl)) continue; diff --git a/src/checker.cpp b/src/checker.cpp index c270e8210..58c71a176 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -622,7 +622,7 @@ void check_scope_usage(Checker *c, Scope *scope) { Array vetted_entities = {}; array_init(&vetted_entities, heap_allocator()); - for_array(i, scope->elements.entries) { + MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) { Entity *e = scope->elements.entries[i].value; if (e == nullptr) continue; VettedEntity ve = {}; diff --git a/src/common_memory.cpp b/src/common_memory.cpp index 2d7a7a246..096c35b5c 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -325,18 +325,32 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) { // TODO(bill): Throughly test! switch (type) { #if defined(GB_COMPILER_MSVC) - case gbAllocation_Alloc: { - isize aligned_size = align_formula_isize(size, alignment); - // TODO(bill): Make sure this is aligned correctly - ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, aligned_size); - } break; - case gbAllocation_Free: - HeapFree(GetProcessHeap(), 0, old_memory); + case gbAllocation_Alloc: + if (size == 0) { + return NULL; + } else { + isize aligned_size = align_formula_isize(size, alignment); + // TODO(bill): Make sure this is aligned correctly + ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, aligned_size); + } + break; + case gbAllocation_Free: + if (old_memory != nullptr) { + HeapFree(GetProcessHeap(), 0, old_memory); + } + break; + case gbAllocation_Resize: + if (old_memory != nullptr && size > 0) { + isize aligned_size = align_formula_isize(size, alignment); + ptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, old_memory, aligned_size); + } else if (old_memory != nullptr) { + HeapFree(GetProcessHeap(), 0, old_memory); + } else if (size != 0) { + isize aligned_size = align_formula_isize(size, alignment); + // TODO(bill): Make sure this is aligned correctly + ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, aligned_size); + } break; - case gbAllocation_Resize: { - isize aligned_size = align_formula_isize(size, alignment); - ptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, old_memory, aligned_size); - } break; #elif defined(GB_SYSTEM_LINUX) // TODO(bill): *nix version that's decent case gbAllocation_Alloc: { diff --git a/src/threading.cpp b/src/threading.cpp index b318e4ff1..e848bba00 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -68,6 +68,40 @@ void yield_thread(void); void yield_process(void); +struct MutexGuard { + MutexGuard() = delete; + MutexGuard(MutexGuard const &) = delete; + + MutexGuard(BlockingMutex *bm) : bm{bm} { + mutex_lock(this->bm); + } + MutexGuard(RecursiveMutex *rm) : rm{rm} { + mutex_lock(this->rm); + } + MutexGuard(BlockingMutex &bm) : bm{&bm} { + mutex_lock(this->bm); + } + MutexGuard(RecursiveMutex &rm) : rm{&rm} { + mutex_lock(this->rm); + } + ~MutexGuard() { + if (this->bm) { + mutex_unlock(this->bm); + } else if (this->rm) { + mutex_unlock(this->rm); + } + } + + operator bool() const { return true; } + + BlockingMutex *bm; + RecursiveMutex *rm; +}; + +#define MUTEX_GUARD_BLOCK(m) if (MutexGuard GB_DEFER_3(_mutex_guard_) = m) +#define MUTEX_GUARD(m) MutexGuard GB_DEFER_3(_mutex_guard_) = m + + #if defined(GB_SYSTEM_WINDOWS) struct BlockingMutex { SRWLOCK srwlock; From 32ec1162bf467359ed47ba0bd4e74ec0c7fbd167 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 10 Jan 2022 14:52:47 +0000 Subject: [PATCH 0161/1258] Use more `{}` ctor --- src/threading.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/threading.cpp b/src/threading.cpp index e848bba00..50d0dfed1 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -98,8 +98,8 @@ struct MutexGuard { RecursiveMutex *rm; }; -#define MUTEX_GUARD_BLOCK(m) if (MutexGuard GB_DEFER_3(_mutex_guard_) = m) -#define MUTEX_GUARD(m) MutexGuard GB_DEFER_3(_mutex_guard_) = m +#define MUTEX_GUARD_BLOCK(m) if (MutexGuard GB_DEFER_3(_mutex_guard_){m}) +#define MUTEX_GUARD(m) MutexGuard GB_DEFER_3(_mutex_guard_){m} #if defined(GB_SYSTEM_WINDOWS) From 8f91e9307c6ea7a243001efb2ecb135d37587301 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Mon, 10 Jan 2022 17:57:33 -0500 Subject: [PATCH 0162/1258] shared library fixes --- src/llvm_backend.cpp | 8 ++++++- src/main.cpp | 51 ++++++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 5acd2a80f..1a657e47b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1238,12 +1238,18 @@ void lb_generate_code(lbGenerator *gen) { // NOTE(bill, 2021-05-04): Target machines must be unique to each module because they are not thread safe auto target_machines = array_make(permanent_allocator(), gen->modules.entries.count); + // NOTE(dweiler): Dynamic libraries require position-independent code. + LLVMRelocMode reloc_mode = LLVMRelocDefault; + if (build_context.build_mode == BuildMode_DynamicLibrary) { + reloc_mode = LLVMRelocPIC; + } + for_array(i, gen->modules.entries) { target_machines[i] = LLVMCreateTargetMachine( target, target_triple, llvm_cpu, llvm_features, code_gen_level, - LLVMRelocDefault, + reloc_mode, code_mode); LLVMSetModuleDataLayout(gen->modules.entries[i].value->mod, LLVMCreateTargetDataLayout(target_machines[i])); } diff --git a/src/main.cpp b/src/main.cpp index 36b30112f..0e8894ed0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -432,40 +432,39 @@ i32 linker_stage(lbGenerator *gen) { // typically executable files on *NIX systems don't have extensions. String output_ext = {}; gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); - char const *linker; + + // NOTE(dweiler): We use clang as a frontend for the linker as there are + // other runtime and compiler support libraries that need to be linked in + // very specific orders such as libgcc_s, ld-linux-so, unwind, etc. + // These are not always typically inside /lib, /lib64, or /usr versions + // of that, e.g libgcc.a is in /usr/lib/gcc/{version}, and can vary on + // the distribution of Linux even. The gcc or clang specs is the only + // reliable way to query this information to call ld directly. if (build_context.build_mode == BuildMode_DynamicLibrary) { - // NOTE(tetra, 2020-11-06): __$startup_runtime must be called at DLL load time. - // Clang, for some reason, won't let us pass the '-init' flag that lets us do this, - // so use ld instead. - // :UseLDForShared - linker = "ld"; + // NOTE(dweiler): Let the frontend know we're building a shared library + // so it doesn't generate symbols which cannot be relocated. + link_settings = gb_string_appendc(link_settings, "-shared "); + + // NOTE(dweiler): __$startup_runtime must be called at initialization + // time of the shared object, we can pass -init to the linker by using + // a comma separated list of arguments to -Wl. + // + // This previously used ld but ld cannot actually build a shared library + // correctly this way since all the other dependencies provided implicitly + // by the compiler frontend are still needed and most of the command + // line arguments prepared previously are incompatible with ld. + // // Shared libraries are .dylib on MacOS and .so on Linux. #if defined(GB_SYSTEM_OSX) output_ext = STR_LIT(".dylib"); - link_settings = gb_string_appendc(link_settings, "-init '___$startup_runtime' "); - link_settings = gb_string_appendc(link_settings, "-dylib -dynamic "); + link_settings = gb_string_appendc(link_settings, "-Wl,-init,'___$startup_runtime' "); #else output_ext = STR_LIT(".so"); - link_settings = gb_string_appendc(link_settings, "-init '__$startup_runtime' "); - link_settings = gb_string_appendc(link_settings, "-shared "); + link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__$startup_runtime' "); #endif } else { - #if defined(GB_SYSTEM_OSX) - linker = "ld"; - #else - // TODO(zangent): Figure out how to make ld work on Linux. - // It probably has to do with including the entire CRT, but - // that's quite a complicated issue to solve while remaining distro-agnostic. - // Clang can figure out linker flags for us, and that's good enough _for now_. - linker = "clang -Wno-unused-command-line-argument"; - #endif - } - - if (build_context.metrics.os == TargetOs_linux) { link_settings = gb_string_appendc(link_settings, "-no-pie "); } - - if (build_context.out_filepath.len > 0) { //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that isize pos = string_extension_position(build_context.out_filepath); @@ -475,7 +474,7 @@ i32 linker_stage(lbGenerator *gen) { } result = system_exec_command_line_app("ld-link", - "%s %s -o \"%.*s%.*s\" %s " + "clang -Wunused-command-line-argument %s -o \"%.*s%.*s\" %s " " %s " " %.*s " " %.*s " @@ -492,7 +491,7 @@ i32 linker_stage(lbGenerator *gen) { // This points the linker to where the entry point is " -e _main " #endif - , linker, object_files, LIT(output_base), LIT(output_ext), + , object_files, LIT(output_base), LIT(output_ext), #if defined(GB_SYSTEM_OSX) "-lSystem -lm -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib", #else From 4334dbe69ac7b2e03d327c93ff559042c03db427 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Mon, 10 Jan 2022 18:00:38 -0500 Subject: [PATCH 0163/1258] disable this warning --- src/main.cpp | 124 +++++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0e8894ed0..444ab44f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,16 +74,16 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { isize cmd_len = 0; va_list va; i32 exit_code = 0; - + va_start(va, fmt); cmd_len = gb_snprintf_va(cmd_line, cmd_cap-1, fmt, va); va_end(va); - + #if defined(GB_SYSTEM_WINDOWS) STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)}; PROCESS_INFORMATION pi = {0}; String16 wcmd = {}; - + start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; start_info.wShowWindow = SW_SHOW; start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); @@ -118,11 +118,11 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { } exit_code = system(cmd_line); #endif - + if (exit_code) { exit(exit_code); } - + return exit_code; } @@ -137,7 +137,7 @@ i32 linker_stage(lbGenerator *gen) { if (is_arch_wasm()) { timings_start_section(timings, str_lit("wasm-ld")); - + #if defined(GB_SYSTEM_WINDOWS) result = system_exec_command_line_app("wasm-ld", "\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", @@ -211,12 +211,12 @@ i32 linker_stage(lbGenerator *gen) { add_path(find_result.windows_sdk_ucrt_library_path); add_path(find_result.vs_library_path); } - - + + StringSet libs = {}; string_set_init(&libs, heap_allocator(), 64); defer (string_set_destroy(&libs)); - + StringSet asm_files = {}; string_set_init(&asm_files, heap_allocator(), 64); defer (string_set_destroy(&asm_files)); @@ -241,13 +241,13 @@ i32 linker_stage(lbGenerator *gen) { string_set_add(&libs, lib); } } - + for_array(i, libs.entries) { String lib = libs.entries[i].value; lib_str = gb_string_append_fmt(lib_str, " \"%.*s\"", LIT(lib)); } - - + + if (build_context.build_mode == BuildMode_DynamicLibrary) { output_ext = "dll"; link_settings = gb_string_append_fmt(link_settings, " /DLL"); @@ -268,7 +268,7 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.ODIN_DEBUG) { link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); } - + for_array(i, asm_files.entries) { String asm_file = asm_files.entries[i].value; String obj_file = concatenate_strings(permanent_allocator(), asm_file, str_lit(".obj")); @@ -283,7 +283,7 @@ i32 linker_stage(lbGenerator *gen) { LIT(obj_file), LIT(build_context.extra_assembler_flags) ); - + if (result) { return result; } @@ -305,7 +305,7 @@ i32 linker_stage(lbGenerator *gen) { LIT(output_base), LIT(build_context.resource_filepath) ); - + if (result) { return result; } @@ -340,11 +340,11 @@ i32 linker_stage(lbGenerator *gen) { lib_str ); } - + if (result) { return result; } - + } else { // lld result = system_exec_command_line_app("msvc-lld-link", "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s.%s\" %s " @@ -360,7 +360,7 @@ i32 linker_stage(lbGenerator *gen) { LIT(build_context.extra_linker_flags), lib_str ); - + if (result) { return result; } @@ -474,7 +474,7 @@ i32 linker_stage(lbGenerator *gen) { } result = system_exec_command_line_app("ld-link", - "clang -Wunused-command-line-argument %s -o \"%.*s%.*s\" %s " + "clang -Wno-unused-command-line-argument %s -o \"%.*s%.*s\" %s " " %s " " %.*s " " %.*s " @@ -501,7 +501,7 @@ i32 linker_stage(lbGenerator *gen) { LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), link_settings); - + if (result) { return result; } @@ -513,7 +513,7 @@ i32 linker_stage(lbGenerator *gen) { result = system_exec_command_line_app("dsymutil", "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) ); - + if (result) { return result; } @@ -674,9 +674,9 @@ enum BuildFlagKind { BuildFlag_IgnoreWarnings, BuildFlag_WarningsAsErrors, BuildFlag_VerboseErrors, - + // internal use only - BuildFlag_InternalIgnoreLazy, + BuildFlag_InternalIgnoreLazy, #if defined(GB_SYSTEM_WINDOWS) BuildFlag_IgnoreVsSearch, @@ -826,7 +826,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_VerboseErrors, str_lit("verbose-errors"), BuildFlagParam_None, Command_all); - + add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); #if defined(GB_SYSTEM_WINDOWS) @@ -1355,7 +1355,7 @@ bool parse_build_flags(Array args) { GB_ASSERT(value.kind == ExactValue_String); build_context.extra_linker_flags = value.value_string; break; - case BuildFlag_ExtraAssemblerFlags: + case BuildFlag_ExtraAssemblerFlags: GB_ASSERT(value.kind == ExactValue_String); build_context.extra_assembler_flags = value.value_string; break; @@ -1817,7 +1817,7 @@ void show_timings(Checker *c, Timings *t) { void remove_temp_files(lbGenerator *gen) { if (build_context.keep_temp_files) return; - + TIME_SECTION("remove keep temp files"); for_array(i, gen->output_temp_paths) { @@ -1866,7 +1866,7 @@ void print_show_help(String const arg0, String const &command) { } else if (command == "strip-semicolon") { print_usage_line(1, "strip-semicolon"); print_usage_line(2, "parse and type check .odin file(s) and then remove unneeded semicolons from the entire project"); - } + } bool doc = command == "doc"; bool build = command == "build"; @@ -2071,7 +2071,7 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-extra-linker-flags:"); print_usage_line(2, "Adds extra linker specific flags in a string"); print_usage_line(0, ""); - + print_usage_line(1, "-extra-assembler-flags:"); print_usage_line(2, "Adds extra assembler specific flags in a string"); print_usage_line(0, ""); @@ -2097,7 +2097,7 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-strict-style"); print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons"); print_usage_line(0, ""); - + print_usage_line(1, "-strict-style-init-only"); print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons, only on the initial project"); print_usage_line(0, ""); @@ -2262,7 +2262,7 @@ gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *writt } written += to_write; prev_offset = token_pos_end(*token).offset; - } + } if (token->flags & TokenFlag_Replace) { if (token->kind == Token_Ellipsis) { if (!gb_file_write(f, "..=", 3)) { @@ -2281,7 +2281,7 @@ gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *writt } written += to_write; } - + if (written_) *written_ = written; return err; } @@ -2292,14 +2292,14 @@ int strip_semicolons(Parser *parser) { AstPackage *pkg = parser->packages[i]; file_count += pkg->files.count; } - + auto generated_files = array_make(permanent_allocator(), 0, file_count); - + for_array(i, parser->packages) { AstPackage *pkg = parser->packages[i]; for_array(j, pkg->files) { AstFile *file = pkg->files[j]; - + bool nothing_to_change = true; for_array(i, file->tokens) { Token *token = &file->tokens[i]; @@ -2308,29 +2308,29 @@ int strip_semicolons(Parser *parser) { break; } } - + if (nothing_to_change) { continue; } - + String old_fullpath = copy_string(permanent_allocator(), file->fullpath); - + // assumes .odin extension String fullpath_base = substring(old_fullpath, 0, old_fullpath.len-5); - + String old_fullpath_backup = concatenate_strings(permanent_allocator(), fullpath_base, str_lit("~backup.odin-temp")); String new_fullpath = concatenate_strings(permanent_allocator(), fullpath_base, str_lit("~temp.odin-temp")); - + array_add(&generated_files, StripSemicolonFile{old_fullpath, old_fullpath_backup, new_fullpath, file}); } } - + gb_printf_err("File count to be stripped of unneeded tokens: %td\n", generated_files.count); - - + + isize generated_count = 0; bool failed = false; - + for_array(i, generated_files) { auto *file = &generated_files[i]; char const *filename = cast(char const *)file->new_fullpath.text; @@ -2338,15 +2338,15 @@ int strip_semicolons(Parser *parser) { defer (if (err != gbFileError_None) { failed = true; }); - - gbFile f = {}; + + gbFile f = {}; err = gb_file_create(&f, filename); if (err) { break; } defer (err = gb_file_close(&f)); generated_count += 1; - + i64 written = 0; defer (err = gb_file_truncate(&f, written)); @@ -2367,23 +2367,23 @@ int strip_semicolons(Parser *parser) { } return 1; } - + isize overwritten_files = 0; - + for_array(i, generated_files) { auto *file = &generated_files[i]; - + char const *old_fullpath = cast(char const *)file->old_fullpath.text; char const *old_fullpath_backup = cast(char const *)file->old_fullpath_backup.text; char const *new_fullpath = cast(char const *)file->new_fullpath.text; - + debugf("Copy '%s' to '%s'\n", old_fullpath, old_fullpath_backup); if (!gb_file_copy(old_fullpath, old_fullpath_backup, false)) { gb_printf_err("failed to copy '%s' to '%s'\n", old_fullpath, old_fullpath_backup); failed = true; break; } - + debugf("Copy '%s' to '%s'\n", new_fullpath, old_fullpath); if (!gb_file_copy(new_fullpath, old_fullpath, false)) { @@ -2400,19 +2400,19 @@ int strip_semicolons(Parser *parser) { if (!gb_file_remove(old_fullpath_backup)) { gb_printf_err("failed to remove '%s'\n", old_fullpath_backup); } - + overwritten_files++; } - + if (!build_context.keep_temp_files) { for_array(i, generated_files) { auto *file = &generated_files[i]; char const *filename = nullptr; filename = cast(char const *)file->new_fullpath.text; - + debugf("Remove '%s'\n", filename); GB_ASSERT_MSG(gb_file_remove(filename), "unable to delete file %s", filename); - + filename = cast(char const *)file->old_fullpath_backup.text; debugf("Remove '%s'\n", filename); if (gb_file_exists(filename) && !gb_file_remove(filename)) { @@ -2423,10 +2423,10 @@ int strip_semicolons(Parser *parser) { } } } - + gb_printf_err("Files stripped of unneeded token: %td\n", generated_files.count); - - + + return cast(int)failed; } @@ -2442,7 +2442,7 @@ int main(int arg_count, char const **arg_ptr) { defer (timings_destroy(&global_timings)); MAIN_TIME_SECTION("initialization"); - + virtual_memory_init(); mutex_init(&fullpath_mutex); mutex_init(&hash_exact_value_mutex); @@ -2617,7 +2617,7 @@ int main(int arg_count, char const **arg_ptr) { init_global_thread_pool(); defer (thread_pool_destroy(&global_thread_pool)); - + init_universal(); // TODO(bill): prevent compiling without a linker @@ -2649,7 +2649,7 @@ int main(int arg_count, char const **arg_ptr) { if (any_errors()) { return 1; } - + if (build_context.command_kind == Command_strip_semicolon) { return strip_semicolons(parser); } @@ -2703,7 +2703,7 @@ int main(int arg_count, char const **arg_ptr) { } remove_temp_files(gen); - + if (build_context.show_timings) { show_timings(checker, &global_timings); } From 847b05013f71c69a4123fe5a4606c88039b716a3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 11 Jan 2022 10:56:07 +0000 Subject: [PATCH 0164/1258] Disable `DEFAULT_TO_THREADED_CHECKER` until race condition is found --- src/bug_report.cpp | 26 +++++++++++++------------- src/build_settings.cpp | 2 +- src/check_decl.cpp | 9 ++++----- src/checker.cpp | 10 +++++----- src/checker.hpp | 2 +- 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 27e7fcf9a..9a1cb2254 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -140,7 +140,7 @@ void report_windows_product_type(DWORD ProductType) { break; default: - gb_printf("Unknown Edition (%08x)", ProductType); + gb_printf("Unknown Edition (%08x)", cast(unsigned)ProductType); } } #endif @@ -316,14 +316,14 @@ void print_bug_report_help() { } if (false) { - gb_printf("dwMajorVersion: %d\n", osvi.dwMajorVersion); - gb_printf("dwMinorVersion: %d\n", osvi.dwMinorVersion); - gb_printf("dwBuildNumber: %d\n", osvi.dwBuildNumber); - gb_printf("dwPlatformId: %d\n", osvi.dwPlatformId); - gb_printf("wServicePackMajor: %d\n", osvi.wServicePackMajor); - gb_printf("wServicePackMinor: %d\n", osvi.wServicePackMinor); - gb_printf("wSuiteMask: %d\n", osvi.wSuiteMask); - gb_printf("wProductType: %d\n", osvi.wProductType); + gb_printf("dwMajorVersion: %u\n", cast(unsigned)osvi.dwMajorVersion); + gb_printf("dwMinorVersion: %u\n", cast(unsigned)osvi.dwMinorVersion); + gb_printf("dwBuildNumber: %u\n", cast(unsigned)osvi.dwBuildNumber); + gb_printf("dwPlatformId: %u\n", cast(unsigned)osvi.dwPlatformId); + gb_printf("wServicePackMajor: %u\n", cast(unsigned)osvi.wServicePackMajor); + gb_printf("wServicePackMinor: %u\n", cast(unsigned)osvi.wServicePackMinor); + gb_printf("wSuiteMask: %u\n", cast(unsigned)osvi.wSuiteMask); + gb_printf("wProductType: %u\n", cast(unsigned)osvi.wProductType); } gb_printf("Windows "); @@ -441,18 +441,18 @@ void print_bug_report_help() { TEXT("DisplayVersion"), RRF_RT_REG_SZ, ValueType, - &DisplayVersion, + DisplayVersion, &ValueSize ); if (status == 0x0) { - gb_printf(" (version: %s)", &DisplayVersion); + gb_printf(" (version: %s)", DisplayVersion); } /* Now print build number. */ - gb_printf(", build %d", osvi.dwBuildNumber); + gb_printf(", build %u", cast(unsigned)osvi.dwBuildNumber); ValueSize = sizeof(UBR); status = RegGetValue( @@ -466,7 +466,7 @@ void print_bug_report_help() { ); if (status == 0x0) { - gb_printf(".%d", UBR); + gb_printf(".%u", cast(unsigned)UBR); } gb_printf("\n"); } diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b8d50898d..ccae0fcf0 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -5,7 +5,7 @@ // #if defined(GB_SYSTEM_WINDOWS) -#define DEFAULT_TO_THREADED_CHECKER +// #define DEFAULT_TO_THREADED_CHECKER // #endif enum TargetOsKind { diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 55ad67abf..3f7d2f33d 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1286,7 +1286,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty using_entities.allocator = heap_allocator(); defer (array_free(&using_entities)); - MUTEX_GUARD_BLOCK(ctx->scope->mutex) { + { if (type->Proc.param_count > 0) { TypeTuple *params = &type->Proc.params->Tuple; for_array(i, params->variables) { @@ -1303,7 +1303,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty if (t->kind == Type_Struct) { Scope *scope = t->Struct.scope; GB_ASSERT(scope != nullptr); - for_array(i, scope->elements.entries) { + MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) { Entity *f = scope->elements.entries[i].value; if (f->kind == Entity_Variable) { Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); @@ -1321,11 +1321,10 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty } } - - for_array(i, using_entities) { + MUTEX_GUARD_BLOCK(ctx->scope->mutex) for_array(i, using_entities) { Entity *e = using_entities[i].e; Entity *uvar = using_entities[i].uvar; - Entity *prev = scope_insert(ctx->scope, uvar); + Entity *prev = scope_insert(ctx->scope, uvar, false); if (prev != nullptr) { error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string)); error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string)); diff --git a/src/checker.cpp b/src/checker.cpp index 58c71a176..b4c5d0c72 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -446,7 +446,7 @@ Entity *scope_lookup(Scope *s, String const &name) { -Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity) { +Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity, bool use_mutex=true) { if (name == "") { return nullptr; } @@ -454,8 +454,8 @@ Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity) { Entity **found = nullptr; Entity *result = nullptr; - mutex_lock(&s->mutex); - defer (mutex_unlock(&s->mutex)); + if (use_mutex) mutex_lock(&s->mutex); + defer (if (use_mutex) mutex_unlock(&s->mutex)); found = string_map_get(&s->elements, key); @@ -485,9 +485,9 @@ end:; return result; } -Entity *scope_insert(Scope *s, Entity *entity) { +Entity *scope_insert(Scope *s, Entity *entity, bool use_mutex) { String name = entity->token.string; - return scope_insert_with_name(s, name, entity); + return scope_insert_with_name(s, name, entity, use_mutex); } diff --git a/src/checker.hpp b/src/checker.hpp index 74435c1d4..db59ebce7 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -423,7 +423,7 @@ Entity *entity_of_node(Ast *expr); Entity *scope_lookup_current(Scope *s, String const &name); Entity *scope_lookup (Scope *s, String const &name); void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_); -Entity *scope_insert (Scope *s, Entity *entity); +Entity *scope_insert (Scope *s, Entity *entity, bool use_mutex=true); void add_type_and_value (CheckerInfo *i, Ast *expression, AddressingMode mode, Type *type, ExactValue value); From 7e4067c44ceb21b4ca0ce89e501df1bf9de106b7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 19:18:54 +0000 Subject: [PATCH 0165/1258] Begin work to move entry point code to Odin itself rather than in C++ side --- core/intrinsics/intrinsics.odin | 5 ++ core/runtime/procs_windows_amd64.odin | 2 +- src/check_builtin.cpp | 6 +++ src/check_decl.cpp | 36 +++++++------ src/checker.cpp | 74 +++++++++++++++------------ src/checker.hpp | 3 ++ src/checker_builtin_procs.hpp | 7 ++- src/llvm_backend.cpp | 15 ++++-- src/llvm_backend_proc.cpp | 8 +++ 9 files changed, 100 insertions(+), 56 deletions(-) diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 2da7a7439..803b04d17 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -197,3 +197,8 @@ type_field_index_of :: proc($T: typeid, $name: string) -> uintptr --- type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) --- type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) --- + + +// Internal compiler use only + +__entry_point :: proc() --- \ No newline at end of file diff --git a/core/runtime/procs_windows_amd64.odin b/core/runtime/procs_windows_amd64.odin index 273bb57b2..e430357be 100644 --- a/core/runtime/procs_windows_amd64.odin +++ b/core/runtime/procs_windows_amd64.odin @@ -22,4 +22,4 @@ windows_trap_type_assertion :: proc "contextless" () -> ! { when ODIN_NO_CRT { @(require) foreign import crt_lib "procs_windows_amd64.asm" -} \ No newline at end of file +} diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index dc8c209c9..82ad6d161 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -219,6 +219,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name)); break; + case BuiltinProc___entry_point: + operand->mode = Addressing_NoValue; + operand->type = nullptr; + mpmc_enqueue(&c->info->intrinsics_entry_point_usage, call); + break; + case BuiltinProc_DIRECTIVE: { ast_node(bd, BasicDirective, ce->proc); String name = bd->name.string; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 3f7d2f33d..f9bc17ba4 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -777,21 +777,23 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (e->pkg != nullptr && e->token.string == "main") { - if (pt->param_count != 0 || - pt->result_count != 0) { - gbString str = type_to_string(proc_type); - error(e->token, "Procedure type of 'main' was expected to be 'proc()', got %s", str); - gb_string_free(str); - } - if (pt->calling_convention != default_calling_convention()) { - error(e->token, "Procedure 'main' cannot have a custom calling convention"); - } - pt->calling_convention = default_calling_convention(); - if (e->pkg->kind == Package_Init) { - if (ctx->info->entry_point != nullptr) { - error(e->token, "Redeclaration of the entry pointer procedure 'main'"); - } else { - ctx->info->entry_point = e; + if (e->pkg->kind != Package_Runtime) { + if (pt->param_count != 0 || + pt->result_count != 0) { + gbString str = type_to_string(proc_type); + error(e->token, "Procedure type of 'main' was expected to be 'proc()', got %s", str); + gb_string_free(str); + } + if (pt->calling_convention != default_calling_convention()) { + error(e->token, "Procedure 'main' cannot have a custom calling convention"); + } + pt->calling_convention = default_calling_convention(); + if (e->pkg->kind == Package_Init) { + if (ctx->info->entry_point != nullptr) { + error(e->token, "Redeclaration of the entry pointer procedure 'main'"); + } else { + ctx->info->entry_point = e; + } } } } @@ -924,7 +926,9 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { "\tother at %s", LIT(name), token_pos_to_string(pos)); } else if (name == "main") { - error(d->proc_lit, "The link name 'main' is reserved for internal use"); + if (d->entity->pkg->kind != Package_Runtime) { + error(d->proc_lit, "The link name 'main' is reserved for internal use"); + } } else { string_map_set(fp, key, e); } diff --git a/src/checker.cpp b/src/checker.cpp index b4c5d0c72..42575f88d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -823,6 +823,7 @@ void init_universal(void) { add_global_bool_constant("ODIN_NO_CRT", bc->no_crt); add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules); add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); + add_global_bool_constant("ODIN_NO_ENTRY_POINT", bc->no_entry_point); // Builtin Procedures @@ -941,6 +942,8 @@ void init_checker_info(CheckerInfo *i) { mutex_init(&i->foreign_mutex); semaphore_init(&i->collect_semaphore); + + mpmc_init(&i->intrinsics_entry_point_usage, a, 1<<10); // just waste some memory here, even if it probably never used } void destroy_checker_info(CheckerInfo *i) { @@ -1228,7 +1231,7 @@ void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *ty while (prev_expr != expr) { prev_expr = expr; expr->tav.mode = mode; - if (type != nullptr && expr->tav.type != nullptr && + if (type != nullptr && expr->tav.type != nullptr && is_type_any(type) && is_type_untyped(expr->tav.type)) { // ignore } else { @@ -1424,7 +1427,7 @@ bool could_entity_be_lazy(Entity *e, DeclInfo *d) { return false; } else if (name == "linkage") { return false; - } + } } } } @@ -1704,7 +1707,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_type_internal(c, bt->RelativeSlice.slice_type); add_type_info_type_internal(c, bt->RelativeSlice.base_integer); break; - + case Type_Matrix: add_type_info_type_internal(c, bt->Matrix.elem); break; @@ -1919,7 +1922,7 @@ void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->RelativeSlice.slice_type); add_min_dep_type_info(c, bt->RelativeSlice.base_integer); break; - + case Type_Matrix: add_min_dep_type_info(c, bt->Matrix.elem); break; @@ -2020,7 +2023,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("__init_context"), str_lit("__type_info_of"), str_lit("cstring_to_string"), - str_lit("_cleanup_runtime"), + str_lit("_cleanup_runtime"), // Pseudo-CRT required procedures str_lit("memset"), @@ -2047,7 +2050,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("gnu_h2f_ieee"), str_lit("gnu_f2h_ieee"), str_lit("extendhfsf2"), - + // WASM Specific str_lit("__ashlti3"), str_lit("__multi3"), @@ -2119,25 +2122,25 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { if (e->flags & EntityFlag_Init) { Type *t = base_type(e->type); GB_ASSERT(t->kind == Type_Proc); - + bool is_init = true; - + if (t->Proc.param_count != 0 || t->Proc.result_count != 0) { gbString str = type_to_string(t); error(e->token, "@(init) procedures must have a signature type with no parameters nor results, got %s", str); gb_string_free(str); is_init = false; } - + if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { error(e->token, "@(init) procedures must be declared at the file scope"); is_init = false; } - + if (is_init) { add_dependency_to_set(c, e); array_add(&c->info.init_procedures, e); - } + } } break; } @@ -3677,11 +3680,6 @@ void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) { error(e->token, "'main' is reserved as the entry point procedure in the initial scope"); return; } - } else if (pkg->kind == Package_Runtime) { - if (e->token.string == "main") { - error(e->token, "'main' is reserved as the entry point procedure in the initial scope"); - return; - } } check_entity_decl(ctx, e, d, nullptr); @@ -3841,7 +3839,7 @@ void add_import_dependency_node(Checker *c, Ast *decl, PtrMap generate_import_dependency_graph(Checker *c) { - PtrMap M = {}; + PtrMap M = {}; map_init(&M, heap_allocator(), 2*c->parser->packages.count); defer (map_destroy(&M)); @@ -4121,11 +4119,11 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { mpmc_enqueue(&ctx->info->required_foreign_imports_through_force_queue, e); add_entity_use(ctx, nullptr, e); } - + if (has_asm_extension(fullpath)) { if (build_context.metrics.arch != TargetArch_amd64 || build_context.metrics.os != TargetOs_windows) { - error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s", + error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s", LIT(target_os_names[build_context.metrics.os]), LIT(target_arch_names[build_context.metrics.arch])); } } @@ -4327,7 +4325,7 @@ void check_with_workers(Checker *c, WorkerTaskProc *proc, isize total_count) { if (!build_context.threaded_checker) { worker_count = 0; } - + semaphore_post(&c->info.collect_semaphore, cast(i32)thread_count); if (worker_count == 0) { ThreadProcCheckerSection section_all = {}; @@ -4351,7 +4349,7 @@ void check_with_workers(Checker *c, WorkerTaskProc *proc, isize total_count) { } GB_ASSERT(remaining_count <= 0); - + for (isize i = 0; i < thread_count; i++) { global_thread_pool_add_task(proc, thread_data+i); } @@ -4750,11 +4748,11 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc ctx.decl = pi->decl; ctx.procs_to_check_queue = procs_to_check_queue; GB_ASSERT(procs_to_check_queue != nullptr); - + GB_ASSERT(pi->type->kind == Type_Proc); TypeProc *pt = &pi->type->Proc; String name = pi->token.string; - + if (pt->is_polymorphic && !pt->is_poly_specialized) { Token token = pi->token; if (pi->poly_def_node != nullptr) { @@ -4832,7 +4830,7 @@ void check_unchecked_bodies(Checker *c) { if (pi->body == nullptr) { continue; } - + debugf("unchecked: %.*s\n", LIT(e->token.string)); mpmc_enqueue(&c->procs_to_check_queue, pi); } @@ -4943,14 +4941,14 @@ void check_procedure_bodies(Checker *c) { } if (worker_count == 0) { auto *this_queue = &c->procs_to_check_queue; - + UntypedExprInfoMap untyped = {}; map_init(&untyped, heap_allocator()); - + for (ProcInfo *pi = nullptr; mpmc_dequeue(this_queue, &pi); /**/) { consume_proc_info_queue(c, pi, this_queue, &untyped); } - + map_destroy(&untyped); debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); @@ -4994,7 +4992,7 @@ void check_procedure_bodies(Checker *c) { GB_ASSERT(total_queued == original_queue_count); semaphore_post(&c->procs_to_check_semaphore, cast(i32)thread_count); - + for (isize i = 0; i < thread_count; i++) { global_thread_pool_add_task(thread_proc_body, thread_data+i); } @@ -5031,7 +5029,7 @@ void check_deferred_procedures(Checker *c) { Entity *dst = src->Procedure.deferred_procedure.entity; GB_ASSERT(dst != nullptr); GB_ASSERT(dst->kind == Entity_Procedure); - + char const *attribute = "deferred_none"; switch (dst_kind) { case DeferredProcedure_none: @@ -5232,7 +5230,7 @@ GB_COMPARE_PROC(init_procedures_cmp) { cmp = 0; return cmp; } - + if (x->pkg != y->pkg) { isize order_x = x->pkg ? x->pkg->order : 0; isize order_y = y->pkg ? y->pkg->order : 0; @@ -5246,14 +5244,14 @@ GB_COMPARE_PROC(init_procedures_cmp) { String fullpath_y = y->file ? y->file->fullpath : (String{}); String file_x = filename_from_path(fullpath_x); String file_y = filename_from_path(fullpath_y); - + cmp = string_compare(file_x, file_y); if (cmp) { return cmp; } } - + cmp = u64_cmp(x->order_in_src, y->order_in_src); if (cmp) { return cmp; @@ -5433,9 +5431,19 @@ void check_parsed_files(Checker *c) { TIME_SECTION("sanity checks"); GB_ASSERT(c->info.entity_queue.count.load(std::memory_order_relaxed) == 0); GB_ASSERT(c->info.definition_queue.count.load(std::memory_order_relaxed) == 0); - + TIME_SECTION("sort init procedures"); check_sort_init_procedures(c); + if (c->info.intrinsics_entry_point_usage.count > 0) { + TIME_SECTION("check intrinsics.__entry_point usage"); + Ast *node = nullptr; + while (mpmc_dequeue(&c->info.intrinsics_entry_point_usage, &node)) { + if (c->info.entry_point == nullptr && node != nullptr) { + warning(node, "usage of intrinsics.__entry_point will be a no-op"); + } + } + } + TIME_SECTION("type check finish"); } diff --git a/src/checker.hpp b/src/checker.hpp index db59ebce7..9a8753efd 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -338,6 +338,9 @@ struct CheckerInfo { MPMCQueue required_global_variable_queue; MPMCQueue required_foreign_imports_through_force_queue; + MPMCQueue intrinsics_entry_point_usage; + + }; struct CheckerContext { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index abd9fc6ca..e8f5174c0 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -250,6 +250,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc__type_end, + BuiltinProc___entry_point, + BuiltinProc_COUNT, }; gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { @@ -497,6 +499,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_hasher_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - + + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + + {STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, }; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1a657e47b..b42ea8211 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -873,7 +873,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) } else { if (m->info->entry_point != nullptr) { lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point); - lb_emit_call(p, entry_point, {}); + lb_emit_call(p, entry_point, {}, ProcInlining_no_inline); } } @@ -1408,6 +1408,7 @@ void lb_generate_code(lbGenerator *gen) { Entity *entry_point = info->entry_point; bool has_dll_main = false; bool has_win_main = false; + bool already_has_entry_point = false; for_array(i, info->entities) { Entity *e = info->entities[i]; @@ -1425,7 +1426,9 @@ void lb_generate_code(lbGenerator *gen) { if (e->Procedure.is_export || (e->Procedure.link_name.len > 0) || ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) { - if (!has_dll_main && name == "DllMain") { + if (name == "main" || name == "DllMain" || name == "WinMain" || name == "mainCRTStartup") { + already_has_entry_point = true; + } else if (!has_dll_main && name == "DllMain") { has_dll_main = true; } else if (!has_win_main && name == "WinMain") { has_win_main = true; @@ -1643,9 +1646,11 @@ void lb_generate_code(lbGenerator *gen) { } - if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) { - TIME_SECTION("LLVM main"); - lb_create_main_procedure(default_module, startup_runtime); + if (!already_has_entry_point) { + if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) { + TIME_SECTION("LLVM main"); + lb_create_main_procedure(default_module, startup_runtime); + } } for_array(j, gen->modules.entries) { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 50aa5f6db..10b8a093f 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1965,6 +1965,14 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return res; } + case BuiltinProc___entry_point: + if (p->module->info->entry_point) { + lbValue entry_point = lb_find_procedure_value_from_entity(p->module, p->module->info->entry_point); + GB_ASSERT(entry_point.value != nullptr); + lb_emit_call(p, entry_point, {}); + } + return {}; + case BuiltinProc_syscall: { unsigned arg_count = cast(unsigned)ce->args.count; From 5ec93677a04f17f38117f0cf301d9a72036a04e7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 19:27:49 +0000 Subject: [PATCH 0166/1258] Correct look for entry point in llvm backend (Windows only currently) --- src/llvm_backend.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index b42ea8211..0b4c674ac 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1406,19 +1406,15 @@ void lb_generate_code(lbGenerator *gen) { isize global_variable_max_count = 0; Entity *entry_point = info->entry_point; - bool has_dll_main = false; - bool has_win_main = false; bool already_has_entry_point = false; for_array(i, info->entities) { Entity *e = info->entities[i]; String name = e->token.string; - bool is_global = e->pkg != nullptr; - if (e->kind == Entity_Variable) { global_variable_max_count++; - } else if (e->kind == Entity_Procedure && !is_global) { + } else if (e->kind == Entity_Procedure) { if ((e->scope->flags&ScopeFlag_Init) && name == "main") { GB_ASSERT(e == entry_point); // entry_point = e; @@ -1426,12 +1422,9 @@ void lb_generate_code(lbGenerator *gen) { if (e->Procedure.is_export || (e->Procedure.link_name.len > 0) || ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) { - if (name == "main" || name == "DllMain" || name == "WinMain" || name == "mainCRTStartup") { + String link_name = e->Procedure.link_name; + if (link_name == "main" || link_name == "DllMain" || link_name == "WinMain" || link_name == "mainCRTStartup") { already_has_entry_point = true; - } else if (!has_dll_main && name == "DllMain") { - has_dll_main = true; - } else if (!has_win_main && name == "WinMain") { - has_win_main = true; } } } @@ -1647,10 +1640,8 @@ void lb_generate_code(lbGenerator *gen) { if (!already_has_entry_point) { - if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) { - TIME_SECTION("LLVM main"); - lb_create_main_procedure(default_module, startup_runtime); - } + TIME_SECTION("LLVM main"); + lb_create_main_procedure(default_module, startup_runtime); } for_array(j, gen->modules.entries) { From 774951e8c0bfca3f9cdd445a003134d8f315ccd4 Mon Sep 17 00:00:00 2001 From: CiD- Date: Wed, 12 Jan 2022 14:36:18 -0500 Subject: [PATCH 0167/1258] os_linux additions + libc to syscalls --- core/os/os_linux.odin | 277 +++++++++++++++++++++++++++++++++++------- 1 file changed, 231 insertions(+), 46 deletions(-) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 260a051ce..6b2fda1e3 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -266,33 +266,142 @@ X_OK :: 1 // Test for execute permission W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission +AT_FDCWD :: -100 +AT_REMOVEDIR :: uintptr(0x200) +AT_SYMLINK_NOFOLLOW :: uintptr(0x100) + +_unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle { + when ODIN_ARCH != "arm64" { + res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) + } else { // NOTE: arm64 does not have open + res := int(intrinsics.syscall(unix.SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) + } + return -1 if res < 0 else Handle(res) +} + +_unix_close :: proc(fd: Handle) -> int { + return int(intrinsics.syscall(unix.SYS_close, uintptr(fd))) +} + +_unix_read :: proc(fd: Handle, buf: rawptr, size: uint) -> int { + return int(intrinsics.syscall(unix.SYS_read, uintptr(fd), uintptr(buf), uintptr(size))) +} + +_unix_write :: proc(fd: Handle, buf: rawptr, size: uint) -> int { + return int(intrinsics.syscall(unix.SYS_write, uintptr(fd), uintptr(buf), uintptr(size))) +} + +_unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 { + when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + return i64(intrinsics.syscall(unix.SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) + } else { + low := uintptr(offset & 0xFFFFFFFF) + high := uintptr(offset >> 32) + result: i64 + res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence))) + return -1 if res < 0 else result + } +} + +_unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int { + when ODIN_ARCH == "amd64" { + return int(intrinsics.syscall(unix.SYS_stat, uintptr(rawptr(path)), uintptr(stat))) + } else when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) + } else { // NOTE: arm64 does not have stat + return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0)) + } +} + +_unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int { + when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + return int(intrinsics.syscall(unix.SYS_fstat, uintptr(fd), uintptr(stat))) + } else { + return int(intrinsics.syscall(unix.SYS_fstat64, uintptr(fd), uintptr(stat))) + } +} + +_unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int { + when ODIN_ARCH == "amd64" { + return int(intrinsics.syscall(unix.SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) + } else when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) + } else { // NOTE: arm64 does not have any lstat + return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) + } +} + +_unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) + } else { // NOTE: arm64 does not have readlink + return int(intrinsics.syscall(unix.SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) + } +} + +_unix_access :: proc(path: cstring, mask: int) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask))) + } else { // NOTE: arm64 does not have access + return int(intrinsics.syscall(unix.SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask))) + } +} + +_unix_getcwd :: proc(buf: rawptr, size: uint) -> int { + return int(intrinsics.syscall(unix.SYS_getcwd, uintptr(buf), uintptr(size))) +} + +_unix_chdir :: proc(path: cstring) -> int { + return int(intrinsics.syscall(unix.SYS_chdir, uintptr(rawptr(path)))) +} + +_unix_rename :: proc(old, new: cstring) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) + } else { // NOTE: arm64 does not have rename + return int(intrinsics.syscall(unix.SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new)))) + } +} + +_unix_unlink :: proc(path: cstring) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path)))) + } else { // NOTE: arm64 does not have unlink + return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0))) + } +} + +_unix_rmdir :: proc(path: cstring) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path)))) + } else { // NOTE: arm64 does not have rmdir + return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR)) + } +} + +_unix_mkdir :: proc(path: cstring, mode: u32) -> int { + when ODIN_ARCH != "arm64" { + return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) + } else { // NOTE: arm64 does not have mkdir + return int(intrinsics.syscall(unix.SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + } +} + foreign libc { @(link_name="__errno_location") __errno_location :: proc() -> ^int --- - @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- - @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- - @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- - @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- - @(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 --- - @(link_name="gettid") _unix_gettid :: proc() -> u64 --- @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int --- - @(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int --- - @(link_name="lstat") _unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> c.int --- - @(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int --- @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int --- - @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t --- - @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int --- @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr --- @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr --- @(link_name="free") _unix_free :: proc(ptr: rawptr) --- @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- + @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- - @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- - @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- @@ -308,51 +417,57 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } +// determine errno from syscall return value +@private +_get_errno :: proc(res: int) -> Errno { + if res < 0 && res > -4096 { + return Errno(-res) + } + return 0 +} + +// get errno from libc get_last_error :: proc() -> int { return __errno_location()^ } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { cstr := strings.clone_to_cstring(path) - handle := _unix_open(cstr, c.int(flags), c.int(mode)) - delete(cstr) - if handle == -1 { - return INVALID_HANDLE, Errno(get_last_error()) + handle := _unix_open(cstr, flags, mode) + defer delete(cstr) + if handle < 0 { + return INVALID_HANDLE, _get_errno(int(handle)) } return handle, ERROR_NONE } close :: proc(fd: Handle) -> Errno { - result := _unix_close(fd) - if result == -1 { - return Errno(get_last_error()) - } - return ERROR_NONE + return _get_errno(_unix_close(fd)) } read :: proc(fd: Handle, data: []byte) -> (int, Errno) { bytes_read := _unix_read(fd, &data[0], c.size_t(len(data))) - if bytes_read == -1 { - return -1, Errno(get_last_error()) + if bytes_read < 0 { + return -1, _get_errno(bytes_read) } - return int(bytes_read), ERROR_NONE + return bytes_read, ERROR_NONE } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { return 0, ERROR_NONE } - bytes_written := _unix_write(fd, &data[0], c.size_t(len(data))) - if bytes_written == -1 { - return -1, Errno(get_last_error()) + bytes_written := _unix_write(fd, &data[0], uint(len(data))) + if bytes_written < 0 { + return -1, _get_errno(bytes_written) } return int(bytes_written), ERROR_NONE } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - res := _unix_seek(fd, offset, c.int(whence)) - if res == -1 { - return -1, Errno(get_last_error()) + res := _unix_seek(fd, offset, whence) + if res < 0 { + return -1, _get_errno(int(res)) } return res, ERROR_NONE } @@ -365,6 +480,75 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { return max(s.size, 0), ERROR_NONE } +rename :: proc(old_path, new_path: string) -> Errno { + old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) + new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) + return _get_errno(_unix_rename(old_path_cstr, new_path_cstr)) +} + +remove :: proc(path: string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + return _get_errno(_unix_unlink(path_cstr)) +} + +make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + return _get_errno(_unix_mkdir(path_cstr, mode)) +} + +remove_directory :: proc(path: string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + return _get_errno(_unix_rmdir(path_cstr)) +} + +is_file_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISREG(s.mode) +} + +is_file_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISREG(s.mode) +} + + +is_dir_handle :: proc(fd: Handle) -> bool { + s, err := _fstat(fd) + if err != ERROR_NONE { + return false + } + return S_ISDIR(s.mode) +} + +is_dir_path :: proc(path: string, follow_links: bool = true) -> bool { + s: OS_Stat + err: Errno + if follow_links { + s, err = _stat(path) + } else { + s, err = _lstat(path) + } + if err != ERROR_NONE { + return false + } + return S_ISDIR(s.mode) +} + +is_file :: proc {is_file_path, is_file_handle} +is_dir :: proc {is_dir_path, is_dir_handle} + // NOTE(bill): Uses startup to initialize it @@ -401,8 +585,8 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { s: OS_Stat result := _unix_stat(cstr, &s) - if result == -1 { - return s, Errno(get_last_error()) + if result < 0 { + return s, _get_errno(result) } return s, ERROR_NONE } @@ -414,8 +598,8 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { s: OS_Stat result := _unix_lstat(cstr, &s) - if result == -1 { - return s, Errno(get_last_error()) + if result < 0 { + return s, _get_errno(result) } return s, ERROR_NONE } @@ -424,8 +608,8 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { s: OS_Stat result := _unix_fstat(fd, &s) - if result == -1 { - return s, Errno(get_last_error()) + if result < 0 { + return s, _get_errno(result) } return s, ERROR_NONE } @@ -530,9 +714,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { access :: proc(path: string, mask: int) -> (bool, Errno) { cstr := strings.clone_to_cstring(path) defer delete(cstr) - result := _unix_access(cstr, c.int(mask)) - if result == -1 { - return false, Errno(get_last_error()) + result := _unix_access(cstr, mask) + if result < 0 { + return false, _get_errno(result) } return true, ERROR_NONE } @@ -567,11 +751,12 @@ get_current_directory :: proc() -> string { page_size := get_page_size() buf := make([dynamic]u8, page_size) for { - #no_bounds_check cwd := _unix_getcwd(cstring(&buf[0]), c.size_t(len(buf))) - if cwd != nil { - return string(cwd) + #no_bounds_check res := _unix_getcwd(&buf[0], uint(len(buf))) + + if res >= 0 { + return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)) } - if Errno(get_last_error()) != ERANGE { + if _get_errno(res) != ERANGE { return "" } resize(&buf, len(buf)+page_size) @@ -582,8 +767,8 @@ get_current_directory :: proc() -> string { set_current_directory :: proc(path: string) -> (err: Errno) { cstr := strings.clone_to_cstring(path, context.temp_allocator) res := _unix_chdir(cstr) - if res == -1 { - return Errno(get_last_error()) + if res < 0 { + return _get_errno(res) } return ERROR_NONE } From 8eaafd5242bb66f1daca84776a5e8560f65a3aa9 Mon Sep 17 00:00:00 2001 From: CiD- Date: Wed, 12 Jan 2022 14:51:49 -0500 Subject: [PATCH 0168/1258] check correct errno in _readlink --- core/os/os_linux.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 6b2fda1e3..1c796f1b8 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -666,9 +666,9 @@ _readlink :: proc(path: string) -> (string, Errno) { buf := make([]byte, bufsz) for { rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) - if rc == -1 { + if rc < 0 { delete(buf) - return "", Errno(get_last_error()) + return "", _get_errno(rc) } else if rc == int(bufsz) { // NOTE(laleksic, 2021-01-21): Any cleaner way to resize the slice? bufsz *= 2 From fb0a3ab7c14d4bc3b821cef723ec6ea3e956c956 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:07:17 +0000 Subject: [PATCH 0169/1258] Correct linkage for entry point procedures on Windows --- src/checker.cpp | 8 +++++++- src/llvm_backend.cpp | 23 +++++++++++------------ src/llvm_backend_proc.cpp | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/checker.cpp b/src/checker.cpp index 42575f88d..f261c8f4a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2113,11 +2113,15 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { case Entity_Variable: if (e->Variable.is_export) { add_dependency_to_set(c, e); + } else if (e->flags & EntityFlag_Require) { + add_dependency_to_set(c, e); } break; case Entity_Procedure: if (e->Procedure.is_export) { add_dependency_to_set(c, e); + } else if (e->flags & EntityFlag_Require) { + add_dependency_to_set(c, e); } if (e->flags & EntityFlag_Init) { Type *t = base_type(e->type); @@ -5440,7 +5444,9 @@ void check_parsed_files(Checker *c) { Ast *node = nullptr; while (mpmc_dequeue(&c->info.intrinsics_entry_point_usage, &node)) { if (c->info.entry_point == nullptr && node != nullptr) { - warning(node, "usage of intrinsics.__entry_point will be a no-op"); + if (node->file()->pkg->kind != Package_Runtime) { + warning(node, "usage of intrinsics.__entry_point will be a no-op"); + } } } } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0b4c674ac..1c3cf86ac 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1405,7 +1405,6 @@ void lb_generate_code(lbGenerator *gen) { isize global_variable_max_count = 0; - Entity *entry_point = info->entry_point; bool already_has_entry_point = false; for_array(i, info->entities) { @@ -1416,14 +1415,17 @@ void lb_generate_code(lbGenerator *gen) { global_variable_max_count++; } else if (e->kind == Entity_Procedure) { if ((e->scope->flags&ScopeFlag_Init) && name == "main") { - GB_ASSERT(e == entry_point); - // entry_point = e; + GB_ASSERT(e == info->entry_point); } if (e->Procedure.is_export || (e->Procedure.link_name.len > 0) || ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) { String link_name = e->Procedure.link_name; - if (link_name == "main" || link_name == "DllMain" || link_name == "WinMain" || link_name == "mainCRTStartup") { + if (link_name == "main" || + link_name == "DllMain" || + link_name == "WinMain" || + link_name == "wWinMain" || + link_name == "mainCRTStartup") { already_has_entry_point = true; } } @@ -1562,6 +1564,11 @@ void lb_generate_code(lbGenerator *gen) { } } + TIME_SECTION("LLVM Runtime Type Information Creation"); + lbProcedure *startup_type_info = lb_create_startup_type_info(default_module); + + TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); + lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); TIME_SECTION("LLVM Global Procedures and Types"); for_array(i, info->entities) { @@ -1621,14 +1628,6 @@ void lb_generate_code(lbGenerator *gen) { } } - - TIME_SECTION("LLVM Runtime Type Information Creation"); - lbProcedure *startup_type_info = lb_create_startup_type_info(default_module); - - TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); - lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); - - TIME_SECTION("LLVM Procedure Generation"); for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 10b8a093f..c52572588 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -304,7 +304,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) { { lbValue *found = string_map_get(&m->members, link_name); - GB_ASSERT(found == nullptr); + GB_ASSERT_MSG(found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name)); } lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); From f1521aa980da5753a6ba6ea951d1cb2ebfd0e66a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:10:23 +0000 Subject: [PATCH 0170/1258] Add proc_windows.odin for custom entry points --- core/runtime/proc_windows.odin | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 core/runtime/proc_windows.odin diff --git a/core/runtime/proc_windows.odin b/core/runtime/proc_windows.odin new file mode 100644 index 000000000..ba3a2b9d8 --- /dev/null +++ b/core/runtime/proc_windows.odin @@ -0,0 +1,44 @@ +//+private +//+build windows +package runtime + +import "core:intrinsics" + +when ODIN_BUILD_MODE == "dynamic" { + @(link_name="DllMain", linkage="strong", require) + DllMain :: proc "stdcall" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 { + context = default_context() + switch fdwReason { + case 1: // DLL_PROCESS_ATTACH + #force_no_inline _startup_runtime() + intrinsics.__entry_point() + case 0: // DLL_PROCESS_DETACH + #force_no_inline _cleanup_runtime() + case 2: // DLL_THREAD_ATTACH + break + case 3: // DLL_THREAD_DETACH + break + } + return true + } +} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT { + when ODIN_ARCH == "386" || ODIN_NO_CRT { + @(link_name="mainCRTStartup", linkage="strong", require) + mainCRTStartup :: proc "stdcall" () -> i32 { + context = default_context() + #force_no_inline _startup_runtime() + intrinsics.__entry_point() + #force_no_inline _cleanup_runtime() + return 0 + } + } else { + @(link_name="main", linkage="strong", require) + main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 { + context = default_context() + #force_no_inline _startup_runtime() + intrinsics.__entry_point() + #force_no_inline _cleanup_runtime() + return 0 + } + } +} \ No newline at end of file From 75b7f2b9feada3cf6ed8aab5142e078d7b07ed59 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:13:38 +0000 Subject: [PATCH 0171/1258] Correct `-init` for *nix to be a different procedure --- core/runtime/proc_unix.odin | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 core/runtime/proc_unix.odin diff --git a/core/runtime/proc_unix.odin b/core/runtime/proc_unix.odin new file mode 100644 index 000000000..7e0d1055a --- /dev/null +++ b/core/runtime/proc_unix.odin @@ -0,0 +1,18 @@ +//+private +//+build linux, darwin +package runtime + +import "core:intrinsics" + +when ODIN_BUILD_MODE == "dynamic" { + @(link_name="_odin_entry_point", linkage="strong", require) + _odin_entry_point :: proc "c" () { + context = default_context() + #force_no_inline _startup_runtime() + } + @(link_name="_odin_exit_point", linkage="strong", require) + _odin_exit_point :: proc "c" () { + context = default_context() + #force_no_inline _cleanup_runtime() + } +} \ No newline at end of file From 6209b02bf9d8dc05c34754beded39c4b80f1d8c6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:16:04 +0000 Subject: [PATCH 0172/1258] Add `intrinsics._entry_point` call to `_odin_entry_point` --- core/runtime/proc_unix.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/runtime/proc_unix.odin b/core/runtime/proc_unix.odin index 7e0d1055a..cb3199ad1 100644 --- a/core/runtime/proc_unix.odin +++ b/core/runtime/proc_unix.odin @@ -9,6 +9,7 @@ when ODIN_BUILD_MODE == "dynamic" { _odin_entry_point :: proc "c" () { context = default_context() #force_no_inline _startup_runtime() + intrinsics._odin_entry_point() } @(link_name="_odin_exit_point", linkage="strong", require) _odin_exit_point :: proc "c" () { From 7df93ea5044bcc4cb5d9bb15a511b449225b2182 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:16:46 +0000 Subject: [PATCH 0173/1258] Initialize `runtime.args__` through `main` --- core/runtime/proc_windows.odin | 1 + 1 file changed, 1 insertion(+) diff --git a/core/runtime/proc_windows.odin b/core/runtime/proc_windows.odin index ba3a2b9d8..ef8b0c529 100644 --- a/core/runtime/proc_windows.odin +++ b/core/runtime/proc_windows.odin @@ -34,6 +34,7 @@ when ODIN_BUILD_MODE == "dynamic" { } else { @(link_name="main", linkage="strong", require) main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 { + args__ = argv[:argc] context = default_context() #force_no_inline _startup_runtime() intrinsics.__entry_point() From e30f16b1f3fa5630c43c62f5602e26aa8d55e53b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:17:30 +0000 Subject: [PATCH 0174/1258] Correct `-init` for *nix --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 444ab44f0..9b2c5d5de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -445,7 +445,7 @@ i32 linker_stage(lbGenerator *gen) { // so it doesn't generate symbols which cannot be relocated. link_settings = gb_string_appendc(link_settings, "-shared "); - // NOTE(dweiler): __$startup_runtime must be called at initialization + // NOTE(dweiler): _odin_entry_point must be called at initialization // time of the shared object, we can pass -init to the linker by using // a comma separated list of arguments to -Wl. // @@ -457,10 +457,10 @@ i32 linker_stage(lbGenerator *gen) { // Shared libraries are .dylib on MacOS and .so on Linux. #if defined(GB_SYSTEM_OSX) output_ext = STR_LIT(".dylib"); - link_settings = gb_string_appendc(link_settings, "-Wl,-init,'___$startup_runtime' "); + link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' "); #else output_ext = STR_LIT(".so"); - link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__$startup_runtime' "); + link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' "); #endif } else { link_settings = gb_string_appendc(link_settings, "-no-pie "); From 3def94505eb72dee3ce46047d8e7820cad8d0c8f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:28:11 +0000 Subject: [PATCH 0175/1258] Add `dynamic` to error message for `-build-mode` --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 9b2c5d5de..35b3d713b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1280,7 +1280,7 @@ bool parse_build_flags(Array args) { } else { gb_printf_err("Unknown build mode '%.*s'\n", LIT(str)); gb_printf_err("Valid build modes:\n"); - gb_printf_err("\tdll, shared\n"); + gb_printf_err("\tdll, shared, dynamic\n"); gb_printf_err("\tobj, object\n"); gb_printf_err("\texe\n"); gb_printf_err("\tasm, assembly, assembler\n"); From 8f038118420ecbca072017b4f0379603688389c4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:30:34 +0000 Subject: [PATCH 0176/1258] Fix typo --- core/runtime/proc_unix.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/runtime/proc_unix.odin b/core/runtime/proc_unix.odin index cb3199ad1..2a62c8d8f 100644 --- a/core/runtime/proc_unix.odin +++ b/core/runtime/proc_unix.odin @@ -9,7 +9,7 @@ when ODIN_BUILD_MODE == "dynamic" { _odin_entry_point :: proc "c" () { context = default_context() #force_no_inline _startup_runtime() - intrinsics._odin_entry_point() + intrinsics.__entry_point() } @(link_name="_odin_exit_point", linkage="strong", require) _odin_exit_point :: proc "c" () { From 80f175cdb0fe13b4bd83239373f890c155b1ecf5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 20:40:34 +0000 Subject: [PATCH 0177/1258] Add empty `main` dynamic builds for *nix systems --- core/runtime/proc_unix.odin | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/runtime/proc_unix.odin b/core/runtime/proc_unix.odin index 2a62c8d8f..119ce3718 100644 --- a/core/runtime/proc_unix.odin +++ b/core/runtime/proc_unix.odin @@ -16,4 +16,8 @@ when ODIN_BUILD_MODE == "dynamic" { context = default_context() #force_no_inline _cleanup_runtime() } + @(link_name="main", linkage="strong", require) + main :: proc(argc: i32, argv: [^]cstring) -> i32 { + return 0 + } } \ No newline at end of file From c9bc7596240ac3c18d48c0545f478e08b0c2a23e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jan 2022 23:04:31 +0000 Subject: [PATCH 0178/1258] Correct calling convention --- core/runtime/proc_unix.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/runtime/proc_unix.odin b/core/runtime/proc_unix.odin index 119ce3718..eb656f39b 100644 --- a/core/runtime/proc_unix.odin +++ b/core/runtime/proc_unix.odin @@ -17,7 +17,7 @@ when ODIN_BUILD_MODE == "dynamic" { #force_no_inline _cleanup_runtime() } @(link_name="main", linkage="strong", require) - main :: proc(argc: i32, argv: [^]cstring) -> i32 { + main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 { return 0 } } \ No newline at end of file From ee260986a9bb5dcf1eed24425313fae95c33f187 Mon Sep 17 00:00:00 2001 From: Dale Weiler Date: Thu, 13 Jan 2022 00:19:04 -0500 Subject: [PATCH 0179/1258] more fixes --- src/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 35b3d713b..9aa9bd2ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -446,8 +446,9 @@ i32 linker_stage(lbGenerator *gen) { link_settings = gb_string_appendc(link_settings, "-shared "); // NOTE(dweiler): _odin_entry_point must be called at initialization - // time of the shared object, we can pass -init to the linker by using - // a comma separated list of arguments to -Wl. + // time of the shared object, similarly, _odin_exit_point must be called + // at deinitialization. We can pass both -init and -fini to the linker by + // using a comma separated list of arguments to -Wl. // // This previously used ld but ld cannot actually build a shared library // correctly this way since all the other dependencies provided implicitly @@ -457,11 +458,11 @@ i32 linker_stage(lbGenerator *gen) { // Shared libraries are .dylib on MacOS and .so on Linux. #if defined(GB_SYSTEM_OSX) output_ext = STR_LIT(".dylib"); - link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' "); #else output_ext = STR_LIT(".so"); - link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' "); #endif + link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); + link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } else { link_settings = gb_string_appendc(link_settings, "-no-pie "); } From 315a08f33f0d3ae9c16377c5a077733824d301d4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 13 Jan 2022 12:04:42 +0000 Subject: [PATCH 0180/1258] Add `main` to proc_unix.odin --- core/runtime/proc_unix.odin | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/core/runtime/proc_unix.odin b/core/runtime/proc_unix.odin index eb656f39b..38116c0f9 100644 --- a/core/runtime/proc_unix.odin +++ b/core/runtime/proc_unix.odin @@ -1,17 +1,17 @@ //+private -//+build linux, darwin +//+build linux, darwin, freebsd package runtime import "core:intrinsics" when ODIN_BUILD_MODE == "dynamic" { - @(link_name="_odin_entry_point", linkage="strong", require) + @(link_name="_odin_entry_point", linkage="strong", require, link_section=".init") _odin_entry_point :: proc "c" () { context = default_context() #force_no_inline _startup_runtime() intrinsics.__entry_point() } - @(link_name="_odin_exit_point", linkage="strong", require) + @(link_name="_odin_exit_point", linkage="strong", require, link_section=".fini") _odin_exit_point :: proc "c" () { context = default_context() #force_no_inline _cleanup_runtime() @@ -20,4 +20,14 @@ when ODIN_BUILD_MODE == "dynamic" { main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 { return 0 } +} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT { + @(link_name="main", linkage="strong", require) + main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 { + args__ = argv[:argc] + context = default_context() + #force_no_inline _startup_runtime() + intrinsics.__entry_point() + #force_no_inline _cleanup_runtime() + return 0 + } } \ No newline at end of file From b33ca6651e442c2ff6122cbdadedec782cb376c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 13 Jan 2022 12:05:22 +0000 Subject: [PATCH 0181/1258] Rename `proc_*` to `entry_*` --- core/runtime/{proc_unix.odin => entry_unix.odin} | 0 core/runtime/{proc_windows.odin => entry_windows.odin} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename core/runtime/{proc_unix.odin => entry_unix.odin} (100%) rename core/runtime/{proc_windows.odin => entry_windows.odin} (100%) diff --git a/core/runtime/proc_unix.odin b/core/runtime/entry_unix.odin similarity index 100% rename from core/runtime/proc_unix.odin rename to core/runtime/entry_unix.odin diff --git a/core/runtime/proc_windows.odin b/core/runtime/entry_windows.odin similarity index 100% rename from core/runtime/proc_windows.odin rename to core/runtime/entry_windows.odin From e15f71466005ff84c6dc97cbfbd10d57f1193e7a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 13 Jan 2022 15:18:47 +0000 Subject: [PATCH 0182/1258] Define wasm `_start` entry point in Odin code --- core/runtime/entry_wasm.odin | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 core/runtime/entry_wasm.odin diff --git a/core/runtime/entry_wasm.odin b/core/runtime/entry_wasm.odin new file mode 100644 index 000000000..125abc756 --- /dev/null +++ b/core/runtime/entry_wasm.odin @@ -0,0 +1,19 @@ +//+private +//+build wasm32, wasm64 +package runtime + +import "core:intrinsics" + +when !ODIN_TEST && !ODIN_NO_ENTRY_POINT { + @(link_name="_start", linkage="strong", require, export) + _start :: proc "c" () { + context = default_context() + #force_no_inline _startup_runtime() + intrinsics.__entry_point() + } + @(link_name="_end", linkage="strong", require, export) + _end :: proc "c" () { + context = default_context() + #force_no_inline _cleanup_runtime() + } +} \ No newline at end of file From 6cf5371d7d55038c0d0789c240813e1be08c0107 Mon Sep 17 00:00:00 2001 From: CiD- Date: Fri, 14 Jan 2022 10:17:49 -0500 Subject: [PATCH 0183/1258] fix push_back and pop_front --- core/container/queue/queue.odin | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/container/queue/queue.odin b/core/container/queue/queue.odin index ff1e85fbd..feca6934c 100644 --- a/core/container/queue/queue.odin +++ b/core/container/queue/queue.odin @@ -86,7 +86,8 @@ push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool { if space(q^) == 0 { _grow(q) or_return } - q.data[q.len] = elem + idx := (q.offset+uint(q.len))%builtin.len(q.data) + q.data[idx] = elem q.len += 1 return true } @@ -126,6 +127,7 @@ pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) { assert(condition=q.len > 0, loc=loc) elem = q.data[q.offset] + q.offset = (q.offset+1)%builtin.len(q.data) q.len -= 1 return } @@ -133,6 +135,7 @@ pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) { pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { if q.len > 0 { elem = q.data[q.offset] + q.offset = (q.offset+1)%builtin.len(q.data) q.len -= 1 ok = true } From c6ed3fa4b5aca2a5e2b444c6b9cd4f8d2ca8f3e1 Mon Sep 17 00:00:00 2001 From: oskarnp Date: Fri, 14 Jan 2022 10:43:33 -0500 Subject: [PATCH 0184/1258] Fix invalid linker flags passed to clang on macOS --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9aa9bd2ac..fe56d451f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -485,16 +485,16 @@ i32 linker_stage(lbGenerator *gen) { // NOTE: If you change this (although this minimum is as low as you can go with Odin working) // make sure to also change the 'mtriple' param passed to 'opt' #if defined(GB_CPU_ARM) - " -macosx_version_min 11.0.0 " + " -mmacosx-version-min=11.0.0 " #else - " -macosx_version_min 10.8.0 " + " -mmacosx-version-min=10.8.0 " #endif // This points the linker to where the entry point is " -e _main " #endif , object_files, LIT(output_base), LIT(output_ext), #if defined(GB_SYSTEM_OSX) - "-lSystem -lm -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib", + "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib", #else "-lc -lm", #endif From 6aa80ee8e4fc8f96c24e9881a5833f14c86eff05 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 15:38:09 +0000 Subject: [PATCH 0185/1258] Correct `_start` as an entry point --- src/llvm_backend.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1c3cf86ac..7a7f20f8d 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1420,13 +1420,16 @@ void lb_generate_code(lbGenerator *gen) { if (e->Procedure.is_export || (e->Procedure.link_name.len > 0) || ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) { - String link_name = e->Procedure.link_name; - if (link_name == "main" || - link_name == "DllMain" || - link_name == "WinMain" || - link_name == "wWinMain" || - link_name == "mainCRTStartup") { - already_has_entry_point = true; + String link_name = e->Procedure.link_name; + if (e->pkg->kind == Package_Runtime) { + if (link_name == "main" || + link_name == "DllMain" || + link_name == "WinMain" || + link_name == "wWinMain" || + link_name == "mainCRTStartup" || + link_name == "_start") { + already_has_entry_point = true; + } } } } From a390ef41f803587ebdf404cd0f10c19a0a651994 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 15:55:01 +0000 Subject: [PATCH 0186/1258] Fix swizzle logic within `lb_build_assign_stmt_array` --- src/llvm_backend_stmt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 20b444058..04e7e0d03 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1766,6 +1766,8 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) { } void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) { + GB_ASSERT(op != Token_Eq); + Type *lhs_type = lb_addr_type(lhs); Type *array_type = base_type(lhs_type); GB_ASSERT(is_type_array_like(array_type)); @@ -1795,7 +1797,6 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, } indices[index_count++] = index; } - gb_sort_array(indices, index_count, gb_i32_cmp(0)); lbValue lhs_ptrs[4] = {}; lbValue x_loads[4] = {}; @@ -1840,7 +1841,6 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, } indices[index_count++] = index; } - gb_sort_array(indices.data, index_count, gb_i32_cmp(0)); lbValue lhs_ptrs[4] = {}; lbValue x_loads[4] = {}; From 7501cc2f17315af368abad8d89f669e414c6cd9e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 16:01:23 +0000 Subject: [PATCH 0187/1258] Remove dead code --- src/llvm_backend_stmt.cpp | 48 --------------------------------------- 1 file changed, 48 deletions(-) diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 04e7e0d03..5882b71ae 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1868,11 +1868,7 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue x = lb_addr_get_ptr(p, lhs); - - if (inline_array_arith) { - #if 1 - #if 1 unsigned n = cast(unsigned)count; auto lhs_ptrs = slice_make(temporary_allocator(), n); @@ -1896,50 +1892,6 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, for (unsigned i = 0; i < n; i++) { lb_emit_store(p, lhs_ptrs[i], ops[i]); } - - #else - lbValue y = lb_address_from_load_or_generate_local(p, rhs); - - unsigned n = cast(unsigned)count; - - auto lhs_ptrs = slice_make(temporary_allocator(), n); - auto rhs_ptrs = slice_make(temporary_allocator(), n); - auto x_loads = slice_make(temporary_allocator(), n); - auto y_loads = slice_make(temporary_allocator(), n); - auto ops = slice_make(temporary_allocator(), n); - - for (unsigned i = 0; i < n; i++) { - lhs_ptrs[i] = lb_emit_array_epi(p, x, i); - } - for (unsigned i = 0; i < n; i++) { - rhs_ptrs[i] = lb_emit_array_epi(p, y, i); - } - for (unsigned i = 0; i < n; i++) { - x_loads[i] = lb_emit_load(p, lhs_ptrs[i]); - } - for (unsigned i = 0; i < n; i++) { - y_loads[i] = lb_emit_load(p, rhs_ptrs[i]); - } - for (unsigned i = 0; i < n; i++) { - ops[i] = lb_emit_arith(p, op, x_loads[i], y_loads[i], elem_type); - } - for (unsigned i = 0; i < n; i++) { - lb_emit_store(p, lhs_ptrs[i], ops[i]); - } - #endif - #else - lbValue y = lb_address_from_load_or_generate_local(p, rhs); - - for (i64 i = 0; i < count; i++) { - lbValue a_ptr = lb_emit_array_epi(p, x, i); - lbValue b_ptr = lb_emit_array_epi(p, y, i); - - lbValue a = lb_emit_load(p, a_ptr); - lbValue b = lb_emit_load(p, b_ptr); - lbValue c = lb_emit_arith(p, op, a, b, elem_type); - lb_emit_store(p, a_ptr, c); - } - #endif } else { lbValue y = lb_address_from_load_or_generate_local(p, rhs); From 79f32d7b71f8ca00fa347ed0ab393d0d8c02111b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 16:03:37 +0000 Subject: [PATCH 0188/1258] Remove unused lbDefer kind --- src/llvm_backend.hpp | 3 --- src/llvm_backend_stmt.cpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e70b1f84c..45e58cacf 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -204,7 +204,6 @@ enum lbDeferExitKind { enum lbDeferKind { lbDefer_Node, - lbDefer_Instr, lbDefer_Proc, }; @@ -215,8 +214,6 @@ struct lbDefer { lbBlock * block; union { Ast *stmt; - // NOTE(bill): 'instr' will be copied every time to create a new one - lbValue instr; struct { lbValue deferred; Array result_as_args; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 5882b71ae..3375ceda9 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -2172,10 +2172,6 @@ void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) { lb_start_block(p, b); if (d.kind == lbDefer_Node) { lb_build_stmt(p, d.stmt); - } else if (d.kind == lbDefer_Instr) { - // NOTE(bill): Need to make a new copy - LLVMValueRef instr = LLVMInstructionClone(d.instr.value); - LLVMInsertIntoBuilder(p->builder, instr); } else if (d.kind == lbDefer_Proc) { lb_emit_call(p, d.proc.deferred, d.proc.result_as_args); } From 9ecbadd457a6a647c88c9b9670e9a9154fb33e5d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 16:16:11 +0000 Subject: [PATCH 0189/1258] Simplify procedure parameters callee logic --- src/llvm_backend.hpp | 1 - src/llvm_backend_proc.cpp | 53 ++++++++++++++------------------------- 2 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 45e58cacf..49f675a49 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -267,7 +267,6 @@ struct lbProcedure { bool is_done; lbAddr return_ptr; - Array params; Array defer_stmts; Array blocks; Array branch_blocks; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index c52572588..eccf9b360 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -107,7 +107,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) gbAllocator a = heap_allocator(); p->children.allocator = a; - p->params.allocator = a; p->defer_stmts.allocator = a; p->blocks.allocator = a; p->branch_blocks.allocator = a; @@ -323,7 +322,6 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type gbAllocator a = permanent_allocator(); p->children.allocator = a; - p->params.allocator = a; p->defer_stmts.allocator = a; p->blocks.allocator = a; p->branch_blocks.allocator = a; @@ -478,42 +476,29 @@ void lb_begin_procedure_body(lbProcedure *p) { if (arg_type->kind == lbArg_Ignore) { continue; } else if (arg_type->kind == lbArg_Direct) { - lbParamPasskind kind = lbParamPass_Value; - LLVMTypeRef param_type = lb_type(p->module, e->type); - if (param_type != arg_type->type) { - kind = lbParamPass_BitCast; + if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { + LLVMTypeRef param_type = lb_type(p->module, e->type); + LLVMValueRef value = LLVMGetParam(p->value, param_offset+param_index); + + value = OdinLLVMBuildTransmute(p, value, param_type); + + lbValue param = {}; + param.value = value; + param.type = e->type; + + lbValue ptr = lb_address_from_load_or_generate_local(p, param); + lb_add_entity(p->module, e, ptr); } - LLVMValueRef value = LLVMGetParam(p->value, param_offset+param_index); - - value = OdinLLVMBuildTransmute(p, value, param_type); - - lbValue param = {}; - param.value = value; - param.type = e->type; - array_add(&p->params, param); - - if (e->token.string.len != 0) { - lbAddr l = lb_add_local(p, e->type, e, false, param_index); - lb_addr_store(p, l, param); - } - - param_index += 1; } else if (arg_type->kind == lbArg_Indirect) { - LLVMValueRef value_ptr = LLVMGetParam(p->value, param_offset+param_index); - LLVMValueRef value = LLVMBuildLoad(p->builder, value_ptr, ""); + if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { + lbValue ptr = {}; + ptr.value = LLVMGetParam(p->value, param_offset+param_index); + ptr.type = alloc_type_pointer(e->type); - lbValue param = {}; - param.value = value; - param.type = e->type; - array_add(&p->params, param); - - lbValue ptr = {}; - ptr.value = value_ptr; - ptr.type = alloc_type_pointer(e->type); - - lb_add_entity(p->module, e, ptr); - param_index += 1; + lb_add_entity(p->module, e, ptr); + } } + param_index += 1; } } From 51dcbc80c3f0ef8755a0dc07b257ca93b264c2cc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 16:26:14 +0000 Subject: [PATCH 0190/1258] Add `LLVMAddMergedLoadStoreMotionPass` on `-debug -opt:0` --- src/llvm_backend_opt.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 5b8468799..8f1c7ad59 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -57,17 +57,13 @@ LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) { if (optimization_level == 0 && build_context.ODIN_DEBUG) { - return; + LLVMAddMergedLoadStoreMotionPass(fpm); + } else { + LLVMAddPromoteMemoryToRegisterPass(fpm); + LLVMAddMergedLoadStoreMotionPass(fpm); + LLVM_ADD_CONSTANT_VALUE_PASS(fpm); + LLVMAddEarlyCSEPass(fpm); } - LLVMAddPromoteMemoryToRegisterPass(fpm); - LLVMAddMergedLoadStoreMotionPass(fpm); - LLVM_ADD_CONSTANT_VALUE_PASS(fpm); - LLVMAddEarlyCSEPass(fpm); - - // LLVM_ADD_CONSTANT_VALUE_PASS(fpm); - // LLVMAddMergedLoadStoreMotionPass(fpm); - // LLVMAddPromoteMemoryToRegisterPass(fpm); - // LLVMAddCFGSimplificationPass(fpm); } void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level) { From 6c4867081985a8dd1cccb3e5c503d72807e4ee87 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 17:34:35 +0000 Subject: [PATCH 0191/1258] Make `ODIN_BUILD_MODE` a enum type --- core/runtime/core.odin | 13 ++++ core/runtime/entry_unix.odin | 2 +- core/runtime/entry_windows.odin | 2 +- core/runtime/internal.odin | 2 +- src/build_settings.cpp | 23 +------ src/check_expr.cpp | 112 ++++++++++++++++++-------------- src/checker.cpp | 64 +++++++++++++++++- 7 files changed, 144 insertions(+), 74 deletions(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index be30eef02..91b6bf5ca 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -386,6 +386,19 @@ Raw_Cstring :: struct { } +/* + // Defined internally by the compiler + Odin_Build_Mode_Type :: enum int { + Executable, + Dynamic, + Object, + Assembly, + LLVM_IR, + } +*/ +Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE) + + ///////////////////////////// // Init Startup Procedures // ///////////////////////////// diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin index 38116c0f9..67d2cbcb7 100644 --- a/core/runtime/entry_unix.odin +++ b/core/runtime/entry_unix.odin @@ -4,7 +4,7 @@ package runtime import "core:intrinsics" -when ODIN_BUILD_MODE == "dynamic" { +when ODIN_BUILD_MODE == .Dynamic { @(link_name="_odin_entry_point", linkage="strong", require, link_section=".init") _odin_entry_point :: proc "c" () { context = default_context() diff --git a/core/runtime/entry_windows.odin b/core/runtime/entry_windows.odin index ef8b0c529..97a5bebe6 100644 --- a/core/runtime/entry_windows.odin +++ b/core/runtime/entry_windows.odin @@ -4,7 +4,7 @@ package runtime import "core:intrinsics" -when ODIN_BUILD_MODE == "dynamic" { +when ODIN_BUILD_MODE == .Dynamic { @(link_name="DllMain", linkage="strong", require) DllMain :: proc "stdcall" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 { context = default_context() diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 6498c4db7..7b283a132 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -8,7 +8,7 @@ IS_WASM :: ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64" @(private) RUNTIME_LINKAGE :: "strong" when ( (ODIN_USE_SEPARATE_MODULES || - ODIN_BUILD_MODE == "dynamic" || + ODIN_BUILD_MODE == .Dynamic || !ODIN_NO_CRT) && !IS_WASM) else "internal" RUNTIME_REQUIRE :: true diff --git a/src/build_settings.cpp b/src/build_settings.cpp index ccae0fcf0..bafa93042 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -119,6 +119,8 @@ enum BuildModeKind { BuildMode_Object, BuildMode_Assembly, BuildMode_LLVM_IR, + + BuildMode_COUNT, }; enum CommandKind : u32 { @@ -172,10 +174,9 @@ struct BuildContext { String ODIN_VENDOR; // compiler vendor String ODIN_VERSION; // compiler version String ODIN_ROOT; // Odin ROOT - String ODIN_BUILD_MODE; bool ODIN_DEBUG; // Odin in debug mode bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not - bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) +bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) TargetEndianKind endian_kind; @@ -855,24 +856,6 @@ void init_build_context(TargetMetrics *cross_target) { bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VERSION = ODIN_VERSION; bc->ODIN_ROOT = odin_root_dir(); - switch (bc->build_mode) { - default: - case BuildMode_Executable: - bc->ODIN_BUILD_MODE = str_lit("executable"); - break; - case BuildMode_DynamicLibrary: - bc->ODIN_BUILD_MODE = str_lit("dynamic"); - break; - case BuildMode_Object: - bc->ODIN_BUILD_MODE = str_lit("object"); - break; - case BuildMode_Assembly: - bc->ODIN_BUILD_MODE = str_lit("assembly"); - break; - case BuildMode_LLVM_IR: - bc->ODIN_BUILD_MODE = str_lit("llvm-ir"); - break; - } bc->copy_file_contents = true; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1162cefee..8667d8734 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -119,6 +119,58 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint); void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); + +void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { + auto results = did_you_mean_results(d); + if (results.count != 0) { + error_line("\tSuggestion: Did you mean?\n"); + for_array(i, results) { + String const &target = results[i].target; + error_line("\t\t%s%.*s\n", prefix, LIT(target)); + // error_line("\t\t%.*s %td\n", LIT(target), results[i].distance); + } + } +} + +void check_did_you_mean_type(String const &name, Array const &fields, char const *prefix = "") { + ERROR_BLOCK(); + + DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); + defer (did_you_mean_destroy(&d)); + + for_array(i, fields) { + did_you_mean_append(&d, fields[i]->token.string); + } + check_did_you_mean_print(&d, prefix); +} + +void check_did_you_mean_type(String const &name, Slice const &fields, char const *prefix = "") { + ERROR_BLOCK(); + + DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); + defer (did_you_mean_destroy(&d)); + + for_array(i, fields) { + did_you_mean_append(&d, fields[i]->token.string); + } + check_did_you_mean_print(&d, prefix); +} + +void check_did_you_mean_scope(String const &name, Scope *scope, char const *prefix = "") { + ERROR_BLOCK(); + + DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.entries.count, name); + defer (did_you_mean_destroy(&d)); + + mutex_lock(&scope->mutex); + for_array(i, scope->elements.entries) { + Entity *e = scope->elements.entries[i].value; + did_you_mean_append(&d, e->token.string); + } + mutex_unlock(&scope->mutex); + check_did_you_mean_print(&d, prefix); +} + Entity *entity_from_expr(Ast *expr) { expr = unparen_expr(expr); switch (expr->kind) { @@ -3361,7 +3413,17 @@ void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_typ } } } + ERROR_BLOCK(); + error(operand->expr, "Cannot convert untyped value '%s' to '%s' from '%s'%s", expr_str, type_str, from_type_str, extra_text); + if (operand->value.kind == ExactValue_String) { + String key = operand->value.value_string; + if (is_type_string(operand->type) && is_type_enum(target_type)) { + gb_printf_err("HERE!\n"); + Type *et = base_type(target_type); + check_did_you_mean_type(key, et->Enum.fields, "."); + } + } gb_string_free(from_type_str); gb_string_free(type_str); @@ -3979,56 +4041,6 @@ ExactValue get_constant_field(CheckerContext *c, Operand const *operand, Selecti if (success_) *success_ = true; return empty_exact_value; } -void check_did_you_mean_print(DidYouMeanAnswers *d) { - auto results = did_you_mean_results(d); - if (results.count != 0) { - error_line("\tSuggestion: Did you mean?\n"); - for_array(i, results) { - String const &target = results[i].target; - error_line("\t\t%.*s\n", LIT(target)); - // error_line("\t\t%.*s %td\n", LIT(target), results[i].distance); - } - } -} - -void check_did_you_mean_type(String const &name, Array const &fields) { - ERROR_BLOCK(); - - DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); - defer (did_you_mean_destroy(&d)); - - for_array(i, fields) { - did_you_mean_append(&d, fields[i]->token.string); - } - check_did_you_mean_print(&d); -} - -void check_did_you_mean_type(String const &name, Slice const &fields) { - ERROR_BLOCK(); - - DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); - defer (did_you_mean_destroy(&d)); - - for_array(i, fields) { - did_you_mean_append(&d, fields[i]->token.string); - } - check_did_you_mean_print(&d); -} - -void check_did_you_mean_scope(String const &name, Scope *scope) { - ERROR_BLOCK(); - - DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.entries.count, name); - defer (did_you_mean_destroy(&d)); - - mutex_lock(&scope->mutex); - for_array(i, scope->elements.entries) { - Entity *e = scope->elements.entries[i].value; - did_you_mean_append(&d, e->token.string); - } - mutex_unlock(&scope->mutex); - check_did_you_mean_print(&d); -} Type *determine_swizzle_array_type(Type *original_type, Type *type_hint, isize new_count) { Type *array_type = base_type(type_deref(original_type)); diff --git a/src/checker.cpp b/src/checker.cpp index f261c8f4a..c3dcd1d11 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -780,6 +780,54 @@ AstPackage *create_builtin_package(char const *name) { return pkg; } +struct GlobalEnumValue { + char const *name; + i64 value; +}; + +Slice add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count) { + Scope *scope = create_scope(nullptr, builtin_pkg->scope); + Entity *e = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved); + + Type *enum_type = alloc_type_enum(); + Type *named_type = alloc_type_named(type_name, enum_type, e); + set_base_type(named_type, enum_type); + enum_type->Enum.base_type = t_int; + enum_type->Enum.scope = scope; + + auto fields = array_make(permanent_allocator(), value_count); + for (isize i = 0; i < value_count; i++) { + i64 value = values[i].value; + Entity *e = alloc_entity_constant(scope, make_token_ident(values[i].name), named_type, exact_value_i64(value)); + e->flags |= EntityFlag_Visited; + e->state = EntityState_Resolved; + fields[i] = e; + + Entity *ie = scope_insert(scope, e); + GB_ASSERT(ie == nullptr); + } + + + enum_type->Enum.fields = fields; + enum_type->Enum.min_value_index = 0; + enum_type->Enum.max_value_index = value_count-1; + enum_type->Enum.min_value = &enum_type->Enum.fields[enum_type->Enum.min_value_index]->Constant.value; + enum_type->Enum.max_value = &enum_type->Enum.fields[enum_type->Enum.max_value_index]->Constant.value; + + return slice_from_array(fields); +} +void add_global_enum_constant(Slice const &fields, char const *name, i64 value) { + for (Entity *field : fields) { + GB_ASSERT(field->kind == Entity_Constant); + if (value == exact_value_to_i64(field->Constant.value)) { + add_global_constant(name, field->type, field->Constant.value); + return; + } + } + GB_PANIC("Unfound enum value for global constant: %s %lld", name, cast(long long)value); +} + + void init_universal(void) { BuildContext *bc = &build_context; @@ -815,7 +863,21 @@ void init_universal(void) { add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION); add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT); - add_global_string_constant("ODIN_BUILD_MODE", bc->ODIN_BUILD_MODE); + { + GlobalEnumValue values[BuildMode_COUNT] = { + {"Executable", BuildMode_Executable}, + {"Dynamic", BuildMode_DynamicLibrary}, + {"Object", BuildMode_Object}, + {"Assembly", BuildMode_Assembly}, + {"LLVM_IR", BuildMode_LLVM_IR}, + }; + + auto fields = add_global_enum_type(str_lit("Odin_Build_Mode_Type"), values, gb_count_of(values)); + add_global_enum_constant(fields, "ODIN_BUILD_MODE", bc->build_mode); + } + + // add_global_string_constant("ODIN_BUILD_MODE", bc->ODIN_BUILD_MODE); + add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG); add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT); add_global_bool_constant("ODIN_DEFAULT_TO_NIL_ALLOCATOR", bc->ODIN_DEFAULT_TO_NIL_ALLOCATOR); From 29ebe0c3c92724f74392687ee859a0c2db503b0d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 17:40:00 +0000 Subject: [PATCH 0192/1258] Rename architecture `386` to `i386` --- core/c/c.odin | 2 +- core/crypto/_fiat/field_poly1305/field.odin | 2 +- core/crypto/chacha20/chacha20.odin | 2 +- core/runtime/entry_windows.odin | 2 +- ...ndows_386.odin => procs_windows_i386.odin} | 0 core/sys/cpu/cpu_x86.odin | 2 +- core/sys/unix/syscalls_linux.odin | 2 +- src/build_settings.cpp | 30 +++++++++---------- src/check_builtin.cpp | 2 +- src/llvm_abi.cpp | 2 +- src/llvm_backend.cpp | 4 +-- src/llvm_backend_expr.cpp | 2 +- src/llvm_backend_proc.cpp | 4 +-- src/llvm_backend_utility.cpp | 2 +- src/microsoft_craziness.h | 10 +++---- 15 files changed, 34 insertions(+), 34 deletions(-) rename core/runtime/{procs_windows_386.odin => procs_windows_i386.odin} (100%) diff --git a/core/c/c.odin b/core/c/c.odin index 139d9920a..d0b8e377f 100644 --- a/core/c/c.odin +++ b/core/c/c.odin @@ -48,7 +48,7 @@ int_least64_t :: builtin.i64 uint_least64_t :: builtin.u64 // Same on Windows, Linux, and FreeBSD -when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" { +when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { int_fast8_t :: builtin.i8 uint_fast8_t :: builtin.u8 int_fast16_t :: builtin.i32 diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index bfb7cf1f9..4ed8acbff 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -22,7 +22,7 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a assert(len(arg1) == 16) - when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" { + when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { // While it may be unwise to do deserialization here on our // own when fiat-crypto provides equivalent functionality, // doing it this way provides a little under 3x performance diff --git a/core/crypto/chacha20/chacha20.odin b/core/crypto/chacha20/chacha20.odin index f6f551692..e32dacb2c 100644 --- a/core/crypto/chacha20/chacha20.odin +++ b/core/crypto/chacha20/chacha20.odin @@ -346,7 +346,7 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) { // Until dedicated assembly can be written leverage the fact that // the callers of this routine ensure that src/dst are valid. - when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" { + when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" { // util.PUT_U32_LE/util.U32_LE are not required on little-endian // systems that also happen to not be strict about aligned // memory access. diff --git a/core/runtime/entry_windows.odin b/core/runtime/entry_windows.odin index 97a5bebe6..35a6bb421 100644 --- a/core/runtime/entry_windows.odin +++ b/core/runtime/entry_windows.odin @@ -22,7 +22,7 @@ when ODIN_BUILD_MODE == .Dynamic { return true } } else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT { - when ODIN_ARCH == "386" || ODIN_NO_CRT { + when ODIN_ARCH == "i386" || ODIN_NO_CRT { @(link_name="mainCRTStartup", linkage="strong", require) mainCRTStartup :: proc "stdcall" () -> i32 { context = default_context() diff --git a/core/runtime/procs_windows_386.odin b/core/runtime/procs_windows_i386.odin similarity index 100% rename from core/runtime/procs_windows_386.odin rename to core/runtime/procs_windows_i386.odin diff --git a/core/sys/cpu/cpu_x86.odin b/core/sys/cpu/cpu_x86.odin index 8f3560a87..146822e61 100644 --- a/core/sys/cpu/cpu_x86.odin +++ b/core/sys/cpu/cpu_x86.odin @@ -1,4 +1,4 @@ -//+build 386, amd64 +//+build i386, amd64 package sys_cpu _cache_line_size :: 64; diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 25c5ed0a1..3dc3d2c74 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -675,7 +675,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_create_ruleset : uintptr : 444 SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 -} else when ODIN_ARCH == "386" { +} else when ODIN_ARCH == "i386" { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 diff --git a/src/build_settings.cpp b/src/build_settings.cpp index bafa93042..5e4534517 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -29,7 +29,7 @@ enum TargetArchKind { TargetArch_Invalid, TargetArch_amd64, - TargetArch_386, + TargetArch_i386, TargetArch_arm64, TargetArch_wasm32, TargetArch_wasm64, @@ -63,7 +63,7 @@ String target_os_names[TargetOs_COUNT] = { String target_arch_names[TargetArch_COUNT] = { str_lit(""), str_lit("amd64"), - str_lit("386"), + str_lit("i386"), str_lit("arm64"), str_lit("wasm32"), str_lit("wasm64"), @@ -269,9 +269,9 @@ bool global_ignore_warnings(void) { } -gb_global TargetMetrics target_windows_386 = { +gb_global TargetMetrics target_windows_i386 = { TargetOs_windows, - TargetArch_386, + TargetArch_i386, 4, 8, str_lit("i386-pc-windows-msvc"), @@ -285,9 +285,9 @@ gb_global TargetMetrics target_windows_amd64 = { str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; -gb_global TargetMetrics target_linux_386 = { +gb_global TargetMetrics target_linux_i386 = { TargetOs_linux, - TargetArch_386, + TargetArch_i386, 4, 8, str_lit("i386-pc-linux-gnu"), @@ -328,9 +328,9 @@ gb_global TargetMetrics target_darwin_arm64 = { str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct? }; -gb_global TargetMetrics target_freebsd_386 = { +gb_global TargetMetrics target_freebsd_i386 = { TargetOs_freebsd, - TargetArch_386, + TargetArch_i386, 4, 8, str_lit("i386-unknown-freebsd-elf"), @@ -401,12 +401,12 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("darwin_amd64"), &target_darwin_amd64 }, { str_lit("darwin_arm64"), &target_darwin_arm64 }, { str_lit("essence_amd64"), &target_essence_amd64 }, - { str_lit("linux_386"), &target_linux_386 }, + { str_lit("linux_i386"), &target_linux_i386 }, { str_lit("linux_amd64"), &target_linux_amd64 }, { str_lit("linux_arm64"), &target_linux_arm64 }, - { str_lit("windows_386"), &target_windows_386 }, + { str_lit("windows_i386"), &target_windows_i386 }, { str_lit("windows_amd64"), &target_windows_amd64 }, - { str_lit("freebsd_386"), &target_freebsd_386 }, + { str_lit("freebsd_i386"), &target_freebsd_i386 }, { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, @@ -879,13 +879,13 @@ void init_build_context(TargetMetrics *cross_target) { #endif #else #if defined(GB_SYSTEM_WINDOWS) - metrics = &target_windows_386; + metrics = &target_windows_i386; #elif defined(GB_SYSTEM_OSX) #error "Build Error: Unsupported architecture" #elif defined(GB_SYSTEM_FREEBSD) - metrics = &target_freebsd_386; + metrics = &target_freebsd_i386; #else - metrics = &target_linux_386; + metrics = &target_linux_i386; #endif #endif @@ -932,7 +932,7 @@ void init_build_context(TargetMetrics *cross_target) { bc->link_flags = str_lit("-arch x86-64 "); break; } - } else if (bc->metrics.arch == TargetArch_386) { + } else if (bc->metrics.arch == TargetArch_i386) { switch (bc->metrics.os) { case TargetOs_windows: bc->link_flags = str_lit("/machine:x86 "); diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 82ad6d161..a42741976 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3225,7 +3225,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case TargetOs_essence: case TargetOs_freebsd: switch (build_context.metrics.arch) { - case TargetArch_386: + case TargetArch_i386: case TargetArch_amd64: case TargetArch_arm64: max_arg_count = 7; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 42f05bb27..310df6639 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1193,7 +1193,7 @@ LB_ABI_INFO(lb_get_abi_info) { } else { return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); } - case TargetArch_386: + case TargetArch_i386: return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); case TargetArch_arm64: return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7a7f20f8d..63fb5d4e9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -783,7 +783,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true); params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true); call_cleanup = false; - } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_386 || build_context.no_crt)) { + } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) { name = str_lit("mainCRTStartup"); } else if (is_arch_wasm()) { name = str_lit("_start"); @@ -1140,7 +1140,7 @@ void lb_generate_code(lbGenerator *gen) { switch (build_context.metrics.arch) { case TargetArch_amd64: - case TargetArch_386: + case TargetArch_i386: LLVMInitializeX86TargetInfo(); LLVMInitializeX86Target(); LLVMInitializeX86TargetMC(); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0b2f6b3fd..1f0ed6434 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -508,7 +508,7 @@ bool lb_is_matrix_simdable(Type *t) { case TargetArch_arm64: // TODO(bill): determine when this is fine return true; - case TargetArch_386: + case TargetArch_i386: case TargetArch_wasm32: case TargetArch_wasm64: return false; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index eccf9b360..2a6eb6bb3 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1361,7 +1361,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_cpu_relax: - if (build_context.metrics.arch == TargetArch_386 || + if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("pause"), {}); @@ -2018,7 +2018,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; - case TargetArch_386: + case TargetArch_i386: { GB_ASSERT(arg_count <= 7); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 3fe96459f..5b1b11b44 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1494,7 +1494,7 @@ lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t case TargetArch_arm64: // possible break; - case TargetArch_386: + case TargetArch_i386: case TargetArch_wasm32: case TargetArch_wasm64: is_possible = false; diff --git a/src/microsoft_craziness.h b/src/microsoft_craziness.h index 02f14dda3..b4f815284 100644 --- a/src/microsoft_craziness.h +++ b/src/microsoft_craziness.h @@ -460,7 +460,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res wchar_t *library_path = nullptr; if (build_context.metrics.arch == TargetArch_amd64) { library_path = concat(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\lib\\x64\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { library_path = concat(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\lib\\x86\\"); } else { continue; @@ -472,7 +472,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res wchar_t *link_exe_path = nullptr; if (build_context.metrics.arch == TargetArch_amd64) { link_exe_path = concat(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\bin\\Hostx64\\x64\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { link_exe_path = concat(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\bin\\Hostx86\\x86\\"); } else { continue; @@ -529,7 +529,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res if (build_context.metrics.arch == TargetArch_amd64) { lib_path = concat(buffer, L"VC\\Lib\\amd64\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { lib_path = concat(buffer, L"VC\\Lib\\"); } else { continue; @@ -542,7 +542,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res if (os_file_exists(vcruntime_filename)) { if (build_context.metrics.arch == TargetArch_amd64) { result->vs_exe_path = concat(buffer, L"VC\\bin\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { // result->vs_exe_path = concat(buffer, L"VC\\bin\\amd64_x86\\"); result->vs_exe_path = concat(buffer, L"VC\\bin\\x86_amd64\\"); } else { @@ -573,7 +573,7 @@ Find_Result find_visual_studio_and_windows_sdk() { if (build_context.metrics.arch == TargetArch_amd64) { result.windows_sdk_um_library_path = concat(result.windows_sdk_root, L"um\\x64\\"); result.windows_sdk_ucrt_library_path = concat(result.windows_sdk_root, L"ucrt\\x64\\"); - } else if (build_context.metrics.arch == TargetArch_386) { + } else if (build_context.metrics.arch == TargetArch_i386) { result.windows_sdk_um_library_path = concat(result.windows_sdk_root, L"um\\x86\\"); result.windows_sdk_ucrt_library_path = concat(result.windows_sdk_root, L"ucrt\\x86\\"); } From 3f59c45740403e538a23f50c2fe4cd25e815531b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 17:42:10 +0000 Subject: [PATCH 0193/1258] Remove `main` creation in llvm_backend.cpp and have it done purely in the runtime package (partial bootstrapping) --- src/llvm_backend.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 63fb5d4e9..304effb7f 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1572,6 +1572,7 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); lbProcedure *startup_runtime = lb_create_startup_runtime(default_module, startup_type_info, global_variables); + gb_unused(startup_runtime); TIME_SECTION("LLVM Global Procedures and Types"); for_array(i, info->entities) { @@ -1640,12 +1641,6 @@ void lb_generate_code(lbGenerator *gen) { } } - - if (!already_has_entry_point) { - TIME_SECTION("LLVM main"); - lb_create_main_procedure(default_module, startup_runtime); - } - for_array(j, gen->modules.entries) { lbModule *m = gen->modules.entries[j].value; for_array(i, m->missing_procedures_to_check) { From f0529535e02ab175bca3f7ff8c3bc2112d949236 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jan 2022 17:53:18 +0000 Subject: [PATCH 0194/1258] `ODIN_ENDIAN` changed to an enum constant; `ODIN_ENUM_STRING` is the new string version of the old constant --- core/crypto/_sha3/_sha3.odin | 4 ++-- core/crypto/haval/haval.odin | 2 +- core/encoding/json/marshal.odin | 4 ++-- core/fmt/fmt.odin | 4 ++-- core/hash/xxhash/streaming.odin | 2 +- core/image/png/example.odin | 2 +- core/image/png/png.odin | 2 +- core/math/bits/bits.odin | 32 ++++++++++++++++---------------- core/runtime/core.odin | 10 ++++++++++ core/runtime/udivmod128.odin | 2 +- src/build_settings.cpp | 20 +++++++++----------- src/checker.cpp | 15 +++++++++++++-- vendor/sdl2/sdl_audio.odin | 2 +- vendor/sdl2/sdl_pixels.odin | 8 ++++---- 14 files changed, 64 insertions(+), 45 deletions(-) diff --git a/core/crypto/_sha3/_sha3.odin b/core/crypto/_sha3/_sha3.odin index 76e09bf24..9846aca42 100644 --- a/core/crypto/_sha3/_sha3.odin +++ b/core/crypto/_sha3/_sha3.odin @@ -52,7 +52,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) { t: u64 = --- bc: [5]u64 = --- - when ODIN_ENDIAN != "little" { + when ODIN_ENDIAN != .Little { v: uintptr = --- for i = 0; i < 25; i += 1 { v := uintptr(&st[i]) @@ -98,7 +98,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) { st[0] ~= keccakf_rndc[r] } - when ODIN_ENDIAN != "little" { + when ODIN_ENDIAN != .Little { for i = 0; i < 25; i += 1 { v = uintptr(&st[i]) t = st[i] diff --git a/core/crypto/haval/haval.odin b/core/crypto/haval/haval.odin index f95ea344d..442a348e9 100644 --- a/core/crypto/haval/haval.odin +++ b/core/crypto/haval/haval.odin @@ -1332,7 +1332,7 @@ update :: proc(ctx: ^Haval_Context, data: []byte) { } ctx.count[1] += str_len >> 29 - when ODIN_ENDIAN == "little" { + when ODIN_ENDIAN == .Little { if rmd_len + str_len >= 128 { copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[:fill_len]) block(ctx, ctx.rounds) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index adbcb95be..aa1c1559c 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -285,8 +285,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { case runtime.Type_Info_Integer: switch info.endianness { case .Platform: return false - case .Little: return ODIN_ENDIAN != "little" - case .Big: return ODIN_ENDIAN != "big" + case .Little: return ODIN_ENDIAN != .Little + case .Big: return ODIN_ENDIAN != .Big } } return false diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index a9ff6ca47..2cc192c12 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1092,8 +1092,8 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { case runtime.Type_Info_Integer: switch info.endianness { case .Platform: return false - case .Little: return ODIN_ENDIAN != "little" - case .Big: return ODIN_ENDIAN != "big" + case .Little: return ODIN_ENDIAN != .Little + case .Big: return ODIN_ENDIAN != .Big } } return false diff --git a/core/hash/xxhash/streaming.odin b/core/hash/xxhash/streaming.odin index 737e37eae..d6df1089f 100644 --- a/core/hash/xxhash/streaming.odin +++ b/core/hash/xxhash/streaming.odin @@ -96,7 +96,7 @@ XXH3_128_canonical_from_hash :: proc(hash: XXH128_hash_t) -> (canonical: XXH128_ #assert(size_of(XXH128_canonical) == size_of(XXH128_hash_t)) t := hash - when ODIN_ENDIAN == "little" { + when ODIN_ENDIAN == .Little { t.high = byte_swap(t.high) t.low = byte_swap(t.low) } diff --git a/core/image/png/example.odin b/core/image/png/example.odin index 5e7dca4c8..f4eb5128e 100644 --- a/core/image/png/example.odin +++ b/core/image/png/example.odin @@ -189,7 +189,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b img := image // PBM 16-bit images are big endian - when ODIN_ENDIAN == "little" { + when ODIN_ENDIAN == .Little { if img.depth == 16 { // The pixel components are in Big Endian. Let's byteswap back. input := mem.slice_data_cast([]u16, img.pixels.buf[:]) diff --git a/core/image/png/png.odin b/core/image/png/png.odin index f77bf7519..da76a4588 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -1611,7 +1611,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH } } } - when ODIN_ENDIAN == "little" { + when ODIN_ENDIAN == .Little { if img.depth == 16 { // The pixel components are in Big Endian. Let's byteswap. input := mem.slice_data_cast([]u16be, img.pixels.buf[:]) diff --git a/core/math/bits/bits.odin b/core/math/bits/bits.odin index bff984cc7..850e8038a 100644 --- a/core/math/bits/bits.odin +++ b/core/math/bits/bits.odin @@ -69,29 +69,29 @@ rotate_left :: proc(x: uint, k: int) -> uint { } from_be_u8 :: proc(i: u8) -> u8 { return i } -from_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } } -from_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } } -from_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } } -from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } } +from_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } +from_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } +from_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } +from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } from_le_u8 :: proc(i: u8) -> u8 { return i } -from_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } } -from_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } } -from_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } } -from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } } +from_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } +from_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } +from_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } +from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } to_be_u8 :: proc(i: u8) -> u8 { return i } -to_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } } -to_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } } -to_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } } -to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } } +to_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } +to_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } +to_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } +to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } to_le_u8 :: proc(i: u8) -> u8 { return i } -to_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } } -to_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } } -to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } } -to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } } +to_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } +to_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } +to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } +to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 91b6bf5ca..424650828 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -398,6 +398,16 @@ Raw_Cstring :: struct { */ Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE) +/* + // Defined internally by the compiler + Odin_Endian_Type :: enum int { + Unknown, + Little, + Big, + } +*/ +Odin_Endian_Type :: type_of(ODIN_ENDIAN) + ///////////////////////////// // Init Startup Procedures // diff --git a/core/runtime/udivmod128.odin b/core/runtime/udivmod128.odin index 1fd1b5f84..87ef73c2c 100644 --- a/core/runtime/udivmod128.odin +++ b/core/runtime/udivmod128.odin @@ -11,7 +11,7 @@ udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 { q, r: [2]u64 sr: u32 = 0 - low :: 1 when ODIN_ENDIAN == "big" else 0 + low :: 1 when ODIN_ENDIAN == .Big else 0 high :: 1 - low U64_BITS :: 8*size_of(u64) U128_BITS :: 8*size_of(u128) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 5e4534517..b4a934ec8 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -170,7 +170,6 @@ struct BuildContext { // Constants String ODIN_OS; // target operating system String ODIN_ARCH; // target architecture - String ODIN_ENDIAN; // target endian String ODIN_VENDOR; // compiler vendor String ODIN_VERSION; // compiler version String ODIN_ROOT; // Odin ROOT @@ -269,7 +268,7 @@ bool global_ignore_warnings(void) { } -gb_global TargetMetrics target_windows_i386 = { +gb_global TargetMetrics target_windows_386 = { TargetOs_windows, TargetArch_i386, 4, @@ -285,7 +284,7 @@ gb_global TargetMetrics target_windows_amd64 = { str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; -gb_global TargetMetrics target_linux_i386 = { +gb_global TargetMetrics target_linux_386 = { TargetOs_linux, TargetArch_i386, 4, @@ -328,7 +327,7 @@ gb_global TargetMetrics target_darwin_arm64 = { str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct? }; -gb_global TargetMetrics target_freebsd_i386 = { +gb_global TargetMetrics target_freebsd_386 = { TargetOs_freebsd, TargetArch_i386, 4, @@ -401,12 +400,12 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("darwin_amd64"), &target_darwin_amd64 }, { str_lit("darwin_arm64"), &target_darwin_arm64 }, { str_lit("essence_amd64"), &target_essence_amd64 }, - { str_lit("linux_i386"), &target_linux_i386 }, + { str_lit("linux_386"), &target_linux_386 }, { str_lit("linux_amd64"), &target_linux_amd64 }, { str_lit("linux_arm64"), &target_linux_arm64 }, - { str_lit("windows_i386"), &target_windows_i386 }, + { str_lit("windows_386"), &target_windows_386 }, { str_lit("windows_amd64"), &target_windows_amd64 }, - { str_lit("freebsd_i386"), &target_freebsd_i386 }, + { str_lit("freebsd_386"), &target_freebsd_386 }, { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, @@ -879,13 +878,13 @@ void init_build_context(TargetMetrics *cross_target) { #endif #else #if defined(GB_SYSTEM_WINDOWS) - metrics = &target_windows_i386; + metrics = &target_windows_386; #elif defined(GB_SYSTEM_OSX) #error "Build Error: Unsupported architecture" #elif defined(GB_SYSTEM_FREEBSD) - metrics = &target_freebsd_i386; + metrics = &target_freebsd_386; #else - metrics = &target_linux_i386; + metrics = &target_linux_386; #endif #endif @@ -904,7 +903,6 @@ void init_build_context(TargetMetrics *cross_target) { bc->metrics = *metrics; bc->ODIN_OS = target_os_names[metrics->os]; bc->ODIN_ARCH = target_arch_names[metrics->arch]; - bc->ODIN_ENDIAN = target_endian_names[target_endians[metrics->arch]]; bc->endian_kind = target_endians[metrics->arch]; bc->word_size = metrics->word_size; bc->max_align = metrics->max_align; diff --git a/src/checker.cpp b/src/checker.cpp index c3dcd1d11..ddb73d33e 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -858,7 +858,6 @@ void init_universal(void) { // TODO(bill): Set through flags in the compiler add_global_string_constant("ODIN_OS", bc->ODIN_OS); add_global_string_constant("ODIN_ARCH", bc->ODIN_ARCH); - add_global_string_constant("ODIN_ENDIAN", bc->ODIN_ENDIAN); add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR); add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION); add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT); @@ -876,7 +875,19 @@ void init_universal(void) { add_global_enum_constant(fields, "ODIN_BUILD_MODE", bc->build_mode); } - // add_global_string_constant("ODIN_BUILD_MODE", bc->ODIN_BUILD_MODE); + add_global_string_constant("ODIN_ENDIAN_STRING", target_endian_names[target_endians[bc->metrics.arch]]); + { + GlobalEnumValue values[TargetEndian_COUNT] = { + {"Unknown", TargetEndian_Invalid}, + + {"Little", TargetEndian_Little}, + {"Big", TargetEndian_Big}, + }; + + auto fields = add_global_enum_type(str_lit("Odin_Endian_Type"), values, gb_count_of(values)); + add_global_enum_constant(fields, "ODIN_ENDIAN", target_endians[bc->metrics.arch]); + } + add_global_bool_constant("ODIN_DEBUG", bc->ODIN_DEBUG); add_global_bool_constant("ODIN_DISABLE_ASSERT", bc->ODIN_DISABLE_ASSERT); diff --git a/vendor/sdl2/sdl_audio.odin b/vendor/sdl2/sdl_audio.odin index e108e31c6..2c5b7fedb 100644 --- a/vendor/sdl2/sdl_audio.odin +++ b/vendor/sdl2/sdl_audio.odin @@ -59,7 +59,7 @@ AUDIO_F32LSB :: 0x8120 /**< 32-bit floating point samples */ AUDIO_F32MSB :: 0x9120 /**< As above, but big-endian byte order */ AUDIO_F32 :: AUDIO_F32LSB -when ODIN_ENDIAN == "little" { +when ODIN_ENDIAN == .Little { AUDIO_U16SYS :: AUDIO_U16LSB AUDIO_S16SYS :: AUDIO_S16LSB AUDIO_S32SYS :: AUDIO_S32LSB diff --git a/vendor/sdl2/sdl_pixels.odin b/vendor/sdl2/sdl_pixels.odin index a8503c621..22f6db440 100644 --- a/vendor/sdl2/sdl_pixels.odin +++ b/vendor/sdl2/sdl_pixels.odin @@ -156,10 +156,10 @@ PixelFormatEnum :: enum u32 { ARGB2101010 = 1<<28 | PIXELTYPE_PACKED32<<24 | PACKEDORDER_ARGB<<20 | PACKEDLAYOUT_2101010<<16 | 32<<8 | 4<<0, /* Aliases for RGBA byte arrays of color data, for the current platform */ - RGBA32 = RGBA8888 when ODIN_ENDIAN == "big" else ABGR8888, - ARGB32 = ARGB8888 when ODIN_ENDIAN == "big" else BGRA8888, - BGRA32 = BGRA8888 when ODIN_ENDIAN == "big" else ARGB8888, - ABGR32 = ABGR8888 when ODIN_ENDIAN == "big" else RGBA8888, + RGBA32 = RGBA8888 when ODIN_ENDIAN == .Big else ABGR8888, + ARGB32 = ARGB8888 when ODIN_ENDIAN == .Big else BGRA8888, + BGRA32 = BGRA8888 when ODIN_ENDIAN == .Big else ARGB8888, + ABGR32 = ABGR8888 when ODIN_ENDIAN == .Big else RGBA8888, YV12 = /**< Planar mode: Y + V + U (3 planes) */ 'Y'<<24 | 'V'<<16 | '1'<<8 | '2'<<0, From d57ec4a11d217c906a1ed18161b0dc6beba02089 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 16 Jan 2022 13:20:12 +0100 Subject: [PATCH 0195/1258] Fix return stmt when it's one lined(check for close brace). --- core/odin/parser/parser.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index e8c2c848d..0366e70d2 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1312,7 +1312,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { } results: [dynamic]^ast.Expr - for p.curr_tok.kind != .Semicolon { + for p.curr_tok.kind != .Semicolon && p.curr_tok.kind != .Close_Brace { result := parse_expr(p, false) append(&results, result) if p.curr_tok.kind != .Comma || From 2a325b3da0fc7b6bf41418aee022cc71f0137bfb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 16 Jan 2022 12:25:39 +0000 Subject: [PATCH 0196/1258] Update `ODIN_ENDIAN` usage --- tests/core/image/test_core_image.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 155b69298..23a7c2561 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -1767,7 +1767,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b img := image // PBM 16-bit images are big endian - when ODIN_ENDIAN == "little" { + when ODIN_ENDIAN == .Little { if img.depth == 16 { // The pixel components are in Big Endian. Let's byteswap back. input := mem.slice_data_cast([]u16, img.pixels.buf[:]) From d4ea02a877cffbb35a19ba6f8eababe1b217c0bf Mon Sep 17 00:00:00 2001 From: Jesse Stiller Date: Mon, 17 Jan 2022 12:19:06 +1000 Subject: [PATCH 0197/1258] Extraneous parameters in hlsl/glsl.saturate removed This is a breaking change to anyone who used glsl/hlsl.saturate functions prior, but the y and z parameters never were used and do not conform to how the saturate function works in HLSL: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-saturate Note however GLSL does not contain a saturate function, but removing it does not accomplish anything good IMO. --- core/math/linalg/glsl/linalg_glsl.odin | 33 +++++++++++++------------- core/math/linalg/hlsl/linalg_hlsl.odin | 32 ++++++++++++------------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/core/math/linalg/glsl/linalg_glsl.odin b/core/math/linalg/glsl/linalg_glsl.odin index 053182794..7bc68b964 100644 --- a/core/math/linalg/glsl/linalg_glsl.odin +++ b/core/math/linalg/glsl/linalg_glsl.odin @@ -693,23 +693,22 @@ saturate :: proc{ saturate_uvec3, saturate_uvec4, } -saturate_i32 :: proc "c" (x, y, z: i32) -> i32 { return builtin.clamp(x, 0, 1) } -saturate_u32 :: proc "c" (x, y, z: u32) -> u32 { return builtin.clamp(x, 0, 1) } -saturate_f32 :: proc "c" (x, y, z: f32) -> f32 { return builtin.clamp(x, 0, 1) } -saturate_f64 :: proc "c" (x, y, z: f64) -> f64 { return builtin.clamp(x, 0, 1) } -saturate_vec2 :: proc "c" (x, y, z: vec2) -> vec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } -saturate_vec3 :: proc "c" (x, y, z: vec3) -> vec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } -saturate_vec4 :: proc "c" (x, y, z: vec4) -> vec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } -saturate_dvec2 :: proc "c" (x, y, z: dvec2) -> dvec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } -saturate_dvec3 :: proc "c" (x, y, z: dvec3) -> dvec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } -saturate_dvec4 :: proc "c" (x, y, z: dvec4) -> dvec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } -saturate_ivec2 :: proc "c" (x, y, z: ivec2) -> ivec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } -saturate_ivec3 :: proc "c" (x, y, z: ivec3) -> ivec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } -saturate_ivec4 :: proc "c" (x, y, z: ivec4) -> ivec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } -saturate_uvec2 :: proc "c" (x, y, z: uvec2) -> uvec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } -saturate_uvec3 :: proc "c" (x, y, z: uvec3) -> uvec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } -saturate_uvec4 :: proc "c" (x, y, z: uvec4) -> uvec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } - +saturate_i32 :: proc "c" (v: i32) -> i32 { return builtin.clamp(v, 0, 1) } +saturate_u32 :: proc "c" (v: u32) -> u32 { return builtin.clamp(v, 0, 1) } +saturate_f32 :: proc "c" (v: f32) -> f32 { return builtin.clamp(v, 0, 1) } +saturate_f64 :: proc "c" (v: f64) -> f64 { return builtin.clamp(v, 0, 1) } +saturate_vec2 :: proc "c" (v: vec2) -> vec2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} } +saturate_vec3 :: proc "c" (v: vec3) -> vec3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} } +saturate_vec4 :: proc "c" (v: vec4) -> vec4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} } +saturate_dvec2 :: proc "c" (v: dvec2) -> dvec2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} } +saturate_dvec3 :: proc "c" (v: dvec3) -> dvec3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} } +saturate_dvec4 :: proc "c" (v: dvec4) -> dvec4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} } +saturate_ivec2 :: proc "c" (v: ivec2) -> ivec2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} } +saturate_ivec3 :: proc "c" (v: ivec3) -> ivec3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} } +saturate_ivec4 :: proc "c" (v: ivec4) -> ivec4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} } +saturate_uvec2 :: proc "c" (v: uvec2) -> uvec2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} } +saturate_uvec3 :: proc "c" (v: uvec3) -> uvec3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} } +saturate_uvec4 :: proc "c" (v: uvec4) -> uvec4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} } mix :: proc{ mix_f32, diff --git a/core/math/linalg/hlsl/linalg_hlsl.odin b/core/math/linalg/hlsl/linalg_hlsl.odin index 0eb8413a9..4391975ba 100644 --- a/core/math/linalg/hlsl/linalg_hlsl.odin +++ b/core/math/linalg/hlsl/linalg_hlsl.odin @@ -772,22 +772,22 @@ saturate :: proc{ saturate_uint3, saturate_uint4, } -saturate_int :: proc "c" (x, y, z: int) -> int { return builtin.clamp(x, 0, 1) } -saturate_uint :: proc "c" (x, y, z: uint) -> uint { return builtin.clamp(x, 0, 1) } -saturate_float :: proc "c" (x, y, z: float) -> float { return builtin.clamp(x, 0, 1) } -saturate_double :: proc "c" (x, y, z: double) -> double { return builtin.clamp(x, 0, 1) } -saturate_float2 :: proc "c" (x, y, z: float2) -> float2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } -saturate_float3 :: proc "c" (x, y, z: float3) -> float3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } -saturate_float4 :: proc "c" (x, y, z: float4) -> float4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } -saturate_double2 :: proc "c" (x, y, z: double2) -> double2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } -saturate_double3 :: proc "c" (x, y, z: double3) -> double3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } -saturate_double4 :: proc "c" (x, y, z: double4) -> double4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } -saturate_int2 :: proc "c" (x, y, z: int2) -> int2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } -saturate_int3 :: proc "c" (x, y, z: int3) -> int3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } -saturate_int4 :: proc "c" (x, y, z: int4) -> int4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } -saturate_uint2 :: proc "c" (x, y, z: uint2) -> uint2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} } -saturate_uint3 :: proc "c" (x, y, z: uint3) -> uint3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} } -saturate_uint4 :: proc "c" (x, y, z: uint4) -> uint4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} } +saturate_int :: proc "c" (v: int) -> int { return builtin.clamp(v, 0, 1) } +saturate_uint :: proc "c" (v: uint) -> uint { return builtin.clamp(v, 0, 1) } +saturate_float :: proc "c" (v: float) -> float { return builtin.clamp(v, 0, 1) } +saturate_double :: proc "c" (v: double) -> double { return builtin.clamp(v, 0, 1) } +saturate_float2 :: proc "c" (v: float2) -> float2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} } +saturate_float3 :: proc "c" (v: float3) -> float3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} } +saturate_float4 :: proc "c" (v: float4) -> float4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} } +saturate_double2 :: proc "c" (v: double2) -> double2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} } +saturate_double3 :: proc "c" (v: double3) -> double3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} } +saturate_double4 :: proc "c" (v: double4) -> double4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} } +saturate_int2 :: proc "c" (v: int2) -> int2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} } +saturate_int3 :: proc "c" (v: int3) -> int3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} } +saturate_int4 :: proc "c" (v: int4) -> int4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} } +saturate_uint2 :: proc "c" (v: uint2) -> uint2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} } +saturate_uint3 :: proc "c" (v: uint3) -> uint3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} } +saturate_uint4 :: proc "c" (v: uint4) -> uint4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} } lerp :: proc{ From 1d293749c2f0751c112e91f1337a83cbc3c5cb04 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 11:38:15 +0000 Subject: [PATCH 0198/1258] Move `core:path` to `core:path/slashpath` This is to reduce the confusion that occurs between that package and the `core:path/filepath` package --- core/path/path_error.odin | 5 +++++ core/path/{ => slashpath}/match.odin | 2 +- core/path/{ => slashpath}/path.odin | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 core/path/path_error.odin rename core/path/{ => slashpath}/match.odin (99%) rename core/path/{ => slashpath}/path.odin (94%) diff --git a/core/path/path_error.odin b/core/path/path_error.odin new file mode 100644 index 000000000..2be0b4cf4 --- /dev/null +++ b/core/path/path_error.odin @@ -0,0 +1,5 @@ +package path + +#panic( +`core:path/slashpath - for paths separated by forward slashes, e.g. paths in URLs, this does not deal with OS-specific paths +core:path/filepath - uses either forward slashes or backslashes depending on the operating system, deals with Windows/NT paths with volume letters or backslashes (on the related platforms)`) diff --git a/core/path/match.odin b/core/path/slashpath/match.odin similarity index 99% rename from core/path/match.odin rename to core/path/slashpath/match.odin index 0bea4f6e7..09e774275 100644 --- a/core/path/match.odin +++ b/core/path/slashpath/match.odin @@ -1,4 +1,4 @@ -package path +package slashpath import "core:strings" import "core:unicode/utf8" diff --git a/core/path/path.odin b/core/path/slashpath/path.odin similarity index 94% rename from core/path/path.odin rename to core/path/slashpath/path.odin index 186176b42..8ac10e655 100644 --- a/core/path/path.odin +++ b/core/path/slashpath/path.odin @@ -1,9 +1,9 @@ -// The path package is only to be used for paths separated by forward slashes, +// The slashpath package is only to be used for paths separated by forward slashes, // e.g. paths in URLs // // This package does not deal with Windows/NT paths with volume letters or backslashes // To manipulate operating system specific paths, use the path/filepath package -package path +package slashpath import "core:strings" From 95620aaf2aced0290133dcbfa96a1920b3ff7578 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 11:48:15 +0000 Subject: [PATCH 0199/1258] Update examples/all --- examples/all/all_main.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index a88cc273e..c24238602 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -40,7 +40,7 @@ import odin_parser "core:odin/parser" import odin_printer "core:odin/printer" import odin_tokenizer "core:odin/tokenizer" import os "core:os" -import path "core:path" +import slashpath "core:path/slashpath" import filepath "core:path/filepath" import reflect "core:reflect" import runtime "core:runtime" @@ -97,7 +97,7 @@ _ :: odin_parser _ :: odin_printer _ :: odin_tokenizer _ :: os -_ :: path +_ :: slashpath _ :: filepath _ :: reflect _ :: runtime From cd6898439e9de6fce42555e2bab5c27e206dbcde Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 12:17:13 +0000 Subject: [PATCH 0200/1258] Comment out `link_section` on procedures --- core/runtime/entry_unix.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin index 67d2cbcb7..dd1e06625 100644 --- a/core/runtime/entry_unix.odin +++ b/core/runtime/entry_unix.odin @@ -5,13 +5,13 @@ package runtime import "core:intrinsics" when ODIN_BUILD_MODE == .Dynamic { - @(link_name="_odin_entry_point", linkage="strong", require, link_section=".init") + @(link_name="_odin_entry_point", linkage="strong", require/*, link_section=".init"*/) _odin_entry_point :: proc "c" () { context = default_context() #force_no_inline _startup_runtime() intrinsics.__entry_point() } - @(link_name="_odin_exit_point", linkage="strong", require, link_section=".fini") + @(link_name="_odin_exit_point", linkage="strong", require/*, link_section=".fini"*/) _odin_exit_point :: proc "c" () { context = default_context() #force_no_inline _cleanup_runtime() From 686dbb4421824f17164443b2538b587e91d400a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 14:43:42 +0000 Subject: [PATCH 0201/1258] Correct odin doc comment printing --- src/docs.cpp | 28 ++++++++++++++++++++++------ src/docs_writer.cpp | 5 +++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/docs.cpp b/src/docs.cpp index 8d65cb83a..3ea3cce1b 100644 --- a/src/docs.cpp +++ b/src/docs.cpp @@ -67,6 +67,14 @@ GB_COMPARE_PROC(cmp_ast_package_by_name) { #include "docs_format.cpp" #include "docs_writer.cpp" +void print_doc_line(i32 indent, String const &data) { + while (indent --> 0) { + gb_printf("\t"); + } + gb_file_write(gb_file_get_standard(gbFileStandard_Output), data.text, data.len); + gb_printf("\n"); +} + void print_doc_line(i32 indent, char const *fmt, ...) { while (indent --> 0) { gb_printf("\t"); @@ -86,6 +94,13 @@ void print_doc_line_no_newline(i32 indent, char const *fmt, ...) { gb_printf_va(fmt, va); va_end(va); } +void print_doc_line_no_newline(i32 indent, String const &data) { + while (indent --> 0) { + gb_printf("\t"); + } + gb_file_write(gb_file_get_standard(gbFileStandard_Output), data.text, data.len); +} + bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { if (g == nullptr) { @@ -106,8 +121,9 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { String comment = g->list[i].string; String original_comment = comment; - bool slash_slash = comment[1] == '/'; + bool slash_slash = false; if (comment[1] == '/') { + slash_slash = true; comment.text += 2; comment.len -= 2; } else if (comment[1] == '*') { @@ -131,7 +147,7 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { } if (slash_slash) { - print_doc_line(indent, "%.*s", LIT(comment)); + print_doc_line(indent, comment); count += 1; } else { isize pos = 0; @@ -143,7 +159,7 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { } } String line = substring(comment, pos, end); - pos = end+1; + pos = end; String trimmed_line = string_trim_whitespace(line); if (trimmed_line.len == 0) { if (count == 0) { @@ -159,7 +175,7 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { line = substring(line, 2, line.len); } - print_doc_line(indent, "%.*s", LIT(line)); + print_doc_line(indent, line); count += 1; } } @@ -263,7 +279,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) { } GB_ASSERT(type_expr != nullptr || init_expr != nullptr); - print_doc_line_no_newline(2, "%.*s", LIT(e->token.string)); + print_doc_line_no_newline(2, e->token.string); if (type_expr != nullptr) { gbString t = expr_to_string(type_expr); gb_printf(": %s ", t); @@ -298,7 +314,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) { for_array(i, pkg->files) { AstFile *f = pkg->files[i]; String filename = remove_directory_from_path(f->fullpath); - print_doc_line(2, "%.*s", LIT(filename)); + print_doc_line(2, filename); } } diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 56ad0561e..94b43be99 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -292,8 +292,9 @@ bool odin_doc_append_comment_group_string(Array *buf, CommentGroup *g) { String comment = g->list[i].string; String original_comment = comment; - bool slash_slash = comment[1] == '/'; + bool slash_slash = false; if (comment[1] == '/') { + slash_slash = true; comment.text += 2; comment.len -= 2; } else if (comment[1] == '*') { @@ -330,7 +331,7 @@ bool odin_doc_append_comment_group_string(Array *buf, CommentGroup *g) { } } String line = substring(comment, pos, end); - pos = end+1; + pos = end; String trimmed_line = string_trim_whitespace(line); if (trimmed_line.len == 0) { if (count == 0) { From 76ccce2942a0d527be5693ff5bedbf92a5de5eb2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 17:57:55 +0000 Subject: [PATCH 0202/1258] Begin work on a html doc printer --- tools/odin-html-docs/odin_html_docs_main.odin | 609 ++++++++++++++++++ tools/odin-html-docs/style.css | 31 + 2 files changed, 640 insertions(+) create mode 100644 tools/odin-html-docs/odin_html_docs_main.odin create mode 100644 tools/odin-html-docs/style.css diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin new file mode 100644 index 000000000..7c822e4a1 --- /dev/null +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -0,0 +1,609 @@ +package odin_html_docs + +import doc "core:odin/doc-format" +import "core:fmt" +import "core:io" +import "core:os" +import "core:strings" +import "core:path/slashpath" +import "core:sort" +import "core:slice" + +header: ^doc.Header +files: []doc.File +pkgs: []doc.Pkg +entities: []doc.Entity +types: []doc.Type + +pkgs_to_use: map[string]^doc.Pkg // trimmed path +pkg_to_path: map[^doc.Pkg]string // trimmed path + +array :: proc(a: $A/doc.Array($T)) -> []T { + return doc.from_array(header, a) +} +str :: proc(s: $A/doc.String) -> string { + return doc.from_string(header, s) +} + +errorf :: proc(format: string, args: ..any) -> ! { + fmt.eprintf("%s ", os.args[0]) + fmt.eprintf(format, ..args) + fmt.eprintln() + os.exit(1) +} + +common_prefix :: proc(strs: []string) -> string { + if len(strs) == 0 { + return "" + } + n := max(int) + for str in strs { + n = min(n, len(str)) + } + + prefix := strs[0][:n] + for str in strs[1:] { + for len(prefix) != 0 && str[:len(prefix)] != prefix { + prefix = prefix[:len(prefix)-1] + } + if len(prefix) == 0 { + break + } + } + return prefix +} + + +write_html_header :: proc(w: io.Writer, title: string) { + fmt.wprintf(w, ` + + + + + %s + + + + + + +`, title) + fmt.wprintln(w, "\n\n\n") +} + +main :: proc() { + if len(os.args) != 2 { + errorf("expected 1 .odin-doc file") + } + data, ok := os.read_entire_file(os.args[1]) + if !ok { + errorf("unable to read file:", os.args[1]) + } + err: doc.Reader_Error + header, err = doc.read_from_bytes(data) + switch err { + case .None: + case .Header_Too_Small: + errorf("file is too small for the file format") + case .Invalid_Magic: + errorf("invalid magic for the file format") + case .Data_Too_Small: + errorf("data is too small for the file format") + case .Invalid_Version: + errorf("invalid file format version") + } + files = array(header.files) + pkgs = array(header.pkgs) + entities = array(header.entities) + types = array(header.types) + + fullpaths: [dynamic]string + defer delete(fullpaths) + + for pkg in pkgs[1:] { + append(&fullpaths, str(pkg.fullpath)) + } + path_prefix := common_prefix(fullpaths[:]) + + pkgs_to_use = make(map[string]^doc.Pkg) + for fullpath, i in fullpaths { + path := strings.trim_prefix(fullpath, path_prefix) + if strings.has_prefix(path, "core/") { + pkgs_to_use[strings.trim_prefix(path, "core/")] = &pkgs[i+1] + } + } + sort.map_entries_by_key(&pkgs_to_use) + for path, pkg in pkgs_to_use { + pkg_to_path[pkg] = path + } + + b := strings.make_builder() + w := strings.to_writer(&b) + { + strings.reset_builder(&b) + write_html_header(w, "core library - pkg.odin-lang.org") + write_core_directory(w) + write_html_footer(w) + os.make_directory("core", 0) + os.write_entire_file("core/index.html", b.buf[:]) + } + + for path, pkg in pkgs_to_use { + strings.reset_builder(&b) + write_html_header(w, fmt.tprintf("package %s - pkg.odin-lang.org", path)) + write_pkg(w, path, pkg) + write_html_footer(w) + os.make_directory(fmt.tprintf("core/%s", path), 0) + os.write_entire_file(fmt.tprintf("core/%s/index.html", path), b.buf[:]) + } +} + + +write_core_directory :: proc(w: io.Writer) { + Node :: struct { + dir: string, + path: string, + name: string, + pkg: ^doc.Pkg, + next: ^Node, + first_child: ^Node, + } + add_child :: proc(parent: ^Node, child: ^Node) -> ^Node { + assert(parent != nil) + end := &parent.first_child + for end^ != nil { + end = &end^.next + } + child.next = end^ + end^ = child + return child + } + + root: Node + for path, pkg in pkgs_to_use { + dir, _, inner := strings.partition(path, "/") + + node: ^Node = nil + for node = root.first_child; node != nil; node = node.next { + if node.dir == dir { + break + } + } + if inner == "" { + if node == nil { + add_child(&root, new_clone(Node{ + dir = dir, + name = dir, + path = path, + pkg = pkg, + })) + } else { + node.dir = dir + node.name = dir + node.path = path + node.pkg = pkg + } + } else { + if node == nil { + node = add_child(&root, new_clone(Node{ + dir = dir, + name = dir, + })) + } + assert(node != nil) + child := add_child(node, new_clone(Node{ + dir = dir, + name = inner, + path = path, + pkg = pkg, + })) + } + } + + + fmt.wprintln(w, "

Directories

") + + fmt.wprintln(w, "\t") + fmt.wprintln(w, "\t\t") + + for dir := root.first_child; dir != nil; dir = dir.next { + if dir.first_child != nil { + fmt.wprint(w, `") + if dir.pkg != nil { + line_doc, _, _ := strings.partition(str(dir.pkg.docs), "\n") + line_doc = strings.trim_space(line_doc) + if line_doc != "" { + fmt.wprintf(w, ``, line_doc) + } + } + fmt.wprintf(w, "\n") + + for child := dir.first_child; child != nil; child = child.next { + assert(child.pkg != nil) + fmt.wprintf(w, `") + + line_doc, _, _ := strings.partition(str(child.pkg.docs), "\n") + line_doc = strings.trim_space(line_doc) + if line_doc != "" { + fmt.wprintf(w, ``, line_doc) + } + + fmt.wprintf(w, "\n") + } + } + + fmt.wprintln(w, "\t\t") + fmt.wprintln(w, "\t
`, dir.dir) + } else { + fmt.wprintf(w, `
`, dir.dir) + } + + if dir.pkg != nil { + fmt.wprintf(w, `%s`, dir.path, dir.name) + } else { + fmt.wprintf(w, "%s", dir.name) + } + fmt.wprintf(w, "%s
`, str(child.pkg.name)) + fmt.wprintf(w, `%s`, child.path, child.name) + fmt.wprintf(w, "%s
") +} + +is_entity_blank :: proc(e: doc.Entity_Index) -> bool { + name := str(entities[e].name) + return name == "" || name == "_" +} + +Write_Type_Flag :: enum { + Is_Results, + Variadic, +} +Write_Type_Flags :: distinct bit_set[Write_Type_Flag] + +write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Write_Type_Flags) { + type_entites := array(type.entities) + type_types := array(type.types) + switch type.kind { + case .Invalid: + // ignore + case .Basic: + type_flags := transmute(doc.Type_Flags_Basic)type.flags + if .Untyped in type_flags { + io.write_string(w, str(type.name)) + } else { + fmt.wprintf(w, `%s`, str(type.name)) + } + case .Named: + e := entities[type_entites[0]] + name := str(type.name) + fmt.wprintf(w, ``) + tn_pkg := files[e.pos.file].pkg + if tn_pkg != pkg { + fmt.wprintf(w, `%s.`, str(pkgs[pkg].name)) + } + fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) + case .Generic: + name := str(type.name) + io.write_byte(w, '$') + io.write_string(w, name) + if len(array(type.types)) == 1 { + io.write_byte(w, '/') + write_type(w, pkg, types[type_types[0]], flags) + } + case .Pointer: + io.write_byte(w, '^') + write_type(w, pkg, types[type_types[0]], flags) + case .Array: + assert(type.elem_count_len == 1) + io.write_byte(w, '[') + io.write_uint(w, uint(type.elem_counts[0])) + io.write_byte(w, ']') + write_type(w, pkg, types[type_types[0]], flags) + case .Enumerated_Array: + io.write_byte(w, '[') + write_type(w, pkg, types[type_types[0]], flags) + io.write_byte(w, ']') + write_type(w, pkg, types[type_types[1]], flags) + case .Slice: + if .Variadic in flags { + io.write_string(w, "..") + } else { + io.write_string(w, "[]") + } + write_type(w, pkg, types[type_types[0]], flags - {.Variadic}) + case .Dynamic_Array: + io.write_string(w, "[dynamic]") + write_type(w, pkg, types[type_types[0]], flags) + case .Map: + io.write_string(w, "map[") + write_type(w, pkg, types[type_types[0]], flags) + io.write_byte(w, ']') + write_type(w, pkg, types[type_types[1]], flags) + case .Struct: + type_flags := transmute(doc.Type_Flags_Struct)type.flags + io.write_string(w, "struct {}") + case .Union: + type_flags := transmute(doc.Type_Flags_Union)type.flags + io.write_string(w, "union {}") + case .Enum: + io.write_string(w, "enum {}") + case .Tuple: + entity_indices := type_entites + if len(entity_indices) == 0 { + return + } + require_parens := (.Is_Results in flags) && (len(entity_indices) > 1 || !is_entity_blank(entity_indices[0])) + if require_parens { io.write_byte(w, '(') } + for entity_index, i in entity_indices { + e := &entities[entity_index] + name := str(e.name) + + if i > 0 { + io.write_string(w, ", ") + } + if .Param_Using in e.flags { io.write_string(w, "using ") } + if .Param_Const in e.flags { io.write_string(w, "#const ") } + if .Param_Auto_Cast in e.flags { io.write_string(w, "#auto_cast ") } + if .Param_CVararg in e.flags { io.write_string(w, "#c_vararg ") } + if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") } + if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } + + if name != "" { + io.write_string(w, name) + io.write_string(w, ": ") + } + param_flags := flags - {.Is_Results} + if .Param_Ellipsis in e.flags { + param_flags += {.Variadic} + } + write_type(w, pkg, types[e.type], param_flags) + } + if require_parens { io.write_byte(w, ')') } + + case .Proc: + type_flags := transmute(doc.Type_Flags_Proc)type.flags + io.write_string(w, "proc") + cc := str(type.calling_convention) + if cc != "" { + io.write_byte(w, ' ') + io.write_quoted_string(w, cc) + io.write_byte(w, ' ') + } + params := array(type.types)[0] + results := array(type.types)[1] + io.write_byte(w, '(') + write_type(w, pkg, types[params], flags) + io.write_byte(w, ')') + if results != 0 { + assert(.Diverging not_in type_flags) + io.write_string(w, " -> ") + write_type(w, pkg, types[results], flags+{.Is_Results}) + } + if .Diverging in type_flags { + io.write_string(w, " -> !") + } + if .Optional_Ok in type_flags { + io.write_string(w, " #optional_ok") + } + + case .Bit_Set: + type_flags := transmute(doc.Type_Flags_Bit_Set)type.flags + case .Simd_Vector: + io.write_string(w, "#simd[") + io.write_uint(w, uint(type.elem_counts[0])) + io.write_byte(w, ']') + case .SOA_Struct_Fixed: + io.write_string(w, "#soa[") + io.write_uint(w, uint(type.elem_counts[0])) + io.write_byte(w, ']') + case .SOA_Struct_Slice: + io.write_string(w, "#soa[]") + case .SOA_Struct_Dynamic: + io.write_string(w, "#soa[dynamic]") + case .Relative_Pointer: + io.write_string(w, "#relative(") + write_type(w, pkg, types[type_types[1]], flags) + io.write_string(w, ") ") + write_type(w, pkg, types[type_types[0]], flags) + case .Relative_Slice: + io.write_string(w, "#relative(") + write_type(w, pkg, types[type_types[1]], flags) + io.write_string(w, ") ") + write_type(w, pkg, types[type_types[0]], flags) + case .Multi_Pointer: + io.write_string(w, "[^]") + write_type(w, pkg, types[type_types[0]], flags) + case .Matrix: + io.write_string(w, "matrix[") + io.write_uint(w, uint(type.elem_counts[0])) + io.write_string(w, ", ") + io.write_uint(w, uint(type.elem_counts[1])) + io.write_string(w, "]") + write_type(w, pkg, types[type_types[0]], flags) + } +} + +write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { + if docs == "" { + return + } + it := docs + was_code := true + was_paragraph := true + for line in strings.split_iterator(&it, "\n") { + if strings.has_prefix(line, "\t") { + if !was_code { + was_code = true; + fmt.wprint(w, `
`)
+			}
+			fmt.wprintf(w, "%s\n", strings.trim_prefix(line, "\t"))
+			continue
+		} else if was_code {
+			was_code = false
+			fmt.wprintln(w, "
") + } + text := strings.trim_space(line) + if text == "" { + if was_paragraph { + was_paragraph = false + fmt.wprintln(w, "

") + } + continue + } + if !was_paragraph { + fmt.wprintln(w, "

") + } + assert(!was_code) + was_paragraph = true + fmt.wprintln(w, text) + } + if was_code { + // assert(!was_paragraph, str(pkg.name)) + was_code = false + fmt.wprintln(w, "") + } else if was_paragraph { + fmt.wprintln(w, "

") + } +} + +write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { + fmt.wprintf(w, "

package core:%s

\n", path) + fmt.wprintln(w, "

Documentation

") + docs := strings.trim_space(str(pkg.docs)) + if docs != "" { + fmt.wprintln(w, "

Overview

") + fmt.wprintln(w, "
") + defer fmt.wprintln(w, "
") + + write_docs(w, pkg, docs) + } + + fmt.wprintln(w, "

Index

") + fmt.wprintln(w, `
`) + pkg_procs: [dynamic]^doc.Entity + pkg_proc_groups: [dynamic]^doc.Entity + pkg_types: [dynamic]^doc.Entity + pkg_vars: [dynamic]^doc.Entity + pkg_consts: [dynamic]^doc.Entity + + for entity_index in array(pkg.entities) { + e := &entities[entity_index] + name := str(e.name) + if name == "" || name[0] == '_' { + continue + } + switch e.kind { + case .Invalid, .Import_Name, .Library_Name: + // ignore + case .Constant: append(&pkg_consts, e) + case .Variable: append(&pkg_vars, e) + case .Type_Name: append(&pkg_types, e) + case .Procedure: append(&pkg_procs, e) + case .Proc_Group: append(&pkg_proc_groups, e) + } + } + + entity_key :: proc(e: ^doc.Entity) -> string { + return str(e.name) + } + + slice.sort_by_key(pkg_procs[:], entity_key) + slice.sort_by_key(pkg_proc_groups[:], entity_key) + slice.sort_by_key(pkg_types[:], entity_key) + slice.sort_by_key(pkg_vars[:], entity_key) + slice.sort_by_key(pkg_consts[:], entity_key) + + print_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { + fmt.wprintf(w, "

%s

\n", name) + fmt.wprintln(w, `
`) + fmt.wprintln(w, "
    ") + for e in entities { + name := str(e.name) + fmt.wprintf(w, "
  • {0:s}
  • \n", name) + } + fmt.wprintln(w, "
") + fmt.wprintln(w, "
") + } + + + print_index(w, "Procedures", pkg_procs[:]) + print_index(w, "Procedure Groups", pkg_proc_groups[:]) + print_index(w, "Types", pkg_types[:]) + print_index(w, "Variables", pkg_vars[:]) + print_index(w, "Constants", pkg_consts[:]) + + fmt.wprintln(w, "
") + + + print_entity :: proc(w: io.Writer, e: ^doc.Entity) { + pkg := &pkgs[files[e.pos.file].pkg] + name := str(e.name) + fmt.wprintf(w, "

{0:s}

\n", name) + switch e.kind { + case .Invalid, .Import_Name, .Library_Name: + // ignore + case .Constant: + case .Variable: + case .Type_Name: + case .Procedure: + fmt.wprint(w, "
")
+			fmt.wprintf(w, "%s :: ", name)
+			write_type(w, files[e.pos.file].pkg, types[e.type], nil)
+			where_clauses := array(e.where_clauses)
+			if len(where_clauses) != 0 {
+				io.write_string(w, " where ")
+				for clause, i in where_clauses {
+					if i > 0 {
+						io.write_string(w, ", ")
+					}
+					io.write_string(w, str(clause))
+				}
+			}
+
+			fmt.wprint(w, " {…}")
+			fmt.wprintln(w, "
") + case .Proc_Group: + } + + write_docs(w, pkg, strings.trim_space(str(e.docs))) + } + print_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) { + fmt.wprintf(w, "

%s

\n", title) + fmt.wprintln(w, `
`) + for e in entities { + print_entity(w, e) + } + fmt.wprintln(w, "
") + } + + print_entities(w, "Procedures", pkg_procs[:]) + print_entities(w, "Procedure Groups", pkg_proc_groups[:]) + print_entities(w, "Types", pkg_types[:]) + print_entities(w, "Variables", pkg_vars[:]) + print_entities(w, "Constants", pkg_consts[:]) + + + fmt.wprintln(w, "

Source Files

") + fmt.wprintln(w, "
    ") + for file_index in array(pkg.files) { + file := files[file_index] + filename := slashpath.base(str(file.name)) + fmt.wprintf(w, `
  • %s
  • `, path, filename, filename) + fmt.wprintln(w) + } + fmt.wprintln(w, "
") + +} \ No newline at end of file diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css new file mode 100644 index 000000000..7c23d0bc7 --- /dev/null +++ b/tools/odin-html-docs/style.css @@ -0,0 +1,31 @@ +.container { + max-width: 60em; + margin: 0 auto; + padding-left: 0.01em 1em; +} + +.directory-pkg { + width: 20em; +} + +.directory-child .pkg-name { + position: relative; + left: 2em; + width: 18em; +} + +pre { + white-space: pre; + tab-size: 8; + background-color: #f8f8f8; + color: #202224; + border: 1px solid #c6c8ca; + border-radius: 0.25rem; + padding: 0.625rem; +} + +.documentation pre a { + text-decoration: none; + font-weight: bold; + color: #00bfd5; +} \ No newline at end of file From 97922406fec4296ce0732d1eefa0b9d7c943086f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 18:23:30 +0000 Subject: [PATCH 0203/1258] Improve printing for record types --- tools/odin-html-docs/odin_html_docs_main.odin | 253 ++++++++++++++---- 1 file changed, 200 insertions(+), 53 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 7c822e4a1..3cbc0d860 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -32,6 +32,17 @@ errorf :: proc(format: string, args: ..any) -> ! { os.exit(1) } +base_type :: proc(t: doc.Type) -> doc.Type { + t := t + for { + if t.kind != .Named { + break + } + t = types[array(t.types)[0]] + } + return t +} + common_prefix :: proc(strs: []string) -> string { if len(strs) == 0 { return "" @@ -270,10 +281,74 @@ is_entity_blank :: proc(e: doc.Entity_Index) -> bool { Write_Type_Flag :: enum { Is_Results, Variadic, + Allow_Indent, } Write_Type_Flags :: distinct bit_set[Write_Type_Flag] +Type_Writer :: struct { + w: io.Writer, + pkg: doc.Pkg_Index, + indent: int, +} + +write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type_Flags) { + write_param_entity :: proc(using writer: ^Type_Writer, e: ^doc.Entity, flags: Write_Type_Flags, name_width := 0) { + name := str(e.name) + + if .Param_Using in e.flags { io.write_string(w, "using ") } + if .Param_Const in e.flags { io.write_string(w, "#const ") } + if .Param_Auto_Cast in e.flags { io.write_string(w, "#auto_cast ") } + if .Param_CVararg in e.flags { io.write_string(w, "#c_vararg ") } + if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") } + if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } + + if name != "" { + io.write_string(w, name) + io.write_string(w, ": ") + } + padding := max(name_width-len(name), 0) + for _ in 0.. 0 { + io.write_string(w, ", ") + } + write_param_entity(writer, &entities[entity_index], flags) + } + io.write_byte(w, ')') + } + do_indent :: proc(using writer: ^Type_Writer, flags: Write_Type_Flags) { + if .Allow_Indent not_in flags { + return + } + for _ in 0.. (name_width: int) { + for entity_index in type_entites { + e := &entities[entity_index] + name := str(e.name) + name_width = max(len(name), name_width) + } + return + } + -write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Write_Type_Flags) { type_entites := array(type.entities) type_types := array(type.types) switch type.kind { @@ -301,75 +376,128 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ io.write_string(w, name) if len(array(type.types)) == 1 { io.write_byte(w, '/') - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) } case .Pointer: io.write_byte(w, '^') - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Array: assert(type.elem_count_len == 1) io.write_byte(w, '[') io.write_uint(w, uint(type.elem_counts[0])) io.write_byte(w, ']') - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Enumerated_Array: io.write_byte(w, '[') - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) io.write_byte(w, ']') - write_type(w, pkg, types[type_types[1]], flags) + write_type(writer, types[type_types[1]], flags) case .Slice: if .Variadic in flags { io.write_string(w, "..") } else { io.write_string(w, "[]") } - write_type(w, pkg, types[type_types[0]], flags - {.Variadic}) + write_type(writer, types[type_types[0]], flags - {.Variadic}) case .Dynamic_Array: io.write_string(w, "[dynamic]") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Map: io.write_string(w, "map[") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) io.write_byte(w, ']') - write_type(w, pkg, types[type_types[1]], flags) + write_type(writer, types[type_types[1]], flags) case .Struct: type_flags := transmute(doc.Type_Flags_Struct)type.flags - io.write_string(w, "struct {}") + io.write_string(w, "struct") + if .Polymorphic in type_flags { + write_poly_params(writer, type, flags) + } + if .Packed in type_flags { io.write_string(w, " #packed") } + if .Raw_Union in type_flags { io.write_string(w, " #raw_union") } + if custom_align := str(type.custom_align); custom_align != "" { + io.write_string(w, " #align") + io.write_string(w, custom_align) + } + io.write_string(w, " {") + do_newline(writer, flags) + indent += 1 + name_width := calc_name_width(type_entites) + + for entity_index in type_entites { + e := &entities[entity_index] + do_indent(writer, flags) + write_param_entity(writer, e, flags, name_width) + io.write_byte(w, ',') + do_newline(writer, flags) + } + indent -= 1 + do_indent(writer, flags) + io.write_string(w, "}") case .Union: type_flags := transmute(doc.Type_Flags_Union)type.flags - io.write_string(w, "union {}") + io.write_string(w, "union") + if .Polymorphic in type_flags { + write_poly_params(writer, type, flags) + } + if .No_Nil in type_flags { io.write_string(w, " #no_nil") } + if .Maybe in type_flags { io.write_string(w, " #maybe") } + if custom_align := str(type.custom_align); custom_align != "" { + io.write_string(w, " #align") + io.write_string(w, custom_align) + } + io.write_string(w, " {") + if len(type_types) > 1 { + do_newline(writer, flags) + indent += 1 + for type_index in type_types { + do_indent(writer, flags) + write_type(writer, types[type_index], flags) + io.write_string(w, ", ") + do_newline(writer, flags) + } + indent -= 1 + do_indent(writer, flags) + } + io.write_string(w, "}") case .Enum: - io.write_string(w, "enum {}") + io.write_string(w, "enum") + io.write_string(w, " {") + do_newline(writer, flags) + indent += 1 + + name_width := calc_name_width(type_entites) + + for entity_index in type_entites { + e := &entities[entity_index] + + do_indent(writer, flags) + io.write_string(w, str(e.name)) + + if init_string := str(e.init_string); init_string != "" { + for _ in 0.. 1 || !is_entity_blank(entity_indices[0])) + require_parens := (.Is_Results in flags) && (len(type_entites) > 1 || !is_entity_blank(type_entites[0])) if require_parens { io.write_byte(w, '(') } - for entity_index, i in entity_indices { - e := &entities[entity_index] - name := str(e.name) - + for entity_index, i in type_entites { if i > 0 { io.write_string(w, ", ") } - if .Param_Using in e.flags { io.write_string(w, "using ") } - if .Param_Const in e.flags { io.write_string(w, "#const ") } - if .Param_Auto_Cast in e.flags { io.write_string(w, "#auto_cast ") } - if .Param_CVararg in e.flags { io.write_string(w, "#c_vararg ") } - if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") } - if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } - - if name != "" { - io.write_string(w, name) - io.write_string(w, ": ") - } - param_flags := flags - {.Is_Results} - if .Param_Ellipsis in e.flags { - param_flags += {.Variadic} - } - write_type(w, pkg, types[e.type], param_flags) + write_param_entity(writer, &entities[entity_index], flags) } if require_parens { io.write_byte(w, ')') } @@ -385,12 +513,12 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ params := array(type.types)[0] results := array(type.types)[1] io.write_byte(w, '(') - write_type(w, pkg, types[params], flags) + write_type(writer, types[params], flags) io.write_byte(w, ')') if results != 0 { assert(.Diverging not_in type_flags) io.write_string(w, " -> ") - write_type(w, pkg, types[results], flags+{.Is_Results}) + write_type(writer, types[results], flags+{.Is_Results}) } if .Diverging in type_flags { io.write_string(w, " -> !") @@ -415,24 +543,24 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ io.write_string(w, "#soa[dynamic]") case .Relative_Pointer: io.write_string(w, "#relative(") - write_type(w, pkg, types[type_types[1]], flags) + write_type(writer, types[type_types[1]], flags) io.write_string(w, ") ") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Relative_Slice: io.write_string(w, "#relative(") - write_type(w, pkg, types[type_types[1]], flags) + write_type(writer, types[type_types[1]], flags) io.write_string(w, ") ") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Multi_Pointer: io.write_string(w, "[^]") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Matrix: io.write_string(w, "matrix[") io.write_uint(w, uint(type.elem_counts[0])) io.write_string(w, ", ") io.write_uint(w, uint(type.elem_counts[1])) io.write_string(w, "]") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) } } @@ -529,12 +657,16 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { print_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { fmt.wprintf(w, "

%s

\n", name) fmt.wprintln(w, `
`) - fmt.wprintln(w, "
    ") - for e in entities { - name := str(e.name) - fmt.wprintf(w, "
  • {0:s}
  • \n", name) + if len(entities) == 0 { + io.write_string(w, "

    This section is empty.

    \n") + } else { + fmt.wprintln(w, "
      ") + for e in entities { + name := str(e.name) + fmt.wprintf(w, "
    • {0:s}
    • \n", name) + } + fmt.wprintln(w, "
    ") } - fmt.wprintln(w, "
") fmt.wprintln(w, "
") } @@ -549,7 +681,13 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { print_entity :: proc(w: io.Writer, e: ^doc.Entity) { - pkg := &pkgs[files[e.pos.file].pkg] + pkg_index := files[e.pos.file].pkg + pkg := &pkgs[pkg_index] + writer := &Type_Writer{ + w = w, + pkg = pkg_index, + } + name := str(e.name) fmt.wprintf(w, "

{0:s}

\n", name) switch e.kind { @@ -558,10 +696,15 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { case .Constant: case .Variable: case .Type_Name: + fmt.wprint(w, "
")
+			fmt.wprintf(w, "%s :: ", name)
+			tn := base_type(types[e.type])
+			write_type(writer, tn, {.Allow_Indent})
+			fmt.wprintln(w, "
") case .Procedure: fmt.wprint(w, "
")
 			fmt.wprintf(w, "%s :: ", name)
-			write_type(w, files[e.pos.file].pkg, types[e.type], nil)
+			write_type(writer, types[e.type], nil)
 			where_clauses := array(e.where_clauses)
 			if len(where_clauses) != 0 {
 				io.write_string(w, " where ")
@@ -583,8 +726,12 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 	print_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) {
 		fmt.wprintf(w, "

%s

\n", title) fmt.wprintln(w, `
`) - for e in entities { - print_entity(w, e) + if len(entities) == 0 { + io.write_string(w, "

This section is empty.

\n") + } else { + for e in entities { + print_entity(w, e) + } } fmt.wprintln(w, "
") } From c85ac955f798fefd149a5eeaecabf0713210b152 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 19:00:47 +0000 Subject: [PATCH 0204/1258] Simplify docs to hide the copyright --- core/compress/common.odin | 3 +++ core/encoding/hxa/doc.odin | 12 ++++++------ core/fmt/doc.odin | 2 +- core/image/common.odin | 2 ++ core/image/png/png.odin | 5 +++++ core/math/big/api.odin | 6 ++---- core/math/big/common.odin | 6 ++---- core/math/big/doc.odin | 28 ++++++++++++++++++++++++++++ core/math/big/helpers.odin | 6 ++---- core/math/big/internal.odin | 28 ++-------------------------- core/math/big/logical.odin | 2 ++ core/math/big/prime.odin | 2 ++ core/math/big/private.odin | 2 ++ core/math/big/public.odin | 2 ++ core/math/big/radix.odin | 2 ++ core/math/big/tune.odin | 2 ++ 16 files changed, 65 insertions(+), 45 deletions(-) create mode 100644 core/math/big/doc.odin diff --git a/core/compress/common.odin b/core/compress/common.odin index 41f292b6f..5f5ef2413 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -5,6 +5,9 @@ List of contributors: Jeroen van Rijn: Initial implementation, optimization. */ + + +// package compress is a collection of utilities to aid with other compression packages package compress import "core:io" diff --git a/core/encoding/hxa/doc.odin b/core/encoding/hxa/doc.odin index 16b94a243..230d6ea66 100644 --- a/core/encoding/hxa/doc.odin +++ b/core/encoding/hxa/doc.odin @@ -27,7 +27,7 @@ // Construction history, or BSP trees would make the format too large to serve its purpose. // The facilities of the formats to store meta data should make the format flexible enough // for most uses. Adding HxA support should be something anyone can do in a days work. - +// // Structure: // ---------- // HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has @@ -45,17 +45,17 @@ // of a number of named layers. All layers in the stack have the same number of elements. Each layer // describes one property of the primitive. Each layer can have multiple channels and each layer can // store data of a different type. - +// // HaX stores 3 kinds of nodes // - Pixel data. // - Polygon geometry data. // - Meta data only. - +// // Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness, // Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the // layers to store things like color. The length of the layer stack is determined by the type and // dimensions stored in the - +// // Geometry data is stored in 3 separate layer stacks for: vertex data, corner data and face data. The // vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first // layer in a vertex stack has to be a 3 channel layer named "position" describing the base position @@ -63,7 +63,7 @@ // for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel // integer layer named "index" describing the vertices used to form polygons. The last value in each // polygon has a negative - 1 index to indicate the end of the polygon. - +// // Example: // A quad and a tri with the vertex index: // [0, 1, 2, 3] [1, 4, 2] @@ -72,7 +72,7 @@ // The face stack stores values per face. the length of the face stack has to match the number of // negative values in the index layer in the corner stack. The face stack can be used to store things // like material index. - +// // Storage // ------- // All data is stored in little endian byte order with no padding. The layout mirrors the structs diff --git a/core/fmt/doc.odin b/core/fmt/doc.odin index 5984da950..668fc9bc6 100644 --- a/core/fmt/doc.odin +++ b/core/fmt/doc.odin @@ -64,6 +64,7 @@ If not present, the width is whatever is necessary to represent the value. Precision is specified after the (optional) width followed by a period followed by a decimal number. If no period is present, a default precision is used. A period with no following number specifies a precision of 0. + Examples: %f default width, default precision %8f width 8, default precision @@ -84,7 +85,6 @@ Other flags: add leading 0z for dozenal (%#z) add leading 0x or 0X for hexadecimal (%#x or %#X) remove leading 0x for %p (%#p) - ' ' (space) leave a space for elided sign in numbers (% d) 0 pad with leading zeros rather than spaces diff --git a/core/image/common.odin b/core/image/common.odin index 3ec8e15be..d72b770d5 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -6,6 +6,8 @@ Jeroen van Rijn: Initial implementation, optimization. Ginger Bill: Cosmetic changes. */ + +// package image implements a general 2D image library to be used with other image related packages package image import "core:bytes" diff --git a/core/image/png/png.odin b/core/image/png/png.odin index da76a4588..bff0afde3 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -6,6 +6,11 @@ Jeroen van Rijn: Initial implementation. Ginger Bill: Cosmetic changes. */ + + +// package png implements a PNG image reader +// +// The PNG specification is at https://www.w3.org/TR/PNG/. package png import "core:compress" diff --git a/core/math/big/api.odin b/core/math/big/api.odin index c9be04da0..bf19e83b6 100644 --- a/core/math/big/api.odin +++ b/core/math/big/api.odin @@ -2,12 +2,10 @@ Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. - An arbitrary precision mathematics implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. - This file collects public proc maps and their aliases. */ + + package math_big /* diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 31ad54b14..2b34a9163 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -1,11 +1,9 @@ /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. - - An arbitrary precision mathematics implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/doc.odin b/core/math/big/doc.odin new file mode 100644 index 000000000..f5e0900f5 --- /dev/null +++ b/core/math/big/doc.odin @@ -0,0 +1,28 @@ +/* +A BigInt implementation in Odin. +For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. +The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. + +========================== Low-level routines ========================== + +IMPORTANT: `internal_*` procedures make certain assumptions about their input. + +The public functions that call them are expected to satisfy their sanity check requirements. +This allows `internal_*` call `internal_*` without paying this overhead multiple times. + +Where errors can occur, they are of course still checked and returned as appropriate. + +When importing `math:core/big` to implement an involved algorithm of your own, you are welcome +to use these procedures instead of their public counterparts. + +Most inputs and outputs are expected to be passed an initialized `Int`, for example. +Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. + +Check the comments above each `internal_*` implementation to see what constraints it expects to have met. + +We pass the custom allocator to procedures by default using the pattern `context.allocator = allocator`. +This way we don't have to add `, allocator` at the end of each call. + +TODO: Handle +/- Infinity and NaN. +*/ +package math_big diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 6d13d32bb..6c4b5dd01 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -1,11 +1,9 @@ /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. - - An arbitrary precision mathematics implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 437f6e5fc..5085898e5 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2,33 +2,9 @@ /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. - - A BigInt implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. - - ========================== Low-level routines ========================== - - IMPORTANT: `internal_*` procedures make certain assumptions about their input. - - The public functions that call them are expected to satisfy their sanity check requirements. - This allows `internal_*` call `internal_*` without paying this overhead multiple times. - - Where errors can occur, they are of course still checked and returned as appropriate. - - When importing `math:core/big` to implement an involved algorithm of your own, you are welcome - to use these procedures instead of their public counterparts. - - Most inputs and outputs are expected to be passed an initialized `Int`, for example. - Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. - - Check the comments above each `internal_*` implementation to see what constraints it expects to have met. - - We pass the custom allocator to procedures by default using the pattern `context.allocator = allocator`. - This way we don't have to add `, allocator` at the end of each call. - - TODO: Handle +/- Infinity and NaN. */ + + package math_big import "core:mem" diff --git a/core/math/big/logical.odin b/core/math/big/logical.odin index e7e55cc47..b5de4cabf 100644 --- a/core/math/big/logical.odin +++ b/core/math/big/logical.odin @@ -8,6 +8,8 @@ This file contains logical operations like `and`, `or` and `xor`. */ + + package math_big /* diff --git a/core/math/big/prime.odin b/core/math/big/prime.odin index eb0cd644c..3cce69675 100644 --- a/core/math/big/prime.odin +++ b/core/math/big/prime.odin @@ -8,6 +8,8 @@ This file contains prime finding operations. */ + + package math_big import rnd "core:math/rand" diff --git a/core/math/big/private.odin b/core/math/big/private.odin index 9989a208a..419f2103f 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -15,6 +15,8 @@ These aren't exported for the same reasons. */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/public.odin b/core/math/big/public.odin index 2673a262f..3227d7bc4 100644 --- a/core/math/big/public.odin +++ b/core/math/big/public.odin @@ -8,6 +8,8 @@ This file contains basic arithmetic operations like `add`, `sub`, `mul`, `div`, ... */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 760c49d77..2b758dc35 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -12,6 +12,8 @@ - Use Barrett reduction for non-powers-of-two. - Also look at extracting and splatting several digits at once. */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/tune.odin b/core/math/big/tune.odin index d67ff61b4..64a73b656 100644 --- a/core/math/big/tune.odin +++ b/core/math/big/tune.odin @@ -7,6 +7,8 @@ For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. */ + + package math_big import "core:time" From 8eda7567141316627973d0018bfb7e80ebdf90aa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 19:01:16 +0000 Subject: [PATCH 0205/1258] Add printing for constants, variables, types, and procedure groups --- tools/odin-html-docs/odin_html_docs_main.odin | 97 +++++++++++++++---- tools/odin-html-docs/style.css | 6 +- 2 files changed, 83 insertions(+), 20 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 3cbc0d860..d1e4f4432 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -114,27 +114,30 @@ main :: proc() { entities = array(header.entities) types = array(header.types) - fullpaths: [dynamic]string - defer delete(fullpaths) + { + fullpaths: [dynamic]string + defer delete(fullpaths) - for pkg in pkgs[1:] { - append(&fullpaths, str(pkg.fullpath)) - } - path_prefix := common_prefix(fullpaths[:]) - - pkgs_to_use = make(map[string]^doc.Pkg) - for fullpath, i in fullpaths { - path := strings.trim_prefix(fullpath, path_prefix) - if strings.has_prefix(path, "core/") { - pkgs_to_use[strings.trim_prefix(path, "core/")] = &pkgs[i+1] + for pkg in pkgs[1:] { + append(&fullpaths, str(pkg.fullpath)) + } + path_prefix := common_prefix(fullpaths[:]) + + pkgs_to_use = make(map[string]^doc.Pkg) + for fullpath, i in fullpaths { + path := strings.trim_prefix(fullpath, path_prefix) + if strings.has_prefix(path, "core/") { + pkgs_to_use[strings.trim_prefix(path, "core/")] = &pkgs[i+1] + } + } + sort.map_entries_by_key(&pkgs_to_use) + for path, pkg in pkgs_to_use { + pkg_to_path[pkg] = path } - } - sort.map_entries_by_key(&pkgs_to_use) - for path, pkg in pkgs_to_use { - pkg_to_path[pkg] = path } b := strings.make_builder() + defer strings.destroy_builder(&b) w := strings.to_writer(&b) { strings.reset_builder(&b) @@ -369,7 +372,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type if tn_pkg != pkg { fmt.wprintf(w, `%s.`, str(pkgs[pkg].name)) } - fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) + fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) case .Generic: name := str(type.name) io.write_byte(w, '$') @@ -694,12 +697,49 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { case .Invalid, .Import_Name, .Library_Name: // ignore case .Constant: + fmt.wprint(w, "
")
+			the_type := types[e.type]
+			if the_type.kind == .Basic && .Untyped in (transmute(doc.Type_Flags_Basic)the_type.flags) {
+				fmt.wprintf(w, "%s :: ", name)
+			} else {
+				fmt.wprintf(w, "%s: ", name)
+				write_type(writer, the_type, {.Allow_Indent})
+				fmt.wprintf(w, " : ")
+			}
+
+			init_string := str(e.init_string)
+			assert(init_string != "")
+			io.write_string(w, init_string)
+			fmt.wprintln(w, "
") case .Variable: + fmt.wprint(w, "
")
+			fmt.wprintf(w, "%s: ", name)
+			write_type(writer, types[e.type], {.Allow_Indent})
+			init_string := str(e.init_string)
+			if init_string != "" {
+				io.write_string(w, " = ")
+				io.write_string(w, init_string)
+			}
+			fmt.wprintln(w, "
") + case .Type_Name: fmt.wprint(w, "
")
 			fmt.wprintf(w, "%s :: ", name)
-			tn := base_type(types[e.type])
-			write_type(writer, tn, {.Allow_Indent})
+			the_type := types[e.type]
+			type_to_print := the_type
+			if the_type.kind == .Named {
+				if e.pos != entities[array(the_type.entities)[0]].pos {
+					io.write_string(w, "distinct ")
+				} else {
+					bt := base_type(the_type)
+					#partial switch bt.kind {
+					case .Struct, .Union, .Proc, .Enum:
+						io.write_string(w, "distinct ")
+						type_to_print = bt
+					}
+				}
+			}
+			write_type(writer, type_to_print, {.Allow_Indent})
 			fmt.wprintln(w, "
") case .Procedure: fmt.wprint(w, "
")
@@ -719,6 +759,25 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 			fmt.wprint(w, " {…}")
 			fmt.wprintln(w, "
") case .Proc_Group: + fmt.wprint(w, "
")
+			fmt.wprintf(w, "%s :: proc{{\n", name)
+			for entity_index in array(e.grouped_entities) {
+				this_proc := &entities[entity_index]
+				this_pkg := files[this_proc.pos.file].pkg
+				io.write_byte(w, '\t')
+				if this_pkg != pkg_index {
+					fmt.wprintf(w, "%s.", str(pkgs[this_pkg].name))
+				}
+				name := str(this_proc.name)
+				fmt.wprintf(w, ``, pkg_to_path[&pkgs[this_pkg]], name)
+				io.write_string(w, name)
+				io.write_string(w, ``)
+				io.write_byte(w, ',')
+				io.write_byte(w, '\n')
+			}
+			fmt.wprintln(w, "}")
+			fmt.wprintln(w, "
") + } write_docs(w, pkg, strings.trim_space(str(e.docs))) diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index 7c23d0bc7..1f334ad91 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -28,4 +28,8 @@ pre { text-decoration: none; font-weight: bold; color: #00bfd5; -} \ No newline at end of file +} + +pre a.code-procedure { + color: #079300; +} From 0d4642825fc0d9ad5009bb4e4cae467ee9900112 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 19:07:25 +0000 Subject: [PATCH 0206/1258] Correct package docs parsing --- src/parser.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/parser.cpp b/src/parser.cpp index 5bf43cee9..7e7146244 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5412,6 +5412,15 @@ bool parse_file(Parser *p, AstFile *f) { if (f->package_token.kind != Token_package) { return false; } + if (docs != nullptr) { + TokenPos end = token_pos_end(docs->list[docs->list.count-1]); + if (end.line == f->package_token.pos.line || end.line+1 == f->package_token.pos.line) { + // Okay + } else { + docs = nullptr; + } + } + Token package_name = expect_token_after(f, Token_Ident, "package"); if (package_name.kind == Token_Ident) { if (package_name.string == "_") { From 2ca2dbcc923a005b95459b1ad4c6f5b5600fd17c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 19:23:24 +0000 Subject: [PATCH 0207/1258] Correct `distinct` printing --- tools/odin-html-docs/odin_html_docs_main.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index d1e4f4432..90010369d 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -370,7 +370,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type fmt.wprintf(w, ``) tn_pkg := files[e.pos.file].pkg if tn_pkg != pkg { - fmt.wprintf(w, `%s.`, str(pkgs[pkg].name)) + fmt.wprintf(w, `%s.`, str(pkgs[tn_pkg].name)) } fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) case .Generic: @@ -727,16 +727,16 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { fmt.wprintf(w, "%s :: ", name) the_type := types[e.type] type_to_print := the_type - if the_type.kind == .Named { - if e.pos != entities[array(the_type.entities)[0]].pos { - io.write_string(w, "distinct ") - } else { + if the_type.kind == .Named && .Type_Alias not_in e.flags { + if e.pos == entities[array(the_type.entities)[0]].pos { bt := base_type(the_type) #partial switch bt.kind { case .Struct, .Union, .Proc, .Enum: + // Okay + case: io.write_string(w, "distinct ") - type_to_print = bt } + type_to_print = bt } } write_type(writer, type_to_print, {.Allow_Indent}) From e9ae6e20e859eb68b01f3e55ca955a2e08cf446b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 20:50:40 +0000 Subject: [PATCH 0208/1258] Fix code, source code links, and add recursive make directory --- tools/odin-html-docs/odin_html_docs_main.odin | 179 ++++++++++++++---- tools/odin-html-docs/style.css | 32 +++- 2 files changed, 174 insertions(+), 37 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 90010369d..4260bd697 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -9,6 +9,8 @@ import "core:path/slashpath" import "core:sort" import "core:slice" +GITHUB_CORE_URL :: "https://github.com/odin-lang/Odin/tree/master/core" + header: ^doc.Header files: []doc.File pkgs: []doc.Pkg @@ -64,6 +66,18 @@ common_prefix :: proc(strs: []string) -> string { return prefix } +recursive_make_directory :: proc(path: string, prefix := "") { + head, _, tail := strings.partition(path, "/") + path_to_make := head + if prefix != "" { + path_to_make = fmt.tprintf("%s/%s", prefix, head) + } + os.make_directory(path_to_make, 0) + if tail != "" { + recursive_make_directory(tail, path_to_make) + } +} + write_html_header :: proc(w: io.Writer, title: string) { fmt.wprintf(w, ` @@ -124,11 +138,21 @@ main :: proc() { path_prefix := common_prefix(fullpaths[:]) pkgs_to_use = make(map[string]^doc.Pkg) - for fullpath, i in fullpaths { + fullpath_loop: for fullpath, i in fullpaths { path := strings.trim_prefix(fullpath, path_prefix) - if strings.has_prefix(path, "core/") { - pkgs_to_use[strings.trim_prefix(path, "core/")] = &pkgs[i+1] + if !strings.has_prefix(path, "core/") { + continue fullpath_loop } + pkg := &pkgs[i+1] + if len(array(pkg.entities)) == 0 { + continue fullpath_loop + } + trimmed_path := strings.trim_prefix(path, "core/") + if strings.has_prefix(trimmed_path, "sys") { + continue fullpath_loop + } + + pkgs_to_use[trimmed_path] = pkg } sort.map_entries_by_key(&pkgs_to_use) for path, pkg in pkgs_to_use { @@ -153,7 +177,7 @@ main :: proc() { write_html_header(w, fmt.tprintf("package %s - pkg.odin-lang.org", path)) write_pkg(w, path, pkg) write_html_footer(w) - os.make_directory(fmt.tprintf("core/%s", path), 0) + recursive_make_directory(path, "core") os.write_entire_file(fmt.tprintf("core/%s/index.html", path), b.buf[:]) } } @@ -304,20 +328,37 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") } if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } - if name != "" { + init_string := str(e.init_string) + switch init_string { + case "#caller_location": + assert(name != "") io.write_string(w, name) - io.write_string(w, ": ") - } - padding := max(name_width-len(name), 0) - for _ in 0..`) + io.write_string(w, init_string) + io.write_string(w, ``) - param_flags := flags - {.Is_Results} - if .Param_Ellipsis in e.flags { - param_flags += {.Variadic} + case: + if name != "" { + io.write_string(w, name) + io.write_string(w, ": ") + } + padding := max(name_width-len(name), 0) + for _ in 0..
") + continue } text := strings.trim_space(line) if text == "" { @@ -604,8 +669,9 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { if was_code { // assert(!was_paragraph, str(pkg.name)) was_code = false - fmt.wprintln(w, "") - } else if was_paragraph { + fmt.wprintln(w, "") + } + if was_paragraph { fmt.wprintln(w, "

") } } @@ -684,6 +750,21 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { print_entity :: proc(w: io.Writer, e: ^doc.Entity) { + write_attributes :: proc(w: io.Writer, e: ^doc.Entity) { + for attr in array(e.attributes) { + io.write_string(w, "@(") + name := str(attr.name) + value := str(attr.value) + io.write_string(w, name) + if value != "" { + io.write_string(w, "=") + io.write_string(w, value) + } + io.write_string(w, ")\n") + } + } + + pkg_index := files[e.pos.file].pkg pkg := &pkgs[pkg_index] writer := &Type_Writer{ @@ -692,7 +773,15 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } name := str(e.name) - fmt.wprintf(w, "

{0:s}

\n", name) + path := pkg_to_path[pkg] + filename := slashpath.base(str(files[e.pos.file].name)) + fmt.wprintf(w, "

{0:s}", name) + fmt.wprintf(w, " ¶

\n") + defer if e.pos.file != 0 && e.pos.line > 0 { + src_url := fmt.tprintf("%s/%s/%s#L%d", GITHUB_CORE_URL, path, filename, e.pos.line) + fmt.wprintf(w, "Source: {0:s}", src_url) + } + switch e.kind { case .Invalid, .Import_Name, .Library_Name: // ignore @@ -713,6 +802,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { fmt.wprintln(w, "") case .Variable: fmt.wprint(w, "
")
+			write_attributes(w, e)
 			fmt.wprintf(w, "%s: ", name)
 			write_type(writer, types[e.type], {.Allow_Indent})
 			init_string := str(e.init_string)
@@ -804,12 +894,35 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 
 	fmt.wprintln(w, "

Source Files

") fmt.wprintln(w, "
    ") - for file_index in array(pkg.files) { + any_hidden := false + source_file_loop: for file_index in array(pkg.files) { file := files[file_index] filename := slashpath.base(str(file.name)) - fmt.wprintf(w, `
  • %s
  • `, path, filename, filename) + switch { + case + strings.has_suffix(filename, "_windows.odin"), + strings.has_suffix(filename, "_darwin.odin"), + strings.has_suffix(filename, "_essence.odin"), + strings.has_suffix(filename, "_freebsd.odin"), + strings.has_suffix(filename, "_wasi.odin"), + strings.has_suffix(filename, "_js.odin"), + strings.has_suffix(filename, "_freestanding.odin"), + + strings.has_suffix(filename, "_amd64.odin"), + strings.has_suffix(filename, "_i386.odin"), + strings.has_suffix(filename, "_arch64.odin"), + strings.has_suffix(filename, "_wasm32.odin"), + strings.has_suffix(filename, "_wasm64.odin"), + false: + any_hidden = true + continue source_file_loop + } + fmt.wprintf(w, `
  • %s
  • `, GITHUB_CORE_URL, path, filename, filename) fmt.wprintln(w) } + if any_hidden { + fmt.wprintln(w, "
  • (hidden platform specific files)
  • ") + } fmt.wprintln(w, "
") } \ No newline at end of file diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index 1f334ad91..61cab3e8c 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -1,3 +1,8 @@ +* { + font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; +} + + .container { max-width: 60em; margin: 0 auto; @@ -15,8 +20,11 @@ } pre { - white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; tab-size: 8; + font-family: Consolas,Liberation Mono,Menlo,monospace!important; background-color: #f8f8f8; color: #202224; border: 1px solid #c6c8ca; @@ -24,12 +32,28 @@ pre { padding: 0.625rem; } -.documentation pre a { +pre a { + font-family: Consolas,Liberation Mono,Menlo,monospace!important; text-decoration: none; - font-weight: bold; + /*font-weight: bold;*/ color: #00bfd5; } -pre a.code-procedure { +.documentation pre a.code-procedure { color: #079300; } + +.documentation-source { + text-decoration: none; + color: #666666; +} +.documentation-source:hover { + text-decoration: underline; +} + +a > .a-hidden { + opacity: 0; +} +a:hover > .a-hidden { + opacity: 100; +} \ No newline at end of file From cafb6e5587d4d3f5211b945bcb9d949a3980aa89 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 21:33:20 +0000 Subject: [PATCH 0209/1258] Correct `//+private` for `odin doc` --- src/checker.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/checker.cpp b/src/checker.cpp index ddb73d33e..44dc90c67 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3446,6 +3446,13 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { } } + if (entity_visibility_kind == EntityVisiblity_Public && + (c->scope->flags&ScopeFlag_File) && + c->scope->file && + (c->scope->file->flags & AstFile_IsPrivate)) { + entity_visibility_kind = EntityVisiblity_PrivateToPackage; + } + if (entity_visibility_kind != EntityVisiblity_Public && !(c->scope->flags&ScopeFlag_File)) { error(decl, "Attribute 'private' is not allowed on a non file scope entity"); } From c7a9c8274fc212ec421d46c2c58f36afdc949898 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 22:16:32 +0000 Subject: [PATCH 0210/1258] Improve type printing --- tools/odin-html-docs/odin_html_docs_main.odin | 243 +++++++++++++----- tools/odin-html-docs/style.css | 32 ++- 2 files changed, 205 insertions(+), 70 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 4260bd697..988c54d9d 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -45,6 +45,14 @@ base_type :: proc(t: doc.Type) -> doc.Type { return t } +is_type_untyped :: proc(type: doc.Type) -> bool { + if type.kind == .Basic { + flags := transmute(doc.Type_Flags_Basic)type.flags + return .Untyped in flags + } + return false +} + common_prefix :: proc(strs: []string) -> string { if len(strs) == 0 { return "" @@ -275,7 +283,9 @@ write_core_directory :: proc(w: io.Writer) { line_doc, _, _ := strings.partition(str(dir.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) if line_doc != "" { - fmt.wprintf(w, `%s`, line_doc) + io.write_string(w, ``) + write_doc_line(w, line_doc) + io.write_string(w, ``) } } fmt.wprintf(w, "\n") @@ -289,7 +299,9 @@ write_core_directory :: proc(w: io.Writer) { line_doc, _, _ := strings.partition(str(child.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) if line_doc != "" { - fmt.wprintf(w, `%s`, line_doc) + io.write_string(w, ``) + write_doc_line(w, line_doc) + io.write_string(w, ``) } fmt.wprintf(w, "\n") @@ -305,16 +317,31 @@ is_entity_blank :: proc(e: doc.Entity_Index) -> bool { return name == "" || name == "_" } +write_where_clauses :: proc(w: io.Writer, where_clauses: []doc.String) { + if len(where_clauses) != 0 { + io.write_string(w, " where ") + for clause, i in where_clauses { + if i > 0 { + io.write_string(w, ", ") + } + io.write_string(w, str(clause)) + } + } +} + + Write_Type_Flag :: enum { Is_Results, Variadic, Allow_Indent, + Poly_Names, } Write_Type_Flags :: distinct bit_set[Write_Type_Flag] Type_Writer :: struct { w: io.Writer, pkg: doc.Pkg_Index, indent: int, + generic_scope: map[string]bool, } write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type_Flags) { @@ -329,30 +356,65 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } init_string := str(e.init_string) - switch init_string { - case "#caller_location": + switch { + case init_string == "#caller_location": assert(name != "") io.write_string(w, name) io.write_string(w, " := ") io.write_string(w, ``) io.write_string(w, init_string) io.write_string(w, ``) - + case strings.has_prefix(init_string, "context."): + io.write_string(w, name) + io.write_string(w, " := ") + io.write_string(w, ``) + io.write_string(w, init_string) + io.write_string(w, ``) case: - if name != "" { - io.write_string(w, name) - io.write_string(w, ": ") - } - padding := max(name_width-len(name), 0) - for _ in 0..%s`, str(type.name)) @@ -408,17 +469,23 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type case .Named: e := entities[type_entites[0]] name := str(type.name) - fmt.wprintf(w, ``) tn_pkg := files[e.pos.file].pkg if tn_pkg != pkg { fmt.wprintf(w, `%s.`, str(pkgs[tn_pkg].name)) } - fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) + if n := strings.contains_rune(name, '('); n >= 0 { + fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name[:n]) + io.write_string(w, name[n:]) + } else { + fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) + } case .Generic: name := str(type.name) - io.write_byte(w, '$') + if name not_in generic_scope { + io.write_byte(w, '$') + } io.write_string(w, name) - if len(array(type.types)) == 1 { + if name not_in generic_scope && len(array(type.types)) == 1 { io.write_byte(w, '/') write_type(writer, types[type_types[0]], flags) } @@ -454,9 +521,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type case .Struct: type_flags := transmute(doc.Type_Flags_Struct)type.flags io.write_string(w, "struct") - if .Polymorphic in type_flags { - write_poly_params(writer, type, flags) - } + write_poly_params(writer, type, flags) if .Packed in type_flags { io.write_string(w, " #packed") } if .Raw_Union in type_flags { io.write_string(w, " #raw_union") } if custom_align := str(type.custom_align); custom_align != "" { @@ -483,9 +548,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type case .Union: type_flags := transmute(doc.Type_Flags_Union)type.flags io.write_string(w, "union") - if .Polymorphic in type_flags { - write_poly_params(writer, type, flags) - } + write_poly_params(writer, type, flags) if .No_Nil in type_flags { io.write_string(w, " #no_nil") } if .Maybe in type_flags { io.write_string(w, " #maybe") } if custom_align := str(type.custom_align); custom_align != "" { @@ -631,6 +694,25 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type } } +write_doc_line :: proc(w: io.Writer, text: string) { + text := text + for len(text) != 0 { + if strings.count(text, "`") >= 2 { + n := strings.index_byte(text, '`') + io.write_string(w, text[:n]) + io.write_string(w, "") + remaining := text[n+1:] + m := strings.index_byte(remaining, '`') + io.write_string(w, remaining[:m]) + io.write_string(w, "") + text = remaining[m+1:] + } else { + io.write_string(w, text) + return + } + } +} + write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { if docs == "" { return @@ -663,8 +745,11 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { fmt.wprintln(w, "

") } assert(!was_code) + was_paragraph = true - fmt.wprintln(w, text) + write_doc_line(w, text) + + io.write_byte(w, '\n') } if was_code { // assert(!was_paragraph, str(pkg.name)) @@ -677,6 +762,24 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { } write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { + write_breadcrumbs :: proc(w: io.Writer, path: string) { + dirs := strings.split(path, "/") + io.write_string(w, "

    \n") + for dir, i in dirs { + url := strings.join(dirs[:i+1], "/") + short_path := strings.join(dirs[1:i+1], "/") + if i == 0 || short_path in pkgs_to_use { + fmt.wprintf(w, "
  • %s
  • ", url, dir) + } else { + fmt.wprintf(w, "
  • %s
  • ", dir) + } + } + io.write_string(w, "
\n") + + } + write_breadcrumbs(w, fmt.tprintf("core/%s", path)) + + fmt.wprintf(w, "

package core:%s

\n", path) fmt.wprintln(w, "

Documentation

") docs := strings.trim_space(str(pkg.docs)) @@ -723,7 +826,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { slice.sort_by_key(pkg_vars[:], entity_key) slice.sort_by_key(pkg_consts[:], entity_key) - print_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { + write_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { fmt.wprintf(w, "

%s

\n", name) fmt.wprintln(w, `
`) if len(entities) == 0 { @@ -740,16 +843,16 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } - print_index(w, "Procedures", pkg_procs[:]) - print_index(w, "Procedure Groups", pkg_proc_groups[:]) - print_index(w, "Types", pkg_types[:]) - print_index(w, "Variables", pkg_vars[:]) - print_index(w, "Constants", pkg_consts[:]) + write_index(w, "Procedures", pkg_procs[:]) + write_index(w, "Procedure Groups", pkg_proc_groups[:]) + write_index(w, "Types", pkg_types[:]) + write_index(w, "Variables", pkg_vars[:]) + write_index(w, "Constants", pkg_consts[:]) fmt.wprintln(w, "
") - print_entity :: proc(w: io.Writer, e: ^doc.Entity) { + write_entity :: proc(w: io.Writer, e: ^doc.Entity) { write_attributes :: proc(w: io.Writer, e: ^doc.Entity) { for attr in array(e.attributes) { io.write_string(w, "@(") @@ -764,23 +867,24 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } } - pkg_index := files[e.pos.file].pkg pkg := &pkgs[pkg_index] writer := &Type_Writer{ w = w, pkg = pkg_index, } + defer delete(writer.generic_scope) name := str(e.name) path := pkg_to_path[pkg] filename := slashpath.base(str(files[e.pos.file].name)) - fmt.wprintf(w, "

{0:s}", name) - fmt.wprintf(w, " ¶

\n") - defer if e.pos.file != 0 && e.pos.line > 0 { + fmt.wprintf(w, "

{0:s}", name) + fmt.wprintf(w, " ¶") + if e.pos.file != 0 && e.pos.line > 0 { src_url := fmt.tprintf("%s/%s/%s#L%d", GITHUB_CORE_URL, path, filename, e.pos.line) - fmt.wprintf(w, "Source: {0:s}", src_url) + fmt.wprintf(w, "", src_url) } + fmt.wprintf(w, "

\n") switch e.kind { case .Invalid, .Import_Name, .Library_Name: @@ -788,7 +892,21 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { case .Constant: fmt.wprint(w, "
")
 			the_type := types[e.type]
-			if the_type.kind == .Basic && .Untyped in (transmute(doc.Type_Flags_Basic)the_type.flags) {
+
+			init_string := str(e.init_string)
+			assert(init_string != "")
+
+			ignore_type := true
+			if the_type.kind == .Basic && is_type_untyped(the_type) {
+			} else {
+				ignore_type = false
+				type_name := str(the_type.name)
+				if type_name != "" && strings.has_prefix(init_string, type_name) {
+					ignore_type = true
+				}
+			}
+
+			if ignore_type {
 				fmt.wprintf(w, "%s :: ", name)
 			} else {
 				fmt.wprintf(w, "%s: ", name)
@@ -796,8 +914,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 				fmt.wprintf(w, " : ")
 			}
 
-			init_string := str(e.init_string)
-			assert(init_string != "")
+
 			io.write_string(w, init_string)
 			fmt.wprintln(w, "
") case .Variable: @@ -835,17 +952,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { fmt.wprint(w, "
")
 			fmt.wprintf(w, "%s :: ", name)
 			write_type(writer, types[e.type], nil)
-			where_clauses := array(e.where_clauses)
-			if len(where_clauses) != 0 {
-				io.write_string(w, " where ")
-				for clause, i in where_clauses {
-					if i > 0 {
-						io.write_string(w, ", ")
-					}
-					io.write_string(w, str(clause))
-				}
-			}
-
+			write_where_clauses(w, array(e.where_clauses))
 			fmt.wprint(w, " {…}")
 			fmt.wprintln(w, "
") case .Proc_Group: @@ -872,24 +979,24 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { write_docs(w, pkg, strings.trim_space(str(e.docs))) } - print_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) { + write_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) { fmt.wprintf(w, "

%s

\n", title) fmt.wprintln(w, `
`) if len(entities) == 0 { io.write_string(w, "

This section is empty.

\n") } else { for e in entities { - print_entity(w, e) + write_entity(w, e) } } fmt.wprintln(w, "
") } - print_entities(w, "Procedures", pkg_procs[:]) - print_entities(w, "Procedure Groups", pkg_proc_groups[:]) - print_entities(w, "Types", pkg_types[:]) - print_entities(w, "Variables", pkg_vars[:]) - print_entities(w, "Constants", pkg_consts[:]) + write_entities(w, "Procedures", pkg_procs[:]) + write_entities(w, "Procedure Groups", pkg_proc_groups[:]) + write_entities(w, "Types", pkg_types[:]) + write_entities(w, "Variables", pkg_vars[:]) + write_entities(w, "Constants", pkg_consts[:]) fmt.wprintln(w, "

Source Files

") diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index 61cab3e8c..cf43a7199 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -21,7 +21,7 @@ pre { white-space: pre-wrap; - word-break: break-all; + word-break: keep-all; word-wrap: break-word; tab-size: 8; font-family: Consolas,Liberation Mono,Menlo,monospace!important; @@ -44,10 +44,15 @@ pre a { } .documentation-source { + display: inline; + float: right; +} + +.documentation-source a { text-decoration: none; color: #666666; } -.documentation-source:hover { +.documentation-source a:hover { text-decoration: underline; } @@ -56,4 +61,27 @@ a > .a-hidden { } a:hover > .a-hidden { opacity: 100; +} + +ul.documentation-breadcrumb { + list-style: none; +} + +ul.documentation-breadcrumb li { + display: inline; +} + +ul.documentation-breadcrumb li+li:before { + padding: 0.2rem; + color: black; + content: "/\00a0"; +} + +.code-inline { + font-family: Consolas,Liberation Mono,Menlo,monospace!important; + background-color: #f8f8f8; + color: #202224; + border: 1px solid #c6c8ca; + border-radius: 0.25rem; + padding: 0.125rem; } \ No newline at end of file From fb01dfe04845a489760956cea4f0019e1464b2e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 22:17:07 +0000 Subject: [PATCH 0211/1258] Improve docs_writer.cpp --- core/math/big/doc.odin | 22 ---------------------- core/math/big/internal.odin | 24 +++++++++++++++++++++++- core/math/big/tune.odin | 3 +-- src/docs_writer.cpp | 2 +- src/types.cpp | 14 +++++--------- 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/core/math/big/doc.odin b/core/math/big/doc.odin index f5e0900f5..0f9b88d01 100644 --- a/core/math/big/doc.odin +++ b/core/math/big/doc.odin @@ -2,27 +2,5 @@ A BigInt implementation in Odin. For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. - -========================== Low-level routines ========================== - -IMPORTANT: `internal_*` procedures make certain assumptions about their input. - -The public functions that call them are expected to satisfy their sanity check requirements. -This allows `internal_*` call `internal_*` without paying this overhead multiple times. - -Where errors can occur, they are of course still checked and returned as appropriate. - -When importing `math:core/big` to implement an involved algorithm of your own, you are welcome -to use these procedures instead of their public counterparts. - -Most inputs and outputs are expected to be passed an initialized `Int`, for example. -Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. - -Check the comments above each `internal_*` implementation to see what constraints it expects to have met. - -We pass the custom allocator to procedures by default using the pattern `context.allocator = allocator`. -This way we don't have to add `, allocator` at the end of each call. - -TODO: Handle +/- Infinity and NaN. */ package math_big diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 5085898e5..dbcd16509 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -1,10 +1,32 @@ -//+ignore /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. + + ========================== Low-level routines ========================== + + IMPORTANT: `internal_*` procedures make certain assumptions about their input. + + The public functions that call them are expected to satisfy their sanity check requirements. + This allows `internal_*` call `internal_*` without paying this overhead multiple times. + + Where errors can occur, they are of course still checked and returned as appropriate. + + When importing `math:core/big` to implement an involved algorithm of your own, you are welcome + to use these procedures instead of their public counterparts. + + Most inputs and outputs are expected to be passed an initialized `Int`, for example. + Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. + + Check the comments above each `internal_*` implementation to see what constraints it expects to have met. + + We pass the custom allocator to procedures by default using the pattern `context.allocator = allocator`. + This way we don't have to add `, allocator` at the end of each call. + + TODO: Handle +/- Infinity and NaN. */ +//+ignore package math_big import "core:mem" diff --git a/core/math/big/tune.odin b/core/math/big/tune.odin index 64a73b656..78a20c12b 100644 --- a/core/math/big/tune.odin +++ b/core/math/big/tune.odin @@ -1,4 +1,3 @@ -//+ignore /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. @@ -8,7 +7,7 @@ The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. */ - +//+ignore package math_big import "core:time" diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 94b43be99..762a2afe1 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -513,7 +513,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { break; case Type_Generic: doc_type.kind = OdinDocType_Generic; - doc_type.name = odin_doc_write_string(w, type->Generic.name); + doc_type.name = odin_doc_write_string(w, type->Generic.entity->token.string); if (type->Generic.specialized) { doc_type.types = odin_doc_type_as_slice(w, type->Generic.specialized); } diff --git a/src/types.cpp b/src/types.cpp index f621d4346..6162a5aa8 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3933,7 +3933,7 @@ gbString write_type_to_string(gbString str, Type *type) { str = gb_string_appendc(str, " = "); str = write_exact_value_to_string(str, var->Constant.value); } else { - str = gb_string_appendc(str, "="); + str = gb_string_appendc(str, " := "); str = write_exact_value_to_string(str, var->Constant.value); } continue; @@ -3961,14 +3961,10 @@ gbString write_type_to_string(gbString str, Type *type) { str = gb_string_appendc(str, "typeid/"); str = write_type_to_string(str, var->type); } else { - if (var->kind == Entity_TypeName) { - str = gb_string_appendc(str, "$"); - str = gb_string_append_length(str, name.text, name.len); - str = gb_string_appendc(str, "="); - str = write_type_to_string(str, var->type); - } else { - str = gb_string_appendc(str, "typeid"); - } + str = gb_string_appendc(str, "$"); + str = gb_string_append_length(str, name.text, name.len); + str = gb_string_appendc(str, "="); + str = write_type_to_string(str, var->type); } } } From 6b830f42b6a8baec77ee0c8d12333ca2ad4a296f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 23:48:46 +0000 Subject: [PATCH 0212/1258] Improve stylization with collapsible directories; Fix name padding --- tools/odin-html-docs/odin_html_docs_main.odin | 75 ++++++++++++++++--- tools/odin-html-docs/style.css | 63 ++++++++++++++-- 2 files changed, 121 insertions(+), 17 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 988c54d9d..317d95a5a 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -107,6 +107,51 @@ write_html_header :: proc(w: io.Writer, title: string) { } write_html_footer :: proc(w: io.Writer) { + io.write_string(w, ` + +`) fmt.wprintf(w, "\n\n") } @@ -255,7 +300,7 @@ write_core_directory :: proc(w: io.Writer) { fmt.wprintln(w, "

Directories

") - fmt.wprintln(w, "\t") + fmt.wprintln(w, "\t
") fmt.wprintln(w, "\t\t") for dir := root.first_child; dir != nil; dir = dir.next { @@ -264,7 +309,7 @@ write_core_directory :: proc(w: io.Writer) { for child := dir.first_child; child != nil; child = child.next { fmt.wprintf(w, "pkg-%s ", str(child.pkg.name)) } - fmt.wprint(w, `" class="directory-pkg">`) + io.write_string(w, ``) } } + io.write_string(w, ``) fmt.wprintf(w, "\n") for child := dir.first_child; child != nil; child = child.next { assert(child.pkg != nil) - fmt.wprintf(w, `") + io.write_string(w, ``) line_doc, _, _ := strings.partition(str(child.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) + io.write_string(w, ``) } + io.write_string(w, ``) + fmt.wprintf(w, "") fmt.wprintf(w, "\n") } } @@ -314,7 +360,7 @@ write_core_directory :: proc(w: io.Writer) { is_entity_blank :: proc(e: doc.Entity_Index) -> bool { name := str(entities[e].name) - return name == "" || name == "_" + return name == "" } write_where_clauses :: proc(w: io.Writer, where_clauses: []doc.String) { @@ -348,6 +394,12 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type write_param_entity :: proc(using writer: ^Type_Writer, e: ^doc.Entity, flags: Write_Type_Flags, name_width := 0) { name := str(e.name) + write_padding :: proc(w: io.Writer, name: string, name_width: int) { + for _ in 0.. Date: Wed, 19 Jan 2022 13:20:38 +0000 Subject: [PATCH 0213/1258] Improve rendering to match the main website's CSS --- tools/odin-html-docs/footer.txt.html | 43 ++++ tools/odin-html-docs/header.txt.html | 34 +++ tools/odin-html-docs/odin_html_docs_main.odin | 226 +++++++++++------- tools/odin-html-docs/style.css | 89 ++----- 4 files changed, 241 insertions(+), 151 deletions(-) create mode 100644 tools/odin-html-docs/footer.txt.html create mode 100644 tools/odin-html-docs/header.txt.html diff --git a/tools/odin-html-docs/footer.txt.html b/tools/odin-html-docs/footer.txt.html new file mode 100644 index 000000000..fbed3146a --- /dev/null +++ b/tools/odin-html-docs/footer.txt.html @@ -0,0 +1,43 @@ + + + + + + + \ No newline at end of file diff --git a/tools/odin-html-docs/header.txt.html b/tools/odin-html-docs/header.txt.html new file mode 100644 index 000000000..cfa1e0175 --- /dev/null +++ b/tools/odin-html-docs/header.txt.html @@ -0,0 +1,34 @@ + + + + + + {0:s} + + + + + + + + + + +
+ +
+
+
\ No newline at end of file diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 317d95a5a..a6b5f428e 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -88,71 +88,62 @@ recursive_make_directory :: proc(path: string, prefix := "") { write_html_header :: proc(w: io.Writer, title: string) { - fmt.wprintf(w, ` - - - - - %s - - - - - - -`, title) - fmt.wprintln(w, "\n
") - fmt.wprintln(w, "\nCore Directory") - + fmt.wprintf(w, string(#load("header.txt.html")), title) } -write_html_footer :: proc(w: io.Writer) { - io.write_string(w, ` - -`) - fmt.wprintf(w, "
\n\n") + } + doc.addEventListener('click', toggle, false); +}(this, this.document)); +`) + } + + fmt.wprintf(w, "\n\n") } main :: proc() { @@ -220,7 +211,7 @@ main :: proc() { strings.reset_builder(&b) write_html_header(w, "core library - pkg.odin-lang.org") write_core_directory(w) - write_html_footer(w) + write_html_footer(w, true) os.make_directory("core", 0) os.write_entire_file("core/index.html", b.buf[:]) } @@ -229,7 +220,7 @@ main :: proc() { strings.reset_builder(&b) write_html_header(w, fmt.tprintf("package %s - pkg.odin-lang.org", path)) write_pkg(w, path, pkg) - write_html_footer(w) + write_html_footer(w, false) recursive_make_directory(path, "core") os.write_entire_file(fmt.tprintf("core/%s/index.html", path), b.buf[:]) } @@ -297,10 +288,19 @@ write_core_directory :: proc(w: io.Writer) { } } + fmt.wprintln(w, `
`) + defer fmt.wprintln(w, `
`) + fmt.wprintln(w, `
`) + defer fmt.wprintln(w, `
`) - fmt.wprintln(w, "

Directories

") + fmt.wprintln(w, "
") + fmt.wprintln(w, "
") + fmt.wprintln(w, "

Core Library Collection

") + fmt.wprintln(w, "
") + fmt.wprintln(w, "
") - fmt.wprintln(w, "\t
") + io.write_string(w, ``) if dir.pkg != nil { line_doc, _, _ := strings.partition(str(dir.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) if line_doc != "" { - io.write_string(w, ``) write_doc_line(w, line_doc) - io.write_string(w, `
`, str(child.pkg.name)) + fmt.wprintf(w, `
`, str(child.pkg.name)) fmt.wprintf(w, `%s`, child.path, child.name) - fmt.wprintf(w, "`) if line_doc != "" { - io.write_string(w, ``) write_doc_line(w, line_doc) - io.write_string(w, `
") + fmt.wprintln(w, "
") + fmt.wprintln(w, "\t
") fmt.wprintln(w, "\t\t") for dir := root.first_child; dir != nil; dir = dir.next { @@ -356,6 +356,7 @@ write_core_directory :: proc(w: io.Writer) { fmt.wprintln(w, "\t\t") fmt.wprintln(w, "\t
") + fmt.wprintln(w, "") } is_entity_blank :: proc(e: doc.Entity_Index) -> bool { @@ -817,23 +818,42 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { } write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { - write_breadcrumbs :: proc(w: io.Writer, path: string) { - dirs := strings.split(path, "/") - io.write_string(w, "
    \n") - for dir, i in dirs { - url := strings.join(dirs[:i+1], "/") - short_path := strings.join(dirs[1:i+1], "/") - if i == 0 || short_path in pkgs_to_use { - fmt.wprintf(w, "
  • %s
  • ", url, dir) - } else { - fmt.wprintf(w, "
  • %s
  • ", dir) + + + fmt.wprintln(w, `
    `) + defer fmt.wprintln(w, `
    `) + + { // breadcrumbs + fmt.wprintln(w, `
\n") + fmt.wprintln(w, ``) + fmt.wprintln(w, ``) } - write_breadcrumbs(w, fmt.tprintf("core/%s", path)) + fmt.wprintln(w, `
`) fmt.wprintf(w, "

package core:%s

\n", path) fmt.wprintln(w, "

Documentation

") @@ -847,7 +867,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } fmt.wprintln(w, "

Index

") - fmt.wprintln(w, `
`) + fmt.wprintln(w, `
`) pkg_procs: [dynamic]^doc.Entity pkg_proc_groups: [dynamic]^doc.Entity pkg_types: [dynamic]^doc.Entity @@ -883,7 +903,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { write_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { fmt.wprintf(w, "

%s

\n", name) - fmt.wprintln(w, `
`) + fmt.wprintln(w, `
`) if len(entities) == 0 { io.write_string(w, "

This section is empty.

\n") } else { @@ -933,11 +953,11 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { name := str(e.name) path := pkg_to_path[pkg] filename := slashpath.base(str(files[e.pos.file].name)) - fmt.wprintf(w, "

{0:s}", name) + fmt.wprintf(w, "

{0:s}", name) fmt.wprintf(w, " ¶") if e.pos.file != 0 && e.pos.line > 0 { src_url := fmt.tprintf("%s/%s/%s#L%d", GITHUB_CORE_URL, path, filename, e.pos.line) - fmt.wprintf(w, "", src_url) + fmt.wprintf(w, "", src_url) } fmt.wprintf(w, "

\n") @@ -945,7 +965,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { case .Invalid, .Import_Name, .Library_Name: // ignore case .Constant: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			the_type := types[e.type]
 
 			init_string := str(e.init_string)
@@ -973,7 +993,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 			io.write_string(w, init_string)
 			fmt.wprintln(w, "
") case .Variable: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			write_attributes(w, e)
 			fmt.wprintf(w, "%s: ", name)
 			write_type(writer, types[e.type], {.Allow_Indent})
@@ -985,7 +1005,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 			fmt.wprintln(w, "
") case .Type_Name: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			fmt.wprintf(w, "%s :: ", name)
 			the_type := types[e.type]
 			type_to_print := the_type
@@ -1004,14 +1024,14 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 			write_type(writer, type_to_print, {.Allow_Indent})
 			fmt.wprintln(w, "
") case .Procedure: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			fmt.wprintf(w, "%s :: ", name)
 			write_type(writer, types[e.type], nil)
 			write_where_clauses(w, array(e.where_clauses))
 			fmt.wprint(w, " {…}")
 			fmt.wprintln(w, "
") case .Proc_Group: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			fmt.wprintf(w, "%s :: proc{{\n", name)
 			for entity_index in array(e.grouped_entities) {
 				this_proc := &entities[entity_index]
@@ -1035,7 +1055,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 		write_docs(w, pkg, strings.trim_space(str(e.docs)))
 	}
 	write_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) {
-		fmt.wprintf(w, "

%s

\n", title) + fmt.wprintf(w, "

{0:s}

\n", title) fmt.wprintln(w, `
`) if len(entities) == 0 { io.write_string(w, "

This section is empty.

\n") @@ -1054,7 +1074,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { write_entities(w, "Constants", pkg_consts[:]) - fmt.wprintln(w, "

Source Files

") + fmt.wprintln(w, `

Source Files

`) fmt.wprintln(w, "
    ") any_hidden := false source_file_loop: for file_index in array(pkg.files) { @@ -1087,4 +1107,38 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } fmt.wprintln(w, "
") + + fmt.wprintln(w, `

`) + { + write_link :: proc(w: io.Writer, id, text: string) { + fmt.wprintf(w, `
  • %s`, id, text) + } + + write_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { + fmt.wprintf(w, `
  • {0:s}`, name) + fmt.wprintln(w, `
      `) + for e in entities { + name := str(e.name) + fmt.wprintf(w, "
    • {0:s}
    • \n", name) + } + fmt.wprintln(w, "
    ") + fmt.wprintln(w, "
  • ") + } + + + fmt.wprintln(w, ``) + } + } \ No newline at end of file diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index c83a046a8..1972e99e1 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -1,26 +1,18 @@ -html { - font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; -} +/* doc directories */ -.container { - max-width: 60em; - margin: 0 auto; - padding-left: 0.01em 1em; -} - -table.documentation-directory { +table.doc-directory { /*border: 1px solid #ccc!important;*/ table-layout: fixed; border-collapse: collapse; } -.documentation-directory tr { +.doc-directory tr { padding-left: 1em!important; border-top: 1px solid #ccc!important; border-bottom: 1px solid #ccc!important; } -.documentation-directory td { +.doc-directory td { padding: 0.25em 0.5em; } .directory-child td { @@ -32,59 +24,62 @@ table.documentation-directory { left: -1.5em!important; padding-right: 0; } -.pkg-line-doc { - color: #444; -} -.documentation-directory tr[aria-controls]:hover { +.doc-directory tr[aria-controls]:hover { background-color: #eee; } -.documentation-directory tr[aria-expanded=true] td.pkg-name:before { +.doc-directory tr[aria-expanded=true] td.pkg-name:before { content: "\2193"; } -.documentation-directory tr[aria-expanded=false] td.pkg-name:before { +.doc-directory tr[aria-expanded=false] td.pkg-name:before { content: "\2192"!important; } -.documentation-directory tr[aria-hidden=true] { +.doc-directory tr[aria-hidden=true] { display: none; } -pre { + +/* doc page */ + +pre.doc-code { white-space: pre-wrap; word-break: keep-all; word-wrap: break-word; tab-size: 8; - font-family: Consolas,Liberation Mono,Menlo,monospace!important; background-color: #f8f8f8; color: #202224; border: 1px solid #c6c8ca; border-radius: 0.25rem; padding: 0.625rem; } - -pre a { +pre.doc-code a { font-family: Consolas,Liberation Mono,Menlo,monospace!important; text-decoration: none; /*font-weight: bold;*/ color: #00bfd5; } -.documentation pre a.code-procedure { +pre.doc-code a.code-procedure { color: #079300; } -.documentation-source { +.pkg-line-doc { + color: #444; +} + + +.doc-source { display: inline; float: right; } -.documentation-source a { +.doc-source a { text-decoration: none; color: #666666; } -.documentation-source a:hover { +.doc-source a:hover { text-decoration: underline; } @@ -95,42 +90,6 @@ a:hover > .a-hidden { opacity: 100; } -ul.documentation-breadcrumb { - list-style: none; -} - -ul.documentation-breadcrumb li { - display: inline; -} - -ul.documentation-breadcrumb li+li:before { - padding: 0.2rem; - color: black; - content: "/\00a0"; -} - -.code-inline { - font-family: Consolas,Liberation Mono,Menlo,monospace!important; - background-color: #f8f8f8; - color: #202224; - border: 1px solid #c6c8ca; - border-radius: 0.25rem; - padding: 0.125rem; -} - -.documentation-directory { - width: 100%; -} - -.documentation-directory tr { - /*background-color: #999;*/ -} - - -.documentation-directory tr[aria-controls] { - cursor: pointer; -} - -.documentation-directory tr.hidden { - display: none; +.documentation h4 { + font-size: calc(1.1rem + .2vw); } \ No newline at end of file From 6bdb210ad8f827c93f0a903c8cdbea73555409ec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jan 2022 13:34:54 +0000 Subject: [PATCH 0214/1258] More improvements to the styling --- tools/odin-html-docs/odin_html_docs_main.odin | 72 ++++++++++--------- tools/odin-html-docs/style.css | 3 +- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index a6b5f428e..a2d516812 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -818,56 +818,60 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { } write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { - - fmt.wprintln(w, `
    `) defer fmt.wprintln(w, `
    `) + fmt.wprintln(w, `
    `) + { // breadcrumbs - fmt.wprintln(w, ``) + if !is_curr && short_path in pkgs_to_use { + fmt.wprintf(w, `%s`, url, dir) + } else { + io.write_string(w, dir) + } + io.write_string(w, "\n") + } } - fmt.wprintln(w, `
    `) fmt.wprintf(w, "

    package core:%s

    \n", path) fmt.wprintln(w, "

    Documentation

    ") - docs := strings.trim_space(str(pkg.docs)) - if docs != "" { + overview_docs := strings.trim_space(str(pkg.docs)) + if overview_docs != "" { fmt.wprintln(w, "

    Overview

    ") fmt.wprintln(w, "
    ") defer fmt.wprintln(w, "
    ") - write_docs(w, pkg, docs) + write_docs(w, pkg, overview_docs) } - fmt.wprintln(w, "

    Index

    ") - fmt.wprintln(w, `
    `) + fmt.wprintln(w, `

    Index

    `) + fmt.wprintln(w, `
    `) + // fmt.wprintln(w, `

    Index

    `) + // fmt.wprintln(w, `
    `) pkg_procs: [dynamic]^doc.Entity pkg_proc_groups: [dynamic]^doc.Entity pkg_types: [dynamic]^doc.Entity @@ -1126,10 +1130,12 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } - fmt.wprintln(w, `
    ") + fmt.wprintln(w, "\nCore Directory") + +} + +write_html_footer :: proc(w: io.Writer) { + fmt.wprintf(w, "