Add first version of m-deque

This commit is contained in:
Patrick Pelissier committed 2017-08-05 18:05:44 +02:00
1 parent f7277884a6
commit ec4aa2a93a
1 file changed
+230
+230
View File
@@ -0,0 +1,230 @@
/*
* M*LIB - DEQUE module
*
* Copyright (c) 2017, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + 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 REGENTS 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 REGENTS AND 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 __M_DEQUE_H
#define __M_DEQUE_H
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "m-core.h"
#include "m-i-list.h"
/* Define a deque of a given type.
USAGE: DEQUE_DEF(name, type [, oplist_of_the_type]) */
#define DEQUE_DEF(name, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(DEQUEI_DEF2(name, __VA_ARGS__, M_DEFAULT_OPLIST, M_C(name,_t), M_C(name,_it_t), M_C(name, _node_t) ), \
DEQUEI_DEF2(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t), M_C(name, _node_t) ))
/********************************** INTERNAL ************************************/
#define DEQUEUI_DEFAULT_SIZE 8
#define DEQUEI_CONTRACT(d) do { \
assert ((d) != NULL); \
assert ((d)->default_size >= DEQUEUI_DEFAULT_SIZE); \
assert ((d)->front->node != NULL); \
assert ((d)->front->index <= (d)->front->node->size); \
assert ((d)->back->node != NULL); \
assert ((d)->back->index <= (d)->back->node->size); \
assert ((d)->front->node != (d)->back->node || \
(d)->front->index <= (d)->back->index); \
assert ((d)->front->node != (d)->back->node || \
(d)->bach->index - (d)->front->index == (d)->count); \
} while (0)
#define DEQUEI_DEF2(name, type, oplist, deque_t, it_t, node_t) \
\
typedef struct M_C(name, _node_s) { \
ILIST_INTERFACE(M_C(name, _node_list), struct M_C(name, _node_s)); \
size_t size; \
type data[]; \
} node_t; \
\
ILIST_DEF(M_C(name, _node_list), node_t, (M_GET_FREE oplist) ) \
\
typedef struct M_C(name, _it_s) { \
node_t *node; \
size_t index; \
} it_t[1]; \
\
typedef struct M_C(name, _s) { \
M_C(name, _node_list_t) list; \
it_t front; \
it_t back; \
size_t default_size; \
size_t count; \
} deque_t[1]; \
\
\
static inline deque_node_t* \
M_C(name, _int_new_node)(deque_t d) \
{ \
/* FIXME: Broken memory interface. How to do ? */ \
size_t def = d->default_size; \
deque_node_t*n = (deque_node_t*) M_GET_REALLOC oplist (char, NULL, \
sizeof(deque_node_t)+def * sizeof(type) ); \
if (n==NULL) { \
M_MEMORY_FULL(sizeof(deque_node_t)+def * sizeof(type)); \
return NULL; \
} \
n->size = def; \
deque_node_list_init_field(n); \
/* Increase default size for next allocation */ \
d->default_size += def/2; \
return n; \
} \
\
static inline void \
M_C(name, _init)(deque_t d) \
{ \
M_C(name, _node_list_init)(d->list); \
d->default_size = DEQUEUI_DEFAULT_SIZE; \
d->count = 0; \
deque_node_t *n = M_C(name, _int_new_node)(d); \
if (n == NULL) return; \
deque_node_list_push_back(d->list, n); \
d->front->node = n; \
d->front->index = DEQUEUI_DEFAULT_SIZE/2; \
d->back->node = n; \
d->back->index = DEQUEUI_DEFAULT_SIZE/2; \
DEQUEI_CONTRACT(d); \
} \
\
static inline void \
M_C(name, _clear)(deque_t d) \
{ \
DEQUEI_CONTRACT(d); \
/* We registered the delete operator to clear all objects */ \
M_C(name, _node_list_clear)(d->list); \
/* This is safer */ \
d->front->node = NULL; \
d->back->node = NULL; \
d->count = 0; \
} \
\
static inline void \
M_C(name, _push_back)(deque_t d, type const x) \
{ \
DEQUEI_CONTRACT(d); \
deque_node_t *n = d->back->node; \
size_t index = d->back->index; \
if (M_UNLIKELY (n->size <= index)) { \
n = M_C(name, _node_list_next_obj)(d->list, n); \
if (n == NULL) { \
n = M_C(name, _int_new_node)(d); \
M_C(name, _node_list_push_back)(d->list, n); \
} \
d->back->node = n; \
index = 0; \
} \
M_GET_INIT_SET oplist (n->data[index], x); \
index++; \
d->count ++; \
d->back->index = index; \
DEQUEI_CONTRACT(d); \
} \
\
static inline void \
M_C(name, _push_front)(deque_t d, type const x) \
{ \
DEQUEI_CONTRACT(d); \
deque_node_t *n = d->front->node; \
size_t index = d->front->index; \
index --; \
/* If overflow */ \
if (M_UNLIKELY (n->size <= index)) { \
n = M_C(name, _node_list_previous_obj)(d->list, n); \
if (n == NULL) { \
n = M_C(name, _int_new_node)(d); \
M_C(name, _node_list_push_front)(d->list, n); \
} \
d->front->node = n; \
index = n->size -1; \
} \
M_GET_INIT_SET oplist (n->data[index], x); \
d->count ++; \
d->front->index = index; \
DEQUEI_CONTRACT(d); \
} \
\
static inline void \
M_C(name, _pop_back)(type *ptr, deque_t d) \
{ \
DEQUEI_CONTRACT(d); \
deque_node_t *n = d->back->node; \
size_t index = d->back->index; \
index --; \
if (M_UNLIKELY (n->size <= index)) { \
n = deque_node_list_previous_obj(d->list, n); \
assert (n != NULL); \
d->back->node = n; \
index = n->size-1; \
} \
if (ptr != NULL) \
M_IF_METHOD(MOVE, oplist) ( \
M_GET_MOVE oplist(*ptr, n->data[index]); else \
, \
M_GET_SET oplist(*ptr, n->data[index]); \
) \
M_GET_CLEAR oplist (n->data[index]); \
d->count --; \
d->back->index = index; \
DEQUEI_CONTRACT(d); \
} \
\
static inline void \
M_C(name, _pop_front)(type *ptr, deque_t d) \
{ \
DEQUEI_CONTRACT(d); \
deque_node_t *n = d->front->node; \
size_t index = d->front->index; \
if (M_UNLIKELY (n->size <= index)) { \
n = deque_node_list_next_obj(d->list, n); \
assert (n != NULL); \
d->front->node = n; \
index = 0; \
} \
if (ptr != NULL) \
M_IF_METHOD(MOVE, oplist) ( \
M_GET_MOVE oplist(*ptr, n->data[index]); else \
, \
M_GET_SET oplist(*ptr, n->data[index]); \
) \
M_GET_CLEAR oplist (n->data[index]); \
index++; \
d->count --; \
d->front->index = index; \
} \
// TODO: init_set, set, move, init_move, equal_p, _hash, iterators*,
// _get, _cget, _clean, _front, _back, _set_at, _push_back_raw,
// _pop_front_raw, _push_back_new, _push_front_new, _empty_p, _size,
// _swap, _swap_at, IO [like array]
#endif