| ... | @@ -96,6 +96,7 @@ pub const WindowsBlock = struct { | ... | @@ -96,6 +96,7 @@ pub const WindowsBlock = struct { |
| 96 | } | 96 | } |
| 97 | }; | 97 | }; |
| 98 | | 98 | |
| | 99 | /// Each key and each value are allocated independently and owned by this data structure. |
| 99 | pub const Map = struct { | 100 | pub const Map = struct { |
| 100 | array_hash_map: ArrayHashMap, | 101 | array_hash_map: ArrayHashMap, |
| 101 | allocator: Allocator, | 102 | allocator: Allocator, |
| ... | @@ -340,9 +341,6 @@ pub const Map = struct { | ... | @@ -340,9 +341,6 @@ pub const Map = struct { |
| 340 | /// Returns a full copy of `em` allocated with `gpa`, which is not necessarily | 341 | /// Returns a full copy of `em` allocated with `gpa`, which is not necessarily |
| 341 | /// the same allocator used to allocate `em`. | 342 | /// the same allocator used to allocate `em`. |
| 342 | pub fn clone(m: *const Map, gpa: Allocator) Allocator.Error!Map { | 343 | pub fn clone(m: *const Map, gpa: Allocator) Allocator.Error!Map { |
| 343 | // Since we need to dupe the keys and values, the only way for error handling to not be a | | |
| 344 | // nightmare is to add keys to an empty map one-by-one. This could be avoided if this | | |
| 345 | // abstraction were a bit less... OOP-esque. | | |
| 346 | var new: Map = .init(gpa); | 344 | var new: Map = .init(gpa); |
| 347 | errdefer new.deinit(); | 345 | errdefer new.deinit(); |
| 348 | try new.array_hash_map.ensureUnusedCapacity(gpa, m.array_hash_map.count()); | 346 | try new.array_hash_map.ensureUnusedCapacity(gpa, m.array_hash_map.count()); |
| ... | @@ -352,6 +350,32 @@ pub const Map = struct { | ... | @@ -352,6 +350,32 @@ pub const Map = struct { |
| 352 | return new; | 350 | return new; |
| 353 | } | 351 | } |
| 354 | | 352 | |
| | 353 | /// Adds all the key-value pairs from `other` into this `m`. |
| | 354 | pub fn putAll(m: *Map, other: *const Map) Allocator.Error!void { |
| | 355 | const gpa = m.allocator; |
| | 356 | try m.array_hash_map.ensureUnusedCapacity(gpa, other.array_hash_map.count()); |
| | 357 | const start = m.count(); |
| | 358 | errdefer while (m.array_hash_map.count() > start) { |
| | 359 | const kv = m.array_hash_map.pop().?; |
| | 360 | gpa.free(kv.key); |
| | 361 | gpa.free(kv.value); |
| | 362 | }; |
| | 363 | for (other.array_hash_map.keys(), other.array_hash_map.values()) |key, value| { |
| | 364 | try m.put(key, value); |
| | 365 | } |
| | 366 | } |
| | 367 | |
| | 368 | /// Set the length to zero, freeing all key and value memory, not freeing |
| | 369 | /// the allocation for the entries. |
| | 370 | pub fn clearRetainingCapacity(m: *Map) void { |
| | 371 | const gpa = m.allocator; |
| | 372 | for (m.array_hash_map.keys(), m.array_hash_map.values()) |k, v| { |
| | 373 | gpa.free(k); |
| | 374 | gpa.free(v); |
| | 375 | } |
| | 376 | m.array_hash_map.clearRetainingCapacity(); |
| | 377 | } |
| | 378 | |
| 355 | /// Creates a null-delimited environment variable block in the format | 379 | /// Creates a null-delimited environment variable block in the format |
| 356 | /// expected by POSIX, from a hash map plus options. | 380 | /// expected by POSIX, from a hash map plus options. |
| 357 | pub fn createPosixBlock( | 381 | pub fn createPosixBlock( |