Added linked lists to handle lists of column pointers in views (not

tested)
This commit is contained in:
Celine Mercier
2017-03-06 16:06:17 +01:00
parent 3319ede837
commit 778acc48cd
5 changed files with 473 additions and 53 deletions

View File

@ -4,6 +4,7 @@
../../../src/dna_seq_indexer.c
../../../src/encode.c
../../../src/hashtable.c
../../../src/linked_list.c
../../../src/murmurhash2.c
../../../src/obi_align.c
../../../src/obiavl.c

167
src/linked_list.c Normal file
View File

@ -0,0 +1,167 @@
/****************************************************************************
* Linked list source file *
****************************************************************************/
/**
* @file linked_list.c
* @author Celine Mercier
* @date February 22th 2017
* @brief Source file for linked list functions.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "linked_list.h"
/**
* @brief Creates a new node.
*
* @warning The returned pointer has to be freed by the caller.
*
* @returns A pointer on the new node.
* @retval NULL if an error occurred.
*
* @since February 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static Linked_list_node_p create_node();
static Linked_list_node_p create_node()
{
Linked_list_node_p node;
node = malloc(sizeof(Linked_list_node_t));
if (node == NULL)
return NULL;
node->value = NULL;
node->previous = NULL;
node->next = NULL;
return node;
}
// Add a value at the end of a linked list
Linked_list_node_p ll_add(Linked_list_node_p head, void* value)
{
Linked_list_node_p node = head;
Linked_list_node_p new_node = NULL;
// First node
if (head == NULL)
{
head = create_node();
if (head == NULL)
return NULL;
head->value = value;
}
else
{
while (node->next != NULL)
node = node->next;
new_node = create_node();
if (new_node == NULL)
return NULL;
node->next = new_node;
new_node->previous = node;
new_node->value = value;
}
return head;
}
// Set a value at a given index of the list
int ll_set(Linked_list_node_p head, int idx, void* value)
{
int i = 0;
Linked_list_node_p node = head;
while ((node != NULL) && (i < idx))
{
node = node->next;
i++;
}
if (node == NULL) // End of list reached before index
return -1;
node->value = value;
return 0;
}
// Get a node with its index
Linked_list_node_p ll_get(Linked_list_node_p head, int idx)
{
int i = 0;
Linked_list_node_p node = head;
while ((node != NULL) && (i < idx))
{
node = node->next;
i++;
}
return node;
}
// Delete a node
Linked_list_node_p ll_delete(Linked_list_node_p head, int idx) // TODO or with value?
{
int i = 0;
Linked_list_node_p node = head;
while ((node != NULL) && (i < idx))
{
node = node->next;
i++;
}
if (node == NULL) // Node didn't exist
return NULL;
if (node->previous != NULL)
(node->previous)->next = node->next;
else // deleting head node: head changes
head = node->next;
if (node->next != NULL)
(node->next)->previous = node->previous;
free(node);
return head;
}
// Free the linked list
void ll_free(Linked_list_node_p head)
{
Linked_list_node_p node = head;
Linked_list_node_p previous = head;
while (node != NULL)
{
previous = node;
node = node->next;
free(previous);
}
}
// Get the index of a node from its value (TODO useless?) -- kinda assumes unique values
//int ll_get_index(Linked_list_node_p head, void* value)
//{
//
//}

113
src/linked_list.h Normal file
View File

@ -0,0 +1,113 @@
/****************************************************************************
* Linked list header file *
****************************************************************************/
/**
* @file linked_list.h
* @author Celine Mercier
* @date February 22th 2017
* @brief Header file for linked list functions.
*/
#ifndef LINKED_LIST_H_
#define LINKED_LIST_H_
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
/**
* @brief Structure for a node in a double linked chain.
*/
typedef struct Linked_list_node {
void* value; /**< A pointer (the value kept).
*/
struct Linked_list_node* next; /**< A pointer on the next node.
*/
struct Linked_list_node* previous; /**< A pointer on the previous node.
*/
} Linked_list_node_t, *Linked_list_node_p;
/**
* @brief Adds a new node at the end of a linked list.
*
* Works even if it is the first node.
*
* @param head A pointer on the first node of the linked list, or NULL if the list is empty.
* @param value The value to associate with the node.
*
* @returns A pointer on the new head node of the linked list.
* @retval NULL if an error occurred.
*
* @since February 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
Linked_list_node_p ll_add(Linked_list_node_p head, void* value);
/**
* @brief Sets a value at a given index of the list.
*
* @param head A pointer on the first node of the linked list, or NULL if the list is empty.
* @param idx The index of the node at which the value should be changed.
* @param value The new value to associate with the node.
*
* @returns A value indicating the success of the operation.
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since February 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
int ll_set(Linked_list_node_p head, int idx, void* value);
/**
* @brief Gets a node from its index.
*
* @warning The pointer returned is a pointer on the node and not on the value.
*
* @param head A pointer on the first node of the linked list, or NULL if the list is empty.
* @param idx The index of the node to retrieve.
*
* @returns A pointer on the retrieved node.
* @retval NULL if an error occurred.
*
* @since February 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
Linked_list_node_p ll_get(Linked_list_node_p head, int idx);
/**
* @brief Deletes a node.
*
* @param head A pointer on the first node of the linked list.
* @param idx The index of the node to delete.
*
* @returns A pointer on the new head node of the linked list.
* @retval NULL if an error occurred.
*
* @since February 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
Linked_list_node_p ll_delete(Linked_list_node_p head, int idx);
/**
* @brief Frees all the nodes of a linked list.
*
* @param head A pointer on the first node of the linked list.
*
* @since February 2017
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
void ll_free(Linked_list_node_p head);
#endif /* LINKED_LIST_H_ */

View File

@ -32,6 +32,7 @@
#include "obidebug.h"
#include "obilittlebigman.h"
#include "hashtable.h"
#include "linked_list.h"
#include "utils.h"
#include "obiblob.h"
@ -169,10 +170,13 @@ static int create_obiview_file(OBIDMS_p dms, const char* view_name);
*
* @param view A pointer on the view.
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since June 2016
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static void update_column_refs(Obiview_p view);
static int update_column_refs(Obiview_p view);
/**
@ -763,21 +767,32 @@ static int create_obiview_file(OBIDMS_p dms, const char* view_name)
}
static void update_column_refs(Obiview_p view)
static int update_column_refs(Obiview_p view)
{
int i;
OBIDMS_column_p column;
for (i=0; i < (view->infos)->column_count; i++)
{
strcpy(((((view->infos)->column_references)[i]).column_refs).column_name, (((view->columns)[i])->header)->name);
((((view->infos)->column_references)[i]).column_refs).version = (((view->columns)[i])->header)->version;
column = *((OBIDMS_column_p*)ll_get(view->columns, i));
if (column == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column from the linked list of column pointers of a view");
return -1;
}
strcpy(((((view->infos)->column_references)[i]).column_refs).column_name, (column->header)->name);
((((view->infos)->column_references)[i]).column_refs).version = (column->header)->version;
}
return 0;
}
static int create_column_dict(Obiview_p view)
{
int i;
OBIDMS_column_p* column_pp;
view->column_dict = ht_create(MAX_NB_OPENED_COLUMNS);
if (view->column_dict == NULL)
@ -798,7 +813,15 @@ static int create_column_dict(Obiview_p view)
return -1;
}
if (ht_set(view->column_dict, (((view->infos)->column_references)[i]).alias, (view->columns)+i) < 0)
column_pp = (OBIDMS_column_p*) ll_get(view->columns, i);
if (column_pp == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column from the linked list of column pointers of a view when creating a column dictionary");
return -1;
}
if (ht_set(view->column_dict, (((view->infos)->column_references)[i]).alias, column_pp) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError adding a column in a column dictionary");
@ -824,14 +847,16 @@ static int update_column_dict(Obiview_p view)
static int update_column_refs_and_dict(Obiview_p view)
{
update_column_refs(view);
if (update_column_refs(view) < 0)
return -1;
return update_column_dict(view);
}
static int update_lines(Obiview_p view, index_t line_count)
{
int i;
int i;
OBIDMS_column_p column;
// Check that the view is not read-only
if (view->read_only)
@ -843,8 +868,16 @@ static int update_lines(Obiview_p view, index_t line_count)
for (i=0; i<((view->infos)->column_count); i++)
{
column = *((OBIDMS_column_p*)ll_get(view->columns, i));
if (column == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column from the linked list of column pointers of a view when updating view lines");
return -1;
}
// Clone the column first if needed
if (!(((view->columns)[i])->writable))
if (!(column->writable))
{
if (clone_column_in_view(view, (((view->infos)->column_references)[i]).alias) < 0)
{
@ -853,13 +886,13 @@ static int update_lines(Obiview_p view, index_t line_count)
}
}
// Enlarge the column if needed
while (line_count > (((view->columns)[i])->header)->line_count)
while (line_count > (column->header)->line_count)
{
if (obi_enlarge_column(((view->columns)[i])) < 0)
if (obi_enlarge_column(column) < 0)
return -1;
}
// Set the number of lines used to the new view line count
(((view->columns)[i])->header)->lines_used = line_count;
(column->header)->lines_used = line_count;
}
(view->infos)->line_count = line_count;
@ -872,6 +905,7 @@ static OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_n
{
int i;
OBIDMS_column_p column = NULL;
OBIDMS_column_p new_column = NULL;
OBIDMS_column_p column_buffer;
bool found;
@ -890,24 +924,37 @@ static OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_n
{ // Clone with the right line selection and replace (for all columns if there is a line selection)
// Save pointer to close column after cloning
column_buffer = (view->columns)[i];
column_buffer = *((OBIDMS_column_p*)ll_get(view->columns, i));
if (column_buffer == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column to clone from the linked list of column pointers of a view");
return NULL;
}
// Clone and replace the column in the view
(view->columns)[i] = obi_clone_column(view->dms, view->line_selection, (((view->columns)[i])->header)->name, (((view->columns)[i])->header)->version, 1);
if ((view->columns)[i] == NULL)
column = obi_clone_column(view->dms, view->line_selection, (column_buffer->header)->name, (column_buffer->header)->version, true);
if (column == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError cloning a column to replace in a view");
return NULL;
}
// Change the pointer in the linked list of column pointers
if (ll_set(view->columns, i, column) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError changing the column pointer of a cloned column in the linked list of column pointers of a view");
return NULL;
}
// Close old cloned column
obi_close_column(column_buffer);
if (!strcmp((((view->infos)->column_references)[i]).alias, column_name))
{ // Found the column to return
column = (view->columns)[i];
}
// Found the column to return
new_column = column;
}
}
@ -922,9 +969,13 @@ static OBIDMS_column_p clone_column_in_view(Obiview_p view, const char* column_n
}
// Update column refs and dict
update_column_refs_and_dict(view);
if (update_column_refs_and_dict(view) < 0)
{
obidebug(1, "\nError updating columns references and dictionary after cloning a column in a view");
return NULL;
}
return column;
return new_column;
}
@ -952,7 +1003,11 @@ static int save_view(Obiview_p view)
(view->infos)->all_lines = true;
}
update_column_refs(view);
if (update_column_refs(view) < 0)
{
obidebug(1, "\nError updating column references when saving a view");
return -1;
}
return 0;
}
@ -1044,12 +1099,20 @@ static int close_view(Obiview_p view)
{
int i;
int ret_value;
OBIDMS_column_p column;
ret_value = 0;
for (i=0; i < ((view->infos)->column_count); i++)
{
if (obi_close_column((view->columns)[i]) < 0)
column = *((OBIDMS_column_p*)ll_get(view->columns, i));
if (column == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column to close from the linked list of column pointers of a view");
return -1;
}
if (obi_close_column(column) < 0)
{
obidebug(1, "\nError closing a column while closing a view");
ret_value = -1;
@ -1066,6 +1129,9 @@ static int close_view(Obiview_p view)
}
}
// Free the linked list of column pointers
ll_free(view->columns);
// Free the column dictionary
ht_free(view->column_dict);
@ -1251,6 +1317,7 @@ static char* view_check_qual_match_seqs(Obiview_p view)
int qual_len;
const uint8_t* qual;
char* seq;
OBIDMS_column_p column;
OBIDMS_column_p qual_column;
OBIDMS_column_p seq_column;
char* predicate;
@ -1260,12 +1327,20 @@ static char* view_check_qual_match_seqs(Obiview_p view)
at_least_one_qual_col = false;
for (i=0; i < ((view->infos)->column_count); i++)
{
column = *((OBIDMS_column_p*)ll_get(view->columns, i));
if (column == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column to clone from the linked list of column pointers of a view");
return NULL;
}
// Check if it's a quality column
if ((((view->columns)[i])->header)->returned_data_type == OBI_QUAL)
if ((column->header)->returned_data_type == OBI_QUAL)
{
at_least_one_qual_col = true;
// Check that the quality arrays match the sequences of the associated column
qual_column = (view->columns)[i];
qual_column = column;
seq_column = obi_open_column(view->dms, ((qual_column->header)->associated_column).column_name, ((qual_column->header)->associated_column).version);
if (seq_column == NULL)
{
@ -1281,7 +1356,7 @@ static char* view_check_qual_match_seqs(Obiview_p view)
return NULL;
}
// Check each sequence and its sequence
// Check each sequence and its quality
for (j=0; j < (view->infos)->line_count; j++)
{
for (k=0; k < nb_elements_per_line; k++)
@ -1434,6 +1509,7 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
int i;
index_t line_nb;
char* clone_comment;
OBIDMS_column_p column;
// Check that the DMS is a valid pointer
if (dms == NULL)
@ -1600,10 +1676,10 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
(view->infos)->column_count = 0;
(view->infos)->line_count = 0;
(view->infos)->all_lines = true;
view->line_selection = NULL;
((view->infos)->created_from)[0] = '\0';
((view->infos)->view_type)[0] = '\0';
//view->columns = NULL; // TODO
view->line_selection = NULL;
view->columns = NULL;
}
// Fill last informations
@ -1641,6 +1717,9 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
((view->infos)->line_selection).version = ((view->line_selection)->header)->version;
}
// Initialize linked list of column pointers
view->columns = NULL;
// Create the column dictionary (hash table) associating column names (or aliases) to column pointers
if (create_column_dict(view) < 0)
{
@ -1654,9 +1733,16 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
(view->infos)->column_count = 0;
for (i=0; i<((view_to_clone->infos)->column_count); i++)
{
column = *((OBIDMS_column_p*)ll_get(view_to_clone->columns, i));
if (column == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column from the linked list of column pointers of a view");
return NULL;
}
if (obi_view_add_column(view,
(((view_to_clone->columns)[i])->header)->name,
(((view_to_clone->columns)[i])->header)->version,
(column->header)->name,
(column->header)->version,
(((view_to_clone->infos)->column_references)[i]).alias,
0,
0,
@ -1964,6 +2050,13 @@ Obiview_p obi_open_view(OBIDMS_p dms, const char* view_name)
return NULL;
}
// Initialize view informations
view->dms = dms;
view->read_only = true;
view->nb_predicates = 0;
view->predicate_functions = NULL;
view->columns = NULL;
// Map view file
view->infos = obi_view_map_file(dms, view_name, true);
if ((view->infos) == NULL)
@ -2000,15 +2093,15 @@ Obiview_p obi_open_view(OBIDMS_p dms, const char* view_name)
close_view(view);
return NULL;
}
(view->columns)[i] = column_pointer;
view->columns = ll_add(view->columns, column_pointer);
if (view->columns == NULL)
{
obidebug(1, "\nError adding a column in the column linked list of a view: column %d: %s, version %d", i, column_name, column_version);
close_view(view);
return NULL;
}
}
view->dms = dms;
view->read_only = true;
view->nb_predicates = 0;
view->predicate_functions = NULL;
// Create the column dictionary associating each column alias with its pointer
if (create_column_dict(view) < 0)
{
@ -2054,16 +2147,31 @@ int obi_view_add_column(Obiview_p view,
{
{ // Clone with the right line selection and replace for all columns
// Save pointer to close column after cloning
column_buffer = (view->columns)[i];
column_buffer = *((OBIDMS_column_p*)ll_get(view->columns, i));
if (column_buffer == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column to clone from the linked list of column pointers of a view");
return -1;
}
// Clone and replace the column in the view
(view->columns)[i] = obi_clone_column(view->dms, view->line_selection, (((view->columns)[i])->header)->name, (((view->columns)[i])->header)->version, 1);
if ((view->columns)[i] == NULL)
column = obi_clone_column(view->dms, view->line_selection, (column_buffer->header)->name, (column_buffer->header)->version, 1);
if (column == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError cloning a column to replace in a view");
return -1;
}
// Change the pointer in the linked list of column pointers
if (ll_set(view->columns, i, column) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError changing the column pointer of a cloned column in the linked list of column pointers of a view");
return -1;
}
// Close old cloned column
obi_close_column(column_buffer);
}
@ -2120,7 +2228,14 @@ int obi_view_add_column(Obiview_p view,
}
// Store column pointer in the view structure
(view->columns)[(view->infos)->column_count] = column;
view->columns = ll_add(view->columns, column);
if (view->columns == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError adding a column in the linked list of column pointers of a view: column %s, version %d", column_name, version_number);
return -1;
}
// If an alias is not defined, it's the original name of the column. // TODO discuss
if (alias == NULL)
@ -2133,7 +2248,11 @@ int obi_view_add_column(Obiview_p view,
(view->infos)->column_count++;
// Update column references and dictionary
update_column_refs_and_dict(view);
if (update_column_refs_and_dict(view) < 0)
{
obidebug(1, "\nError updating column references and dictionary after adding a column to a view");
return -1;
}
// // Print dict
// for (i=0; i<((view->infos)->column_count); i++)
@ -2150,6 +2269,7 @@ int obi_view_delete_column(Obiview_p view, const char* column_name)
{
int i;
bool found;
OBIDMS_column_p column;
// Check that the view is not read-only
if (view->read_only)
@ -2162,22 +2282,40 @@ int obi_view_delete_column(Obiview_p view, const char* column_name)
found = false;
for (i=0; i<((view->infos)->column_count); i++)
{
column = *((OBIDMS_column_p*)ll_get(view->columns, i));
if (column == NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError getting a column from the linked list of column pointers of a view when deleting a column from a view");
return -1;
}
if ((!found) && (!strcmp((((view->infos)->column_references)[i]).alias, column_name)))
{
obi_close_column((view->columns)[i]);
obi_close_column(column);
view->columns = ll_delete(view->columns, i);
if (view->columns != NULL)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to delete a column: column not found in linked list of column pointers");
return -1;
}
found = true;
}
if (found)
{
if (i != (((view->infos)->column_count) - 1)) // not the last one
{ // Shift the pointer and the references
(view->columns)[i] = (view->columns)[i+1];
{ // Shift the references
strcpy((((view->infos)->column_references)[i]).alias, (((view->infos)->column_references)[i+1]).alias);
strcpy(((((view->infos)->column_references)[i]).column_refs).column_name, ((((view->infos)->column_references)[i+1]).column_refs).column_name);
((((view->infos)->column_references)[i]).column_refs).version = ((((view->infos)->column_references)[i+1]).column_refs).version;
}
else // Last column
(view->columns)[i] = NULL;
{
strcpy((((view->infos)->column_references)[i]).alias, "");
strcpy(((((view->infos)->column_references)[i]).column_refs).column_name, "");
((((view->infos)->column_references)[i]).column_refs).version = -1;
}
}
}

View File

@ -26,6 +26,7 @@
#include "obidmscolumn.h"
#include "obierrno.h"
#include "hashtable.h"
#include "linked_list.h"
#include "obiblob.h"
@ -105,25 +106,25 @@ typedef struct Obiview_infos {
* @brief Structure for an opened view.
*/
typedef struct Obiview {
Obiview_infos_p infos; /**< A pointer on the mapped view informations.
Obiview_infos_p infos; /**< A pointer on the mapped view informations.
*/
OBIDMS_p dms; /**< A pointer on the DMS to which the view belongs.
OBIDMS_p dms; /**< A pointer on the DMS to which the view belongs.
*/
bool read_only; /**< Whether the view is read-only or can be modified.
bool read_only; /**< Whether the view is read-only or can be modified.
*/
OBIDMS_column_p line_selection; /**< A pointer on the column containing the line selection
OBIDMS_column_p line_selection; /**< A pointer on the column containing the line selection
* associated with the view if there is one.
* This line selection is read-only, and when a line from the view is read,
* it is this line selection that is used.
*/
OBIDMS_column_p columns[MAX_NB_OPENED_COLUMNS]; /**< Array of pointers on all the columns of the view.
Linked_list_node_p columns; /**< Double linked chain containing the pointers on all the columns of the view.
*/
hashtable_p column_dict; /**< Hash table storing the pairs of column names or aliases with the associated
hashtable_p column_dict; /**< Hash table storing the pairs of column names or aliases with the associated
* pointers on column pointers (OBIDMS_column_p*).
*/
int nb_predicates; /**< Number of predicates to test when closing the view.
*/
char* (**predicate_functions)(struct Obiview* view); /**< Array of pointers on all predicate functions to test when closing the view.
int nb_predicates; /**< Number of predicates to test when closing the view.
*/
char* (**predicate_functions)(struct Obiview* view); /**< Array of pointers on all predicate functions to test when closing the view.
*/
} Obiview_t, *Obiview_p;