Skip to content

Commit

Permalink
zcbor_common.h: Refactor state initialization
Browse files Browse the repository at this point in the history
To allow for adding member variables in the future.

Signed-off-by: Øyvind Rønningstad <[email protected]>
  • Loading branch information
oyvindronningstad committed Dec 3, 2024
1 parent d71fa55 commit 2ff886b
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 46 deletions.
4 changes: 4 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# zcbor v. 0.9.99

* `zcbor_new_state` and `zcbor_entry_function` are now deprecated in favor of `zcbor_state_init`and `zcbor_entry_func` respectively.
They still work as before, but will be removed in a few more releases.
The new functions take a struct as parameter to allow parameters to be added in the future without breaking compatibility.


# zcbor v. 0.9.0

Expand Down
44 changes: 35 additions & 9 deletions include/zcbor_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,13 @@ union {
processed. */
};
uint8_t const *payload_bak; /**< Temporary backup of payload. */
size_t elem_count; /**< The current element is part of a LIST or a MAP,
and this keeps count of how many elements are
expected. This will be checked before processing
and decremented if the element is correctly
processed. */
size_t elem_count; /**< Keeps count of how many elements are expected/have been
encoded. This count is decremented for each element when
decoding, or incremented for each element when encoding.
When decoding, this is checked before decoding any element,
and decoding will fail if elem_count is 0.
When encoding, this value is eventually used to populate
the header of a list or map, when in canonical mode. */
uint8_t const *payload_end; /**< The end of the payload. This will be
checked against payload before
processing each element. */
Expand Down Expand Up @@ -323,23 +325,47 @@ bool zcbor_union_elem_code(zcbor_state_t *state);
*/
bool zcbor_union_end_code(zcbor_state_t *state);

/** Initialization parameters for zcbor_state_init() and zcbor_entry_func().
*
* Note that members may be added to this struct, so initialize it in a way where
* such members will be set to 0, either via a designated initializer (params = {...}),
* or by memseting the struct to 0 before assigning the members.
*/
struct zcbor_state_init_params {
zcbor_state_t *states; // Memory used for the state, backup states, constant state, and flags.
size_t n_states; // Size of the states array.
const uint8_t *payload; // Note that in encoding, payload will be modified despite the `const`.
size_t payload_len; // Length in bytes of the payload buffer
size_t payload_len_out; // Will be written with the actual length used (encoded/decoded)
size_t elem_count; // The initial elem_count, i.e. how many elements are expected. Should be 0 for encoding.
uint8_t *flags; // Memory used for flags, when using ZCBOR_MAP_SMART_SEARCH and unordered maps. Ignored when ZCBOR_MAP_SMART_SEARCH is not defined.
size_t flags_bytes; // Length in bytes of the flags buffer. Or, if non-zero while flags is NULL, how much memory will be taken from the states array for use as flags.
};

/** Initialize a state with backups.
* As long as n_states is more than 1, one of the states in the array is used
* as a struct zcbor_state_constant object.
* If there is no struct zcbor_state_constant (n_states == 1), error codes are
* not available.
* This means that you get a state with (n_states - 2) backups.
* payload, payload_len, elem_count, and elem_state are used to initialize the first state.
* The elem_state is only needed for unordered maps, when ZCBOR_MAP_SMART_SEARCH is enabled.
* payload, payload_len, elem_count, and flags are used to initialize the first state.
* The flags is only needed for unordered maps, when ZCBOR_MAP_SMART_SEARCH is enabled.
* It is ignored otherwise.
*/

void zcbor_state_init(struct zcbor_state_init_params *params);

/** [DEPRECATED] Old variant of zcbor_state_init, kept for backwards compatibility. */
void zcbor_new_state(zcbor_state_t *state_array, size_t n_states,
const uint8_t *payload, size_t payload_len, size_t elem_count,
uint8_t *elem_state, size_t elem_state_bytes);
uint8_t *flags, size_t flags_bytes);

/** Do boilerplate entry function procedure.
* Initialize states, call function, and check the result.
*/
int zcbor_entry_func(zcbor_decoder_t func, void *result, struct zcbor_state_init_params *params);

/** [DEPRECATED] Old variant of zcbor_entry_func, kept for backwards compatibility. */
int zcbor_entry_function(const uint8_t *payload, size_t payload_len,
void *result, size_t *payload_len_out, zcbor_state_t *state, zcbor_decoder_t func,
size_t n_states, size_t elem_count);
Expand Down Expand Up @@ -505,10 +531,10 @@ float zcbor_float16_to_32(uint16_t input);
*/
uint16_t zcbor_float32_to_16(float input);

#ifdef ZCBOR_MAP_SMART_SEARCH
#define ZCBOR_ROUND_UP(x, align) (((x) + (align) - 1) / (align) * (align))
#define ZCBOR_BITS_PER_BYTE 8

#ifdef ZCBOR_MAP_SMART_SEARCH
/** Calculate the number of bytes needed to hold @p num_flags 1 bit flags
*/
static inline size_t zcbor_flags_to_bytes(size_t num_flags)
Expand Down
20 changes: 14 additions & 6 deletions include/zcbor_decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extern "C" {
*/


/** See @ref zcbor_new_state() */
/** [DEPRECATED] See @ref zcbor_new_state() and @ref zcbor_state_init() */
void zcbor_new_decode_state(zcbor_state_t *state_array, size_t n_states,
const uint8_t *payload, size_t payload_len, size_t elem_count,
uint8_t *elem_state, size_t elem_state_bytes);
Expand All @@ -35,19 +35,27 @@ void zcbor_new_decode_state(zcbor_state_t *state_array, size_t n_states,
*
* @param[in] name The name of the new state variable.
* @param[in] num_backups The number of backup slots to keep in the state.
* @param[in] payload The payload to work on.
* @param[in] payload_buf The payload to work on.
* @param[in] payload_size The size (in bytes) of @p payload.
* @param[in] elem_count The starting elem_count (typically 1).
* @param[in] init_elem_count The starting elem_count (typically 1).
* @param[in] n_flags For use if ZCBOR_MAP_SMART_SEARCH is enabled, ignored otherwise.
* The total number of unordered map search flags needed.
* I.e. the largest number of elements expected in an unordered map,
* including elements in nested unordered maps.
*/
#define ZCBOR_STATE_D(name, num_backups, payload, payload_size, elem_count, n_flags) \
#define ZCBOR_STATE_D(name, num_backups, payload_buf, payload_size, init_elem_count, n_flags) \
zcbor_state_t name[((num_backups) + 2 + ZCBOR_FLAG_STATES(n_flags))]; \
do { \
zcbor_new_decode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count, \
(uint8_t *)&name[(num_backups) + 1], ZCBOR_FLAG_STATES(n_flags) * sizeof(zcbor_state_t)); \
struct zcbor_state_init_params params = { \
.states = name, \
.n_states = ZCBOR_ARRAY_SIZE(name), \
.payload = payload_buf, \
.payload_len = payload_size, \
.elem_count = init_elem_count, \
.flags = NULL, \
.flags_bytes = ZCBOR_ROUND_UP(n_flags, ZCBOR_BITS_PER_BYTE) / ZCBOR_BITS_PER_BYTE, \
}; \
zcbor_state_init(&params); \
} while(0)


Expand Down
17 changes: 13 additions & 4 deletions include/zcbor_encode.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,23 @@ void zcbor_new_encode_state(zcbor_state_t *state_array, size_t n_states,
*
* @param[in] name The name of the new state variable.
* @param[in] num_backups The number of backup slots to keep in the state.
* @param[in] payload The payload to work on.
* @param[in] payload_buf The payload to work on.
* @param[in] payload_size The size (in bytes) of @p payload.
* @param[in] elem_count The starting elem_count (typically 1).
* @param[in] init_elem_count The starting elem_count (typically 1).
*/
#define ZCBOR_STATE_E(name, num_backups, payload, payload_size, elem_count) \
#define ZCBOR_STATE_E(name, num_backups, payload_buf, payload_size, init_elem_count) \
zcbor_state_t name[((num_backups) + 2)]; \
do { \
zcbor_new_encode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count); \
struct zcbor_state_init_params params = { \
.states = name, \
.n_states = ZCBOR_ARRAY_SIZE(name), \
.payload = payload_buf, \
.payload_len = payload_size, \
.elem_count = init_elem_count, \
.flags = NULL, \
.flags_bytes = 0, \
}; \
zcbor_state_init(&params); \
} while(0)


Expand Down
94 changes: 72 additions & 22 deletions src/zcbor_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,33 +131,41 @@ bool zcbor_union_end_code(zcbor_state_t *state)
return true;
}

void zcbor_new_state(zcbor_state_t *state_array, size_t n_states,
const uint8_t *payload, size_t payload_len, size_t elem_count,
uint8_t *flags, size_t flags_bytes)
void zcbor_state_init(struct zcbor_state_init_params *params)
{
state_array[0].payload = payload;
state_array[0].payload_end = payload + payload_len;
state_array[0].elem_count = elem_count;
zcbor_state_t *state_array = params->states;

#ifdef ZCBOR_MAP_SMART_SEARCH
if (params->flags == NULL) {
size_t flag_state_index =
params->n_states - ZCBOR_BYTE_STATES(params->flags_bytes);
params->flags = (uint8_t *)&state_array[flag_state_index];
params->n_states = flag_state_index;
}
#endif

state_array[0].payload = params->payload;
state_array[0].payload_end = params->payload + params->payload_len;
state_array[0].elem_count = params->elem_count;
state_array[0].payload_moved = false;
state_array[0].decode_state.indefinite_length_array = false;
#ifdef ZCBOR_MAP_SMART_SEARCH
state_array[0].decode_state.map_search_elem_state = flags;
state_array[0].decode_state.map_search_elem_state = params->flags;
state_array[0].decode_state.map_elem_count = 0;
#else
state_array[0].decode_state.map_elems_processed = 0;
(void)flags;
(void)flags_bytes;
#endif
state_array[0].constant_state = NULL;

if (n_states < 2) {
if (params->n_states < 2) {
return;
}

/* Use the last state as a struct zcbor_state_constant object. */
state_array[0].constant_state = (struct zcbor_state_constant *)&state_array[n_states - 1];
state_array[0].constant_state =
(struct zcbor_state_constant *)&state_array[params->n_states - 1];
state_array[0].constant_state->backup_list = NULL;
state_array[0].constant_state->num_backups = n_states - 2;
state_array[0].constant_state->num_backups = params->n_states - 2;
state_array[0].constant_state->current_backup = 0;
state_array[0].constant_state->error = ZCBOR_SUCCESS;
#ifdef ZCBOR_STOP_ON_ERROR
Expand All @@ -166,13 +174,32 @@ void zcbor_new_state(zcbor_state_t *state_array, size_t n_states,
state_array[0].constant_state->enforce_canonical = ZCBOR_ENFORCE_CANONICAL_DEFAULT;
state_array[0].constant_state->manually_process_elem = ZCBOR_MANUALLY_PROCESS_ELEM_DEFAULT;
#ifdef ZCBOR_MAP_SMART_SEARCH
state_array[0].constant_state->map_search_elem_state_end = flags + flags_bytes;
state_array[0].constant_state->map_search_elem_state_end =
params->flags + params->flags_bytes;
#endif
if (n_states > 2) {
if (params->n_states > 2) {
state_array[0].constant_state->backup_list = &state_array[1];
}
}


void zcbor_new_state(zcbor_state_t *state_array, size_t n_states,
const uint8_t *payload, size_t payload_len, size_t elem_count,
uint8_t *flags, size_t flags_bytes)
{
struct zcbor_state_init_params params = {
.states = state_array,
.n_states = n_states,
.payload = payload,
.payload_len = payload_len,
.elem_count = elem_count,
.flags = flags,
.flags_bytes = flags_bytes,
};

zcbor_state_init(&params);
}

void zcbor_update_state(zcbor_state_t *state,
const uint8_t *payload, size_t payload_len)
{
Expand Down Expand Up @@ -299,11 +326,13 @@ size_t zcbor_remaining_str_len(zcbor_state_t *state)
}


int zcbor_entry_function(const uint8_t *payload, size_t payload_len,
void *result, size_t *payload_len_out, zcbor_state_t *state, zcbor_decoder_t func,
size_t n_states, size_t elem_count)
int zcbor_entry_func(zcbor_decoder_t func, void *result, struct zcbor_state_init_params *params)
{
zcbor_new_state(state, n_states, payload, payload_len, elem_count, NULL, 0);
zcbor_state_t *state = params->states;

zcbor_state_init(params);

state->constant_state->manually_process_elem = true;

bool ret = func(state, result);

Expand All @@ -314,14 +343,35 @@ int zcbor_entry_function(const uint8_t *payload, size_t payload_len,
return err;
}

if (payload_len_out != NULL) {
*payload_len_out = MIN(payload_len,
(size_t)state[0].payload - (size_t)payload);
}
params->payload_len_out = MIN(params->payload_len,
(size_t)state[0].payload - (size_t)params->payload);
return ZCBOR_SUCCESS;
}


int zcbor_entry_function(const uint8_t *payload, size_t payload_len,
void *result, size_t *payload_len_out, zcbor_state_t *state, zcbor_decoder_t func,
size_t n_states, size_t elem_count)
{
struct zcbor_state_init_params params = {
.states = state,
.n_states = n_states,
.payload = payload,
.payload_len = payload_len,
.elem_count = elem_count,
.flags_bytes = 0,
};

int ret = zcbor_entry_func(func, result, &params);

if (payload_len_out != NULL && ret == ZCBOR_SUCCESS) {
*payload_len_out = params.payload_len_out;
}

return ret;
}


/* Float16: */
#define F16_SIGN_OFFS 15 /* Bit offset of the sign bit. */
#define F16_EXPO_OFFS 10 /* Bit offset of the exponent. */
Expand Down
12 changes: 11 additions & 1 deletion src/zcbor_decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1607,5 +1607,15 @@ void zcbor_new_decode_state(zcbor_state_t *state_array, size_t n_states,
const uint8_t *payload, size_t payload_len, size_t elem_count,
uint8_t *flags, size_t flags_bytes)
{
zcbor_new_state(state_array, n_states, payload, payload_len, elem_count, flags, flags_bytes);
struct zcbor_state_init_params params = {
.states = state_array,
.n_states = n_states,
.payload = payload,
.payload_len = payload_len,
.elem_count = elem_count,
.flags = flags,
.flags_bytes = flags_bytes,
};

zcbor_state_init(&params);
}
12 changes: 11 additions & 1 deletion src/zcbor_encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,5 +599,15 @@ bool zcbor_multi_encode(const size_t num_encode, zcbor_encoder_t encoder,
void zcbor_new_encode_state(zcbor_state_t *state_array, size_t n_states,
uint8_t *payload, size_t payload_len, size_t elem_count)
{
zcbor_new_state(state_array, n_states, payload, payload_len, elem_count, NULL, 0);
struct zcbor_state_init_params params = {
.states = state_array,
.n_states = n_states,
.payload = payload,
.payload_len = payload_len,
.elem_count = elem_count,
.flags = NULL,
.flags_bytes = 0,
};

zcbor_state_init(&params);
}
18 changes: 15 additions & 3 deletions zcbor/zcbor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2874,9 +2874,21 @@ def render_entry_function(self, xcoder, mode):
{{
zcbor_state_t states[{xcoder.num_backups() + 2}];
return zcbor_entry_function(payload, payload_len, (void *){func_arg}, payload_len_out, states,
(zcbor_decoder_t *){func_name}, sizeof(states) / sizeof(zcbor_state_t), {
xcoder.list_counts()[1]});
struct zcbor_state_init_params params = {{
.states = states,
.n_states = sizeof(states) / sizeof(zcbor_state_t),
.payload = payload,
.payload_len = payload_len,
.elem_count = {xcoder.list_counts()[1]},
}};
int ret = zcbor_entry_func((zcbor_decoder_t *){func_name}, (void *){func_arg}, &params);
if (payload_len_out != NULL && ret == ZCBOR_SUCCESS) {{
*payload_len_out = params.payload_len_out;
}}
return ret;
}}"""

def render_file_header(self, line_prefix):
Expand Down

0 comments on commit 2ff886b

Please sign in to comment.