Commit 778acc48 authored by Celine Mercier's avatar Celine Mercier

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

tested)
parent 3319ede8
......@@ -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
......
/****************************************************************************
* 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)
//{
//
//}
/****************************************************************************
* 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_ */
......@@ -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;
}