Skip to content

File comp_rlitt_grafting.c

File List > comp-rlitt_grafting > src > comp_rlitt_grafting.c

Go to the documentation of this file

/******************************************************************************/
/************************** Includes ******************************************/
/******************************************************************************/

#include "comp_rlitt_grafting.h"
#include "bits/stdint-intn.h"
#include "stdbool.h"
#include "stdint.h"
#include "stdio.h"
#include "stdlib.h"

/******************************************************************************/
/************************** Defines *******************************************/
/******************************************************************************/

#define COMP_RLITT_GRAFTING_STACK_SIZE    (UTIL_TANG_DEFS_MAX_CROSSINGNUM)

/******************************************************************************/
/************************** Typedefs ******************************************/
/******************************************************************************/

/******************************************************************************/
/************************** Private Function Declarations *********************/
/******************************************************************************/
STATIC_INLINE_UINT8 comp_rlitt_grafting_copy_tree(const note_wptt_t *tree);
STATIC_INLINE void comp_rlitt_grafting_copy_nodevals(const note_wptt_node_t *src,
                                                     note_wptt_node_t *dest);
STATIC_INLINE_UINT8 comp_rlitt_grafting_graft(note_wptt_node_t *scion);

/******************************************************************************/
/************************** Local Variables ***********************************/
/******************************************************************************/

static note_wptt_node_t *comp_rlitt_grafting_localnodes;

static size_t comp_rlitt_grafting_nodes_idx = 0;

static size_t comp_rlitt_grafting_nodes_count = 0;

static comp_rlitt_grafting_config_t *comp_rlitt_grafting_localcfg = NULL;

static comp_rlitt_grafting_result_t comp_rlitt_grafting_localrestult = { NULL };

static bool comp_rlitt_grafting_executed = false;
/******************************************************************************/
/************************** Public Function Definitions ***********************/
/******************************************************************************/

/*
 *  Documentation in header
 */
uint8_t comp_rlitt_grafting_config(comp_rlitt_grafting_config_t *config_arg)
{
    uint8_t ret_val = COMP_DEFS_CONFIG_FAIL;

    comp_rlitt_grafting_localcfg   = NULL;
    comp_rlitt_grafting_localnodes = NULL;
    comp_rlitt_grafting_localrestult.grafted_wptt = NULL;
    comp_rlitt_grafting_nodes_idx   = 0;
    comp_rlitt_grafting_nodes_count = 0;

    /*Ensure the cfg is not empty.*/
    if (config_arg == NULL)
    {
        ret_val |= COMP_RLITT_GRAFTING_CONFIG_IS_NULL;
    }
    /*Ensure the rootstock is not empty.*/
    else if (config_arg->rootstock == NULL)
    {
        ret_val |= COMP_RLITT_GRAFTING_CONFIG_ROOTSTOCK;
    }
    /*Ensure the scion is not empty.*/
    else if (config_arg->scion == NULL)
    {
        ret_val |= COMP_RLITT_GRAFTING_CONFIG_SCION;
    }
    /*Ensure the output buffer is not empty.*/
    else if ((config_arg->output_wptt == NULL) ||
             (config_arg->output_wptt->node_buffer->buffer == NULL) ||
             (config_arg->output_wptt->node_buffer->size == 0))
    {
        ret_val |= COMP_RLITT_GRAFTING_CONFIG_BUFFER;
    }
    else
    {
        /* Set the config. */
        comp_rlitt_grafting_localcfg = config_arg;

        /* Set the return value*/
        comp_rlitt_grafting_localnodes =
            comp_rlitt_grafting_localcfg->output_wptt->node_buffer->buffer;
        comp_rlitt_grafting_nodes_idx =
            comp_rlitt_grafting_localcfg->output_wptt->node_buffer->idx;
        comp_rlitt_grafting_nodes_count =
            comp_rlitt_grafting_localcfg->output_wptt->node_buffer->size;
        comp_rlitt_grafting_localrestult.grafted_wptt =
            comp_rlitt_grafting_localcfg->output_wptt;

        /*clear the executed status*/
        comp_rlitt_grafting_executed = false;

        ret_val = COMP_DEFS_CONFIG_SUCCESS;
    }
    return ret_val;
}

/*
 *  Documentation in header
 */
uint8_t comp_rlitt_grafting_compute()
{
    uint8_t ret_val = COMP_DEFS_COMPUTE_FAIL;

    /*Ensure the cfg is not empty.*/
    if (comp_rlitt_grafting_localcfg == NULL)
    {
        ret_val |= COMP_RLITT_GRAFTING_COMPUTE_CFG_ERROR;
    } /*Ensure not executed.*/
    else if (comp_rlitt_grafting_executed != false)
    {
        ret_val |= COMP_RLITT_GRAFTING_COMPUTE_ALREADY_COMPUTED;
    }
    else
    {
        comp_rlitt_grafting_executed = true;
        note_wptt_node_t *scion_root = NULL;

        ret_val = COMP_DEFS_COMPUTE_SUCCESS;

        /* Set output data. */
        comp_rlitt_grafting_localrestult.grafted_wptt->root =
            &comp_rlitt_grafting_localnodes[comp_rlitt_grafting_nodes_idx];
        comp_rlitt_grafting_localrestult.grafted_wptt->label =
            comp_rlitt_grafting_localcfg->rootstock->label;
        comp_rlitt_grafting_nodes_idx++;

        /* Copy rootstock into output buffer */
        ret_val |= comp_rlitt_grafting_copy_tree(comp_rlitt_grafting_localcfg->rootstock);

        /* If we have room left in the buffer after our copy we copy the scion. */
        if ((COMP_DEFS_COMPUTE_SUCCESS == ret_val) &&
            (comp_rlitt_grafting_localcfg->rlitt_grafting_idx < comp_rlitt_grafting_nodes_idx))
        {
            scion_root = &comp_rlitt_grafting_localnodes[comp_rlitt_grafting_nodes_idx];
            comp_rlitt_grafting_nodes_idx++;

            ret_val |= comp_rlitt_grafting_copy_tree(comp_rlitt_grafting_localcfg->scion);
            ret_val |= comp_rlitt_grafting_graft(scion_root);


            /* write to storage interface */
            if ((COMP_DEFS_COMPUTE_SUCCESS == ret_val) &&
                (comp_rlitt_grafting_localcfg->storage_write != NULL))
            {
                uint8_t write_retval = NOTE_DEFS_ENCODE_SUCCESS;
                char    rootstock_str[NOTE_WPTT_MAX_STR_LEN] = "";
                char    scion_str[NOTE_WPTT_MAX_STR_LEN]     = "";
                char    result_str[NOTE_WPTT_MAX_STR_LEN]    = "";
                write_retval |= note_wptt_encode(*comp_rlitt_grafting_localcfg->rootstock,
                                                 rootstock_str,
                                                 NOTE_WPTT_MAX_STR_LEN);
                write_retval |= note_wptt_encode(*comp_rlitt_grafting_localcfg->scion,
                                                 scion_str,
                                                 NOTE_WPTT_MAX_STR_LEN);
                write_retval |= note_wptt_encode(*comp_rlitt_grafting_localrestult.grafted_wptt,
                                                 result_str,
                                                 NOTE_WPTT_MAX_STR_LEN);
                if (write_retval == NOTE_DEFS_ENCODE_SUCCESS)
                {
                    comp_rlitt_grafting_localcfg->storage_write(result_str,
                                                                "rootstock",
                                                                rootstock_str);
                    comp_rlitt_grafting_localcfg->storage_write(result_str,
                                                                "scion",
                                                                scion_str);
                }
                else
                {
                    ret_val |= COMP_DEFS_COMPUTE_FAIL;
                }
            }
        }
        else
        {
            ret_val |= COMP_DEFS_COMPUTE_FAIL;
        }
    }
    return ret_val;
}

/*
 *  Documentation in header
 */
const comp_rlitt_grafting_result_t *comp_rlitt_grafting_result()
{
    const comp_rlitt_grafting_result_t *ret_val = NULL;

    if (comp_rlitt_grafting_localcfg == NULL)
    {
        ret_val = NULL;
    }
    /*Ensure previously executed.*/
    else if (comp_rlitt_grafting_executed == false)
    {
        ret_val = NULL;
    }
    else
    {
        ret_val = (const comp_rlitt_grafting_result_t *)&comp_rlitt_grafting_localrestult;
    }
    return ret_val;
}

/******************************************************************************/
/************************** Private Function Declarations *********************/
/******************************************************************************/

STATIC_INLINE_UINT8 comp_rlitt_grafting_copy_tree(const note_wptt_t *tree)
{
    uint8_t           ret_val = COMP_DEFS_COMPUTE_SUCCESS;
    note_wptt_node_t *old_stack[COMP_RLITT_GRAFTING_STACK_SIZE]      = { NULL };
    note_wptt_node_t *new_stack[COMP_RLITT_GRAFTING_STACK_SIZE]      = { NULL };
    size_t            childidx_stack[COMP_RLITT_GRAFTING_STACK_SIZE] = { 0 };

    /* We are going to use count instead of index. This helps with intuiting the state of the stack.
     * The count starts at 1 since the root is going to be added to the stack before the main loop.
     */
    size_t stack_count = 1;

    old_stack[stack_count - 1] = tree->root;
    new_stack[stack_count - 1] = &comp_rlitt_grafting_localnodes[comp_rlitt_grafting_nodes_idx - 1];
    comp_rlitt_grafting_copy_nodevals(old_stack[stack_count - 1], new_stack[stack_count - 1]);

    /* While stack is not empty. */
    while (stack_count != 0)
    {
        note_wptt_node_t *active_node_p = old_stack[stack_count - 1];

        /* Have all the children of the active vertex been exhausted?*/
        if (active_node_p->number_of_children <= childidx_stack[stack_count - 1])
        {
            /*Pop stack*/
            stack_count--;
        }
        else
        {
            note_wptt_node_t *newchild_p = NULL;
            size_t            child_idx  = childidx_stack[stack_count - 1];

            comp_rlitt_grafting_nodes_idx++;
            newchild_p =
                &comp_rlitt_grafting_localnodes[comp_rlitt_grafting_nodes_idx - 1];
            new_stack[stack_count - 1]->children[child_idx] = newchild_p;

            /* Push child onto stack. */
            childidx_stack[stack_count - 1]++;
            if (stack_count < COMP_RLITT_GRAFTING_STACK_SIZE)
            {
                stack_count++;
                old_stack[stack_count - 1] = active_node_p->children[child_idx];
                new_stack[stack_count - 1] = newchild_p;
                comp_rlitt_grafting_copy_nodevals(old_stack[stack_count - 1],
                                                  new_stack[stack_count - 1]);
                childidx_stack[stack_count - 1] = 0;
            }
            else
            {
                ret_val |= COMP_STATUS_BLDR(COMP_DEFS_COMPUTE_FAIL,
                                            COMP_RLITT_GRAFTING_COMPUTE_COPYERROR);
                break;
            }
        }
    }

    return ret_val;
}

STATIC_INLINE void comp_rlitt_grafting_copy_nodevals(const note_wptt_node_t *src,
                                                     note_wptt_node_t *dest)
{
    size_t i = 0;

    for (i = 0; i < src->number_of_children; i++)
    {
        dest->weights[i] = src->weights[i];
    }
    dest->weights[i] = src->weights[i];

    dest->number_of_children = src->number_of_children;
    dest->number_of_rings    = src->number_of_rings;
    dest->order = src->order;
}

STATIC_INLINE_UINT8 comp_rlitt_grafting_graft(note_wptt_node_t *scion)
{
    uint8_t retval = COMP_STATUS_BLDR(COMP_DEFS_COMPUTE_FAIL,
                                      COMP_RLITT_GRAFTING_COMPUTE_GRAFTING_RLITT);
    size_t            idx            = comp_rlitt_grafting_localcfg->rlitt_grafting_idx;
    note_wptt_node_t *rootstock_node = &comp_rlitt_grafting_localnodes[idx];

    /* If there is room for a new child */
    if (rootstock_node->number_of_children < NOTE_WPTT_DECODE_MAX_CHILDREN - 1)
    {
        /* Start shifting the weights */
        int8_t weight_to_move = rootstock_node->weights[rootstock_node->number_of_children];
        rootstock_node->weights[rootstock_node->number_of_children] = 0;

        /* Add the child */
        rootstock_node->children[rootstock_node->number_of_children] = scion;
        rootstock_node->number_of_children++;

        /* Finish shifting the weights */
        rootstock_node->weights[rootstock_node->number_of_children] = weight_to_move;
        retval = COMP_DEFS_COMPUTE_SUCCESS;
    }
    return retval;
}