This commit is contained in:
gingerBill
2024-01-17 22:41:28 +00:00
19 changed files with 280 additions and 212 deletions
+3 -1
View File
@@ -1,3 +1,5 @@
package xml
/* /*
An XML 1.0 / 1.1 parser An XML 1.0 / 1.1 parser
@@ -9,7 +11,7 @@
List of contributors: List of contributors:
Jeroen van Rijn: Initial implementation. Jeroen van Rijn: Initial implementation.
*/ */
package xml
import "core:io" import "core:io"
import "core:fmt" import "core:fmt"
+1 -1
View File
@@ -20,7 +20,7 @@ example :: proc() {
xml.destroy(docs[round]) xml.destroy(docs[round])
} }
DOC :: #load("../../../../tests/core/assets/XML/unicode.xml") DOC :: #load("../../../../tests/core/assets/XML/utf8.xml")
input := DOC input := DOC
for round in 0..<N { for round in 0..<N {
+3 -1
View File
@@ -1,3 +1,5 @@
package xml
/* /*
An XML 1.0 / 1.1 parser An XML 1.0 / 1.1 parser
@@ -6,7 +8,7 @@
This file contains helper functions. This file contains helper functions.
*/ */
package xml
// Find parent's nth child with a given ident. // Find parent's nth child with a given ident.
find_child_by_ident :: proc(doc: ^Document, parent_id: Element_ID, ident: string, nth := 0) -> (res: Element_ID, found: bool) { find_child_by_ident :: proc(doc: ^Document, parent_id: Element_ID, ident: string, nth := 0) -> (res: Element_ID, found: bool) {
+3 -1
View File
@@ -1,3 +1,5 @@
package xml
/* /*
An XML 1.0 / 1.1 parser An XML 1.0 / 1.1 parser
@@ -9,7 +11,7 @@
List of contributors: List of contributors:
Jeroen van Rijn: Initial implementation. Jeroen van Rijn: Initial implementation.
*/ */
package xml
import "core:fmt" import "core:fmt"
import "core:unicode" import "core:unicode"
+54 -131
View File
@@ -1,10 +1,10 @@
/* /*
An XML 1.0 / 1.1 parser XML 1.0 / 1.1 parser
Copyright 2021-2022 Jeroen van Rijn <nom@duclavier.com>. 2021-2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license. 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). from-scratch XML implementation, loosely modelled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816).
Features: Features:
- Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage. - Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage.
@@ -22,7 +22,7 @@
- Serialize/deserialize Odin types? - Serialize/deserialize Odin types?
List of contributors: List of contributors:
Jeroen van Rijn: Initial implementation. - Jeroen van Rijn: Initial implementation.
*/ */
package xml package xml
// An XML 1.0 / 1.1 parser // An XML 1.0 / 1.1 parser
@@ -43,48 +43,32 @@ DEFAULT_OPTIONS :: Options{
} }
Option_Flag :: enum { Option_Flag :: enum {
/* // If the caller says that input may be modified, we can perform in-situ parsing.
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.
If this flag isn't provided, the XML parser first duplicates the input so that it can.
*/
Input_May_Be_Modified, Input_May_Be_Modified,
/* // Document MUST start with `<?xml` prologue.
Document MUST start with `<?xml` prologue.
*/
Must_Have_Prolog, Must_Have_Prolog,
/* // Document MUST have a `<!DOCTYPE`.
Document MUST have a `<!DOCTYPE`.
*/
Must_Have_DocType, Must_Have_DocType,
/* // By default we skip comments. Use this option to intern a comment on a parented Element.
By default we skip comments. Use this option to intern a comment on a parented Element.
*/
Intern_Comments, Intern_Comments,
/* // How to handle unsupported parts of the specification, like <! other than <!DOCTYPE and <![CDATA[
How to handle unsupported parts of the specification, like <! other than <!DOCTYPE and <![CDATA[
*/
Error_on_Unsupported, Error_on_Unsupported,
Ignore_Unsupported, Ignore_Unsupported,
/* // By default CDATA tags are passed-through as-is.
By default CDATA tags are passed-through as-is. // This option unwraps them when encountered.
This option unwraps them when encountered.
*/
Unbox_CDATA, Unbox_CDATA,
/* // By default SGML entities like `&gt;`, `&#32;` and `&#x20;` are passed-through as-is.
By default SGML entities like `&gt;`, `&#32;` and `&#x20;` are passed-through as-is. // This option decodes them when encountered.
This option decodes them when encountered.
*/
Decode_SGML_Entities, Decode_SGML_Entities,
/* // If a tag body has a comment, it will be stripped unless this option is given.
If a tag body has a comment, it will be stripped unless this option is given.
*/
Keep_Tag_Body_Comments, Keep_Tag_Body_Comments,
} }
Option_Flags :: bit_set[Option_Flag; u16] Option_Flags :: bit_set[Option_Flag; u16]
@@ -97,28 +81,20 @@ Document :: struct {
encoding: Encoding, encoding: Encoding,
doctype: struct { doctype: struct {
/* // We only scan the <!DOCTYPE IDENT part and skip the rest.
We only scan the <!DOCTYPE IDENT part and skip the rest.
*/
ident: string, ident: string,
rest: string, rest: string,
}, },
/* // If we encounter comments before the root node, and the option to intern comments is given, this is where they'll live.
If we encounter comments before the root node, and the option to intern comments is given, this is where they'll live. // Otherwise they'll be in the element tree.
Otherwise they'll be in the element tree.
*/
comments: [dynamic]string, comments: [dynamic]string,
/* // Internal
Internal
*/
tokenizer: ^Tokenizer, tokenizer: ^Tokenizer,
allocator: mem.Allocator, allocator: mem.Allocator,
/* // Input. Either the original buffer, or a copy if `.Input_May_Be_Modified` isn't specified.
Input. Either the original buffer, or a copy if `.Input_May_Be_Modified` isn't specified.
*/
input: []u8, input: []u8,
strings_to_free: [dynamic]string, strings_to_free: [dynamic]string,
} }
@@ -158,34 +134,24 @@ Encoding :: enum {
UTF_8, UTF_8,
ISO_8859_1, ISO_8859_1,
/* // Aliases
Aliases
*/
LATIN_1 = ISO_8859_1, LATIN_1 = ISO_8859_1,
} }
Error :: enum { Error :: enum {
/* // General return values.
General return values.
*/
None = 0, None = 0,
General_Error, General_Error,
Unexpected_Token, Unexpected_Token,
Invalid_Token, Invalid_Token,
/* // Couldn't find, open or read file.
Couldn't find, open or read file.
*/
File_Error, File_Error,
/* // File too short.
File too short.
*/
Premature_EOF, Premature_EOF,
/* // XML-specific errors.
XML-specific errors.
*/
No_Prolog, No_Prolog,
Invalid_Prolog, Invalid_Prolog,
Too_Many_Prologs, Too_Many_Prologs,
@@ -194,11 +160,9 @@ Error :: enum {
Too_Many_DocTypes, Too_Many_DocTypes,
DocType_Must_Preceed_Elements, DocType_Must_Preceed_Elements,
/* // If a DOCTYPE is present _or_ the caller
If a DOCTYPE is present _or_ the caller // asked for a specific DOCTYPE and the DOCTYPE
asked for a specific DOCTYPE and the DOCTYPE // and root tag don't match, we return `.Invalid_DocType`.
and root tag don't match, we return `.Invalid_DocType`.
*/
Invalid_DocType, Invalid_DocType,
Invalid_Tag_Value, Invalid_Tag_Value,
@@ -211,27 +175,20 @@ Error :: enum {
Unsupported_Version, Unsupported_Version,
Unsupported_Encoding, Unsupported_Encoding,
/* // <!FOO are usually skipped.
<!FOO are usually skipped.
*/
Unhandled_Bang, Unhandled_Bang,
Duplicate_Attribute, Duplicate_Attribute,
Conflicting_Options, Conflicting_Options,
} }
/*
Implementation starts here.
*/
parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) { parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) {
data := data data := data
context.allocator = allocator context.allocator = allocator
opts := validate_options(options) or_return 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` is not specified, we duplicate the input so that we can modify it in-place.
*/
if .Input_May_Be_Modified not_in opts.flags { if .Input_May_Be_Modified not_in opts.flags {
data = bytes.clone(data) data = bytes.clone(data)
} }
@@ -252,10 +209,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
element, parent: Element_ID element, parent: Element_ID
open: Token open: Token
/* // If a DOCTYPE is present, the root tag has to match.
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.
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 expected_doctype := options.expected_doctype
loop: for { loop: for {
@@ -263,17 +218,13 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
// NOTE(Jeroen): This is faster as a switch. // NOTE(Jeroen): This is faster as a switch.
switch t.ch { switch t.ch {
case '<': case '<':
/* // Consume peeked `<`
Consume peeked `<`
*/
advance_rune(t) advance_rune(t)
open = scan(t) open = scan(t)
// NOTE(Jeroen): We're not using a switch because this if-else chain ordered by likelihood is 2.5% faster at -o:size and -o:speed. // NOTE(Jeroen): We're not using a switch because this if-else chain ordered by likelihood is 2.5% faster at -o:size and -o:speed.
if likely(open.kind, Token_Kind.Ident) == .Ident { if likely(open.kind, Token_Kind.Ident) == .Ident {
/* // e.g. <odin - Start of new element.
e.g. <odin - Start of new element.
*/
element = new_element(doc) element = new_element(doc)
if element == 0 { // First Element if element == 0 { // First Element
parent = element parent = element
@@ -286,11 +237,9 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
parse_attributes(doc, &doc.elements[element].attribs) or_return parse_attributes(doc, &doc.elements[element].attribs) or_return
/* // If a DOCTYPE is present _or_ the caller
If a DOCTYPE is present _or_ the caller // asked for a specific DOCTYPE and the DOCTYPE
asked for a specific DOCTYPE and the DOCTYPE // and root tag don't match, we return .Invalid_Root_Tag.
and root tag don't match, we return .Invalid_Root_Tag.
*/
if element == 0 { // Root tag? if element == 0 { // Root tag?
if len(expected_doctype) > 0 && expected_doctype != open.text { if len(expected_doctype) > 0 && expected_doctype != open.text {
error(t, t.offset, "Root Tag doesn't match DOCTYPE. Expected: %v, got: %v\n", expected_doctype, open.text) error(t, t.offset, "Root Tag doesn't match DOCTYPE. Expected: %v, got: %v\n", expected_doctype, open.text)
@@ -298,23 +247,17 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
} }
} }
/* // One of these should follow:
One of these should follow: // - `>`, which means we've just opened this tag and expect a later element to close it.
- `>`, 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.
- `/>`, which means this is an 'empty' or self-closing tag.
*/
end_token := scan(t) end_token := scan(t)
#partial switch end_token.kind { #partial switch end_token.kind {
case .Gt: case .Gt:
/* // We're now the new parent.
We're now the new parent.
*/
parent = element parent = element
case .Slash: case .Slash:
/* // Empty tag. Close it.
Empty tag. Close it.
*/
expect(t, .Gt) or_return expect(t, .Gt) or_return
parent = doc.elements[element].parent parent = doc.elements[element].parent
element = parent element = parent
@@ -325,9 +268,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
} }
} else if open.kind == .Slash { } else if open.kind == .Slash {
/* // Close tag.
Close tag.
*/
ident := expect(t, .Ident) or_return ident := expect(t, .Ident) or_return
_ = expect(t, .Gt) or_return _ = expect(t, .Gt) or_return
@@ -339,9 +280,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
element = parent element = parent
} else if open.kind == .Exclaim { } else if open.kind == .Exclaim {
/* // <!
<!
*/
next := scan(t) next := scan(t)
#partial switch next.kind { #partial switch next.kind {
case .Ident: case .Ident:
@@ -370,10 +309,8 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
} }
case .Dash: case .Dash:
/* // Comment: <!-- -->.
Comment: <!-- -->. // The grammar does not allow a comment to end in --->
The grammar does not allow a comment to end in --->
*/
expect(t, .Dash) expect(t, .Dash)
comment := scan_comment(t) or_return comment := scan_comment(t) or_return
@@ -395,23 +332,17 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
} }
} else if open.kind == .Question { } else if open.kind == .Question {
/* // <?xml
<?xml
*/
next := scan(t) next := scan(t)
#partial switch next.kind { #partial switch next.kind {
case .Ident: case .Ident:
if len(next.text) == 3 && strings.equal_fold(next.text, "xml") { if len(next.text) == 3 && strings.equal_fold(next.text, "xml") {
parse_prologue(doc) or_return parse_prologue(doc) or_return
} else if len(doc.prologue) > 0 { } else if len(doc.prologue) > 0 {
/* // We've already seen a prologue.
We've already seen a prologue.
*/
return doc, .Too_Many_Prologs return doc, .Too_Many_Prologs
} else { } else {
/* // Could be `<?xml-stylesheet`, etc. Ignore it.
Could be `<?xml-stylesheet`, etc. Ignore it.
*/
skip_element(t) or_return skip_element(t) or_return
} }
case: case:
@@ -425,15 +356,11 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
} }
case -1: case -1:
/* // End of file.
End of file.
*/
break loop break loop
case: case:
/* // This should be a tag's body text.
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 := .Unbox_CDATA in opts.flags
needs_processing |= .Decode_SGML_Entities in opts.flags needs_processing |= .Decode_SGML_Entities in opts.flags
@@ -613,9 +540,7 @@ parse_prologue :: proc(doc: ^Document) -> (err: Error) {
doc.encoding = .LATIN_1 doc.encoding = .LATIN_1
case: case:
/* // Unrecognized encoding, assume UTF-8.
Unrecognized encoding, assume UTF-8.
*/
error(t, offset, "[parse_prologue] Warning: Unrecognized encoding: %v\n", attr.val) error(t, offset, "[parse_prologue] Warning: Unrecognized encoding: %v\n", attr.val)
} }
@@ -675,9 +600,7 @@ parse_doctype :: proc(doc: ^Document) -> (err: Error) {
offset := t.offset offset := t.offset
skip_element(t) or_return 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.
-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 = string(t.src[offset : t.offset - 1]) doc.doctype.rest = string(t.src[offset : t.offset - 1])
return .None return .None
} }
+9
View File
@@ -96,6 +96,15 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
str := fmt.bprintf(buf[:], format, la.prefix, padding, old_memory, old_size, size, alignment) str := fmt.bprintf(buf[:], format, la.prefix, padding, old_memory, old_size, size, alignment)
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location) context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
case .Resize_Non_Zeroed:
format: string
switch la.size_fmt {
case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Resize_Non_Zeroed, ptr=%p, old_size=%d, size=%d, alignment=%d)"
case .Human: format = "%s%s>>> ALLOCATOR(mode=.Resize_Non_Zeroed, ptr=%p, old_size=%m, size=%m, alignment=%d)"
}
str := fmt.bprintf(buf[:], format, la.prefix, padding, old_memory, old_size, size, alignment)
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
case .Query_Features: case .Query_Features:
str := fmt.bprintf(buf[:], "%s%sALLOCATOR(mode=.Query_Features)", la.prefix, padding) str := fmt.bprintf(buf[:], "%s%sALLOCATOR(mode=.Query_Features)", la.prefix, padding)
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location) context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
+6 -4
View File
@@ -88,17 +88,19 @@ div_sat :: proc(x, y: $T/Fixed($Backing, $Fraction_Width)) -> (z: T) {
@(require_results) @(require_results)
floor :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing { floor :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
if x.i >= 0 {
return x.i >> Fraction_Width return x.i >> Fraction_Width
} else {
return (x.i - (1 << (Fraction_Width - 1)) + (1 << (Fraction_Width - 2))) >> Fraction_Width
}
} }
@(require_results) @(require_results)
ceil :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing { ceil :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
Integer :: 8*size_of(Backing) - Fraction_Width return (x.i + (1 << Fraction_Width - 1)) >> Fraction_Width
return (x.i + (1 << Integer-1)) >> Fraction_Width
} }
@(require_results) @(require_results)
round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing { round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
Integer :: 8*size_of(Backing) - Fraction_Width return (x.i + (1 << (Fraction_Width - 1))) >> Fraction_Width
return (x.i + (1 << (Integer - 1))) >> Fraction_Width
} }
+23 -1
View File
@@ -11,6 +11,8 @@ Allocator_Mode :: enum byte {
Free_All, Free_All,
Resize, Resize,
Query_Features, Query_Features,
Alloc_Non_Zeroed,
Resize_Non_Zeroed,
} }
*/ */
@@ -243,12 +245,26 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
res = raw_data(data) res = raw_data(data)
return return
} }
@(require_results)
default_resize_bytes_align_non_zeroed :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
return _default_resize_bytes_align(old_data, new_size, alignment, false, allocator, loc)
}
@(require_results) @(require_results)
default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
return _default_resize_bytes_align(old_data, new_size, alignment, true, allocator, loc)
}
@(require_results)
_default_resize_bytes_align :: #force_inline proc(old_data: []byte, new_size, alignment: int, should_zero: bool, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
old_memory := raw_data(old_data) old_memory := raw_data(old_data)
old_size := len(old_data) old_size := len(old_data)
if old_memory == nil { if old_memory == nil {
if should_zero {
return alloc_bytes(new_size, alignment, allocator, loc) return alloc_bytes(new_size, alignment, allocator, loc)
} else {
return alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
}
} }
if new_size == 0 { if new_size == 0 {
@@ -260,7 +276,13 @@ default_resize_bytes_align :: proc(old_data: []byte, new_size, alignment: int, a
return old_data, .None return old_data, .None
} }
new_memory, err := alloc_bytes(new_size, alignment, allocator, loc) new_memory : []byte
err : Allocator_Error
if should_zero {
new_memory, err = alloc_bytes(new_size, alignment, allocator, loc)
} else {
new_memory, err = alloc_bytes_non_zeroed(new_size, alignment, allocator, loc)
}
if new_memory == nil || err != nil { if new_memory == nil || err != nil {
return nil, err return nil, err
} }
+21 -14
View File
@@ -88,10 +88,13 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case .Resize: case .Resize:
return default_resize_bytes_align(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena)) return default_resize_bytes_align(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena))
case .Resize_Non_Zeroed:
return default_resize_bytes_align_non_zeroed(byte_slice(old_memory, old_size), size, alignment, arena_allocator(arena))
case .Query_Features: case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory) set := (^Allocator_Mode_Set)(old_memory)
if set != nil { if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Query_Features} set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features}
} }
return nil, nil return nil, nil
@@ -259,7 +262,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
} }
clear(&s.leaked_allocations) clear(&s.leaked_allocations)
case .Resize: case .Resize, .Resize_Non_Zeroed:
begin := uintptr(raw_data(s.data)) begin := uintptr(raw_data(s.data))
end := begin + uintptr(len(s.data)) end := begin + uintptr(len(s.data))
old_ptr := uintptr(old_memory) old_ptr := uintptr(old_memory)
@@ -278,7 +281,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case .Query_Features: case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory) set := (^Allocator_Mode_Set)(old_memory)
if set != nil { if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features} set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features}
} }
return nil, nil return nil, nil
@@ -406,9 +409,9 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
s.prev_offset = 0 s.prev_offset = 0
s.curr_offset = 0 s.curr_offset = 0
case .Resize: case .Resize, .Resize_Non_Zeroed:
if old_memory == nil { if old_memory == nil {
return raw_alloc(s, size, alignment, true) return raw_alloc(s, size, alignment, mode == .Resize)
} }
if size == 0 { if size == 0 {
return nil, nil return nil, nil
@@ -434,7 +437,7 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data))) old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data)))
if old_offset != header.prev_offset { if old_offset != header.prev_offset {
data, err := raw_alloc(s, size, alignment, true) data, err := raw_alloc(s, size, alignment, mode == .Resize)
if err == nil { if err == nil {
runtime.copy(data, byte_slice(old_memory, old_size)) runtime.copy(data, byte_slice(old_memory, old_size))
} }
@@ -455,7 +458,7 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case .Query_Features: case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory) set := (^Allocator_Mode_Set)(old_memory)
if set != nil { if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features} set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features}
} }
return nil, nil return nil, nil
case .Query_Info: case .Query_Info:
@@ -565,9 +568,9 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case .Free_All: case .Free_All:
s.offset = 0 s.offset = 0
case .Resize: case .Resize, .Resize_Non_Zeroed:
if old_memory == nil { if old_memory == nil {
return raw_alloc(s, size, align, true) return raw_alloc(s, size, align, mode == .Resize)
} }
if size == 0 { if size == 0 {
return nil, nil return nil, nil
@@ -590,7 +593,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return byte_slice(old_memory, size), nil return byte_slice(old_memory, size), nil
} }
data, err := raw_alloc(s, size, align, true) data, err := raw_alloc(s, size, align, mode == .Resize)
if err == nil { if err == nil {
runtime.copy(data, byte_slice(old_memory, old_size)) runtime.copy(data, byte_slice(old_memory, old_size))
} }
@@ -599,7 +602,7 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
case .Query_Features: case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory) set := (^Allocator_Mode_Set)(old_memory)
if set != nil { if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Query_Features} set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features}
} }
return nil, nil return nil, nil
@@ -649,7 +652,7 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode
case .Free_All: case .Free_All:
dynamic_pool_free_all(pool) dynamic_pool_free_all(pool)
return nil, nil return nil, nil
case .Resize: case .Resize, .Resize_Non_Zeroed:
if old_size >= size { if old_size >= size {
return byte_slice(old_memory, size), nil return byte_slice(old_memory, size), nil
} }
@@ -662,7 +665,7 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode
case .Query_Features: case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory) set := (^Allocator_Mode_Set)(old_memory)
if set != nil { if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Query_Features, .Query_Info} set^ = {.Alloc, .Alloc_Non_Zeroed, .Free_All, .Resize, .Resize_Non_Zeroed, .Query_Features, .Query_Info}
} }
return nil, nil return nil, nil
@@ -826,6 +829,10 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
if size > 0 { if size > 0 {
panic("mem: panic allocator, .Resize called", loc=loc) panic("mem: panic allocator, .Resize called", loc=loc)
} }
case .Resize_Non_Zeroed:
if size > 0 {
panic("mem: panic allocator, .Resize_Non_Zeroed called", loc=loc)
}
case .Free: case .Free:
if old_memory != nil { if old_memory != nil {
panic("mem: panic allocator, .Free called", loc=loc) panic("mem: panic allocator, .Free called", loc=loc)
@@ -958,7 +965,7 @@ tracking_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
if data.clear_on_free_all { if data.clear_on_free_all {
clear_map(&data.allocation_map) clear_map(&data.allocation_map)
} }
case .Resize: case .Resize, .Resize_Non_Zeroed:
if old_memory != result_ptr { if old_memory != result_ptr {
delete_key(&data.allocation_map, old_memory) delete_key(&data.allocation_map, old_memory)
} }
+1 -1
View File
@@ -288,7 +288,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
err = .Mode_Not_Implemented err = .Mode_Not_Implemented
case .Free_All: case .Free_All:
arena_free_all(arena, location) arena_free_all(arena, location)
case .Resize: case .Resize, .Resize_Non_Zeroed:
old_data := ([^]byte)(old_memory) old_data := ([^]byte)(old_memory)
switch { switch {
+7 -7
View File
@@ -210,15 +210,15 @@ 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) -> (new_memory: []byte, err: mem.Allocator_Error) { aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int, zero_memory := true) -> (new_memory: []byte, err: mem.Allocator_Error) {
if p == nil { if p == nil {
return nil, nil return nil, nil
} }
new_memory = aligned_alloc(new_size, new_alignment, p) or_return new_memory = aligned_alloc(new_size, new_alignment, p, zero_memory) or_return
// NOTE: heap_resize does not zero the new memory, so we do it // NOTE: heap_resize does not zero the new memory, so we do it
if new_size > old_size { if zero_memory && new_size > old_size {
new_region := mem.raw_data(new_memory[old_size:]) new_region := mem.raw_data(new_memory[old_size:])
mem.zero(new_region, new_size - old_size) mem.zero(new_region, new_size - old_size)
} }
@@ -235,16 +235,16 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
case .Free_All: case .Free_All:
return nil, .Mode_Not_Implemented return nil, .Mode_Not_Implemented
case .Resize: case .Resize, .Resize_Non_Zeroed:
if old_memory == nil { if old_memory == nil {
return aligned_alloc(size, alignment) return aligned_alloc(size, alignment, nil, mode == .Resize)
} }
return aligned_resize(old_memory, old_size, size, alignment) return aligned_resize(old_memory, old_size, size, alignment, mode == .Resize)
case .Query_Features: case .Query_Features:
set := (^mem.Allocator_Mode_Set)(old_memory) set := (^mem.Allocator_Mode_Set)(old_memory)
if set != nil { if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Resize, .Query_Features} set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Resize, .Resize_Non_Zeroed, .Query_Features}
} }
return nil, nil return nil, nil
+1
View File
@@ -307,6 +307,7 @@ Allocator_Mode :: enum byte {
Query_Features, Query_Features,
Query_Info, Query_Info,
Alloc_Non_Zeroed, Alloc_Non_Zeroed,
Resize_Non_Zeroed,
} }
Allocator_Mode_Set :: distinct bit_set[Allocator_Mode] Allocator_Mode_Set :: distinct bit_set[Allocator_Mode]
+90 -15
View File
@@ -169,10 +169,16 @@ clear :: proc{clear_dynamic_array, clear_map}
@builtin @builtin
reserve :: proc{reserve_dynamic_array, reserve_map} reserve :: proc{reserve_dynamic_array, reserve_map}
@builtin
non_zero_reserve :: proc{non_zero_reserve_dynamic_array}
// `resize` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`). // `resize` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
@builtin @builtin
resize :: proc{resize_dynamic_array} resize :: proc{resize_dynamic_array}
@builtin
non_zero_resize :: proc{non_zero_resize_dynamic_array}
// Shrinks the capacity of a dynamic array or map down to the current length, or the given capacity. // Shrinks the capacity of a dynamic array or map down to the current length, or the given capacity.
@builtin @builtin
shrink :: proc{shrink_dynamic_array, shrink_map} shrink :: proc{shrink_dynamic_array, shrink_map}
@@ -406,10 +412,7 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
return return
} }
_append_elem :: #force_inline proc(array: ^$T/[dynamic]$E, arg: E, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
@builtin
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return 0, nil return 0, nil
} }
@@ -420,7 +423,13 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) ->
} else { } else {
if cap(array) < len(array)+1 { if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1) cap := 2 * cap(array) + max(8, 1)
err = reserve(array, cap, loc) // do not 'or_return' here as it could be a partial success
// do not 'or_return' here as it could be a partial success
if should_zero {
err = reserve(array, cap, loc)
} else {
err = non_zero_reserve(array, cap, loc)
}
} }
if cap(array)-len(array) > 0 { if cap(array)-len(array) > 0 {
a := (^Raw_Dynamic_Array)(array) a := (^Raw_Dynamic_Array)(array)
@@ -437,7 +446,16 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) ->
} }
@builtin @builtin
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elem(array, arg, true, loc=loc)
}
@builtin
non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elem(array, arg, false, loc=loc)
}
_append_elems :: #force_inline proc(array: ^$T/[dynamic]$E, should_zero: bool, loc := #caller_location, args: ..E) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil { if array == nil {
return 0, nil return 0, nil
} }
@@ -454,7 +472,13 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
} else { } else {
if cap(array) < len(array)+arg_len { if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len) cap := 2 * cap(array) + max(8, arg_len)
err = reserve(array, cap, loc) // do not 'or_return' here as it could be a partial success
// do not 'or_return' here as it could be a partial success
if should_zero {
err = reserve(array, cap, loc)
} else {
err = non_zero_reserve(array, cap, loc)
}
} }
arg_len = min(cap(array)-len(array), arg_len) arg_len = min(cap(array)-len(array), arg_len)
if arg_len > 0 { if arg_len > 0 {
@@ -470,11 +494,33 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
} }
} }
@builtin
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elems(array, true, loc, ..args)
}
@builtin
non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elems(array, false, loc, ..args)
}
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type // The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
args := transmute([]E)arg
if should_zero {
return append_elems(array, ..args, loc=loc)
} else {
return non_zero_append_elems(array, ..args, loc=loc)
}
}
@builtin @builtin
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
args := transmute([]E)arg return _append_elem_string(array, arg, true, loc)
return append_elems(array, ..args, loc=loc) }
@builtin
non_zero_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elem_string(array, arg, false, loc)
} }
@@ -494,6 +540,7 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
// The append built-in procedure appends elements to the end of a dynamic array // The append built-in procedure appends elements to the end of a dynamic array
@builtin append :: proc{append_elem, append_elems, append_elem_string} @builtin append :: proc{append_elem, append_elems, append_elem_string}
@builtin non_zero_append :: proc{non_zero_append_elem, non_zero_append_elems, non_zero_append_elem_string}
@builtin @builtin
@@ -638,8 +685,7 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
// `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`). // `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
// //
// Note: Prefer the procedure group `reserve`. // Note: Prefer the procedure group `reserve`.
@builtin _reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
if array == nil { if array == nil {
return nil return nil
} }
@@ -658,7 +704,12 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
new_size := capacity * size_of(E) new_size := capacity * size_of(E)
allocator := a.allocator allocator := a.allocator
new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return new_data: []byte
if should_zero {
new_data = mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
} else {
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
}
if new_data == nil && new_size > 0 { if new_data == nil && new_size > 0 {
return .Out_Of_Memory return .Out_Of_Memory
} }
@@ -668,11 +719,20 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
return nil return nil
} }
@builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_dynamic_array(array, capacity, true, loc)
}
@builtin
non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_dynamic_array(array, capacity, false, loc)
}
// `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`). // `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
// //
// Note: Prefer the procedure group `resize` // Note: Prefer the procedure group `resize`
@builtin _resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
if array == nil { if array == nil {
return nil return nil
} }
@@ -692,7 +752,12 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
new_size := length * size_of(E) new_size := length * size_of(E)
allocator := a.allocator allocator := a.allocator
new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return new_data : []byte
if should_zero {
new_data = mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
} else {
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
}
if new_data == nil && new_size > 0 { if new_data == nil && new_size > 0 {
return .Out_Of_Memory return .Out_Of_Memory
} }
@@ -703,6 +768,16 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
return nil return nil
} }
@builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
return _resize_dynamic_array(array, length, true, loc=loc)
}
@builtin
non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
return _resize_dynamic_array(array, length, false, loc=loc)
}
/* /*
Shrinks the capacity of a dynamic array down to the current length, or the given capacity. Shrinks the capacity of a dynamic array down to the current length, or the given capacity.
+1 -1
View File
@@ -195,7 +195,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
err = .Mode_Not_Implemented err = .Mode_Not_Implemented
case .Free_All: case .Free_All:
arena_free_all(arena, location) arena_free_all(arena, location)
case .Resize: case .Resize, .Resize_Non_Zeroed:
old_data := ([^]byte)(old_memory) old_data := ([^]byte)(old_memory)
switch { switch {
+5 -1
View File
@@ -10,7 +10,7 @@ nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, .None return nil, .None
case .Free_All: case .Free_All:
return nil, .Mode_Not_Implemented return nil, .Mode_Not_Implemented
case .Resize: case .Resize, .Resize_Non_Zeroed:
if size == 0 { if size == 0 {
return nil, .None return nil, .None
} }
@@ -55,6 +55,10 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
if size > 0 { if size > 0 {
panic("panic allocator, .Resize called", loc=loc) panic("panic allocator, .Resize called", loc=loc)
} }
case .Resize_Non_Zeroed:
if size > 0 {
panic("panic allocator, .Alloc_Non_Zeroed called", loc=loc)
}
case .Free: case .Free:
if old_memory != nil { if old_memory != nil {
panic("panic allocator, .Free called", loc=loc) panic("panic allocator, .Free called", loc=loc)
+1 -1
View File
@@ -19,7 +19,7 @@ when ODIN_DEFAULT_TO_NIL_ALLOCATOR {
case .Free_All: case .Free_All:
return nil, .Mode_Not_Implemented return nil, .Mode_Not_Implemented
case .Resize: case .Resize, .Resize_Non_Zeroed:
data, err = _windows_default_resize(old_memory, old_size, size, alignment) data, err = _windows_default_resize(old_memory, old_size, size, alignment)
case .Query_Features: case .Query_Features:
+20 -1
View File
@@ -187,7 +187,7 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle
return return
} }
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { _mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
if allocator.procedure == nil { if allocator.procedure == nil {
return nil, nil return nil, nil
} }
@@ -198,15 +198,27 @@ mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAUL
} }
return return
} else if ptr == nil { } else if ptr == nil {
if should_zero {
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
} else {
return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, new_size, alignment, nil, 0, loc)
}
} else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 { } else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 {
data = ([^]byte)(ptr)[:old_size] data = ([^]byte)(ptr)[:old_size]
return return
} }
if should_zero {
data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc) data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
} else {
data, err = allocator.procedure(allocator.data, .Resize_Non_Zeroed, new_size, alignment, ptr, old_size, loc)
}
if err == .Mode_Not_Implemented { if err == .Mode_Not_Implemented {
if should_zero {
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
} else {
data, err = allocator.procedure(allocator.data, .Alloc_Non_Zeroed, new_size, alignment, nil, 0, loc)
}
if err != nil { if err != nil {
return return
} }
@@ -216,6 +228,13 @@ mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAUL
return return
} }
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
return _mem_resize(ptr, old_size, new_size, alignment, allocator, true, loc)
}
non_zero_mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
return _mem_resize(ptr, old_size, new_size, alignment, allocator, false, loc)
}
memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
switch { switch {
case n == 0: return true case n == 0: return true
+1 -1
View File
@@ -511,7 +511,7 @@ cmark_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mod
case .Free_All: case .Free_All:
return nil, .Mode_Not_Implemented return nil, .Mode_Not_Implemented
case .Resize: case .Resize, .Resize_Non_Zeroed:
new_ptr := cmark_alloc.realloc(old_memory, c.size_t(size)) new_ptr := cmark_alloc.realloc(old_memory, c.size_t(size))
res = transmute([]byte)runtime.Raw_Slice{new_ptr, size} res = transmute([]byte)runtime.Raw_Slice{new_ptr, size}
if size > old_size { if size > old_size {
+1 -1
View File
@@ -1774,7 +1774,7 @@ MemAllocatorProc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
MemFree(old_memory) MemFree(old_memory)
return nil, nil return nil, nil
case .Resize: case .Resize, .Resize_Non_Zeroed:
ptr := MemRealloc(old_memory, c.uint(size)) ptr := MemRealloc(old_memory, c.uint(size))
if ptr == nil { if ptr == nil {
err = .Out_Of_Memory err = .Out_Of_Memory