mt-lang 0.2.17 → 0.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2b1f14318677bf9232d4163ad6aac3905650056716de05bf89762f08e1aa7d5
4
- data.tar.gz: af90e63fd1c9fd21f6af721c1c039b61159d931d20eaa3eaca3b41369da053c1
3
+ metadata.gz: '076938689f867b9d3d7f60eab7f4654c03a45ea69b429f1af17c86a3afef51a5'
4
+ data.tar.gz: 6f01bf9d070e1307666949acf47d99170d6b28c0048c868a6310663f2d55c919
5
5
  SHA512:
6
- metadata.gz: cef8b0d7f55c4d9496f41d02b0ace0df87f233ff8c24892768543ff3518e68271a2e4613a7654cef661506d42835d1ea8baa9b3d84225614aae420c0d105a0a4
7
- data.tar.gz: b55024abb91b7fdf2694b4be82bf972f1410aa01b949952d30fb49be517fddd501467ebc55fcf3a6dc1a1eb01334709aa74c26a231348026e3197cc5b163b74c
6
+ metadata.gz: 8141047ac65832b64b8eab1d565b5c3eb3bf8841b5541624605179a1e4bc0479f4dab16a92b3b7055e2eb844e37781aac7acab2aa812b348e53d9a151a16fe97
7
+ data.tar.gz: e5ead28d45b33a6c7fdb5c46f84cdd9a887e6bca593b841687a1d1124ba904f02ee09bdb1ef8dab87f2b8dcfcd6480190e94cea57e8b3b4853148d06d199f6e6
data/README.md CHANGED
@@ -855,7 +855,7 @@ Core modules in `std/`:
855
855
  - `std.option.Option[T]` — optional value with `is_some`, `is_none`, `unwrap`, `expect`, `unwrap_or`, `unwrap_or_else` (auto-imported via prelude)
856
856
  - `std.result.Result[T, E]` — fallible computation with `is_success`, `is_failure`, `unwrap`, `unwrap_error`, `unwrap_or`, `unwrap_or_else`, `ok`, `error`, `map_error` (auto-imported via prelude)
857
857
 
858
- **Collections**: `std.vec.Vec[T]`, `std.deque.Deque[T]`, `std.map.Map[K,V]`, `std.set.Set[T]`, `std.ordered_map.OrderedMap[K,V]`, `std.ordered_set.OrderedSet[T]`, `std.binary_heap.BinaryHeap[T]`, `std.priority_queue.PriorityQueue[T]`, `std.linked_map.LinkedMap[K,V]`, `std.linked_set.LinkedSet[T]`, `std.counter.Counter[T]`, `std.multiset.MultiSet[T]`, `std.queue.Queue[T]`, `std.stack.Stack[T]`
858
+ **Collections**: `std.vec.Vec[T]`, `std.deque.Deque[T]`, `std.map.Map[K,V]`, `std.set.Set[T]`, `std.ordered_map.OrderedMap[K,V]`, `std.ordered_set.OrderedSet[T]`, `std.binary_heap.BinaryHeap[T]`, `std.priority_queue.PriorityQueue[T]`, `std.linked_map.LinkedMap[K,V]`, `std.linked_set.LinkedSet[T]`, `std.counter.Counter[T]`, `std.multiset.MultiSet[T]`, `std.queue.Queue[T]`, `std.stack.Stack[T]`, `std.bitset.Bitset`, `std.spatial.SpatialGrid[T]`, `std.ring_buffer.RingBuffer[T]`, `std.sparse_set.SparseSet[T]`, `std.lru_cache.LruCache[K,V]`
859
859
 
860
860
  **Serialization**: `std.json`, `std.toml`, `std.uri`, `std.serialize`
861
861
 
@@ -872,7 +872,7 @@ Core modules in `std/`:
872
872
  **Other**: `std.bytes`, `std.ctype`, `std.asset_pack`, `std.cell`
873
873
 
874
874
  See module source for full method surface. Iterator forms:
875
- - Pointer-returning (`next() -> nullable ptr[T]`): `Vec`, `Deque`, `BinaryHeap`/`PriorityQueue`/`OrderedSet` (read-only), `OrderedMap.keys`/`Map.keys`/`Set`/`LinkedMap.keys`/`LinkedSet`/`Counter.keys`/`MultiSet.values`, `Queue`/`Stack` (mutable)
875
+ - Pointer-returning (`next() -> nullable ptr[T]`): `Vec`, `Deque`, `BinaryHeap`/`PriorityQueue`/`OrderedSet` (read-only), `OrderedMap.keys`/`Map.keys`/`Set`/`LinkedMap.keys`/`LinkedSet`/`Counter.keys`/`MultiSet.values`, `Queue`/`Stack` (mutable), `RingBuffer`, `SparseSet`
876
876
  - `next() -> bool` + `current()`: `OrderedMap.entries`/`iter`, `Map.entries`/`iter`, `LinkedMap.entries`/`iter`, `Counter.counts`/`entries`/`iter`, `MultiSet.entries`/`iter`, `SnapshotValues`/`SnapshotEntries`
877
877
 
878
878
  ## 12. Strings, Text, And Builders
data/docs/index.html CHANGED
@@ -2164,6 +2164,11 @@ function attach(window: ref[Window]) -> Result[void, EventError]:
2164
2164
  <tr><td><code>std.multiset</code></td><td><code>MultiSet[T]</code></td><td>Values read-only; entries <code>current()</code></td><td>Bag with per-element counts</td></tr>
2165
2165
  <tr><td><code>std.queue</code></td><td><code>Queue[T]</code></td><td>Mutable <code>ptr[T]?</code></td><td>FIFO facade over Deque</td></tr>
2166
2166
  <tr><td><code>std.stack</code></td><td><code>Stack[T]</code></td><td>Mutable <code>ptr[T]?</code></td><td>LIFO facade over Deque</td></tr>
2167
+ <tr><td><code>std.bitset</code></td><td><code>Bitset</code></td><td>&mdash;</td><td>Bit-level set with popcount</td></tr>
2168
+ <tr><td><code>std.spatial</code></td><td><code>SpatialGrid[T]</code></td><td>&mdash;</td><td>Uniform spatial hash grid (returns Vec)</td></tr>
2169
+ <tr><td><code>std.ring_buffer</code></td><td><code>RingBuffer[T]</code></td><td>Mutable <code>ptr[T]?</code></td><td>Fixed-capacity circular buffer</td></tr>
2170
+ <tr><td><code>std.sparse_set</code></td><td><code>SparseSet[T]</code></td><td>Mutable <code>ptr[T]?</code></td><td>O(1) insert/remove; dense iteration</td></tr>
2171
+ <tr><td><code>std.lru_cache</code></td><td><code>LruCache[K,V]</code></td><td><code>entries()</code></td><td>Capacity-bounded LRU eviction map</td></tr>
2167
2172
  </table>
2168
2173
  </div>
2169
2174
 
@@ -1129,6 +1129,11 @@ The current shipped collection modules in `std` are:
1129
1129
  - `std.multiset.MultiSet[T]`: insertion-ordered bag built on `Counter[T]`, with `create`, `with_capacity`, `len`, `total_count`, `distinct_len`, `capacity`, `is_empty`, `count`, `contains`, `values`, `entries`, `iter`, `is_subset`, `union_with`, `intersection`, `difference`, `symmetric_difference`, `clear`, `release`, `reserve`, `insert`, `add`, `remove_one`, and `remove_all`.
1130
1130
  - `std.queue.Queue[T]`: FIFO facade over `Deque[T]`, with `create`, `with_capacity`, `len`, `capacity`, `is_empty`, `iter`, `peek`, `clear`, `release`, `reserve`, `enqueue`, and `dequeue`.
1131
1131
  - `std.stack.Stack[T]`: LIFO facade over `Deque[T]`, with `create`, `with_capacity`, `len`, `capacity`, `is_empty`, `iter`, `peek`, `clear`, `release`, `reserve`, `push`, and `pop`.
1132
+ - `std.bitset.Bitset`: bit-level set backed by a heap-allocated word array, with `create`, `with_capacity`, `len`, `is_empty`, `set`, `clear`, `test`, `toggle`, `count`, `any`, `all`, `none`, `find_first_set`, `find_first_clear`, `clear_all`, `reserve`, and `release`.
1133
+ - `std.spatial.SpatialGrid[T]`: uniform spatial hash grid with `create`, `with_origin`, `insert`, `insert_many`, `query_radius`, `clear`, `release`, `cell_count`, `occupied_cells`, and `entity_count`.
1134
+ - `std.ring_buffer.RingBuffer[T]`: fixed-capacity circular buffer that overwrites oldest entries when full, with `with_capacity`, `len`, `capacity`, `is_empty`, `is_full`, `iter`, `get`, `at`, `peek`, `push`, `pop`, `clear`, and `release`.
1135
+ - `std.sparse_set.SparseSet[T]`: O(1) insert/remove/contains with cache-friendly dense iteration, keyed by `ptr_uint` handle, with `create`, `with_capacity`, `len`, `is_empty`, `iter`, `get`, `at`, `contains`, `key_at`, `insert`, `remove`, `clear`, `reserve`, and `release`.
1136
+ - `std.lru_cache.LruCache[K, V]`: capacity-bounded linked hash map with LRU eviction, keyed by the canonical `hash[K](...)` and `equal[K](...)` hooks, with `with_capacity`, `len`, `capacity`, `is_empty`, `iter`, `get`, `at`, `contains`, `set`, `remove`, `clear`, and `release`.
1132
1137
  - `std.linked_map_view.SnapshotValues[K, V]`: read-only snapshot view over `LinkedMap` values in insertion order, with `create(values: linked_map.Entries[K, V])` and `iter`.
1133
1138
  - `std.linked_map_view.SnapshotEntries[K, V]`: read-only snapshot view over `LinkedMap` entries in insertion order, with `create(values: linked_map.Entries[K, V])` and `iter`.
1134
1139
 
@@ -1151,7 +1156,10 @@ Iterator notes for those collection modules:
1151
1156
  - `MultiSet.values()` uses the pointer-returning iterator form with read-only value pointers in first-seen order.
1152
1157
  - `MultiSet.entries()` and `MultiSet.iter()` use the `next() -> bool` plus `current()` iterator form and yield immutable `{ value, count }` snapshots.
1153
1158
  - `Queue.iter()` and `Stack.iter()` use the same mutable pointer-returning iterator form as `Deque.iter()`, and `peek()` returns a mutable element pointer because changing an element value does not violate FIFO/LIFO ordering invariants.
1159
+ - `RingBuffer.iter()` uses the pointer-returning iterator form with mutable element pointers.
1160
+ - `SparseSet.iter()` uses the pointer-returning iterator form with mutable element pointers in dense order.
1154
1161
  - `SnapshotValues.iter()` and `SnapshotEntries.iter()` use the `next() -> bool` plus `current()` iterator form in insertion order.
1162
+ - `SpatialGrid` does not expose a direct iterator; query results are returned as a `Vec[T]`.
1155
1163
 
1156
1164
  ## 8. Strings, C Strings, And Format Strings
1157
1165
 
data/lib/milk_tea/base.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "pathname"
4
4
 
5
5
  module MilkTea
6
- VERSION = "0.2.17"
6
+ VERSION = "0.2.19"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -122,11 +122,12 @@ module MilkTea
122
122
  start_line = [binding.ast.respond_to?(:line) ? binding.ast.line : nil, snapshots.first.line].compact.min
123
123
  end_line = snapshots.last.line
124
124
 
125
- # Generic function bodies are not analysed during structural checking,
126
- # so the frame only has the initial snapshot at the declaration line.
127
- # Extend end_line to cover the actual body so that completion and hover
128
- # lookups for parameters resolve correctly inside the body.
129
- if snapshots.length == 1 && binding.ast.respond_to?(:body) && binding.ast.body
125
+ # Extend end_line to cover the actual function body so that completion
126
+ # and hover lookups resolve correctly even when snapshots don't reach
127
+ # the final body line (common for generic functions whose bodies are
128
+ # only partially analysed, and functions whose last statement does not
129
+ # record a snapshot).
130
+ if binding.ast.respond_to?(:body) && binding.ast.body
130
131
  body_end = last_ast_line(binding.ast.body)
131
132
  end_line = body_end if body_end && body_end > end_line
132
133
  end
@@ -334,6 +334,7 @@ module MilkTea
334
334
  when AST::LocalDecl
335
335
  check_expr_names(stmt.value, scopes, binding, names) if stmt.value
336
336
  names.add(stmt.name) if stmt.name
337
+ try_record_generic_local_snapshot(stmt, scopes, binding) if stmt.name && stmt.value
337
338
  when AST::Assignment
338
339
  check_expr_names(stmt.target, scopes, binding, names)
339
340
  check_expr_names(stmt.value, scopes, binding, names)
@@ -457,6 +458,138 @@ module MilkTea
457
458
  raise_sema_error("unknown name #{name}", node)
458
459
  end
459
460
 
461
+ # When a generic method body contains a let/var declaration, always record a
462
+ # completion snapshot so hover and completion can discover the local, even
463
+ # when full type inference is impossible. The inferred type is used when
464
+ # available; otherwise the explicit type annotation on the declaration is
465
+ # consulted. As a last resort a fallback primitive type is used so the
466
+ # binding is never silently dropped.
467
+ def try_record_generic_local_snapshot(stmt, scopes, binding)
468
+ type = infer_local_initializer_type(stmt, scopes) ||
469
+ explicit_declaration_type_for(stmt) ||
470
+ fallback_completion_type
471
+
472
+ decl_kind = stmt.kind == :var ? :var : :let
473
+ vb = value_binding(name: stmt.name, type: type, mutable: stmt.kind == :var, kind: decl_kind)
474
+ new_scopes = scopes.dup.unshift({ stmt.name => vb })
475
+ record_local_completion_snapshot(stmt.line, stmt.column, new_scopes)
476
+ end
477
+
478
+ def infer_local_initializer_type(stmt, scopes)
479
+ return nil unless stmt.value
480
+
481
+ infer_simple_local_type(stmt.value, scopes)
482
+ end
483
+
484
+ def explicit_declaration_type_for(stmt)
485
+ annotation = stmt.respond_to?(:type) ? stmt.type : nil
486
+ return nil unless annotation
487
+
488
+ name = annotation.respond_to?(:name) ? annotation.name : annotation.to_s
489
+ @ctx.types[name]
490
+ end
491
+
492
+ def fallback_completion_type
493
+ @ctx.types["int"] || @ctx.types.values.first
494
+ end
495
+
496
+ def infer_simple_local_type(value, scopes)
497
+ case value
498
+ when AST::Call
499
+ infer_call_return_type(value, scopes)
500
+ when AST::MemberAccess
501
+ infer_member_access_field_type(value, scopes)
502
+ when AST::Identifier
503
+ (binding = lookup_value(value.name, scopes)) ? binding.type : nil
504
+ when AST::IntegerLiteral
505
+ @ctx.types["int"]
506
+ when AST::FloatLiteral
507
+ @ctx.types["float"] || @ctx.types["double"]
508
+ when AST::CharLiteral
509
+ @ctx.types["ubyte"]
510
+ when AST::BooleanLiteral
511
+ @ctx.types["bool"]
512
+ when AST::StringLiteral
513
+ @ctx.types["str"]
514
+ when AST::PrefixCast
515
+ if value.target_type.respond_to?(:name)
516
+ @ctx.types[value.target_type.name] || @ctx.types["int"]
517
+ else
518
+ @ctx.types["int"]
519
+ end
520
+ end
521
+ end
522
+
523
+ def infer_member_access_field_type(value, scopes)
524
+ receiver_type = case value.receiver
525
+ when AST::Identifier
526
+ if value.receiver.name == "this"
527
+ (binding = lookup_value("this", scopes)) ? binding.type : nil
528
+ else
529
+ (binding = lookup_value(value.receiver.name, scopes)) ? binding.type : nil
530
+ end
531
+ end
532
+ return nil unless receiver_type
533
+
534
+ field_receiver = receiver_type_for_fields(receiver_type)
535
+ field_receiver&.respond_to?(:fields) ? field_receiver.fields[value.member] : nil
536
+ end
537
+
538
+ def infer_call_return_type(call, scopes)
539
+ callee = call.callee
540
+ callee = callee.callee while callee.is_a?(AST::Specialization)
541
+
542
+ case callee
543
+ when AST::Identifier
544
+ func = @ctx.top_level_functions[callee.name]
545
+ return func.type.return_type if func
546
+
547
+ member = callee.name
548
+ this_binding = lookup_value("this", scopes)
549
+ if this_binding && (rt = receiver_type_for_fields(this_binding.type))
550
+ method = @ctx.methods.dig(rt, member)
551
+ return method.type.return_type if method
552
+ end
553
+ when AST::MemberAccess
554
+ name = resolve_receiver_name_for_call_inference(callee, scopes)
555
+ member = callee.member
556
+ return nil unless name
557
+
558
+ if (import = @ctx.imports[name])
559
+ func = import.functions[member]
560
+ return func.type.return_type if func
561
+ end
562
+
563
+ receiver_type = @ctx.types[name]
564
+ if receiver_type && @ctx.methods.key?(receiver_type)
565
+ method = @ctx.methods[receiver_type]["static:#{member}"] || @ctx.methods[receiver_type][member]
566
+ return method.type.return_type if method
567
+ end
568
+ end
569
+ nil
570
+ end
571
+
572
+ def resolve_receiver_name_for_call_inference(callee, scopes)
573
+ case callee.receiver
574
+ when AST::Identifier
575
+ if callee.receiver.name == "this"
576
+ binding = lookup_value("this", scopes)
577
+ return nil unless binding
578
+ this_type = receiver_type_for_fields(binding.type)
579
+ this_type&.name
580
+ else
581
+ callee.receiver.name
582
+ end
583
+ end
584
+ end
585
+
586
+ def receiver_type_for_fields(type)
587
+ type = type.base while type.is_a?(Types::Nullable)
588
+ type = type.arguments.first if type.respond_to?(:name) && type.name == 'ref' && type.respond_to?(:arguments) && type.arguments&.length == 1
589
+ type = type.definition if type.respond_to?(:definition)
590
+ type
591
+ end
592
+
460
593
  # Scans generic method bodies for assignments to this through a
461
594
  # non-editable receiver. Full body checking is deferred to call-site
462
595
  # specialization, but immutable-this violations are type-independent.
@@ -491,8 +624,10 @@ module MilkTea
491
624
  with_scope(binding.body_params) do |scopes|
492
625
  start_local_completion_frame(binding, scopes)
493
626
  if binding.type_params.any?
494
- check_generic_method_immutable_this(binding, scopes)
495
- check_generic_method_names(binding, scopes)
627
+ if binding.ast.respond_to?(:body)
628
+ check_generic_method_immutable_this(binding, scopes)
629
+ check_generic_method_names(binding, scopes)
630
+ end
496
631
  return
497
632
  end
498
633
 
@@ -22,7 +22,19 @@ module MilkTea
22
22
  if @nullability_flow_result && idx + 1 < statements.length
23
23
  apply_nullability_continuation_refinements!(nested_scopes, statements[idx + 1])
24
24
  end
25
- record_local_completion_snapshot(statement_end_line(statement), 1_000_000, nested_scopes)
25
+ end_line = statement_end_line(statement)
26
+ # When the statement spans multiple lines (e.g. let … else:),
27
+ # record an extra snapshot at the declaration line so that
28
+ # hover and completion lookups on the declaration line itself
29
+ # can still find the new binding.
30
+ if end_line && statement.respond_to?(:line) && statement.line && end_line > statement.line
31
+ record_local_completion_snapshot(
32
+ statement.line,
33
+ statement.respond_to?(:column) ? statement.column : 0,
34
+ nested_scopes,
35
+ )
36
+ end
37
+ record_local_completion_snapshot(end_line, 1_000_000, nested_scopes)
26
38
  rescue SemanticError => e
27
39
  if @collecting_errors
28
40
  @structural_errors << e
@@ -1264,9 +1264,14 @@ module MilkTea
1264
1264
 
1265
1265
  header_line_tokens = non_trivia_tokens_on_line(tokens, current.line)
1266
1266
  header = header_line_tokens.first
1267
+ type_index = 1
1268
+ if header&.type == :public
1269
+ header = header_line_tokens[1]
1270
+ type_index = 2
1271
+ end
1267
1272
  return nil unless [:struct, :union].include?(header&.type)
1268
1273
 
1269
- type_token = header_line_tokens[1]
1274
+ type_token = header_line_tokens[type_index]
1270
1275
  return nil unless type_token&.type == :identifier
1271
1276
 
1272
1277
  return resolve_type_receiver_info(facts, type_token.lexeme, type_token.lexeme)
@@ -462,7 +462,9 @@ module MilkTea
462
462
  struct_type = find_struct_containing_field(facts, field_name)
463
463
  return nil unless struct_type
464
464
 
465
- changes = collect_struct_field_changes(uri, field_name, new_name)
465
+ changes = {}
466
+ edits = collect_struct_field_changes(uri, field_name, new_name)
467
+ changes[uri] = edits if edits
466
468
  related_uris = @workspace.related_open_document_uris(uri)
467
469
  related_uris.each do |related_uri|
468
470
  next if related_uri == uri
@@ -237,6 +237,8 @@ module MilkTea
237
237
  true
238
238
  elsif (expr = extract_expr(stmt)) && own_struct_field_transfer?(expr, name)
239
239
  true
240
+ elsif stmt.is_a?(AST::Assignment) && stmt.value.is_a?(AST::Identifier) && stmt.value.name == name
241
+ true
240
242
  else
241
243
  false
242
244
  end
@@ -821,6 +821,7 @@ module MilkTea
821
821
  message: "every #{kind} branch returns a value; rewrite as `return #{kind} …` expression",
822
822
  )
823
823
  elsif stmts.all? { |s| s.is_a?(AST::Assignment) && s.operator == "=" } &&
824
+ stmts.all? { |s| s.target.respond_to?(:name) } &&
824
825
  stmts.map { |s| node_fingerprint(s.target) }.uniq.size == 1
825
826
  target_name = stmts.first.target.name
826
827
  emit_conciseness_hint(
@@ -247,7 +247,7 @@ public function sleep_release(frame: ptr[void]) -> void:
247
247
 
248
248
  if not state.closing:
249
249
  state.closing = true
250
- let handle = timer_as_handle(unsafe: ptr[NativeTimerHandle]<-state.timer)
250
+ let handle = timer_as_handle(ptr[NativeTimerHandle]<-state.timer)
251
251
  libuv.close(handle, sleep_timer_close)
252
252
 
253
253
 
@@ -323,7 +323,7 @@ public function work_release[T](frame: ptr[void]) -> void:
323
323
 
324
324
  state.released = true
325
325
  if state.queued and state.work != null:
326
- libuv.cancel(work_as_req(unsafe: ptr[NativeWorkRequest]<-state.work))
326
+ libuv.cancel(work_as_req(ptr[NativeWorkRequest]<-state.work))
327
327
 
328
328
 
329
329
  public function work_take_result[T](frame: ptr[void]) -> T:
data/std/behavior_tree.mt CHANGED
@@ -128,7 +128,7 @@ function tick_node[Context](tree: ref[Tree[Context]], node_id: ptr_uint, context
128
128
 
129
129
  var saw_running = false
130
130
  for child_ptr in read(node).children:
131
- let child_status = tick_node(tree, unsafe: read(child_ptr), context)
131
+ let child_status = tick_node(tree, read(child_ptr), context)
132
132
  match child_status:
133
133
  Status.success:
134
134
  pass
@@ -148,7 +148,7 @@ function tick_node[Context](tree: ref[Tree[Context]], node_id: ptr_uint, context
148
148
 
149
149
  var saw_running = false
150
150
  for child_ptr in read(node).children:
151
- let child_status = tick_node(tree, unsafe: read(child_ptr), context)
151
+ let child_status = tick_node(tree, read(child_ptr), context)
152
152
  match child_status:
153
153
  Status.success:
154
154
  return Status.success
data/std/deque.mt CHANGED
@@ -140,6 +140,35 @@ extending Deque[T]:
140
140
  this.capacity = new_capacity
141
141
 
142
142
 
143
+ public editable function shrink_to_fit() -> void:
144
+ if this.len == 0:
145
+ heap.release(this.data)
146
+ this.data = null
147
+ this.head = 0
148
+ this.capacity = 0
149
+ return
150
+
151
+ if this.len == this.capacity:
152
+ return
153
+
154
+ let new_data = heap.must_alloc[T](this.len)
155
+ let old_data = this.data
156
+ if old_data != null:
157
+ unsafe:
158
+ let old_ptr = ptr[T]<-old_data
159
+ let new_ptr = ptr[T]<-new_data
160
+ var index: ptr_uint = 0
161
+ while index < this.len:
162
+ let source_index = Deque[T].physical_index(this.head, this.capacity, index)
163
+ read(new_ptr + index) = read(old_ptr + source_index)
164
+ index += 1
165
+
166
+ heap.release(old_data)
167
+ this.data = new_data
168
+ this.head = 0
169
+ this.capacity = this.len
170
+
171
+
143
172
  public editable function push_back(value: T) -> void:
144
173
  if this.len == this.capacity:
145
174
  this.reserve(this.len + 1)
data/std/goap.mt CHANGED
@@ -323,13 +323,12 @@ extending Planner[World, Goal, Context]:
323
323
  action_index += 1
324
324
  continue
325
325
 
326
- if next_cost < unsafe: read(existing_ptr).cost_so_far:
327
- unsafe:
328
- read(existing_ptr).parent_index = current_index
329
- read(existing_ptr).has_parent = true
330
- read(existing_ptr).action_index = action_index
331
- read(existing_ptr).cost_so_far = next_cost
332
- read(existing_ptr).closed = false
326
+ if next_cost < read(existing_ptr).cost_so_far:
327
+ read(existing_ptr).parent_index = current_index
328
+ read(existing_ptr).has_parent = true
329
+ read(existing_ptr).action_index = action_index
330
+ read(existing_ptr).cost_so_far = next_cost
331
+ read(existing_ptr).closed = false
333
332
  if not open_list_contains(ref_of(open_list), existing_payload.value):
334
333
  open_list.push(existing_payload.value)
335
334
  action_index += 1
data/std/lru_cache.mt ADDED
@@ -0,0 +1,75 @@
1
+ import std.linked_map as linked_map
2
+
3
+ public struct LruCache[K, V]:
4
+ values: linked_map.LinkedMap[K, V]
5
+ max_capacity: ptr_uint
6
+
7
+
8
+ extending LruCache[K, V]:
9
+ public static function with_capacity(capacity: ptr_uint) -> LruCache[K, V]:
10
+ return LruCache[K, V](values = linked_map.LinkedMap[K, V].with_capacity(capacity), max_capacity = capacity)
11
+
12
+
13
+ public function len() -> ptr_uint:
14
+ return this.values.len()
15
+
16
+
17
+ public function capacity() -> ptr_uint:
18
+ return this.max_capacity
19
+
20
+
21
+ public function is_empty() -> bool:
22
+ return this.values.is_empty()
23
+
24
+
25
+ public function iter() -> linked_map.Entries[K, V]:
26
+ return this.values.entries()
27
+
28
+
29
+ public editable function get(key: K) -> ptr[V]?:
30
+ let removed = this.values.remove_entry(key)
31
+ match removed:
32
+ Option.some as entry:
33
+ this.values.set(key, entry.value.value)
34
+ return this.values.get(key)
35
+ Option.none:
36
+ return null
37
+
38
+
39
+ public editable function at(key: K) -> Option[V]:
40
+ let p = this.get(key) else:
41
+ return Option[V].none
42
+
43
+ unsafe:
44
+ return Option[V].some(value = read(p))
45
+
46
+
47
+ public function contains(key: K) -> bool:
48
+ return this.values.contains(key)
49
+
50
+
51
+ public editable function clear() -> void:
52
+ this.values.clear()
53
+
54
+
55
+ public editable function release() -> void:
56
+ this.values.release()
57
+
58
+
59
+ public editable function set(key: K, value: V) -> void:
60
+ this.values.remove(key)
61
+
62
+ if this.values.len() == this.max_capacity:
63
+ var key_iter = this.values.keys()
64
+ let first_key_ptr = key_iter.next() else:
65
+ return
66
+
67
+ unsafe:
68
+ let first_key = read(ptr[K]<-first_key_ptr)
69
+ this.values.remove(first_key)
70
+
71
+ this.values.set(key, value)
72
+
73
+
74
+ public editable function remove(key: K) -> bool:
75
+ return this.values.remove(key).is_some()
data/std/net/manager.mt CHANGED
@@ -331,7 +331,7 @@ public function create_server(
331
331
  is_server = true,
332
332
  max_players = config.max_players,
333
333
  mux_session = session_p.value,
334
- mux_connection = unsafe: zero[mux.MuxedConnection],
334
+ mux_connection = zero[mux.MuxedConnection],
335
335
  local_player_id = 0u,
336
336
  players = vec.Vec[PlayerState].create(),
337
337
  next_player_id = 1u,
@@ -357,7 +357,7 @@ public function create_client(
357
357
  let client_mgr = NetworkManager(
358
358
  is_server = false,
359
359
  max_players = config.max_players,
360
- mux_session = unsafe: zero[mux.MuxedSession],
360
+ mux_session = zero[mux.MuxedSession],
361
361
  mux_connection = mux_conn_p.value,
362
362
  local_player_id = 0u,
363
363
  players = vec.Vec[PlayerState].create(),
data/std/net/packet.mt CHANGED
@@ -164,7 +164,7 @@ extending Stream:
164
164
  Result.failure as error_payload:
165
165
  return Result[ptr_uint, Error].failure(error = error_from_net(error_payload.error))
166
166
  Result.success as write_payload:
167
- unsafe: write_payload.value
167
+ write_payload.value
168
168
  return Result[ptr_uint, Error].success(value = content.len)
169
169
 
170
170
 
@@ -183,7 +183,7 @@ extending Stream:
183
183
  Result.failure as discard_payload:
184
184
  return Result[bytes.Bytes, Error].failure(error = discard_payload.error)
185
185
  Result.success as discard_payload:
186
- unsafe: discard_payload.value
186
+ discard_payload.value
187
187
  return Result[bytes.Bytes, Error].failure(error = packet_error(
188
188
  -2,
189
189
  "packet exceeds configured maximum"
data/std/net.mt CHANGED
@@ -736,7 +736,7 @@ function connect_cleanup_and_release(state: ptr[ConnectState]) -> void:
736
736
  read(state).result_owned = false
737
737
 
738
738
  if read(state).handle != null[ptr[NativeTcpHandle]]:
739
- close_tcp_handle(unsafe: ptr[NativeTcpHandle]<-read(state).handle)
739
+ close_tcp_handle(ptr[NativeTcpHandle]<-read(state).handle)
740
740
  read(state).handle = null
741
741
 
742
742
  heap.release(state)
data/std/process.mt CHANGED
@@ -94,7 +94,7 @@ public function parent_environment() -> vec.Vec[EnvironmentEntry]:
94
94
  nname.reserve(eq_pos)
95
95
  var ni: ptr_uint = 0
96
96
  while ni < eq_pos:
97
- nname.push_byte(ubyte<-(unsafe: read(entry_cstr + ni)))
97
+ nname.push_byte(ubyte<-(read(entry_cstr + ni)))
98
98
  ni += 1
99
99
  var nvalue = string.String.create()
100
100
  let vlen = len - eq_pos - 1
@@ -102,7 +102,7 @@ public function parent_environment() -> vec.Vec[EnvironmentEntry]:
102
102
  nvalue.reserve(vlen)
103
103
  var vi: ptr_uint = 0
104
104
  while vi < vlen:
105
- nvalue.push_byte(ubyte<-(unsafe: read(entry_cstr + eq_pos + 1 + vi)))
105
+ nvalue.push_byte(ubyte<-(read(entry_cstr + eq_pos + 1 + vi)))
106
106
  vi += 1
107
107
  result.push(EnvironmentEntry(
108
108
  name = nname.as_str(),
data/std/queue.mt CHANGED
@@ -47,6 +47,10 @@ extending Queue[T]:
47
47
  this.values.reserve(min_capacity)
48
48
 
49
49
 
50
+ public editable function shrink_to_fit() -> void:
51
+ this.values.shrink_to_fit()
52
+
53
+
50
54
  public editable function enqueue(value: T) -> void:
51
55
  this.values.push_back(value)
52
56
 
@@ -0,0 +1,131 @@
1
+ import std.mem.heap as heap
2
+
3
+ public struct RingBuffer[T]:
4
+ data: own[T]?
5
+ head: ptr_uint
6
+ len: ptr_uint
7
+ capacity: ptr_uint
8
+
9
+ public struct Iter[T]:
10
+ data: ptr[T]?
11
+ head: ptr_uint
12
+ len: ptr_uint
13
+ capacity: ptr_uint
14
+ index: ptr_uint
15
+
16
+
17
+ extending RingBuffer[T]:
18
+ public static function with_capacity(capacity: ptr_uint) -> RingBuffer[T]:
19
+ let data = heap.must_alloc[T](capacity)
20
+ return RingBuffer[T](data = data, head = 0, len = 0, capacity = capacity)
21
+
22
+
23
+ static function physical_index(head: ptr_uint, capacity: ptr_uint, index: ptr_uint) -> ptr_uint:
24
+ let raw = head + index
25
+ if raw >= capacity:
26
+ return raw - capacity
27
+
28
+ return raw
29
+
30
+
31
+ public function len() -> ptr_uint:
32
+ return this.len
33
+
34
+
35
+ public function capacity() -> ptr_uint:
36
+ return this.capacity
37
+
38
+
39
+ public function is_empty() -> bool:
40
+ return this.len == 0
41
+
42
+
43
+ public function is_full() -> bool:
44
+ return this.len == this.capacity
45
+
46
+
47
+ public function iter() -> Iter[T]:
48
+ return Iter[T](data = this.data, head = this.head, len = this.len, capacity = this.capacity, index = 0)
49
+
50
+
51
+ public function get(index: ptr_uint) -> ptr[T]?:
52
+ if index >= this.len:
53
+ return null
54
+
55
+ let data = this.data else:
56
+ fatal(c"ring_buffer.RingBuffer.get missing storage")
57
+
58
+ return unsafe: ptr[T]<-data + RingBuffer[T].physical_index(this.head, this.capacity, index)
59
+
60
+
61
+ public function at(index: ptr_uint) -> Option[T]:
62
+ let p = this.get(index) else:
63
+ return Option[T].none
64
+
65
+ unsafe:
66
+ return Option[T].some(value = read(p))
67
+
68
+
69
+ public function peek() -> ptr[T]?:
70
+ return this.get(0)
71
+
72
+
73
+ public editable function push(value: T) -> void:
74
+ let data = this.data else:
75
+ fatal(c"ring_buffer.RingBuffer.push missing storage")
76
+
77
+ let tail = RingBuffer[T].physical_index(this.head, this.capacity, this.len)
78
+
79
+ unsafe:
80
+ let data_ptr = ptr[T]<-data
81
+ read(data_ptr + tail) = value
82
+
83
+ if this.len == this.capacity:
84
+ this.head = RingBuffer[T].physical_index(this.head, this.capacity, 1)
85
+ else:
86
+ this.len += 1
87
+
88
+
89
+ public editable function pop() -> Option[T]:
90
+ if this.len == 0:
91
+ return Option[T].none
92
+
93
+ let data = this.data else:
94
+ fatal(c"ring_buffer.RingBuffer.pop missing storage")
95
+
96
+ unsafe:
97
+ let data_ptr = ptr[T]<-data
98
+ let value = read(data_ptr + this.head)
99
+ this.head = RingBuffer[T].physical_index(this.head, this.capacity, 1)
100
+ this.len -= 1
101
+ return Option[T].some(value = value)
102
+
103
+
104
+ public editable function clear() -> void:
105
+ this.head = 0
106
+ this.len = 0
107
+
108
+
109
+ public editable function release() -> void:
110
+ heap.release(this.data)
111
+ this.data = null
112
+ this.head = 0
113
+ this.len = 0
114
+ this.capacity = 0
115
+
116
+
117
+ extending Iter[T]:
118
+ public function iter() -> Iter[T]:
119
+ return this
120
+
121
+
122
+ public editable function next() -> ptr[T]?:
123
+ if this.index >= this.len:
124
+ return null
125
+
126
+ let data = this.data else:
127
+ fatal(c"ring_buffer.Iter.next missing storage")
128
+
129
+ let current_index = this.index
130
+ this.index += 1
131
+ return unsafe: ptr[T]<-data + RingBuffer[T].physical_index(this.head, this.capacity, current_index)
data/std/serialize.mt CHANGED
@@ -25,7 +25,7 @@ public function unpack[T](source: span[ubyte]) -> Result[T, bin.Error]:
25
25
  error = raw_unpack_error("source too short for target type")
26
26
  )
27
27
 
28
- var result = unsafe: zero[T]
28
+ var result = zero[T]
29
29
  var dest = unsafe: ptr[ubyte]<-ptr_of(result)
30
30
  var i: ptr_uint = 0
31
31
  while i < total:
@@ -59,7 +59,7 @@ extending bin.Reader:
59
59
  error = raw_unpack_error("reader returned empty data")
60
60
  )
61
61
 
62
- var result = unsafe: zero[T]
62
+ var result = zero[T]
63
63
  var dest = unsafe: ptr[ubyte]<-ptr_of(result)
64
64
  var i: ptr_uint = 0
65
65
  while i < total:
data/std/sparse_set.mt ADDED
@@ -0,0 +1,176 @@
1
+ import std.vec as vec
2
+
3
+ const SPARSE_EMPTY: ptr_uint = ~ptr_uint<-0
4
+
5
+ public struct SparseSet[T]:
6
+ sparse: vec.Vec[ptr_uint]
7
+ dense: vec.Vec[T]
8
+ keys: vec.Vec[ptr_uint]
9
+
10
+ public struct Iter[T]:
11
+ data: ptr[T]?
12
+ index: ptr_uint
13
+ len: ptr_uint
14
+
15
+
16
+ extending SparseSet[T]:
17
+ public static function create() -> SparseSet[T]:
18
+ return SparseSet[T](
19
+ sparse = vec.Vec[ptr_uint].create(),
20
+ dense = vec.Vec[T].create(),
21
+ keys = vec.Vec[ptr_uint].create(),
22
+ )
23
+
24
+
25
+ public static function with_capacity(capacity: ptr_uint) -> SparseSet[T]:
26
+ var result = SparseSet[T].create()
27
+ result.reserve(capacity)
28
+ return result
29
+
30
+
31
+ public function len() -> ptr_uint:
32
+ return this.dense.len()
33
+
34
+
35
+ public function is_empty() -> bool:
36
+ return this.dense.is_empty()
37
+
38
+
39
+ public function iter() -> Iter[T]:
40
+ let view = this.dense.as_span()
41
+ return Iter[T](data = view.data, index = 0, len = view.len)
42
+
43
+
44
+ public function get(key: ptr_uint) -> ptr[T]?:
45
+ if key >= this.sparse.len():
46
+ return null
47
+
48
+ let position = this.sparse.get(key) else:
49
+ fatal(c"sparse_set.SparseSet.get missing sparse storage")
50
+
51
+ unsafe:
52
+ let index = read(ptr[ptr_uint]<-position)
53
+ if index == SPARSE_EMPTY:
54
+ return null
55
+
56
+ return this.dense.get(index)
57
+
58
+
59
+ public function at(key: ptr_uint) -> Option[T]:
60
+ let p = this.get(key) else:
61
+ return Option[T].none
62
+
63
+ unsafe:
64
+ return Option[T].some(value = read(p))
65
+
66
+
67
+ public function contains(key: ptr_uint) -> bool:
68
+ return this.get(key) != null
69
+
70
+
71
+ public function key_at(dense_index: ptr_uint) -> ptr_uint:
72
+ let key_ptr = this.keys.get(dense_index) else:
73
+ fatal(c"sparse_set.SparseSet.key_at missing keys storage")
74
+
75
+ unsafe:
76
+ return read(ptr[ptr_uint]<-key_ptr)
77
+
78
+
79
+ public editable function clear() -> void:
80
+ this.sparse.clear()
81
+ this.dense.clear()
82
+ this.keys.clear()
83
+
84
+
85
+ public editable function release() -> void:
86
+ this.sparse.release()
87
+ this.dense.release()
88
+ this.keys.release()
89
+
90
+
91
+ public editable function reserve(min_capacity: ptr_uint) -> void:
92
+ this.dense.reserve(min_capacity)
93
+ this.keys.reserve(min_capacity)
94
+
95
+
96
+ public editable function shrink_to_fit() -> void:
97
+ this.sparse.shrink_to_fit()
98
+ this.dense.shrink_to_fit()
99
+ this.keys.shrink_to_fit()
100
+
101
+
102
+ public editable function insert(key: ptr_uint, value: T) -> bool:
103
+ while key >= this.sparse.len():
104
+ this.sparse.push(SPARSE_EMPTY)
105
+
106
+ let position = this.sparse.get(key) else:
107
+ fatal(c"sparse_set.SparseSet.insert missing sparse storage")
108
+
109
+ unsafe:
110
+ if read(ptr[ptr_uint]<-position) != SPARSE_EMPTY:
111
+ return false
112
+
113
+ let dense_index = this.dense.len()
114
+ this.dense.push(value)
115
+ this.keys.push(key)
116
+
117
+ unsafe:
118
+ read(ptr[ptr_uint]<-position) = dense_index
119
+
120
+ return true
121
+
122
+
123
+ public editable function remove(key: ptr_uint) -> bool:
124
+ if key >= this.sparse.len():
125
+ return false
126
+
127
+ let dense_index_ptr = this.sparse.get(key) else:
128
+ fatal(c"sparse_set.SparseSet.remove missing sparse storage")
129
+
130
+ unsafe:
131
+ let dense_index = read(ptr[ptr_uint]<-dense_index_ptr)
132
+ if dense_index == SPARSE_EMPTY:
133
+ return false
134
+
135
+ let last_index = this.dense.len() - 1
136
+ if dense_index != last_index:
137
+ let last_value = this.dense.get(last_index) else:
138
+ fatal(c"sparse_set.SparseSet.remove missing last dense value")
139
+ let dense_slot = this.dense.get(dense_index) else:
140
+ fatal(c"sparse_set.SparseSet.remove missing dense slot")
141
+ read(dense_slot) = read(last_value)
142
+
143
+ let last_key = this.keys.get(last_index) else:
144
+ fatal(c"sparse_set.SparseSet.remove missing last key")
145
+ let moved_key = read(ptr[ptr_uint]<-last_key)
146
+
147
+ let key_slot = this.keys.get(dense_index) else:
148
+ fatal(c"sparse_set.SparseSet.remove missing key slot")
149
+ read(ptr[ptr_uint]<-key_slot) = moved_key
150
+
151
+ let moved_sparse_ptr = this.sparse.get(moved_key) else:
152
+ fatal(c"sparse_set.SparseSet.remove missing sparse entry for moved key")
153
+ read(ptr[ptr_uint]<-moved_sparse_ptr) = dense_index
154
+
155
+ this.dense.pop()
156
+ this.keys.pop()
157
+ read(ptr[ptr_uint]<-dense_index_ptr) = SPARSE_EMPTY
158
+
159
+ return true
160
+
161
+
162
+ extending Iter[T]:
163
+ public function iter() -> Iter[T]:
164
+ return this
165
+
166
+
167
+ public editable function next() -> ptr[T]?:
168
+ if this.index >= this.len:
169
+ return null
170
+
171
+ let data = this.data else:
172
+ fatal(c"sparse_set.Iter.next missing storage")
173
+
174
+ let current_index = this.index
175
+ this.index += 1
176
+ return unsafe: ptr[T]<-data + current_index
data/std/spatial.mt CHANGED
@@ -9,7 +9,53 @@ public struct SpatialGrid[T]:
9
9
  origin_y: float
10
10
 
11
11
 
12
+ function cell_index[T](grid: ref[SpatialGrid[T]], x: float, y: float) -> Option[ptr_uint]:
13
+ let cx = int<-(float<-((x - grid.origin_x) / grid.cell_size))
14
+ let cy = int<-(float<-((y - grid.origin_y) / grid.cell_size))
15
+ if cx < 0 or cy < 0 or uint<-cx >= grid.cols or uint<-cy >= grid.rows:
16
+ return Option[ptr_uint].none()
17
+ return Option[ptr_uint].some(value = ptr_uint<-cx + ptr_uint<-cy * ptr_uint<-grid.cols)
18
+
19
+
12
20
  extending SpatialGrid[T]:
21
+ public static function create(cell_size: float, width: float, height: float) -> SpatialGrid[T]:
22
+ var cols: uint = uint<-(float<-width / cell_size)
23
+ var rows: uint = uint<-(float<-height / cell_size)
24
+ if cols == 0:
25
+ cols = 1
26
+ if rows == 0:
27
+ rows = 1
28
+
29
+ var cells = vec.Vec[vec.Vec[T]].create()
30
+ var total: ptr_uint = ptr_uint<-cols * ptr_uint<-rows
31
+ var i: ptr_uint = 0
32
+ while i < total:
33
+ cells.push(vec.Vec[T].create())
34
+ i += 1
35
+
36
+ return SpatialGrid[T](
37
+ cells = cells,
38
+ cell_size = cell_size,
39
+ cols = cols,
40
+ rows = rows,
41
+ origin_x = 0.0,
42
+ origin_y = 0.0
43
+ )
44
+
45
+
46
+ public static function with_origin(
47
+ cell_size: float,
48
+ width: float,
49
+ height: float,
50
+ origin_x: float,
51
+ origin_y: float
52
+ ) -> SpatialGrid[T]:
53
+ var grid = SpatialGrid[T].create(cell_size, width, height)
54
+ grid.origin_x = origin_x
55
+ grid.origin_y = origin_y
56
+ return grid
57
+
58
+
13
59
  public editable function release() -> void:
14
60
  var i: ptr_uint = 0
15
61
  while i < this.cells.len():
@@ -20,53 +66,6 @@ extending SpatialGrid[T]:
20
66
  this.cells.release()
21
67
 
22
68
 
23
- function cell_index[T](grid: ref[SpatialGrid[T]], x: float, y: float) -> Option[ptr_uint]:
24
- let cx = int<-(float<-((x - grid.origin_x) / grid.cell_size))
25
- let cy = int<-(float<-((y - grid.origin_y) / grid.cell_size))
26
- if cx < 0 or cy < 0 or uint<-cx >= grid.cols or uint<-cy >= grid.rows:
27
- return Option[ptr_uint].none()
28
- return Option[ptr_uint].some(value = ptr_uint<-cx + ptr_uint<-cy * ptr_uint<-grid.cols)
29
-
30
-
31
- public function new[T](cell_size: float, width: float, height: float) -> SpatialGrid[T]:
32
- var cols: uint = uint<-(float<-width / cell_size)
33
- var rows: uint = uint<-(float<-height / cell_size)
34
- if cols == 0:
35
- cols = 1
36
- if rows == 0:
37
- rows = 1
38
-
39
- var cells = vec.Vec[vec.Vec[T]].create()
40
- var total: ptr_uint = ptr_uint<-cols * ptr_uint<-rows
41
- var i: ptr_uint = 0
42
- while i < total:
43
- cells.push(vec.Vec[T].create())
44
- i += 1
45
-
46
- return SpatialGrid[T](
47
- cells = cells,
48
- cell_size = cell_size,
49
- cols = cols,
50
- rows = rows,
51
- origin_x = 0.0,
52
- origin_y = 0.0
53
- )
54
-
55
-
56
- public function new_with_origin[T](
57
- cell_size: float,
58
- width: float,
59
- height: float,
60
- origin_x: float,
61
- origin_y: float
62
- ) -> SpatialGrid[T]:
63
- var grid = new[T](cell_size, width, height)
64
- grid.origin_x = origin_x
65
- grid.origin_y = origin_y
66
- return grid
67
-
68
-
69
- extending SpatialGrid[T]:
70
69
  public editable function insert(entity: T, x: float, y: float) -> void:
71
70
  let idx_opt = cell_index(ref_of(this), x, y)
72
71
  match idx_opt:
data/std/stack.mt CHANGED
@@ -47,6 +47,10 @@ extending Stack[T]:
47
47
  this.values.reserve(min_capacity)
48
48
 
49
49
 
50
+ public editable function shrink_to_fit() -> void:
51
+ this.values.shrink_to_fit()
52
+
53
+
50
54
  public editable function push(value: T) -> void:
51
55
  this.values.push_back(value)
52
56
 
data/std/string.mt CHANGED
@@ -133,6 +133,26 @@ extending String:
133
133
  this.capacity = new_capacity
134
134
 
135
135
 
136
+ public editable function shrink_to_fit() -> void:
137
+ if not this.owns_storage:
138
+ return
139
+
140
+ if this.len == 0:
141
+ heap.release(this.data)
142
+ this.data = null
143
+ this.capacity = 0
144
+ return
145
+
146
+ if this.len == this.capacity:
147
+ return
148
+
149
+ let resized = heap.resize[ubyte](this.data, this.len) else:
150
+ fatal(c"string.shrink_to_fit out of memory")
151
+
152
+ this.data = resized
153
+ this.capacity = this.len
154
+
155
+
136
156
  public editable function push_byte(value: ubyte) -> void:
137
157
  if this.len == this.capacity:
138
158
  this.reserve(this.len + 1)
data/std/toml.mt CHANGED
@@ -1214,7 +1214,7 @@ function append_value(output: ref[string.String], value: Value) -> void:
1214
1214
  let item = values.values.get(index) else:
1215
1215
  fatal(c"toml.append_value missing array item")
1216
1216
 
1217
- append_value(output, unsafe: read(item))
1217
+ append_value(output, read(item))
1218
1218
  index += 1
1219
1219
 
1220
1220
  output.push_byte(byte_right_bracket)
@@ -1233,7 +1233,7 @@ function append_value(output: ref[string.String], value: Value) -> void:
1233
1233
  let entry = object_entries.entries.get(index) else:
1234
1234
  fatal(c"toml.append_value missing object entry")
1235
1235
 
1236
- let current = unsafe: read(entry)
1236
+ let current = read(entry)
1237
1237
  append_entry_key(output, current.key.as_str())
1238
1238
  output.append(" = ")
1239
1239
  append_value(output, current.value)
data/std/vec.mt CHANGED
@@ -117,6 +117,23 @@ extending Vec[T]:
117
117
  this.capacity = new_capacity
118
118
 
119
119
 
120
+ public editable function shrink_to_fit() -> void:
121
+ if this.len == 0:
122
+ heap.release(this.data)
123
+ this.data = null
124
+ this.capacity = 0
125
+ return
126
+
127
+ if this.len == this.capacity:
128
+ return
129
+
130
+ let resized = heap.resize[T](this.data, this.len) else:
131
+ fatal(c"vec.shrink_to_fit out of memory")
132
+
133
+ this.data = resized
134
+ this.capacity = this.len
135
+
136
+
120
137
  public editable function append_span(values: span[T]) -> void:
121
138
  if values.len == 0:
122
139
  return
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mt-lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.17
4
+ version: 0.2.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Long (Teefan) Tran
@@ -498,6 +498,7 @@ files:
498
498
  - std/linked_map_view.mt
499
499
  - std/linked_set.mt
500
500
  - std/log.mt
501
+ - std/lru_cache.mt
501
502
  - std/map.mt
502
503
  - std/math.mt
503
504
  - std/mem/arena.mt
@@ -543,6 +544,7 @@ files:
543
544
  - std/raylib/tracy_gpu.mt
544
545
  - std/raymath.mt
545
546
  - std/result.mt
547
+ - std/ring_buffer.mt
546
548
  - std/rlgl.mt
547
549
  - std/rpng.mt
548
550
  - std/rres.mt
@@ -550,6 +552,7 @@ files:
550
552
  - std/sdl3/runtime.mt
551
553
  - std/serialize.mt
552
554
  - std/set.mt
555
+ - std/sparse_set.mt
553
556
  - std/spatial.mt
554
557
  - std/sqlite3.mt
555
558
  - std/stack.mt
@@ -583,7 +586,7 @@ metadata:
583
586
  homepage_uri: https://teefan.github.io/mt-lang/
584
587
  source_code_uri: https://github.com/teefan/mt-lang
585
588
  post_install_message: |
586
- Milk Tea 0.2.17 installed!
589
+ Milk Tea 0.2.19 installed!
587
590
 
588
591
  System requirements:
589
592
  - A C compiler (gcc or clang) must be available on PATH