3 #include "gvariant-vectors.h"
4 #include "gtestutils.h"
7 append_zeros (GByteArray *array,
12 g_byte_array_append (array, zeros, n);
16 g_variant_vectors_init (GVariantVectors *vectors)
19 /* The first 8 bytes of 'extra_bytes' is always 0. We use this for
20 * inserting padding in between two GBytes records.
22 vectors->extra_bytes = g_byte_array_new ();
23 append_zeros (vectors->extra_bytes, 8);
25 vectors->vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
27 vectors->offsets = g_byte_array_new ();
31 g_variant_vectors_append_pad (GVariantVectors *vectors,
34 /* If the last vector that we stored was 'pad' or 'copy' then we will
35 * expand it instead of adding a new one.
37 if (vectors->vectors->len)
39 GVariantVector *expand_vector = &g_array_index (vectors->vectors, GVariantVector, vectors->vectors->len - 1);
41 if (expand_vector->gbytes == NULL)
43 expand_vector->size += padding;
45 /* If the vector points to data, we need to add the padding to
46 * the end of that data. If it points to the zero bytes at
47 * the start then we can just grow it (but we must ensure that
48 * it doesn't get too large).
50 if (expand_vector->data.offset)
51 append_zeros (vectors->extra_bytes, padding);
53 g_assert (expand_vector->size < 8);
58 /* If the last vector was a GBytes then fall through */
61 /* Otherwise, record a new vector pointing to the padding bytes at the
71 g_array_append_val (vectors->vectors, v);
78 g_variant_vectors_append_copy (GVariantVectors *vectors,
82 /* If the last vector that we stored was 'pad' or 'copy' then we will
83 * expand it instead of adding a new one.
85 if (vectors->vectors->len)
87 GVariantVector *expand_vector = &g_array_index (vectors->vectors, GVariantVector, vectors->vectors->len - 1);
89 if (expand_vector->gbytes == NULL)
91 /* If this was a padding vector then we must convert it to
94 if (expand_vector->data.offset == 0)
96 expand_vector->data.offset = vectors->extra_bytes->len;
97 append_zeros (vectors->extra_bytes, expand_vector->size);
100 /* We have a vector pointing to data at the end of the
101 * extra_bytes array, so just append there and grow the
104 g_byte_array_append (vectors->extra_bytes, data, size);
105 expand_vector->size += size;
109 /* If the last vector was a GBytes then fall through */
112 /* Otherwise, copy the data and record a new vector. */
117 v.data.offset = vectors->extra_bytes->len;
120 g_byte_array_append (vectors->extra_bytes, data, size);
121 g_array_append_val (vectors->vectors, v);
126 g_variant_vectors_append_gbytes (GVariantVectors *vectors,
133 /* Some very rough profiling has indicated that the trade-off for
134 * overhead on the atomic operations involved in the ref/unref on the
135 * GBytes is larger than the cost of the copy at ~128 bytes.
139 g_variant_vectors_append_copy (vectors, data, size);
143 v.gbytes = g_bytes_ref (gbytes);
144 v.data.pointer = data;
147 g_array_append_val (vectors->vectors, v);
150 typedef void (* WriteFunction) (gpointer base, gsize offset, gsize value);
151 static void write_1 (gpointer base, gsize offset, gsize value) { ((guint8 *) base)[offset] = value; }
152 static void write_2 (gpointer base, gsize offset, gsize value) { ((guint16 *) base)[offset] = GUINT16_TO_LE (value); }
153 static void write_4 (gpointer base, gsize offset, gsize value) { ((guint32 *) base)[offset] = GUINT32_TO_LE (value); }
154 static void write_8 (gpointer base, gsize offset, gsize value) { ((guint64 *) base)[offset] = GUINT64_TO_LE (value); }
163 g_variant_vectors_reserve_offsets (GVariantVectors *vectors,
167 OffsetsHeader *header;
172 total_size = n_offsets * offset_size;
174 /* Add room for the metadata and round up to multiple of 8 */
175 add_size = (sizeof (OffsetsHeader) + total_size + 7) & ~7ull;
176 key = vectors->offsets->len;
177 g_byte_array_set_size (vectors->offsets, key + add_size);
178 header = (OffsetsHeader *) (vectors->offsets->data + key);
179 key += sizeof (OffsetsHeader);
180 header->size = total_size;
185 header->func = write_1;
189 header->func = write_2;
193 header->func = write_4;
197 header->func = write_8;
201 g_assert_not_reached ();
208 g_variant_vectors_write_to_offsets (GVariantVectors *vectors,
213 OffsetsHeader *header;
216 offsets = vectors->offsets->data + key;
217 header = (OffsetsHeader *) (offsets - sizeof (OffsetsHeader));
219 header->func (offsets, offset, value);
223 g_variant_vectors_commit_offsets (GVariantVectors *vectors,
226 OffsetsHeader *header;
229 offsets = vectors->offsets->data + key;
230 header = (OffsetsHeader *) (offsets - sizeof (OffsetsHeader));
232 g_variant_vectors_append_copy (vectors, offsets, header->size);
233 g_byte_array_set_size (vectors->offsets, key - sizeof (OffsetsHeader));