Skip to content

Commit 4dd0048

Browse files
authored
Merge branch 'odin-lang:master' into master
2 parents 7c5b561 + 208ace0 commit 4dd0048

39 files changed

+24649
-113
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ odin
277277
*.bin
278278
demo.bin
279279
libLLVM*.so*
280+
*.a
280281

281282
# shared collection
282283
shared/

check_all.bat

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
@echo off
22

33
if "%1" == "" (
4-
echo Checking darwin_amd64 - expect vendor:cgtlf panic
4+
echo Checking darwin_amd64 - expect vendor:cgltf panic
55
odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:darwin_amd64
6-
echo Checking darwin_arm64 - expect vendor:cgtlf panic
6+
echo Checking darwin_arm64 - expect vendor:cgltf panic
77
odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:darwin_arm64
88
echo Checking linux_i386
99
odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_i386

check_all.sh

100644100755
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ wasm)
4545
;;
4646

4747
*)
48-
echo Checking darwin_amd64 - expect vendor:cgtlf panic
48+
echo Checking darwin_amd64 - expect vendor:cgltf panic
4949
odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:darwin_amd64
50-
echo Checking darwin_arm64 - expect vendor:cgtlf panic
50+
echo Checking darwin_arm64 - expect vendor:cgltf panic
5151
odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:darwin_arm64
5252
echo Checking linux_i386
5353
odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_i386

core/mem/allocators.odin

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2196,7 +2196,7 @@ The buddy allocator data.
21962196
*/
21972197
Buddy_Allocator :: struct {
21982198
head: ^Buddy_Block,
2199-
tail: ^Buddy_Block,
2199+
tail: ^Buddy_Block `fmt:"-"`,
22002200
alignment: uint,
22012201
}
22022202

@@ -2239,6 +2239,7 @@ buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint,
22392239
b.head.is_free = true
22402240
b.tail = buddy_block_next(b.head)
22412241
b.alignment = alignment
2242+
assert(uint(len(data)) >= 2 * buddy_block_size_required(b, 1), "The size of the backing buffer must be large enough to hold at least two 1-byte allocations given the alignment requirements, otherwise it cannot split.", loc)
22422243
// sanitizer.address_poison(data)
22432244
}
22442245

@@ -2247,12 +2248,14 @@ Get required block size to fit in the allocation as well as the alignment paddin
22472248
*/
22482249
@(require_results)
22492250
buddy_block_size_required :: proc(b: ^Buddy_Allocator, size: uint) -> uint {
2250-
size := size
2251-
actual_size := b.alignment
2252-
size += size_of(Buddy_Block)
2253-
size = align_forward_uint(size, b.alignment)
2254-
for size > actual_size {
2255-
actual_size <<= 1
2251+
assert(size > 0)
2252+
// NOTE: `size_of(Buddy_Block)` will be accounted for in `b.alignment`.
2253+
// This calculation is also previously guarded against being given a `size`
2254+
// 0 by `buddy_allocator_alloc_bytes_non_zeroed` checking for that.
2255+
actual_size := b.alignment + size
2256+
if intrinsics.count_ones(actual_size) != 1 {
2257+
// We're not a power of two. Let's fix that.
2258+
actual_size = 1 << (size_of(uint) * 8 - intrinsics.count_leading_zeros(actual_size))
22562259
}
22572260
return actual_size
22582261
}
@@ -2315,7 +2318,7 @@ buddy_allocator_alloc_bytes_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint)
23152318
if size != 0 {
23162319
actual_size := buddy_block_size_required(b, size)
23172320
found := buddy_block_find_best(b.head, b.tail, actual_size)
2318-
if found != nil {
2321+
if found == nil {
23192322
// Try to coalesce all the free buddy blocks and then search again
23202323
buddy_block_coalescence(b.head, b.tail)
23212324
found = buddy_block_find_best(b.head, b.tail, actual_size)
@@ -2325,6 +2328,7 @@ buddy_allocator_alloc_bytes_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint)
23252328
}
23262329
found.is_free = false
23272330
data := ([^]byte)(found)[b.alignment:][:size]
2331+
assert(cast(uintptr)raw_data(data)+cast(uintptr)size < cast(uintptr)buddy_block_next(found), "Buddy_Allocator has made an allocation which overlaps a block header.")
23282332
// ensure_poisoned(data)
23292333
// sanitizer.address_unpoison(data)
23302334
return data, nil

examples/all/all_vendor.odin

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,7 @@ package all
4545
@(require) import stbi "vendor:stb/image"
4646
@(require) import "vendor:stb/rect_pack"
4747
@(require) import "vendor:stb/truetype"
48-
@(require) import "vendor:stb/vorbis"
48+
@(require) import "vendor:stb/vorbis"
49+
50+
51+
@(require) import "vendor:kb_text_shape"

tests/issues/run.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style
1717
..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b
1818
..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b
1919
..\..\..\odin test ..\test_issue_2694.odin %COMMON% || exit /b
20+
..\..\..\odin test ..\test_issue_3435.odin %COMMON% || exit /b
2021
..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b
2122
..\..\..\odin test ..\test_issue_4364.odin %COMMON% || exit /b
2223
..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b

tests/issues/run.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ $ODIN test ../test_issue_2615.odin $COMMON
1818
$ODIN test ../test_issue_2637.odin $COMMON
1919
$ODIN test ../test_issue_2666.odin $COMMON
2020
$ODIN test ../test_issue_2694.odin $COMMON
21+
$ODIN test ../test_issue_3435.odin $COMMON
2122
$ODIN test ../test_issue_4210.odin $COMMON
2223
$ODIN test ../test_issue_4364.odin $COMMON
2324
$ODIN test ../test_issue_4584.odin $COMMON

tests/issues/test_issue_3435.odin

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package main
2+
3+
import "base:runtime"
4+
import "core:mem"
5+
import "core:testing"
6+
import "core:time"
7+
8+
@test
9+
test_issue_3435 :: proc(t: ^testing.T) {
10+
testing.set_fail_timeout(t, time.Second)
11+
allocator: mem.Buddy_Allocator
12+
data := runtime.make_aligned([]byte, 64, 32)
13+
defer delete(data)
14+
15+
// mem.buddy_allocator_init(&allocator, data, 32)
16+
17+
// Bypass the assertion that would normally keep this from happening by
18+
// manually putting the allocator together.
19+
allocator.head = cast(^mem.Buddy_Block)raw_data(data)
20+
allocator.head.size = len(data)
21+
allocator.head.is_free = true
22+
allocator.tail = mem.buddy_block_next(allocator.head)
23+
allocator.alignment = 32
24+
25+
context.allocator = mem.buddy_allocator(&allocator)
26+
27+
// Three allocations in the space above is all that's needed to reproduce
28+
// the bug seen in #3435; this is the most minimal reproduction possible.
29+
a := make([]u8, 1)
30+
testing.expect(t, len(a) == 1)
31+
b := make([]u8, 1)
32+
testing.expect(t, len(b) == 0)
33+
c := make([]u8, 1)
34+
testing.expect(t, len(c) == 0)
35+
36+
// With the bugfix in place, the allocator should be sensible enough to not
37+
// fall into an infinite loop anymore, even if the assertion is disabled.
38+
}

vendor/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,9 @@ Se also LICENCE in `cgltf` directory itself.
158158
## fontstash (Port)
159159

160160
[Font stash](https://github.com/memononen/fontstash) is a light-weight online font texture atlas builder. It uses stb_truetype to render fonts on demand to a texture atlas.
161+
162+
## kb
163+
164+
[kb](https://github.com/JimmyLefevre/kb) provides ICU-like text segmentation (i.e. breaking Unicode text by direction, line, word and grapheme). It also provides Harfbuzz-like text shaping for OpenType fonts, which means it is capable of handling complex script layout and ligatures, among other things.
165+
166+
It does not handle rasterization. It will only help you know which glyphs to display where!
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package vendor_kb_text_shape
2+
3+
when ODIN_OS == .Windows {
4+
foreign import lib {
5+
"lib/kb_text_shape.lib",
6+
}
7+
} else {
8+
foreign import lib {
9+
"kb_text_shape.a",
10+
}
11+
}
12+
13+
import "core:mem"
14+
15+
@(default_calling_convention="c", link_prefix="kbts_", require_results)
16+
foreign lib {
17+
FontIsValid :: proc(Font: ^font) -> b32 ---
18+
SizeOfShapeState :: proc(Font: ^font) -> un ---
19+
20+
ResetShapeState :: proc(State: ^shape_state) ---
21+
22+
ShapeConfig :: proc(Font: ^font, Script: script, Language: language) -> shape_config ---
23+
ShaperIsComplex :: proc(Shaper: shaper) -> b32 ---
24+
ScriptIsComplex :: proc(Script: script) -> b32 ---
25+
26+
Shape :: proc(State: ^shape_state, Config: ^shape_config,
27+
MainDirection, RunDirection: direction,
28+
Glyphs: [^]glyph, GlyphCount: ^u32, GlyphCapacity: u32) -> b32 ---
29+
30+
Cursor :: proc(Direction: direction) -> cursor ---
31+
BeginBreak :: proc(State: ^break_state, MainDirection: direction, JapaneseLineBreakStyle: japanese_line_break_style) ---
32+
BreakStateIsValid :: proc(State: ^break_state) -> b32 ---
33+
BreakAddCodepoint :: proc(State: ^break_state, Codepoint: rune, PositionIncrement: u32, EndOfText: b32) ---
34+
BreakFlush :: proc(State: ^break_state) ---
35+
Break :: proc(State: ^break_state, Break: ^break_type) -> b32 ---
36+
CodepointToGlyph :: proc(Font: ^font, Codepoint: rune) -> glyph ---
37+
InferScript :: proc(Direction: ^direction, Script: ^script, GlyphScript: script) ---
38+
}
39+
40+
@(require_results)
41+
PlaceShapeState :: proc "c" (Memory: []byte) -> ^shape_state {
42+
@(default_calling_convention="c", require_results)
43+
foreign lib {
44+
kbts_PlaceShapeState :: proc(Address: rawptr, Size: un) -> ^shape_state ---
45+
}
46+
47+
return kbts_PlaceShapeState(raw_data(Memory), un(len(Memory)))
48+
}
49+
50+
@(require_results)
51+
DecodeUtf8 :: proc "contextless" (String: string) -> (Codepoint: rune, SourceCharactersConsumed: u32, Valid: bool) {
52+
decode :: struct {
53+
Codepoint: rune,
54+
55+
SourceCharactersConsumed: u32,
56+
Valid: b32,
57+
}
58+
59+
@(default_calling_convention="c", require_results)
60+
foreign lib {
61+
kbts_DecodeUtf8 :: proc(Utf8: [^]byte, Length: uint) -> decode ---
62+
}
63+
64+
Decode := kbts_DecodeUtf8(raw_data(String), len(String))
65+
return Decode.Codepoint, Decode.SourceCharactersConsumed, bool(Decode.Valid)
66+
}
67+
68+
69+
@(require_results)
70+
ReadFontHeader :: proc "c" (Font: ^font, Data: []byte) -> un {
71+
@(default_calling_convention="c", require_results)
72+
foreign lib {
73+
kbts_ReadFontHeader :: proc(Font: ^font, Data: rawptr, Size: un) -> un ---
74+
}
75+
76+
return kbts_ReadFontHeader(Font, raw_data(Data), un(len(Data)))
77+
}
78+
@(require_results)
79+
ReadFontData :: proc "c" (Font: ^font, Scratch: []byte) -> un {
80+
@(default_calling_convention="c", require_results)
81+
foreign lib {
82+
kbts_ReadFontData :: proc(Font: ^font, Scratch: rawptr, ScratchSize: un) -> un ---
83+
}
84+
85+
return kbts_ReadFontData(Font, raw_data(Scratch), un(len(Scratch)))
86+
}
87+
@(require_results)
88+
PostReadFontInitialize :: proc "c" (Font: ^font, Memory: []byte) -> b32 {
89+
@(default_calling_convention="c", require_results)
90+
foreign lib {
91+
kbts_PostReadFontInitialize :: proc(Font: ^font, Memory: rawptr, MemorySize: un) -> b32 ---
92+
}
93+
94+
return kbts_PostReadFontInitialize(Font, raw_data(Memory), un(len(Memory)))
95+
}
96+
97+
@(require_results)
98+
FontFromMemory :: proc(Data: []byte, allocator: mem.Allocator) -> (Result: font, Err: mem.Allocator_Error) {
99+
ClonedData := mem.make_aligned([]byte, len(Data), 16, allocator) or_return
100+
defer if Err != nil {
101+
delete(ClonedData, allocator)
102+
}
103+
copy(ClonedData, Data)
104+
105+
ScratchSize := ReadFontHeader(&Result, ClonedData)
106+
Scratch := mem.make_aligned([]byte, ScratchSize, 16, allocator) or_return
107+
MemorySize := ReadFontData(&Result, Scratch)
108+
109+
Memory := Scratch
110+
if MemorySize > ScratchSize {
111+
delete(Scratch, allocator)
112+
Memory = mem.make_aligned([]byte, MemorySize, 16, allocator) or_return
113+
}
114+
defer if Err != nil {
115+
delete(Memory, allocator)
116+
}
117+
118+
_ = PostReadFontInitialize(&Result, Memory)
119+
return
120+
121+
}
122+
FreeFont :: proc(Font: ^font, allocator: mem.Allocator) {
123+
free(Font.FileBase, allocator)
124+
free(Font.GlyphLookupMatrix, allocator)
125+
Font^ = {}
126+
}
127+
128+
@(require_results)
129+
CreateShapeState :: proc(Font: ^font, allocator: mem.Allocator) -> (Result: ^shape_state, Err: mem.Allocator_Error) {
130+
Size := SizeOfShapeState(Font)
131+
Memory := mem.make_aligned([]byte, Size, 16, allocator) or_return
132+
Result = PlaceShapeState(Memory)
133+
return
134+
}
135+
FreeShapeState :: proc(State: ^shape_state, allocator: mem.Allocator) {
136+
free(State, allocator)
137+
}
138+
139+
@(require_results)
140+
PositionGlyph :: proc(Cursor: ^cursor, Glyph: ^glyph) -> (X, Y: i32) {
141+
@(default_calling_convention="c", require_results)
142+
foreign lib {
143+
kbts_PositionGlyph :: proc(Cursor: ^cursor, Glyph: ^glyph, X, Y: ^i32) ---
144+
}
145+
kbts_PositionGlyph(Cursor, Glyph, &X, &Y)
146+
return
147+
}
148+
149+
@(require_results)
150+
ShapeDynamic :: proc(State: ^shape_state, Config: ^shape_config,
151+
MainDirection, RunDirection: direction,
152+
Glyphs: ^[dynamic]glyph) -> b32 {
153+
GlyphCount := u32(len(Glyphs^))
154+
GlyphCapacity := u32(cap(Glyphs^))
155+
Res := Shape(State, Config, MainDirection, RunDirection, raw_data(Glyphs^), &GlyphCount, GlyphCapacity)
156+
resize(Glyphs, int(GlyphCount))
157+
return Res
158+
}

0 commit comments

Comments
 (0)