@@ -9,8 +9,9 @@ const type_root = @import("../type/root.zig");
99const itemsPerChunk = type_root .itemsPerChunk ;
1010const chunkDepth = type_root .chunkDepth ;
1111
12- const BaseTreeView = @import ("root.zig" ).BaseTreeView ;
1312const BasicPackedChunks = @import ("chunks.zig" ).BasicPackedChunks ;
13+ const assertTreeViewType = @import ("utils/assert.zig" ).assertTreeViewType ;
14+ const CloneOpts = @import ("utils/clone_opts.zig" ).CloneOpts ;
1415
1516/// A specialized tree view for SSZ vector types with basic element types.
1617/// Elements are packed into chunks (multiple elements per leaf node).
@@ -24,8 +25,9 @@ pub fn ArrayBasicTreeView(comptime ST: type) type {
2425 }
2526 }
2627
27- return struct {
28- base_view : BaseTreeView ,
28+ const TreeView = struct {
29+ allocator : Allocator ,
30+ chunks : Chunks ,
2931
3032 pub const SszType = ST ;
3133 pub const Element = ST .Element .Type ;
@@ -38,69 +40,96 @@ pub fn ArrayBasicTreeView(comptime ST: type) type {
3840 const items_per_chunk : usize = itemsPerChunk (ST .Element );
3941 const Chunks = BasicPackedChunks (ST , chunk_depth , items_per_chunk );
4042
41- pub fn init (allocator : Allocator , pool : * Node.Pool , root : Node.Id ) ! Self {
42- return Self {
43- .base_view = try BaseTreeView .init (allocator , pool , root ),
44- };
43+ pub fn init (allocator : Allocator , pool : * Node.Pool , root : Node.Id ) ! * Self {
44+ const ptr = try allocator .create (Self );
45+ errdefer allocator .destroy (ptr );
46+
47+ try Chunks .init (& ptr .chunks , allocator , pool , root );
48+ ptr .allocator = allocator ;
49+ return ptr ;
4550 }
4651
47- pub fn clone (self : * Self , opts : BaseTreeView.CloneOpts ) ! Self {
48- return Self { .base_view = try self .base_view .clone (opts ) };
52+ pub fn clone (self : * Self , opts : CloneOpts ) ! * Self {
53+ const ptr = try self .allocator .create (Self );
54+ errdefer self .allocator .destroy (ptr );
55+
56+ try Chunks .clone (& self .chunks , opts , & ptr .chunks );
57+ ptr .allocator = self .allocator ;
58+ return ptr ;
4959 }
5060
5161 pub fn deinit (self : * Self ) void {
52- self .base_view .deinit ();
62+ self .chunks .deinit ();
63+ self .allocator .destroy (self );
5364 }
5465
5566 pub fn commit (self : * Self ) ! void {
56- try self .base_view .commit ();
67+ try self .chunks .commit ();
5768 }
5869
5970 pub fn clearCache (self : * Self ) void {
60- self .base_view .clearCache ();
71+ self .chunks .clearCache ();
72+ }
73+
74+ pub fn hashTreeRootInto (self : * Self , out : * [32 ]u8 ) ! void {
75+ try self .commit ();
76+ out .* = self .chunks .state .root .getRoot (self .chunks .state .pool ).* ;
6177 }
6278
63- /// Return the root hash of the tree.
64- /// The returned array is owned by the internal pool and must not be modified.
6579 pub fn hashTreeRoot (self : * Self ) ! * const [32 ]u8 {
66- return try self .base_view .hashTreeRoot ();
80+ try self .commit ();
81+ return self .chunks .state .root .getRoot (self .chunks .state .pool );
82+ }
83+
84+ pub fn fromValue (allocator : Allocator , pool : * Node.Pool , value : * const ST.Type ) ! * Self {
85+ const root = try ST .tree .fromValue (pool , value );
86+ errdefer pool .unref (root );
87+ return try Self .init (allocator , pool , root );
88+ }
89+
90+ pub fn toValue (self : * Self , _ : Allocator , out : * ST.Type ) ! void {
91+ try self .commit ();
92+ try ST .tree .toValue (self .chunks .state .root , self .chunks .state .pool , out );
93+ }
94+
95+ pub fn getRoot (self : * const Self ) Node.Id {
96+ return self .chunks .state .root ;
6797 }
6898
6999 pub fn get (self : * Self , index : usize ) ! Element {
70100 if (index >= length ) return error .IndexOutOfBounds ;
71- return try Chunks . get (& self . base_view , index );
101+ return self . chunks . get (index );
72102 }
73103
74104 pub fn set (self : * Self , index : usize , value : Element ) ! void {
75105 if (index >= length ) return error .IndexOutOfBounds ;
76- try Chunks . set (& self . base_view , index , value );
106+ try self . chunks . set (index , value );
77107 }
78108
109+ /// Caller is responsible for freeing the returned slice using the same allocator.
79110 pub fn getAll (self : * Self , allocator : Allocator ) ! []Element {
80- return try Chunks . getAll (& self . base_view , allocator , length );
111+ return try self . chunks . getAll (allocator , length );
81112 }
82113
83114 pub fn getAllInto (self : * Self , values : []Element ) ! []Element {
84- return try Chunks . getAllInto (& self . base_view , length , values );
115+ return try self . chunks . getAllInto (length , values );
85116 }
86117
87118 /// Serialize the tree view into a provided buffer.
88119 /// Returns the number of bytes written.
89120 pub fn serializeIntoBytes (self : * Self , out : []u8 ) ! usize {
90121 try self .commit ();
91- return try ST .tree .serializeIntoBytes (self .base_view . data .root , self .base_view .pool , out );
122+ return try ST .tree .serializeIntoBytes (self .chunks . state .root , self .chunks . state .pool , out );
92123 }
93124
94125 /// Get the serialized size of this tree view.
95126 pub fn serializedSize (_ : * Self ) usize {
96127 return ST .fixed_size ;
97128 }
98-
99- pub fn toValue (self : * Self , _ : Allocator , out : * ST.Type ) ! void {
100- try self .commit ();
101- try ST .tree .toValue (self .base_view .data .root , self .base_view .pool , out );
102- }
103129 };
130+
131+ assertTreeViewType (TreeView );
132+ return TreeView ;
104133}
105134
106135const UintType = @import ("../type/uint.zig" ).UintType ;
@@ -135,12 +164,13 @@ test "TreeView vector element roundtrip" {
135164 var expected_root : [32 ]u8 = undefined ;
136165 try VectorType .hashTreeRoot (& expected , & expected_root );
137166
138- const actual_root = try view .hashTreeRoot ();
167+ var actual_root : [32 ]u8 = undefined ;
168+ try view .hashTreeRootInto (& actual_root );
139169
140- try std .testing .expectEqualSlices (u8 , & expected_root , actual_root );
170+ try std .testing .expectEqualSlices (u8 , & expected_root , & actual_root );
141171
142172 var roundtrip : VectorType.Type = undefined ;
143- try VectorType .tree .toValue (view .base_view . data . root , & pool , & roundtrip );
173+ try VectorType .tree .toValue (view .getRoot () , & pool , & roundtrip );
144174 try std .testing .expectEqualSlices (u64 , & expected , & roundtrip );
145175}
146176
@@ -208,7 +238,6 @@ test "TreeView vector getAllAlloc repeat reflects updates" {
208238
209239 try view .set (3 , 99 );
210240
211- try view .commit ();
212241 const second = try view .getAll (allocator );
213242 defer allocator .free (second );
214243 values [3 ] = 99 ;
@@ -301,13 +330,13 @@ test "TreeView vector clone(true) does not transfer cache" {
301330 defer v .deinit ();
302331
303332 _ = try v .get (0 );
304- try std .testing .expect (v .base_view . data .children_nodes .count () > 0 );
333+ try std .testing .expect (v .chunks . state .children_nodes .count () > 0 );
305334
306335 var cloned_no_cache = try v .clone (.{ .transfer_cache = false });
307336 defer cloned_no_cache .deinit ();
308337
309- try std .testing .expect (v .base_view . data .children_nodes .count () > 0 );
310- try std .testing .expectEqual (@as (usize , 0 ), cloned_no_cache .base_view . data .children_nodes .count ());
338+ try std .testing .expect (v .chunks . state .children_nodes .count () > 0 );
339+ try std .testing .expectEqual (@as (usize , 0 ), cloned_no_cache .chunks . state .children_nodes .count ());
311340}
312341
313342test "TreeView vector clone(false) transfers cache and clears source" {
@@ -325,13 +354,13 @@ test "TreeView vector clone(false) transfers cache and clears source" {
325354 defer v .deinit ();
326355
327356 _ = try v .get (0 );
328- try std .testing .expect (v .base_view . data .children_nodes .count () > 0 );
357+ try std .testing .expect (v .chunks . state .children_nodes .count () > 0 );
329358
330359 var cloned = try v .clone (.{});
331360 defer cloned .deinit ();
332361
333- try std .testing .expectEqual (@as (usize , 0 ), v .base_view . data .children_nodes .count ());
334- try std .testing .expect (cloned .base_view . data .children_nodes .count () > 0 );
362+ try std .testing .expectEqual (@as (usize , 0 ), v .chunks . state .children_nodes .count ());
363+ try std .testing .expect (cloned .chunks . state .children_nodes .count () > 0 );
335364}
336365
337366// Tests ported from TypeScript ssz packages/ssz/test/unit/byType/vector/tree.test.ts
@@ -382,8 +411,9 @@ test "ArrayBasicTreeView - serialize (uint64 vector)" {
382411 const view_size = view .serializedSize ();
383412 try std .testing .expectEqual (tc .expected_serialized .len , view_size );
384413
385- const hash_root = try view .hashTreeRoot ();
386- try std .testing .expectEqualSlices (u8 , & tc .expected_root , hash_root );
414+ var hash_root : [32 ]u8 = undefined ;
415+ try view .hashTreeRootInto (& hash_root );
416+ try std .testing .expectEqualSlices (u8 , & tc .expected_root , & hash_root );
387417 }
388418}
389419
0 commit comments