Coverage Report

Created: 2025-08-29 06:48

/src/libxmlb/src/xb-stack.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2018 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "XbMachine"
8
9
#include "config.h"
10
11
#include <gio/gio.h>
12
13
#include "xb-opcode-private.h"
14
#include "xb-stack-private.h"
15
16
/**
17
 * xb_stack_unref:
18
 * @self: a #XbStack
19
 *
20
 * Decrements the reference count of the stack, freeing the object when the
21
 * refcount drops to zero.
22
 *
23
 * Since: 0.1.3
24
 **/
25
void
26
xb_stack_unref(XbStack *self)
27
0
{
28
0
  g_assert(self->ref > 0);
29
0
  if (G_UNLIKELY(--self->ref > 0))
30
0
    return;
31
0
  for (guint i = 0; i < self->pos; i++)
32
0
    xb_opcode_clear(&self->opcodes[i]);
33
0
  if (!self->stack_allocated)
34
0
    g_free(self);
35
0
}
36
37
/**
38
 * xb_stack_ref:
39
 * @self: a #XbStack
40
 *
41
 * Increments the refcount of the stack.
42
 *
43
 * Returns: (transfer none): the original @self #XbStack instance
44
 *
45
 * Since: 0.1.3
46
 **/
47
XbStack *
48
xb_stack_ref(XbStack *self)
49
0
{
50
0
  self->ref++;
51
0
  return self;
52
0
}
53
54
/**
55
 * xb_stack_pop:
56
 * @self: a #XbStack
57
 * @opcode_out: (out caller-allocates) (optional): return location for the popped #XbOpcode
58
 * @error: a #GError, or %NULL
59
 *
60
 * Pops an opcode off the stack.
61
 *
62
 * Returns: %TRUE if popping succeeded, %FALSE if the stack was empty already
63
 *
64
 * Since: 0.2.0
65
 **/
66
gboolean
67
xb_stack_pop(XbStack *self, XbOpcode *opcode_out, GError **error)
68
0
{
69
0
  if (G_UNLIKELY(self->pos == 0)) {
70
0
    g_set_error(error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "stack is empty");
71
0
    return FALSE;
72
0
  }
73
0
  self->pos--;
74
0
  if (opcode_out != NULL)
75
0
    *opcode_out = self->opcodes[self->pos];
76
0
  return TRUE;
77
0
}
78
79
/**
80
 * xb_stack_pop_two: (skip):
81
 **/
82
gboolean
83
xb_stack_pop_two(XbStack *self, XbOpcode *opcode1_out, XbOpcode *opcode2_out, GError **error)
84
0
{
85
0
  if (G_UNLIKELY(self->pos < 2)) {
86
0
    g_set_error_literal(error,
87
0
            G_IO_ERROR,
88
0
            G_IO_ERROR_INVALID_DATA,
89
0
            "stack is not full enough");
90
0
    return FALSE;
91
0
  }
92
0
  if (opcode1_out != NULL)
93
0
    *opcode1_out = self->opcodes[self->pos - 1];
94
0
  if (opcode2_out != NULL)
95
0
    *opcode2_out = self->opcodes[self->pos - 2];
96
0
  self->pos -= 2;
97
0
  return TRUE;
98
0
}
99
100
/**
101
 * xb_stack_peek:
102
 * @self: a #XbStack
103
 * @idx: index
104
 *
105
 * Peeks an opcode from the stack.
106
 *
107
 * Returns: (transfer none): a #XbOpcode
108
 *
109
 * Since: 0.1.3
110
 **/
111
XbOpcode *
112
xb_stack_peek(XbStack *self, guint idx)
113
0
{
114
0
  if (G_UNLIKELY(idx >= self->pos))
115
0
    return NULL;
116
0
  return &self->opcodes[idx];
117
0
}
118
119
/* private */
120
gboolean
121
xb_stack_push_bool(XbStack *self, gboolean val, GError **error)
122
0
{
123
0
  XbOpcode *op;
124
0
  if (!xb_stack_push(self, &op, error))
125
0
    return FALSE;
126
0
  xb_opcode_bool_init(op, val);
127
0
  return TRUE;
128
0
}
129
130
/* private */
131
XbOpcode *
132
xb_stack_peek_head(XbStack *self)
133
0
{
134
0
  if (self->pos == 0)
135
0
    return NULL;
136
0
  return &self->opcodes[0];
137
0
}
138
139
/* private */
140
XbOpcode *
141
xb_stack_peek_tail(XbStack *self)
142
0
{
143
0
  if (self->pos == 0)
144
0
    return NULL;
145
0
  return &self->opcodes[self->pos - 1];
146
0
}
147
148
/**
149
 * xb_stack_push:
150
 * @self: a #XbStack
151
 * @opcode_out: (out) (nullable): return location for the new #XbOpcode
152
 * @error: a #GError, or %NULL
153
 *
154
 * Pushes a new empty opcode onto the end of the stack. A pointer to the opcode
155
 * is returned in @opcode_out so that the caller can initialise it. This must be
156
 * done before the stack is next used as, for performance reasons, the newly
157
 * pushed opcode is not zero-initialised.
158
 *
159
 * Returns: %TRUE if a new empty opcode was returned, or %FALSE if the stack has
160
 *    reached its maximum size
161
 * Since: 0.2.0
162
 **/
163
gboolean
164
xb_stack_push(XbStack *self, XbOpcode **opcode_out, GError **error)
165
0
{
166
0
  if (G_UNLIKELY(self->pos >= self->max_size)) {
167
0
    *opcode_out = NULL;
168
0
    g_set_error(error,
169
0
          G_IO_ERROR,
170
0
          G_IO_ERROR_NO_SPACE,
171
0
          "stack is already at maximum size of %u",
172
0
          self->max_size);
173
0
    return FALSE;
174
0
  }
175
176
0
  *opcode_out = &self->opcodes[self->pos++];
177
0
  return TRUE;
178
0
}
179
180
/**
181
 * xb_stack_get_size:
182
 * @self: a #XbStack
183
 *
184
 * Gets the current size of the stack.
185
 *
186
 * Returns: integer, where 0 is "empty"
187
 *
188
 * Since: 0.1.3
189
 **/
190
guint
191
xb_stack_get_size(XbStack *self)
192
0
{
193
0
  return self->pos;
194
0
}
195
196
/**
197
 * xb_stack_get_max_size:
198
 * @self: a #XbStack
199
 *
200
 * Gets the maximum size of the stack.
201
 *
202
 * Returns: integer
203
 *
204
 * Since: 0.1.3
205
 **/
206
guint
207
xb_stack_get_max_size(XbStack *self)
208
0
{
209
0
  return self->max_size;
210
0
}
211
212
/**
213
 * xb_stack_to_string:
214
 * @self: a #XbStack
215
 *
216
 * Returns a string representing a stack.
217
 *
218
 * Returns: text
219
 *
220
 * Since: 0.1.4
221
 **/
222
gchar *
223
xb_stack_to_string(XbStack *self)
224
0
{
225
0
  GString *str = g_string_new(NULL);
226
0
  for (guint i = 0; i < self->pos; i++) {
227
0
    g_autofree gchar *tmp = xb_opcode_to_string(&self->opcodes[i]);
228
0
    g_string_append_printf(str, "%s,", tmp);
229
0
  }
230
0
  if (str->len > 0)
231
0
    g_string_truncate(str, str->len - 1);
232
0
  return g_string_free(str, FALSE);
233
0
}
234
235
/**
236
 * xb_stack_new:
237
 * @max_size: maximum size of the stack
238
 *
239
 * Creates a stack for the XbMachine request. Only #XbOpcode's can be pushed and
240
 * popped from the stack.
241
 *
242
 * Unlike with xb_stack_new_inline(), this stack will be allocated on the heap.
243
 *
244
 * Returns: (transfer full): a #XbStack
245
 *
246
 * Since: 0.1.3
247
 **/
248
XbStack *
249
xb_stack_new(guint max_size)
250
0
{
251
0
  XbStack *self = g_malloc(sizeof(XbStack) + max_size * sizeof(XbOpcode));
252
0
  self->ref = 1;
253
0
  self->stack_allocated = FALSE;
254
0
  self->pos = 0;
255
0
  self->max_size = max_size;
256
0
  return self;
257
0
}
258
259
GType
260
xb_stack_get_type(void)
261
0
{
262
0
  static GType type = 0;
263
0
  if (G_UNLIKELY(!type)) {
264
0
    type = g_boxed_type_register_static("XbStack",
265
0
                (GBoxedCopyFunc)xb_stack_ref,
266
0
                (GBoxedFreeFunc)xb_stack_unref);
267
0
  }
268
0
  return type;
269
0
}