@@ -32,11 +32,24 @@ MemRef Node::create_node(size_t size, Allocator& alloc, bool context_flag, Type
3232 size_t byte_size = std::max (byte_size_0, size_t (initial_capacity));
3333
3434 MemRef mem = alloc.alloc (byte_size); // Throws
35- char * header = mem.get_addr ();
36-
37- init_header (header, type == type_InnerBptreeNode, type != type_Normal, context_flag, width_type, width, size,
38- byte_size);
39-
35+ const auto header = mem.get_addr ();
36+ REALM_ASSERT_DEBUG (width_type != WidthType::wtype_Extend);
37+ Encoding encoding{static_cast <int >(width_type)};
38+
39+ uint8_t flags = 0 ;
40+ if (type == type_InnerBptreeNode)
41+ flags |= static_cast <uint8_t >(Flags::InnerBPTree) | static_cast <uint8_t >(Flags::HasRefs);
42+ if (type != type_Normal)
43+ flags |= static_cast <uint8_t >(Flags::HasRefs);
44+ if (context_flag)
45+ flags |= static_cast <uint8_t >(Flags::Context);
46+ // width must be passed to init_header in bits, but for wtype_Multiply and wtype_Ignore
47+ // it is provided by the caller of this function in bytes, so convert to bits
48+ if (width_type != wtype_Bits)
49+ width = width * 8 ;
50+
51+ init_header (header, encoding, flags, width, size);
52+ set_capacity_in_header (byte_size, header);
4053 return mem;
4154}
4255
@@ -69,17 +82,20 @@ size_t Node::calc_item_count(size_t bytes, size_t width) const noexcept
6982void Node::alloc (size_t init_size, size_t new_width)
7083{
7184 REALM_ASSERT (is_attached ());
72-
85+ char * header = get_header_from_data (m_data);
86+ REALM_ASSERT (!wtype_is_extended (header));
7387 size_t needed_bytes = calc_byte_len (init_size, new_width);
7488 // this method is not public and callers must (and currently do) ensure that
7589 // needed_bytes are never larger than max_array_payload.
7690 REALM_ASSERT_RELEASE (init_size <= max_array_size);
7791
78- if (is_read_only ())
92+ if (is_read_only ()) {
7993 do_copy_on_write (needed_bytes);
94+ // header has changed after copy on write if the array was compressed
95+ header = get_header_from_data (m_data);
96+ }
8097
8198 REALM_ASSERT (!m_alloc.is_read_only (m_ref));
82- char * header = get_header_from_data (m_data);
8399 size_t orig_capacity_bytes = get_capacity_from_header (header);
84100 size_t orig_width = get_width_from_header (header);
85101
@@ -114,18 +130,28 @@ void Node::alloc(size_t init_size, size_t new_width)
114130 // this array instance in a corrupt state
115131 update_parent (); // Throws
116132 }
117-
118- // Update header
133+ // update width (important when we convert from normal uncompressed array into compressed format)
119134 if (new_width != orig_width) {
120135 set_width_in_header (int (new_width), header);
121136 }
122137 set_size_in_header (init_size, header);
123138 m_size = init_size;
124139}
125140
141+ void Node::destroy () noexcept
142+ {
143+ if (!is_attached ())
144+ return ;
145+ char * header = get_header_from_data (m_data);
146+ m_alloc.free_ (m_ref, header);
147+ m_data = nullptr ;
148+ }
149+
126150void Node::do_copy_on_write (size_t minimum_size)
127151{
128152 const char * header = get_header_from_data (m_data);
153+ // only type A arrays should be allowed during copy on write
154+ REALM_ASSERT (!wtype_is_extended (header));
129155
130156 // Calculate size in bytes
131157 size_t array_size = calc_byte_size (get_wtype_from_header (header), m_size, get_width_from_header (header));
@@ -140,7 +166,6 @@ void Node::do_copy_on_write(size_t minimum_size)
140166 const char * old_end = header + array_size;
141167 char * new_begin = mref.get_addr ();
142168 realm::safe_copy_n (old_begin, old_end - old_begin, new_begin);
143-
144169 ref_type old_ref = m_ref;
145170
146171 // Update internal data
@@ -150,7 +175,6 @@ void Node::do_copy_on_write(size_t minimum_size)
150175 // Update capacity in header. Uses m_data to find header, so
151176 // m_data must be initialized correctly first.
152177 set_capacity_in_header (new_size, new_begin);
153-
154178 update_parent ();
155179
156180#if REALM_ENABLE_MEMDEBUG
0 commit comments