Commit 6c078583 authored by Giovanne Marcelo's avatar Giovanne Marcelo
Browse files

add list

parent f69b999a
Pipeline #6390 failed with stage
in 4 minutes and 42 seconds
......@@ -39,8 +39,8 @@ LFLAGS = -lpq -ljansson -lgsl -lgslcblas -lm
INCL = -I./include
SRC = ./src
DEPS = ./include/db_interface.h ./include/log.h ./include/main.h ./include/data_prepare.h ./include/matrix.h \
./include/algorithm.h
OBJ = db_interface.o log.o matrix.o data_prepare.o algorithm.o main.o
./include/algorithm.h ./include/list.h
OBJ = db_interface.o log.o matrix.o data_prepare.o algorithm.o list.o main.o
APP=recommender
all: $(APP)
......
......@@ -2,6 +2,8 @@
#define _ALGORITHM_H
#include "matrix.h"
#include "list.h"
typedef struct {
matrix residual;
......
/* vim: set ft=c et ts=3 sw=3 sts=3:
*
* Copyright (C) 2013 James McLaughlin. All rights reserved.
* http://github.com/udp/list
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _list_h
#define _list_h
typedef struct list_head list_head;
typedef struct list_element list_element;
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
/* This file, along with list.c, implements a simple generic linked list with
* the following characteristics:
*
* - "Object in list" rather than "list in object": the listed objects do not
* have to be aware of the list
*
* - The linked list logic (and internal representation) is separate from the
* macros
*
* - The list head does not require initialisation other than being cleared
* with null bytes
*
* - The macros are intuitive and do not require any unnecessary parameters.
* In particular, the list type does not need to be passed to each operation.
*
* - The list macros expand to the head of a for loop, so the syntax for using
* them isn't buggered up. This means that one can use break and continue
* normally.
*
* To accomplish this we use a boatload of unholy macro tricks, rampant and
* sadistic subversion of the C type system, and a liberal sprinkling of GCC
* extensions to stamp out any remaining chance of portability.
*
* List operations:
*
* list(type, name) Declare a list
* list_push(list, value) Push value to back
* list_push_front(list, value) Push value to front
* list_pop(list) Pop and return value from back
* list_pop_front(list) Pop and return value from front
* list_length(list) Returns the list length
* list_remove(list, value) Remove first occurrence of value from list
* list_clear(list) Clear the list (freeing all memory)
*
* Element operations:
*
* list_elem_front(list) Returns element at the front of list
* list_elem_back(list) Returns element at the back of list
* list_elem_next(elem) Returns element after elem
* list_elem_prev(elem) Returns element before elem
* list_elem_remove(elem) Remove element elem
*
* Loops:
*
* list_each(list, elem) { ... }
*
* Loops through each list element, front to back. elem will be declared
* and set to the actual value of each element (not a pointer or iterator)
*
* list_each_r(list, elem) { ... }
*
* Loops through each list element, back to front. elem will be declared
* and set to the actual value of each element (not a pointer or iterator)
*
* list_each_elem(list, elem) { ... }
*
* Loops through each list element, front to back. elem will be declared
* and set to a pointer to each element
*
* list_each_r_elem(list, elem) { ... }
*
* Loops through each list element, back to front. elem will be declared
* and set to pointer to each element
*/
#define list_type(type) \
type *
#define list(type, name) \
list_type (type) name
#define list_push(list, value) do { \
typeof (*list) _v_copy = (typeof (*list)) value; \
_list_push ((list_head **) &list, sizeof (_v_copy), &_v_copy); \
} while (0) \
#define list_push_front(list, value) do { \
typeof (*list) _v_copy = (typeof (*list)) value; \
_list_push_front ((list_head **) &list, sizeof (_v_copy), &_v_copy); \
} while (0) \
#define list_elem(list) \
typeof (list)
#define list_elem_front(list) \
((typeof (list)) _list_front ((list_head *) list)) \
#define list_elem_back(list) \
((typeof (list)) _list_back ((list_head *) list)) \
#define list_elem_next(elem) \
((typeof (elem)) _list_next ((list_element *) elem)) \
#define list_elem_prev(elem) \
((typeof (elem)) _list_prev ((list_element *) elem)) \
#define list_each_elem(list, e) \
for (typeof (list) e = list_elem_front (list), \
e##_next = list_elem_next (e); e; \
e = e##_next, e##_next = list_elem_next (e)) \
#define list_each_r_elem(list, e) \
for (typeof (list) e = list_elem_back (list), \
e##_prev = list_elem_prev (e); e; \
e = e##_prev, e##_prev = list_elem_prev (e)) \
#define list_each(list, e) \
for (typeof (*list) e, * _##e = list_elem_front (list), \
* _##e##_next = list_elem_next (_##e); _##e; \
_##e = _##e##_next, _##e##_next = list_elem_next (_##e)) \
if (!memcpy (&e, _##e, sizeof (e))) {} else \
#define list_each_r(list, e) \
for (typeof (*list) e, * _##e = list_elem_back (list), \
* _##e##_prev = list_elem_prev (_##e); _##e; \
_##e = _##e##_prev, _##e##_prev = list_elem_prev (_##e)) \
if (!memcpy (&e, _##e, sizeof (e))) {} else \
/* The only macro that has to use a statement expression. As list_find has to
* be able to create an l-value from value but also has to work as an
* expression, I can't see a way to accomplish this without.
*
* Since MSVC doesn't support statement expressions, a template function is
* used instead.
*/
#ifndef _MSC_VER
#define list_find(list, value) ({ \
list_elem (list) elem = list_elem_front (list); \
for (; elem; elem = list_elem_next (elem)) \
if (*elem == value) \
break; \
elem; \
})
#else
template <class T> inline T * list_find (T * list, T value)
{
list_elem (list) elem = list_elem_front (list);
for (; elem; elem = list_elem_next (elem))
if (*elem == value)
return elem;
return 0;
}
#endif
#define list_remove(list, value) \
list_elem_remove (list_find (list, value)) \
#define list_elem_remove(elem) \
_list_remove ((list_element *) elem) \
#define list_length(list) \
_list_length ((list_head *) (list)) \
#define list_clear(list) \
_list_clear ((list_head **) &(list), sizeof (*list)) \
#define list_front(list) \
(*list_elem_front (list)) \
#define list_back(list) \
(*list_elem_back (list)) \
#define list_pop_front(list) \
list_elem_remove (list_elem_front (list)) \
#define list_pop_back(list) \
list_elem_remove (list_elem_back (list)) \
#ifdef __cplusplus
extern "C"
{
#endif
void _list_push (list_head **, size_t value_size, void * value);
void _list_push_front (list_head **, size_t value_size, void * value);
list_element* _list_front (list_head *);
list_element* _list_back (list_head *);
list_element* _list_next (list_element *);
list_element* _list_prev (list_element *);
size_t _list_length (list_head *);
void _list_remove (list_element *);
void _list_clear (list_head **, size_t value_size);
#ifdef __cplusplus
}
#endif
#endif
/* vim: set ft=c et ts=3 sw=3 sts=3:
*
* Copyright (C) 2013 James McLaughlin. All rights reserved.
* http://github.com/udp/list
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "list.h"
/* This file contains private helper functions for the macros defined in list.h.
*
* These functions provide the actual linked list logic, keeping it out of the
* macros (and therefore out of anything but list.o).
*/
struct list_head
{
list_element * first, * last;
size_t length;
};
struct list_element
{
list_head * list;
list_element * prev, * next;
};
static list_element * get_element (list_element * elem)
{
return elem ? (elem - 1) : 0;
}
static void * get_value_ptr (list_element * elem)
{
return elem ? (elem + 1) : 0;
}
size_t _list_length (list_head * list)
{
return list ? list->length : 0;
}
void _list_push (list_head ** p_list, size_t value_size, void * value)
{
if (!*p_list)
*p_list = (list_head *) calloc (sizeof (list_head), 1);
list_head * list = *p_list;
++ list->length;
list_element * elem = (list_element *)
malloc (sizeof (*elem) + value_size);
memset (elem, 0, sizeof (*elem));
memcpy (get_value_ptr (elem), value, value_size);
elem->list = list;
elem->prev = list->last;
if (list->last)
{
list->last->next = elem;
list->last = elem;
}
else
{
list->first = list->last = elem;
}
}
void _list_push_front (list_head ** p_list, size_t value_size, void * value)
{
if (!*p_list)
*p_list = (list_head *) calloc (sizeof (list_head), 1);
list_head * list = *p_list;
++ list->length;
list_element * elem = (list_element *)
malloc (sizeof (*elem) + value_size);
memset (elem, 0, sizeof (*elem));
memcpy (get_value_ptr (elem), value, value_size);
elem->list = list;
elem->next = list->first;
if (list->first)
{
list->first->prev = elem;
list->first = elem;
}
else
{
list->first = list->last = elem;
}
}
list_element * _list_front (list_head * list)
{
return list ? (list_element *) get_value_ptr (list->first) : 0;
}
list_element * _list_back (list_head * list)
{
return list ? (list_element *) get_value_ptr (list->last) : 0;
}
list_element * _list_next (list_element * elem)
{
if (!elem || ! (elem = get_element (elem)->next))
return 0;
return (list_element *) get_value_ptr (elem);
}
list_element * _list_prev (list_element * elem)
{
if (!elem || ! (elem = get_element (elem)->prev))
return 0;
return (list_element *) get_value_ptr (elem);
}
void _list_remove (list_element * elem)
{
if (!elem)
return;
elem = get_element (elem);
list_head * list = elem->list;
-- list->length;
if (elem->next)
elem->next->prev = elem->prev;
if (elem->prev)
elem->prev->next = elem->next;
if (elem == list->first)
list->first = elem->next;
if (elem == list->last)
list->last = elem->prev;
free (elem);
}
void _list_clear (list_head ** list, size_t value_size)
{
if (!*list)
return;
list_element * elem = (*list)->first;
while (elem)
{
list_element * next = elem->next;
free (elem);
elem = next;
}
free (*list);
*list = 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment