[core] Added tdata, sexpr libraries to the project;
parent
1cfb0aed3c
commit
3ef4cece81
@ -1,2 +1,6 @@
|
||||
nobase_include_HEADERS = sxmp/sxmp.h sxmp/errno.h sxmp/limits.h sxmp/version.h \
|
||||
sxmp/base64.h
|
||||
sxmp/base64.h \
|
||||
sexpr/cstring.h sexpr/faststack.h sexpr/sexp_errors.h sexpr/sexp.h \
|
||||
sexpr/sexp_memory.h sexpr/sexp_ops.h sexpr/sexp_vis.h \
|
||||
tdata/bitwise.h tdata/idx_allocator.h tdata/macro.h tdata/tree.h \
|
||||
tdata/usrtc.h tdata/list.h tdata/ctrie.h
|
||||
|
@ -0,0 +1,142 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
/**
|
||||
* cstring.h : c string library to make Ron happy. Wrapper around plain
|
||||
* C strings that handles automatically growing the string as data is
|
||||
* concattenated to the end. (note: this is an improved version of cstring
|
||||
* from supermon. Migrate it into that library eventually... )
|
||||
*
|
||||
* -matt sottile
|
||||
*/
|
||||
#ifndef __CSTRING_H__
|
||||
#define __CSTRING_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Structure wrapping the character pointer and size counters (allocated vs.
|
||||
* actual used).
|
||||
*/
|
||||
typedef struct __cstring {
|
||||
/**
|
||||
* Base address of the string.
|
||||
*/
|
||||
char *base;
|
||||
|
||||
/**
|
||||
* Size of the memory allocated and pointed to by the base pointer.
|
||||
*/
|
||||
size_t len;
|
||||
|
||||
/**
|
||||
* Current size of the string stored in the buffer. len >= curlen
|
||||
* always, and when len < curlen would be true after a concat operation,
|
||||
* we realloc bigger space to keep len >= curlen.
|
||||
*/
|
||||
size_t curlen;
|
||||
} CSTRING;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Set the growth size. Values less than one are ignored.
|
||||
*/
|
||||
void sgrowsize(size_t s);
|
||||
|
||||
/**
|
||||
* Allocate a new CSTRING of the given size.
|
||||
* A NULL return value indicates that something went wrong and that
|
||||
* sexp_errno should be checked for the cause.
|
||||
*/
|
||||
CSTRING *snew(size_t s);
|
||||
|
||||
/**
|
||||
* Concatenate the second argument to the CSTRING passed in the first.
|
||||
* The second argument must be a pointer to a null terminated string.
|
||||
* A NULL return value indicates that something went wrong and that
|
||||
* sexp_errno should be checked for the cause. The contents of s are
|
||||
* left alone. As such, the caller should check the pointer returned
|
||||
* before overwriting the value of s, as this may result in a memory
|
||||
* leak if an error condition occurs.
|
||||
*/
|
||||
CSTRING *sadd(CSTRING *s, char *a);
|
||||
|
||||
/**
|
||||
* Append a character to the end of the CSTRING.
|
||||
* A NULL return value indicates that something went wrong and that
|
||||
* sexp_errno should be checked for the cause. The contents of s are
|
||||
* left alone. As such, the caller should check the pointer returned
|
||||
* before overwriting the value of s, as this may result in a memory
|
||||
* leak if an error condition occurs.
|
||||
*/
|
||||
CSTRING *saddch(CSTRING *s, char a);
|
||||
|
||||
/**
|
||||
* Trim the allocated memory to precisely the string length plus one char
|
||||
* to hold the null terminator
|
||||
* A NULL return value indicates that something went wrong and that
|
||||
* sexp_errno should be checked for the cause. The contents of s are
|
||||
* left alone. As such, the caller should check the pointer returned
|
||||
* before overwriting the value of s, as this may result in a memory
|
||||
* leak if an error condition occurs.
|
||||
*/
|
||||
CSTRING *strim(CSTRING *s);
|
||||
|
||||
/**
|
||||
* Return the base pointer of the CSTRING. NULL either means the base
|
||||
* pointer was null, or the CSTRING itself was NULL.
|
||||
*/
|
||||
char *toCharPtr(CSTRING *s);
|
||||
|
||||
/**
|
||||
* Set the current length to zero, effectively dumping the string without
|
||||
* deallocating it so we can use it later without reallocating any memory.
|
||||
*/
|
||||
void sempty(CSTRING *s);
|
||||
|
||||
/**
|
||||
* Destroy the CSTRING struct and the data it points at.
|
||||
*/
|
||||
void sdestroy(CSTRING *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __CSTRING_H__ */
|
@ -0,0 +1,152 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
/**
|
||||
* \file faststack.h
|
||||
*
|
||||
* \brief Implementation of a fast stack with smart memory management.
|
||||
*/
|
||||
#ifndef __FASTSTACK_H__
|
||||
#define __FASTSTACK_H__
|
||||
|
||||
/**
|
||||
* Structure representing a single level in the stack. Has a pointer to the
|
||||
* level above and below itself and a pointer to a generic blob of data
|
||||
* associated with this level.
|
||||
*/
|
||||
typedef struct stack_level {
|
||||
/**
|
||||
* Pointer to the level above this one. If NULL, then this level is the
|
||||
* top of the stack. If above is non-NULL, this level *may* be the top,
|
||||
* but all that can be guaranteed is that there are other allocated
|
||||
* but potentially unused levels above this one.
|
||||
*/
|
||||
struct stack_level *above;
|
||||
|
||||
/**
|
||||
* Pointer to the level below this one. If NULL, then this level is the
|
||||
* bottom.
|
||||
*/
|
||||
struct stack_level *below;
|
||||
|
||||
/**
|
||||
* Pointer to some data associated with this level. User is responsible
|
||||
* for knowing what to cast the \c void \c * pointer into.
|
||||
*/
|
||||
void *data;
|
||||
} stack_lvl_t;
|
||||
|
||||
/**
|
||||
* Wrapper around the stack levels - keeps a pointer to the current top and
|
||||
* bottom of the stack and a count of the current height. This allows the top
|
||||
* to have non-null above pointer resulting from previously allocated stack
|
||||
* levels that may be recycled later without \c malloc overhead.
|
||||
*/
|
||||
typedef struct stack_wrapper {
|
||||
/**
|
||||
* The top of the stack. If this is NULL, the stack is empty.
|
||||
*/
|
||||
stack_lvl_t *top;
|
||||
|
||||
/**
|
||||
* The bottom of the stack. If this is NULL, the stack is empty.
|
||||
*/
|
||||
stack_lvl_t *bottom;
|
||||
|
||||
/**
|
||||
* The current height of the stack, in terms of allocated and used levels.
|
||||
*/
|
||||
int height;
|
||||
} faststack_t;
|
||||
|
||||
/** functions **/
|
||||
|
||||
/* this is for C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Return a pointer to an empty stack structure. If the return value is
|
||||
* NULL, one should check sexp_errno to determine why.
|
||||
*/
|
||||
faststack_t *make_stack();
|
||||
|
||||
/**
|
||||
* Given a stack structure, destroy it and free all of the stack levels.
|
||||
* <B>Important note</B> : This function <I>does not</I> free the data
|
||||
* pointed to from each level of the stack - the user is responsible
|
||||
* for freeing this data themselves before calling this function to
|
||||
* prevent memory leakage.
|
||||
*/
|
||||
void destroy_stack(faststack_t *s);
|
||||
|
||||
/**
|
||||
* Given a stack, push a new level on referring to the data pointer.
|
||||
* If a new level cannot be allocated, NULL is returned and sexp_errno
|
||||
* is set with the appropriate error condition. Memory allocation errors
|
||||
* will result in SEXP_ERR_MEMORY, while a null stack will result in
|
||||
* SEXP_ERR_BAD_STACK.
|
||||
*/
|
||||
faststack_t *push(faststack_t *cur_stack, void *data);
|
||||
|
||||
/**
|
||||
* Given a stack, pop a level off and return a pointer to that level.
|
||||
* The user is responsible for extracting the data, but the stack_lvl_t
|
||||
* structures pointed to from the level (above and below) should be left
|
||||
* alone. If NULL is returned, either the stack contained nothing, or
|
||||
* the incoming stack s was NULL. Consult sexp_errno to determine which
|
||||
* was the case -- SEXP_ERR_BAD_STACK indicates a null stack was passed in.
|
||||
*/
|
||||
stack_lvl_t *pop(faststack_t *s);
|
||||
|
||||
/* this is for C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Given a stack \a s, examine the data pointer at the top.
|
||||
*/
|
||||
#define top_data(s) (s->top->data)
|
||||
|
||||
/**
|
||||
* Given a stack \a s, check to see if the stack is empty or not. Value
|
||||
* is boolean true or false.
|
||||
*/
|
||||
#define empty_stack(s) (s->top == NULL)
|
||||
|
||||
#endif /* __FASTSTACK_H__ */
|
@ -0,0 +1,806 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#ifndef __SEXP_H__
|
||||
#define __SEXP_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h> /* for BUFSIZ only */
|
||||
#include "faststack.h"
|
||||
#include "cstring.h"
|
||||
#include "sexp_memory.h"
|
||||
#include "sexp_errors.h"
|
||||
|
||||
/* doxygen documentation groups defined here */
|
||||
|
||||
/**
|
||||
* \defgroup IO I/O routines
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup parser Parser routines
|
||||
*/
|
||||
|
||||
/**
|
||||
* \mainpage A small and quick S-expression parsing library.
|
||||
*
|
||||
* \section intro Introduction
|
||||
*
|
||||
* This library was created to provide s-expression parsing and manipulation
|
||||
* facilities to C and C++ programs. The primary goals were speed and
|
||||
* efficiency - low memory impact, and the highest speed we could achieve in
|
||||
* parsing. Suprisingly, no other libraries on the net were found that were
|
||||
* not bloated with features or involved embedding a full-fledged LISP or
|
||||
* Scheme interpreter into our programs. So, this library evolved to fill
|
||||
* this gap. As such, it does not guarantee that every valid LISP
|
||||
* expression is parseable, and many features that are not required aren't
|
||||
* implemented. See Rivest's S-expression library for an example of a much
|
||||
* more featureful library.
|
||||
*
|
||||
* What features does this library include? At the heart of the code is a
|
||||
* continuation-based parser implementing a basic parser state machine.
|
||||
* Continuations allow users to accumulate multiple streams of characters,
|
||||
* and parse each stream simultaneously. A continuation allows the parser
|
||||
* to stop midstream, start working on a new expression, and return to the
|
||||
* first without corruption of complex state management in the users code.
|
||||
* No threads, no forking, nothing more than a data structure that must be
|
||||
* passed in and captured as data becomes available to parse. Once an
|
||||
* expression has been parsed, a simple structure is returned that
|
||||
* represents the "abstract syntax tree" of the parsed expression. For the
|
||||
* majority of users, the parser and this data structure will be all that
|
||||
* they will ever need to see. For convenience reasons, other functions
|
||||
* such as I/O wrappers and AST traversal routines have been included, but
|
||||
* they are not required if users don't wish to use them.
|
||||
*
|
||||
* \section credits Credits
|
||||
*
|
||||
* SFSEXP: Small, Fast S-Expression Library version 1.2, October 2007 \n
|
||||
* Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
*
|
||||
* \section license License Information
|
||||
*
|
||||
* Copyright (2003-2006). The Regents of the University of California. This
|
||||
* material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
* Alamos National Laboratory, which is operated by the University of
|
||||
* California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
* to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
* THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
* LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
* derivative works, such modified software should be clearly marked, so as not
|
||||
* to confuse it with the version available from LANL.
|
||||
*
|
||||
* Additionally, this library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
*
|
||||
* LA-CC-04-094
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file sexp.h
|
||||
*
|
||||
* \brief API for a small, fast and portable s-expression parser library.
|
||||
*/
|
||||
|
||||
/*==============*/
|
||||
/* ENUMERATIONS */
|
||||
/*==============*/
|
||||
|
||||
/**
|
||||
* An element in an s-expression can be one of three types: a <i>value</i>
|
||||
* represents an atom with an associated text value. A <i>list</i>
|
||||
* represents an s-expression, and the element contains a pointer to
|
||||
* the head element of the associated s-expression.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* An atom of some type. See atom type (aty) field of element structure
|
||||
* for details as to which atom type this is.
|
||||
*/
|
||||
SEXP_VALUE,
|
||||
|
||||
/**
|
||||
* A list. This means the element points to an element representing the
|
||||
* head of a list.
|
||||
*/
|
||||
SEXP_LIST
|
||||
} elt_t;
|
||||
|
||||
/**
|
||||
* For an element that represents a value, the value can be interpreted
|
||||
* as a more specific type. A <i>basic</i> value is a simple string with
|
||||
* no whitespace (and therefore no quotes required). A <i>double quote</i>
|
||||
* value, or <i>dquote</i>, is one that contains characters (such as
|
||||
* whitespace) that requires quotation marks to contain the string. A
|
||||
* <i>single quote</i> value, or <i>squote</i>, represents an element that is
|
||||
* prefaced with a single tick-mark. This can be either an atom or
|
||||
* s-expression, and the result is that the parser does not attempt to parse
|
||||
* the element following the tick mark. It is simply stored as text. This
|
||||
* is similar to the meaning of a tick mark in the Scheme or LISP family
|
||||
* of programming languages. Finally, <i>binary</I> allows raw binary to
|
||||
* be stored within an atom. Note that if the binary type is used, the data
|
||||
* is stored in bindata with the length in binlength. Otherwise, the data
|
||||
* us stored in the val field with val_used and val_allocated tracking the
|
||||
* size of the value string and the total memory allocated for it.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* Basic, unquoted value.
|
||||
*/
|
||||
SEXP_BASIC,
|
||||
|
||||
/**
|
||||
* Single quote (tick-mark) value - contains a string representing
|
||||
* a non-parsed portion of the s-expression.
|
||||
*/
|
||||
SEXP_SQUOTE,
|
||||
|
||||
/**
|
||||
* Double-quoted string. Similar to a basic value, but potentially
|
||||
* containing white-space.
|
||||
*/
|
||||
SEXP_DQUOTE,
|
||||
|
||||
/**
|
||||
* Binary data. This is used when the specialized parser is active
|
||||
* and supports inlining of binary blobs of data inside an expression.
|
||||
*/
|
||||
SEXP_BINARY
|
||||
} atom_t;
|
||||
|
||||
/*============*/
|
||||
/* STRUCTURES */
|
||||
/*============*/
|
||||
|
||||
/**
|
||||
* An s-expression is represented as a linked structure of elements,
|
||||
* where each element is either an <I>atom</I> or <I>list</I>. An
|
||||
* atom corresponds to a string, while a list corresponds to an
|
||||
* s-expression. The following grammar represents our definition of
|
||||
* an s-expression:<P>
|
||||
*
|
||||
* <pre>
|
||||
* sexpr ::= ( sx )
|
||||
* sx ::= atom sxtail | sexpr sxtail | 'sexpr sxtail | 'atom sxtail | NULL
|
||||
* sxtail ::= sx | NULL
|
||||
* atom ::= quoted | value
|
||||
* quoted ::= "ws_string"
|
||||
* value ::= nws_string
|
||||
* </pre>
|
||||
* <P>
|
||||
*
|
||||
* An atom can either be a quoted string, which is a string containing
|
||||
* whitespace (possibly) surrounded by double quotes, or a non-whitespace
|
||||
* string that does not require surrounding quotes. An element representing
|
||||
* an atom will have a type of <i>value</i> and data stored in the <i>val</i>
|
||||
* field. An element of type <i>list</i> represents an s-expression
|
||||
* corresponding to <i>sexpr</i> in the grammar, and will have a pointer to
|
||||
* the head of the appropriate s-expression. Details regarding these fields
|
||||
* and their values given with the fields themselves. Notice that a single
|
||||
* quote can appear directly before an s-expression or atom, similar to the
|
||||
* use in LISP.
|
||||
*/
|
||||
typedef struct elt {
|
||||
/**
|
||||
* The element has a type that determines how the structure is used.
|
||||
* If the type is <B>SEXP_VALUE</B>, then a programmer knows that
|
||||
* either the val field or bindata field is meaningful dependin on
|
||||
* the value of the aty field, and contains the data associated with
|
||||
* this element of the s-expression. If the type is
|
||||
* <B>SEXP_LIST</B>, then the list field contains a pointer to the
|
||||
* s-expression element representing the head of the list. For each
|
||||
* case, the field for the opposite case contains no meaningful data
|
||||
* and using them in any way is likely to cause an error.
|
||||
*/
|
||||
elt_t ty;
|
||||
|
||||
/**
|
||||
* If the type of the element is <B>SEXP_VALUE</B> and the aty field
|
||||
* is not <B>SEXP_BINARY</B>, this field will contain the actual data
|
||||
* represented by this element.
|
||||
*/
|
||||
char *val;
|
||||
|
||||
/**
|
||||
* Number of bytes allocated for val.
|
||||
*/
|
||||
size_t val_allocated;
|
||||
|
||||
/**
|
||||
* Number of bytes used in val (<= val_allocated).
|
||||
*/
|
||||
size_t val_used;
|
||||
|
||||
/**
|
||||
* If the type of the element is <B>SEXP_LIST</B>, this field will contain
|
||||
* a pointer to the head element of the list.
|
||||
*/
|
||||
struct elt *list;
|
||||
|
||||
/**
|
||||
* The <I>next</I> field is a pointer to the next element in the current
|
||||
* expression. If this element is the last element in the s-expression,
|
||||
* this field will be <I>NULL</I>.
|
||||
*/
|
||||
struct elt *next;
|
||||
|
||||
/**
|
||||
* For elements that represent <I>values</I>, this field will specify the
|
||||
* specific type of value that it represents. This can be used by
|
||||
* functions to determine how this value should be printed (ie: how it
|
||||
* should be quoted) or interpreted (ie: interpreting s-expressions that
|
||||
* are prefixed with a tick-mark.). This value also indicates whether or
|
||||
* not the programmer should look in the val field or bindata field for
|
||||
* the atom data.
|
||||
*/
|
||||
atom_t aty;
|
||||
|
||||
/**
|
||||
* For elements that represent <i>binary</I> blobs, this field will
|
||||
* point to a memory location where the data resides. The length
|
||||
* of this memory blob is the next field. char* implies byte sized
|
||||
* elements. This is only used in INLINE_BINARY parser mode.
|
||||
* <B>IMPORTANT NOTE</B>: The data in this field is freed on a
|
||||
* destroy_sexp() call, so users should copy it to memory they allocate
|
||||
* if they wish it to persist after the sexp_t has been freed.
|
||||
*/
|
||||
char *bindata;
|
||||
|
||||
/**
|
||||
* The length of the data pointed at by bindata in bytes.
|
||||
*/
|
||||
size_t binlength;
|
||||
} sexp_t;
|
||||
|
||||
/**
|
||||
* parser mode flag used by continuation to toggle special parser
|
||||
* behaviour.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* normal (LISP-style) s-expression parser behaviour.
|
||||
*/
|
||||
PARSER_NORMAL,
|
||||
|
||||
/**
|
||||
* treat atoms beginning with \#b\# as inlined binary data. everything
|
||||
* else is treated the same as in PARSER_NORMAL mode.
|
||||
*/
|
||||
PARSER_INLINE_BINARY,
|
||||
|
||||
/**
|
||||
* if the event_handlers field in the continuation contains a non-null
|
||||
* value, the handlers specified in the parser_event_handlers_t struct
|
||||
* will be called as appropriate, but the parser will not allocate a
|
||||
* structure composed of sexp_t structs. Note that if the event_handlers
|
||||
* is set to null and this mode is selected, the user would be better off
|
||||
* not calling anything in the first place, as they are telling the parser
|
||||
* to walk the string, but do nothing productive in the process.
|
||||
*/
|
||||
PARSER_EVENTS_ONLY
|
||||
} parsermode_t;
|
||||
|
||||
/**
|
||||
* Some users would prefer to, instead of parsing a full string and walking
|
||||
* a potentially huge sexp_t structure, use an XML SAX-style parser where
|
||||
* events are triggered as certain parts of the s-expression are encountered.
|
||||
* This structure contains a set of function pointers that are called by
|
||||
* the parser as it hits expression start and end, and completes reading
|
||||
* atoms and binary data. NOTE: The parser_event_handler struct that is
|
||||
* a field in the continuation data structure is NOT freed by
|
||||
* destroy_continuation since structs for callbacks are ALWAYS malloc'd
|
||||
* by the user, not the library.
|
||||
*/
|
||||
typedef struct parser_event_handlers {
|
||||
/**
|
||||
* The start_sexpr function pointer is called when an open parenthesis
|
||||
* is encountered starting an expression.
|
||||
*/
|
||||
void (* start_sexpr)();
|
||||
|
||||
/**
|
||||
* The end_sexpr function pointer is called when an close parenthesis
|
||||
* is encountered ending an expression.
|
||||
*/
|
||||
void (* end_sexpr)();
|
||||
|
||||
/**
|
||||
* The characters function pointer is called when an atom is completely
|
||||
* parsed. The function must take three arguments: a pointer to the
|
||||
* atom data, the number of elements the atom contains, and the
|
||||
* specific type of atom that the data represents.
|
||||
*/
|
||||
void (* characters)(const char *data, size_t len, atom_t aty);
|
||||
|
||||
/**
|
||||
* The binary function pointer is called when the parser is functioning
|
||||
* in INLINE_BINARY mode and binary data is encountered. The function
|
||||
* must take two arguments: a pointer to the beginning of the binary data
|
||||
* and the number of bytes of data present.
|
||||
*/
|
||||
void (* binary)(const char *data, size_t len);
|
||||
} parser_event_handlers_t;
|
||||
|
||||
/**
|
||||
* A continuation is used by the parser to save and restore state between
|
||||
* invocations to support partial parsing of strings. For example, if we
|
||||
* pass the string "(foo bar)(goo car)" to the parser, we want to be able
|
||||
* to retrieve each s-expression one at a time - it would be difficult to
|
||||
* return all s-expressions at once without knowing how many there are in
|
||||
* advance (this would require more memory management than we want...).
|
||||
* So, by using a continuation-based parser, we can call it with this string
|
||||
* and have it return a continuation when it has parsed the first
|
||||
* s-expression. Once we have processed the s-expression (accessible
|
||||
* through the <i>last_sexpr</i> field of the continuation), we can call
|
||||
* the parser again with the same string and continuation, and it will be
|
||||
* able to pick up where it left off.<P>
|
||||
*
|
||||
* We use continuations instead of a state-ful parser to allow multiple
|
||||
* concurrent strings to be parsed by simply maintaining a set of
|
||||
* continuations. Manipulating continuations by hand is required if the
|
||||
* continuation-based parser is called directly. This is <b>not
|
||||
* recommended</b> unless you are willing to deal with potential errors and
|
||||
* are willing to learn exactly how the continuation relates to the
|
||||
* internals of the parser. A simpler approach is to use either the
|
||||
* <i>parse_sexp</i> function that simply returns an s-expression without
|
||||
* exposing the continuations, or the <i>iparse_sexp</i> function that
|
||||
* allows iteratively popping one s-expression at a time from a string
|
||||
* containing one or more s-expressions. Refer to the documentation for
|
||||
* each parsing function for further details on behavior and usage.
|
||||
*/
|
||||
typedef struct pcont {
|
||||
/**
|
||||
* The parser stack used for iterative parsing.
|
||||
*/
|
||||
faststack_t *stack;
|
||||
|
||||
/**
|
||||
* The last full s-expression encountered by the parser. If this is
|
||||
* NULL, the parser has not encountered a full s-expression and more
|
||||
* data is required for the current s-expression being parsed. If this
|
||||
* is non-NULL, then the parser has encountered one s-expression and may
|
||||
* be partially through parsing the next s-expression.
|
||||
*/
|
||||
sexp_t *last_sexp;
|
||||
|
||||
/**
|
||||
* Pointer to a temporary buffer used to store atom values during parsing.
|
||||
*/
|
||||
char *val;
|
||||
|
||||
/**
|
||||
* Current number of bytes allocated for val.
|
||||
*/
|
||||
size_t val_allocated;
|
||||
|
||||
/**
|
||||
* Current number of used bytes in val.
|
||||
*/
|
||||
size_t val_used;
|
||||
|
||||
/**
|
||||
* Pointer to the character following the last character in the current
|
||||
* atom value being parsed.
|
||||
*/
|
||||
char *vcur;
|
||||
|
||||
/**
|
||||
* Pointer to the last character to examine in the string being parsed.
|
||||
* When the parser is called with the continuation, this is the first
|
||||
* character that will be processed. If this is NULL, the parser will
|
||||
* start parsing at the beginning of the string passed into the parser.
|
||||
*/
|
||||
char *lastPos;
|
||||
|
||||
/**
|
||||
* This is a pointer to the beginning of the current string being
|
||||
* processed. lastPos is a pointer to some value inside the string
|
||||
* that this points to.
|
||||
*/
|
||||
char *sbuffer;
|
||||
|
||||
/**
|
||||
* This is the depth of parenthesis (the number of left parens encountered)
|
||||
* that the parser is currently working with.
|
||||
*/
|
||||
unsigned int depth;
|
||||
|
||||
/**
|
||||
* This is the depth of parenthesis encountered after a single quote (tick)
|
||||
* if the character immediately following the tick was a left paren.
|
||||
*/
|
||||
unsigned int qdepth;
|
||||
|
||||
/**
|
||||
* This is the state ID of the current state of the parser in the
|
||||
* DFA representing the parser. The current parser is a DFA based parser
|
||||
* to simplify restoring the proper state from a continuation.
|
||||
*/
|
||||
unsigned int state;
|
||||
|
||||
/**
|
||||
* This is a flag indicating whether the next character to be processed
|
||||
* should be assumed to have been prefaced with a '\' character to escape
|
||||
* it.
|
||||
*/
|
||||
unsigned int esc;
|
||||
|
||||
/**
|
||||
* Flag whether or not we are processing an atom that was preceeded by
|
||||
* a single quote.
|
||||
*/
|
||||
unsigned int squoted;
|
||||
|
||||
/**
|
||||
* Error code. Used to indicate that the continuation being returned does
|
||||
* not represent a successful parsing and thus the contents aren't of much
|
||||
* value.
|
||||
*/
|
||||
sexp_errcode_t error;
|
||||
|
||||
/**
|
||||
* Mode. The parsers' specialized behaviours can be activated by
|
||||
* tweaking the mode setting. There are currently two available:
|
||||
* normal and inline_binary. Inline_binary treats atoms that start
|
||||
* with \#b\# specially, assuming that they have the structure:
|
||||
*
|
||||
* \#b\#s\#data
|
||||
*
|
||||
* Where s is a positive (greater than 0) integer representing the length
|
||||
* of the data, and data is s bytes of binary data following the \#
|
||||
* sign. After the s bytes, it is assumed normal s-expression data
|
||||
* continues.
|
||||
*/
|
||||
parsermode_t mode;
|
||||
|
||||
/* -----------------------------------------------------------------
|
||||
* These fields below are related to dealing with INLINE_BINARY mode
|
||||
* ----------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Length to expect of the current binary data being read in.
|
||||
* this also corresponds to the size of the memory allocated for
|
||||
* reading this binary data into.
|
||||
*/
|
||||
size_t binexpected;
|
||||
|
||||
/**
|
||||
* Number of bytes of the binary blob that have already been read in.
|
||||
*/
|
||||
size_t binread;
|
||||
|
||||
/**
|
||||
* Pointer to the memory containing the binary data being read in.
|
||||
*/
|
||||
char *bindata;
|
||||
|
||||
/**
|
||||
* Pointer to a structure holding handlers for sexpr events. NULL for
|
||||
* normal parser operation. This field is NOT freed by
|
||||
* destroy_continuation and must be free'd by the user. This is because
|
||||
* these are malloc'd outside the library ALWAYS, so they are the user's
|
||||
* responsibility.
|
||||
*/
|
||||
parser_event_handlers_t *event_handlers;
|
||||
} pcont_t;
|
||||
|
||||
/**
|
||||
* \ingroup IO
|
||||
* This structure is a wrapper around a standard I/O file descriptor and
|
||||
* the parsing infrastructure (continuation and a buffer) required to
|
||||
* parse off of it. This is used so that routines can hide the loops and
|
||||
* details required to accumulate up data read off of the file descriptor
|
||||
* and parse expressions individually out of it.
|
||||
*/
|
||||
typedef struct sexp_iowrap {
|
||||
/**
|
||||
* Continuation used to parse off of the file descriptor.
|
||||
*/
|
||||
pcont_t *cc;
|
||||
|
||||
/**
|
||||
* The file descriptor. Currently CANNOT be a socket since implementation
|
||||
* uses read(), not recv().
|
||||
*/
|
||||
int fd;
|
||||
|
||||
/**
|
||||
* Buffer to read data into before parsing.
|
||||
*/
|
||||
char buf[BUFSIZ];
|
||||
|
||||
/**
|
||||
* Byte count for last read. If it is -1, there was an error. Otherwise,
|
||||
* it will be a value from 0 to BUFSIZ.
|
||||
*/
|
||||
size_t cnt;
|
||||
} sexp_iowrap_t;
|
||||
|
||||
/*========*/
|
||||
/* GLOBAL */
|
||||
/*========*/
|
||||
|
||||
/**
|
||||
* Global value indicating the most recent error condition encountered.
|
||||
* This value can be reset to SEXP_ERR_OK by calling sexp_errno_reset().
|
||||
*/
|
||||
extern sexp_errcode_t sexp_errno;
|
||||
|
||||
/*===========*/
|
||||
/* FUNCTIONS */
|
||||
/*===========*/
|
||||
|
||||
/* this is for C++ users */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**
|
||||
* \ingroup parser
|
||||
* Set the parameters on atom value buffer allocation and growth sizes.
|
||||
* This is an important point for performance tuning, as many factors in
|
||||
* the expected expression structure must be taken into account such as:
|
||||
*
|
||||
* - Average size of atom values
|
||||
* - Variance in sizes of atom values
|
||||
* - Amount of memory that is tolerably ''wasted'' (allocated but not
|
||||
* used)
|
||||
*
|
||||
* The \a ss parameter specifies the initial size of all atom buffers.
|
||||
* Ideally, this should be sufficiently large to capture MOST atom values,
|
||||
* or at least close enough such that one growth is required. The
|
||||
* \a gs parameter specifies the number of bytes to increase the buffer size
|
||||
* by when space is exhausted. A safe choice for parameter sizes would
|
||||
* be on the order of the average size for \a ss, and one standard
|
||||
* deviation for \a gs. This ensures that 50% of all expressions are
|
||||
* guaranteed to fit in the initial buffer, and rougly 80-90% will fit in
|
||||
* one growth. If memory is not an issue, choosing ss to be the mean plus
|
||||
* one standard deviation will capture 80-90% of expressions in the initial
|
||||
* buffer, and a gs of one standard deviation will capture nearly all
|
||||
* expressions.
|
||||
*
|
||||
* Note: These parameters can be tuned at runtime as needs change, and they
|
||||
* will be applied to all expressions and expression elements parsed after
|
||||
* they are modified. They will not be applied retroactively to expressions
|
||||
* that have already been parsed.
|
||||
*/
|
||||
sexp_errcode_t set_parser_buffer_params(size_t ss, size_t gs);
|
||||
|
||||
/**
|
||||
* return an allocated sexp_t. This structure may be an already allocated
|
||||
* one from the stack or a new one if none are available. Use this instead
|
||||
* of manually mallocing if you want to avoid excessive mallocs. <I>Note:
|
||||
* Mallocing your own expressions is fine - you can even use
|
||||
* sexp_t_deallocate to deallocate them and put them in the pool.</I>
|
||||
* Also, if the stack has not been initialized yet, this does so.
|
||||
*/
|
||||
sexp_t *sexp_t_allocate(void);
|
||||
|
||||
/**
|
||||
* given a malloc'd sexp_t element, put it back into the already-allocated
|
||||
* element stack. This method will allocate a stack if one has not been
|
||||
* allocated already.
|
||||
*/
|
||||
void sexp_t_deallocate(sexp_t *s);
|
||||
|
||||
/**
|
||||
* In the event that someone wants us to release ALL of the memory used
|
||||
* between calls by the library, they can free it. If you don't call
|
||||
* this, the caches will be persistent for the lifetime of the library
|
||||
* user. Note that in the event of an error condition resulting in
|
||||
* sexp_errno being set, the user might consider calling this to clean up
|
||||
* any memory that may be lingering around that should be cleaned up.
|
||||
*/
|
||||
void sexp_cleanup(void);
|
||||
|
||||
/**
|
||||
* print a sexp_t struct as a string in the LISP style. If the buffer
|
||||
* is large enough and the conversion is successful, the return value
|
||||
* represents the length of the string contained in the buffer. If the
|
||||
* buffer was too small, or some other error occurred, the return
|
||||
* value is -1 and the contents of the buffer should not be assumed to
|
||||
* contain any useful information. When the return value is -1, the
|
||||
* caller should check the contents of sexp_errno for details on what
|
||||
* error may have occurred.
|
||||
*/
|
||||
int print_sexp(char *loc, size_t size, const sexp_t *e);
|
||||
|
||||
/**
|
||||
* print a sexp_t structure to a buffer, growing it as necessary instead
|
||||
* of relying on fixed size buffers like print_sexp. Important argument
|
||||
* to tune for performance reasons is <tt>ss</tt> - the
|
||||
* buffer start size. The growsize used by the CSTRING routines also should
|
||||
* be considered for tuning via the sgrowsize() function. This routine no
|
||||
* longer requires the user to specify the growsize, and uses the current
|
||||
* setting without changing it.
|
||||
*/
|
||||
int print_sexp_cstr(CSTRING **s, const sexp_t *e, size_t ss);
|
||||
|
||||
/**
|
||||
* Allocate a new sexp_t element representing a list.
|
||||
*/
|
||||
sexp_t *new_sexp_list(sexp_t *l);
|
||||
|
||||
/**
|
||||
* Allocate a new sexp_t element representing a raw binary atom.
|
||||
* This element will contain a pointer to the raw binary data
|
||||
* provided, as well as the binary data length. The character
|
||||
* atom fields will be NULL and the corresponding val
|
||||
* length and allocation size will be set to zero since this
|
||||
* element is carrying a binary pointer only.
|
||||
*/
|
||||
sexp_t *new_sexp_binary_atom(char *data, size_t binlength);
|
||||
|
||||
/**
|
||||
* Allocate a new sexp_t element representing a value. The user must
|
||||
* specify the precise type of the atom. This used to default to
|
||||
* SEXP_BASIC, but this can lead to errors if the user did not expect this
|
||||
* assumption. By explicitly passing in the atom type, the caller should
|
||||
* ensure that the data in the buffer is valid given the requested atom
|
||||
* type. For performance reasons, such checks are left to the caller if
|
||||
* they are desired, and not performed in the library if they are not
|
||||
* wanted.
|
||||
*/
|
||||
sexp_t *new_sexp_atom(const char *buf, size_t bs, atom_t aty);
|
||||
|
||||
/**
|
||||
* create an initial continuation for parsing the given string
|
||||
*/
|
||||
pcont_t *init_continuation(char *str);
|
||||
|
||||
/**
|
||||
* destroy a continuation. This involves cleaning up what it contains,
|
||||
* and cleaning up the continuation itself.
|
||||
*/
|
||||
void destroy_continuation (pcont_t * pc);
|
||||
|
||||
/**
|
||||
* \ingroup IO
|
||||
* create an IO wrapper structure around a file descriptor. A NULL return
|
||||
* value indicates some problem occurred allocating the wrapper, so the
|
||||
* user should check the value of sexp_errno for further information.
|
||||
*/
|
||||
sexp_iowrap_t *init_iowrap(int fd);
|
||||
|
||||
/**
|
||||
* \ingroup IO
|
||||
* destroy an IO wrapper structure. The file descriptor wrapped in the
|
||||
* wrapper will <B>not</B> be closed, so the caller is responsible
|
||||
* for manually calling close on the file descriptor.
|
||||
*/
|
||||
void destroy_iowrap(sexp_iowrap_t *iow);
|
||||
|
||||
/**
|
||||
* \ingroup IO
|
||||
* given and IO wrapper handle, read one s-expression
|
||||
* off of it. this expression may be contained in a continuation,
|
||||
* so there is no guarantee that under the covers an IO read
|
||||
* actually is occuring. A return value of NULL can either indicate
|
||||
* a parser error or no more data on the input IO handle. In the
|
||||
* event that NULL is returned, the user should check to see if
|
||||
* sexp_errno contains SEXP_ERR_IO_EMPTY (no more data) or a more
|
||||
* problematic error.
|
||||
*/
|
||||
sexp_t *read_one_sexp(sexp_iowrap_t *iow);
|
||||
|
||||
/**
|
||||
* \ingroup parser
|
||||
* wrapper around parser for compatibility.
|
||||
*/
|
||||
sexp_t *parse_sexp(char *s, size_t len);
|
||||
|
||||
/**
|
||||
* \ingroup parser
|
||||
* wrapper around parser for friendlier continuation use
|
||||
* pre-condition : continuation (cc) is NON-NULL!
|
||||
*/
|
||||
sexp_t *iparse_sexp(char *s, size_t len, pcont_t *cc);
|
||||
|
||||
/**
|
||||
* \ingroup parser
|
||||
* given a LISP style s-expression string, parse it into a set of
|
||||
* connected sexp_t structures.
|
||||
*/
|
||||
pcont_t *cparse_sexp(char *s, size_t len, pcont_t *pc);
|
||||
|
||||
/**
|
||||
* given a sexp_t structure, free the memory it uses (and recursively free
|
||||
* the memory used by all sexp_t structures that it references). Note
|
||||
* that this will call the deallocation routine for sexp_t elements.
|
||||
* This means that memory isn't freed, but stored away in a cache of
|
||||
* pre-allocated elements. This is an optimization to speed up the
|
||||
* parser to eliminate wasteful free and re-malloc calls. Note: If using
|
||||
* inlined binary mode, this will free the data pointed to by the bindata
|
||||
* field. So, if you care about the data after the lifetime of the
|
||||
* s-expression, make sure to make a copy before cleaning up the sexpr.
|
||||
*/
|
||||
void destroy_sexp(sexp_t *s);
|
||||
|
||||
/**
|
||||
* reset the value of sexp_errno to SEXP_ERR_OK.
|
||||
*/
|
||||
void reset_sexp_errno();
|
||||
|
||||
/**
|
||||
* print the contents of the parser continuation stack to a buffer.
|
||||
* this is useful if an expression is partially parsed and the caller
|
||||
* realizes that something is wrong with it. with this routine,
|
||||
* the caller can reconstruct the expression parsed so far and use it
|
||||
* for error reporting. this works with fixed size buffers allocated
|
||||
* by the caller. there is not a CSTRING-based version currently.
|
||||
*/
|
||||
void print_pcont(pcont_t * pc, char * buf, size_t buflen);
|
||||
|
||||
/* this is for C++ users */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sexp helpers */
|
||||
#define SEXP_IS_LIST(sx) \
|
||||
((sx)->ty == SEXP_LIST) ? 1 : 0
|
||||
|
||||
#define SEXP_IS_TYPE(sx,type) \
|
||||
((sx)->ty == SEXP_VALUE && (sx)->aty == (type)) ? 1 : 0
|
||||
|
||||
#define SEXP_ITERATE_LIST(lst, iter, ind) \
|
||||
for((ind) = 0, (iter) = (lst)->list; (ind) < sexp_list_length(lst); \
|
||||
(ind)++, (iter) = (iter)->next)
|
||||
|
||||
/* additional functions to work with sexp */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int sexp_list_cdr(sexp_t *expr, sexp_t **sx);
|
||||
int sexp_list_car(sexp_t *expr, sexp_t **sx);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "sexp_ops.h"
|
||||
|
||||
#endif /* __SEXP_H__ */
|
||||
|
@ -0,0 +1,148 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#ifndef __SEXP_ERRORS_H__
|
||||
#define __SEXP_ERRORS_H__
|
||||
|
||||
/**
|
||||
* \file sexp_errors.h
|
||||
*
|
||||
* \brief Error conditions are enumerated here along with any routines for
|
||||
* translating error codes to human readable messages.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Error codes used by the library are defined in this enumeration. They
|
||||
* are either used as values for the error field within the continuation
|
||||
* structures, or as return values for functions with a return type of
|
||||
* sexp_errcode_t.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* no error.
|
||||
*/
|
||||
SEXP_ERR_OK = 0,
|
||||
|
||||
/**
|
||||
* memory error. malloc/realloc/calloc failures may result in this error
|
||||
* code. this can either result from the system calls failing, or in the
|
||||
* limited memory mode of the library, the memory limit being exceeded.
|
||||
* In limited memory mode, if this error condition is present, one should
|
||||
* check the memory limits that were in place during the erroneous call.
|
||||
*/
|
||||
SEXP_ERR_MEMORY,
|
||||
|
||||
/**
|
||||
* badly formed expression. Missing, misplaced, or mismatched parenthesis
|
||||
* will result in this error.
|
||||
*/
|
||||
SEXP_ERR_BADFORM,
|
||||
|
||||
/**
|
||||
* a sexp_t that is inconsistent will result in this error code. An example
|
||||
* is a SEXP_BASIC sexp_t with a null val field but a non-zero val_used
|
||||
* value. Similar cases exist for SEXP_DQUOTE, SQUOTE, and BINARY types.
|
||||
* This value is also used in the parser to flag a case where an inlined
|
||||
* binary block is given a negative length.
|
||||
*/
|
||||
SEXP_ERR_BADCONTENT,
|
||||
|
||||
/**
|
||||
* if a null string is passed into the parser, this error occurs.
|
||||
*/
|
||||
SEXP_ERR_NULLSTRING,
|
||||
|
||||
/**
|
||||
* general IO related errors, such as failure of fopen(). these are
|
||||
* basically non-starters with respect to getting the IO routines going.
|
||||
*/
|
||||
SEXP_ERR_IO,
|
||||
|
||||
/**
|
||||
* I/O routines that return NULL may simply have nothing to read. This is
|
||||
* sometimes an error condition if the io wrapper continuation contains a
|
||||
* partially complete s-expression, but nothing more is present (yet) on the
|
||||
* file descriptor.
|
||||
*/
|
||||
SEXP_ERR_IO_EMPTY,
|
||||
|
||||
/**
|
||||
* when running the library under limited memory (ie, _SEXP_LIMIT_MEMORY_
|
||||
* defined at build time), this error will be produced when the memory
|
||||
* limit is exceeded.
|
||||
*/
|
||||
SEXP_ERR_MEM_LIMIT,
|
||||
|
||||
/**
|
||||
* buffer for unparsing is full.
|
||||
*/
|
||||
SEXP_ERR_BUFFER_FULL,
|
||||
|
||||
/**
|
||||
* routines that take parameters such as memory limits, growth sizes, or
|
||||
* default sizes, can produce this error if a bad value has been passed in.
|
||||
* this error usually will indicate that the parameters were bad and the
|
||||
* default values were used instead (ie, it is non-fatal.).
|
||||
*/
|
||||
SEXP_ERR_BAD_PARAM,
|
||||
|
||||
/**
|
||||
* bad stack state encountered.
|
||||
*/
|
||||
SEXP_ERR_BAD_STACK,
|
||||
|
||||
/**
|
||||
* unknown parser state
|
||||
*/
|
||||
SEXP_ERR_UNKNOWN_STATE,
|
||||
|
||||
/**
|
||||
* parsing is incomplete and need more data to complete it.
|
||||
*/
|
||||
SEXP_ERR_INCOMPLETE,
|
||||
|
||||
/**
|
||||
* this error code indicates that an atom was created with
|
||||
* the incorrect constructor. For example, attempting to
|
||||
* create a binary mode atom with the new_sexp_atom
|
||||
* constructor intended for text atoms will cause this to
|
||||
* be set.
|
||||
*/
|
||||
SEXP_ERR_BAD_CONSTRUCTOR
|
||||
|
||||
} sexp_errcode_t;
|
||||
|
||||
#endif /* __SEXP_ERRORS_H__ */
|
@ -0,0 +1,160 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#ifndef __SEXP_MEMORY_H__
|
||||
#define __SEXP_MEMORY_H__
|
||||
|
||||
/**
|
||||
* \file sexp_memory.h
|
||||
*
|
||||
* \brief Wrappers around basic memory allocation/deallocation routines to
|
||||
* allow memory usage limiting. Only enabled if _SEXP_LIMIT_MEMORY_
|
||||
* is defined when building the library, otherwise the routines
|
||||
* are defined to be the standard malloc/calloc/realloc/free
|
||||
* functions.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef _SEXP_LIMIT_MEMORY_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup memory Memory management routines.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* Wrapper around malloc, will check and increment memory usage
|
||||
* counters if space is available. Returns NULL if no memory left
|
||||
* to use, otherwise returns whatever malloc returns.
|
||||
* Due to the fact that NULL could mean either the memory limit was exceeded
|
||||
* or the system call returned NULL, the user must check sexp_errno to
|
||||
* determine the root cause.
|
||||
*/
|
||||
void *sexp_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* Wrapper around calloc, will check and increment memory usage
|
||||
* counters if space is available. Returns NULL if no memory left
|
||||
* to use, otherwise returns whatever calloc returns
|
||||
* Due to the fact that NULL could mean either the memory limit was exceeded
|
||||
* or the system call returned NULL, the user must check sexp_errno to
|
||||
* determine the root cause.
|
||||
*/
|
||||
void *sexp_calloc(size_t count, size_t size);
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* Wrapper around free. Instead of trusting sizeof(ptr) to return the
|
||||
* proper value, we explicitly pass the size of memory associated with
|
||||
* ptr. Decrements memory usage counter and frees ptr.
|
||||
*/
|
||||
void sexp_free(void *ptr, size_t size);
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* Wrapper around realloc. Instead of trusting sizeof(ptr) to return the
|
||||
* proper value, we explicitly pass the size of memory associated with
|
||||
* ptr as the oldsize. Increments the memory usage counter by
|
||||
* (size-oldsize) if enough space available for realloc.
|
||||
* Returns NULL if no memory left to use, otherwise returns whatever
|
||||
* realloc returns.
|
||||
* Due to the fact that NULL could mean either the memory limit was exceeded
|
||||
* or the system call returned NULL, the user must check sexp_errno to
|
||||
* determine the root cause.
|
||||
*/
|
||||
void *sexp_realloc(void *ptr, size_t size, size_t oldsize);
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* Return the memory limit imposed by the library if memory limiting was
|
||||
* enabled at compile time.
|
||||
*/
|
||||
size_t get_sexp_max_memory();
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* Return the amount of memory used.
|
||||
*/
|
||||
size_t get_sexp_used_memory();
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* Set the memory limit if memory limiting was enabled. If the new value
|
||||
* is zero or less, -1 is returned and sexp_errno is set. Similarly, if
|
||||
* the new value is less than the current amount used by the library,
|
||||
* -1 is returned and sexp_errno is set. If the new value is valid, the
|
||||
* new value is returned.
|
||||
*/
|
||||
int set_sexp_max_memory(size_t newsize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* _SEXP_LIMIT_MEMORY_ not defined. This is a macro that maps to calloc().
|
||||
*/
|
||||
#define sexp_calloc(count,size) calloc(count,size)
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* _SEXP_LIMIT_MEMORY_ not defined. This is a macro that maps to malloc().
|
||||
*/
|
||||
#define sexp_malloc(size) malloc(size)
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* _SEXP_LIMIT_MEMORY_ not defined. This is a macro that maps to free().
|
||||
*/
|
||||
#define sexp_free(ptr,size) free(ptr)
|
||||
|
||||
/**
|
||||
* \ingroup memory
|
||||
* _SEXP_LIMIT_MEMORY_ not defined. This is a macro that maps to realloc().
|
||||
*/
|
||||
#define sexp_realloc(ptr,size,oldsize) realloc((ptr),(size))
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __SEXP_MEMORY_H__ */
|
@ -0,0 +1,133 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#ifndef __SEXP_OPS_H__
|
||||
#define __SEXP_OPS_H__
|
||||
|
||||
/**
|
||||
* \file sexp_ops.h
|
||||
*
|
||||
* \brief A collection of useful operations to perform on s-expressions.
|
||||
*
|
||||
* A set of routines for operating on s-expressions.
|
||||
*/
|
||||
|
||||
#include "sexp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*========*/
|
||||
/* MACROS */
|
||||
/*========*/
|
||||
|
||||
/**
|
||||
* Return the head of a list \a s by reference, not copy.
|
||||
*/
|
||||
#define hd_sexp(s) ((s)->list)
|
||||
|
||||
/**
|
||||
* Return the tail of a list \a s by reference, not copy.
|
||||
*/
|
||||
#define tl_sexp(s) ((s)->list->next)
|
||||
|
||||
/**
|
||||
* Return the element following the argument \a s.
|
||||
*/
|
||||
#define next_sexp(s) ((s)->next)
|
||||
|
||||
/**
|
||||
* Reset the continuation \a c by setting the \c lastPos pointer to
|
||||
* \c NULL.
|
||||
*/
|
||||
#define reset_pcont(c) ((c)->lastPos = NULL)
|
||||
|
||||
/**
|
||||
* Find an atom in a sexpression data structure and return a pointer to
|
||||
* it. Return NULL if the string doesn't occur anywhere as an atom.
|
||||
* This is a depth-first search algorithm.
|
||||
*
|
||||
* \param name Value to search for.
|
||||
* \param start Root element of the s-expression to search from.
|
||||
* \return If the value is found, return a pointer to the first
|
||||
* occurrence in a depth-first traversal. NULL if not found.
|
||||
*/
|
||||
sexp_t *find_sexp(const char *name, sexp_t *start);
|
||||
|
||||
/**
|
||||
* Breadth first search for s-expressions. Depth first search will find
|
||||
* the first occurance of a string in an s-expression by basically finding
|
||||
* the earliest occurance in the string representation of the expression
|
||||
* itself. Breadth first search will find the first occurance of a string
|
||||
* in relation to the structure of the expression itself (IE: the instance
|
||||
* with the lowest depth will be found).
|
||||
*
|
||||
* \param name Value to search for.
|
||||
* \param start Root element of the s-expression to search from.
|
||||
* \return If the value is found, return a pointer to the first
|
||||
* occurrence in a breadth-first traversal. NULL if not found.
|
||||
*/
|
||||
sexp_t *bfs_find_sexp(const char *name, sexp_t *start);
|
||||
|
||||
/**
|
||||
* Given an s-expression, determine the length of the list that it encodes.
|
||||
* A null expression has length 0. An atom has length 1. A list has
|
||||
* length equal to the number of sexp_t elements from the list head
|
||||
* to the end of the ->next linked list from that point.
|
||||
*
|
||||
* \param sx S-expression input.
|
||||
* \return Number of sexp_t elements at the same level as sx, 0 for
|
||||
* NULL, 1 for an atom.
|
||||
*/
|
||||
int sexp_list_length(const sexp_t *sx);
|
||||
|
||||
/**
|
||||
* Copy an s-expression. This is a deep copy - so the resulting s-expression
|
||||
* shares no pointers with the original. The new one can be changed without
|
||||
* damaging the contents of the original.
|
||||
*
|
||||
* \param sx S-expression to copy.
|
||||
* \return A pointer to a copy of sx. This is a deep copy, so no memory
|
||||
* is shared between the original and the returned copy.
|
||||
*/
|
||||
sexp_t *copy_sexp(const sexp_t *sx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SEXP_OPS_H__ */
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
/**
|
||||
* \defgroup viz Visualization and debugging routines
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file sexp_vis.h
|
||||
*
|
||||
* \brief API for emitting graphviz data structure visualizations.
|
||||
*/
|
||||
#ifndef __SEXP_VIS_H__
|
||||
#define __SEXP_VIS_H__
|
||||
|
||||
/**
|
||||
* \ingroup viz
|
||||
*
|
||||
* Given a s-expression and a filename, this routine creates a DOT-file that
|
||||
* can be used to generate a visualization of the s-expression data structure.
|
||||
* This is useful for debugging to ensure that the structure is correct and
|
||||
* follows what was expected by the programmer. Non-trivial s-expressions
|
||||
* can yield very large visualizations though. Sometimes it is more
|
||||
* practical to visualize a portion of the structure if one knows where a bug
|
||||
* is likely to occur.
|
||||
*
|
||||
* \param sx S-expression data structure to create a DOT file based on.
|
||||
* \param fname Filename of the DOT file to emit.
|
||||
*/
|
||||
sexp_errcode_t sexp_to_dotfile(const sexp_t *sx, const char *fname);
|
||||
|
||||
#endif /* __SEXP_VIS_H__ */
|
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* (c) Copyright 2006,2007,2008 Jari OS Core Team <http://jarios.org>
|
||||
* (c) Copyright 2008 Dmitry Gromada <gromada82@gmail.com>
|
||||
* (c) Copyright 2010 Alexander Vdolainen <vdo@askele.com>
|
||||
*
|
||||
* (c) Copyright 2012 - 2013 Askele Oy <http://askele.com>
|
||||
*
|
||||
* Implements bitwise operations with multiword bitmaps
|
||||
*/
|
||||
|
||||
#ifndef __BITWISE_H__
|
||||
#define __BITWISE_H__
|
||||
|
||||
/* TODO: add arch deps */
|
||||
//#include <arch/bitwise.h>
|
||||
|
||||
/* TODO: add linux headers tests */
|
||||
#include <asm-generic/bitsperlong.h>
|
||||
|
||||
#ifdef __BITS_PER_LONG
|
||||
#define BITS_PER_LONG __BITS_PER_LONG
|
||||
#endif
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
#define TYPE_LONG_SHIFT 6
|
||||
#endif
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
#define TYPE_LONG_SHIFT 5
|
||||
#endif
|
||||
|
||||
typedef struct __bitmap {
|
||||
int nwords;
|
||||
unsigned long *map;
|
||||
} bitmap_t;
|
||||
|
||||
/**
|
||||
* @fn static inline void bit_set(void *bitmap, int bit)
|
||||
* Set bit number @a bit in the bitmap @a bitmap
|
||||
* @note The limit of @a bitmap = sizeof(unsigned long)
|
||||
*
|
||||
* @param[out] bitmap - A pointer to the bitmap
|
||||
* @param bit - Number of bit to set
|
||||
*/
|
||||
#ifndef ARCH_BIT_SET
|
||||
static inline void bit_set(void *bitmap, int bit)
|
||||
{
|
||||
*(unsigned long *)bitmap |= (1 << bit);
|
||||
}
|
||||
#else
|
||||
#define bit_set(bitmap, bit) arch_bit_set(bitmap, bit)
|
||||
#endif /* ARCH_BIT_SET */
|
||||
|
||||
/**
|
||||
* @fn static inline void bit_clear(void *bitmap, int bit)
|
||||
* Clear bit number @a bit in the bitmap @a bitmap
|
||||
* @note The limit of @a bitmap = sizeof(unsigned long)
|
||||
*
|
||||
* @param[out] bitmap - A pointer to the bitmap
|
||||
* @param bit - Number of bit to clear
|
||||
*/
|
||||
#ifndef ARCH_BIT_CLEAR
|
||||
static inline void bit_clear(void *bitmap, int bit)
|
||||
{
|
||||
*(unsigned long *)bitmap &= ~(1 << bit);
|
||||
}
|
||||
#else
|
||||
#define bit_clear(bitmap, bit) arch_bit_clear(bitmap, bit)
|
||||
#endif /* ARCH_BIT_CLEAR */
|
||||
|
||||
/**
|
||||
* @fn static inline void bit_toggle(void *bitmap, int bit)
|
||||
* Toggle bit @a bit in the bitmap @a bitmap.
|
||||
* @note The limit of @a bitmap = sizeof(unsigned long)
|
||||
*
|
||||
* @param[out] bitmap - A pointer to the bitmap.
|
||||
* @param bit - Number of bit to toggle
|
||||
*/
|
||||
#ifndef ARCH_BIT_TOGGLE
|
||||
static inline void bit_toggle(void *bitmap, int bit)
|
||||
{
|
||||
*(unsigned long *)bitmap ^= (1 << bit);
|
||||
}
|
||||
#else
|
||||
#define bit_toggle(bitmap, bit) arch_bit_toggle(bitmap, bit)
|
||||
#endif /* ARCH_BIT_TOGGLE */
|
||||
|
||||
/**
|
||||
* @fn static inline int bit_test(void *bitmap, int bitno)
|
||||
* Test if bit with number @a bitno is set in the bitmap @a bitmap.
|
||||
* @note The limit of @a bitmap = sizeof(unsigned long)
|
||||
*
|
||||
* @param bitmap - A pointer to the bitmap.
|
||||
* @param bitno - Number of bit to test
|
||||
* @return 1 if bit is set and 0 otherwise
|
||||
*/
|
||||
#ifndef ARCH_BIT_TEST
|
||||
static inline int bit_test(void *bitmap, int bitno)
|
||||
{
|
||||
return ((*(unsigned long *)bitmap & (1 << bitno)) >> bitno);
|
||||
}
|
||||
#else
|
||||
#define bit_test(bitmap, bitno) arch_bit_test(bitmap, bitno)
|
||||
#endif /* ARCH_BIT_TEST */
|
||||
|
||||
/**
|
||||
* @fn static inline int bit_test_and_set(void *bitmap, int bitno)
|
||||
* @brief Get old value of bit with number @a bitno and set @a bitno bit in the bitmap
|
||||
*
|
||||
* This function is similar to bit_set() except it copies old bit value before
|
||||
* setting it to 1 and return that value after needed bit was setted.
|
||||
* @note The limit of @a bitmap = sizeof(unsigned long)
|
||||
*
|
||||
* @param bitmap - A pointer to the bitmap
|
||||
* @param bitno - The number of bit to test and set
|
||||
* @return Old value of bit with number @a bitno
|
||||
*/
|
||||
#ifndef ARCH_BIT_TEST_AND_SET
|
||||
static inline int bit_test_and_set(void *bitmap, int bitno)
|
||||
{
|
||||
int val = (*(unsigned long *)bitmap & (1 << bitno));
|
||||
*(unsigned long *)bitmap |= (1 << bitno);
|
||||
|
||||
return val;
|
||||
}
|
||||
#else
|
||||
#define bit_test_and_set(bitmap, bitno) arch_bit_test_and_set(bitmap, bitno)
|
||||
#endif /* ARCH_BIT_TEST_AND_SET */
|
||||
|
||||
/**
|
||||
* @fn static inline int bit_test_and_reset(void *bitmap, int bitno)
|
||||
* @brief Get old value of bit with number @a bitno and clear @a bitno bit in the bitmap
|
||||
*
|
||||
* This function is similar to bit_clear() except it copies old bit value before
|
||||
* setting it to 1 and return that value after needed bit was setted.
|
||||
* @note The limit of @a bitmap = sizeof(unsigned long)
|
||||
*
|
||||
* @param bitmap - A pointer to the bitmap
|
||||
* @param bitno - The number of bit to test and set
|
||||
* @return Old value of bit with number @a bitno
|
||||
*/
|
||||
#ifndef ARCH_BIT_TEST_AND_RESET
|
||||
static inline int bit_test_and_reset(void *bitmap, int bitno)
|
||||
{
|
||||
int val = (*(unsigned long *)bitmap & (1 << bitno));
|
||||
*(unsigned long *)bitmap &= ~(1 << bitno);
|
||||
|
||||
return val;
|
||||
}
|
||||
#else
|
||||
#define bit_test_and_reset(bitmap, bitno) arch_bit_test_and_reset(bitmap, bitno)
|
||||
#endif /* ARCH_BIT_TEST_AND_RESET */
|
||||
|
||||
/**
|
||||
* @fn static inline long bit_find_lsf(unsigned long word)
|
||||
* Find first set least significant bit.
|
||||
*
|
||||
* @param word - Where to search
|
||||
* @return Found bit number on success, negative value on failure.
|
||||
*/
|
||||
#ifndef ARCH_BIT_FIND_LSF
|
||||
static inline long bit_find_lsf(unsigned long word)
|
||||
{
|
||||
long c = -1;
|
||||
|
||||
for (; word; c++, word >>= 1) {
|
||||
if ((word & 0x01)) {
|
||||
c++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
#else
|
||||
#define bit_find_lsf(word) arch_bit_find_lsf(word)
|
||||
#endif /* ARCH_BIT_FIND_LSF */
|
||||
|
||||
#ifndef ARCH_ZERO_BIT_FIND_LSF
|
||||
#define zero_bit_find_lsf(word) bit_find_lsf(~(word))
|
||||
#else
|
||||
#define zero_bit_find_lsf(word) arch_zero_bit_find_lsf(word)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @fn static inline long bit_find_msf(unsigned long word)
|
||||
* Find most significant set bit in the @a word.
|
||||
*
|
||||
* @param word - Where to search.
|
||||
* @return Found bit number on success, negative value on failure.
|
||||
*/
|
||||
#ifndef ARCH_BIT_FIND_MSF
|
||||
static inline long bit_find_msf(unsigned long word)
|
||||
{
|
||||
long c = -1;
|
||||
|
||||
while (word) {
|
||||
c++;
|
||||
word >>= 1;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
#else
|
||||
#define bit_find_msf(word) arch_bit_find_msf(word)
|
||||
#endif /* ARCH_BIT_FIND_MSF */
|
||||
|
||||
/**
|
||||
* @fn static inline long bit_find_lsfz(unsigned long word)
|
||||
* Find first zero least significant bit.
|
||||
*
|
||||
* @param word - Where to search
|
||||
* @return Found bit number on success, negative value on failure.
|
||||
*/
|
||||
#ifndef ARCH_BIT_FIND_LSFZ
|
||||
static inline long bit_find_lsfz(unsigned long word)
|
||||
{
|
||||
long c = -1;
|
||||
|
||||
word = ~word;
|
||||
|
||||
for (; word; c++, word >>= 1) {
|
||||
if ((word & 0x01)) {
|
||||
c++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
#else
|
||||
#define bit_find_lsfz(word) arch_bit_find_lsfz(word)
|
||||
#endif /* ARCH_BIT_FIND_LSFZ */
|
||||
|
||||
/**
|
||||
* @fn static inline long bit_find_msfz(unsigned long word)
|
||||
* Find most significant zero bit in the @a word.
|
||||
*
|
||||
* @param word - Where to search.
|
||||
* @return Found bit number on success, negative value on failure.
|
||||
*/
|
||||
#ifndef ARCH_BIT_FIND_MSFZ
|
||||
static inline long bit_find_msfz(unsigned long word)
|
||||
{
|
||||
long c = -1;
|
||||
|
||||
word = ~word;
|
||||
|
||||
while (word) {
|
||||
c++;
|
||||
word >>= 1;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
#else
|
||||
#define bit_find_msfz(word) arch_bit_find_msfz(word)
|
||||
#endif /* ARCH_BIT_FIND_MSFZ */
|
||||
|
||||
/**
|
||||
* @fn static inline void bits_or(void *word, unsigned long flags)
|
||||
* Executes logical OR with @a word and @a flags and writes result to @a word
|
||||
* @note The limit of @a word = sizeof(unsigned long)
|
||||
*
|
||||
* @param[out] word - A pointer to memory results will be written to
|
||||
* @param flsgs - Flags that will be OR'ed with @a word
|
||||
*/
|
||||
#ifndef ARCH_BITS_OR
|
||||
static inline void bits_or(void *word, unsigned long flags)
|
||||
{
|
||||
*(unsigned long *)word |= flags;
|
||||
}
|
||||
#define bits_or(word, flags) panic("bits_or uniplemented")
|
||||
#else
|
||||
#define bits_or(word, flags) arch_bits_or(word, flags)
|
||||
#endif /* ARCH_BITS_OR */
|
||||
|
||||
/**
|
||||
* @fn static inline void bits_and(void *word, unsigned long mask)
|
||||
* Executes logical AND with @a word and @a mask and writes result to @a word.
|
||||
* @note The limit of @a word = sizeof(unsigned long)
|
||||
*
|
||||
* @param[out] word - A pointer to memory results will be written to
|
||||
* @param mask - A mask that will be AND'ed with @a word
|
||||
*/
|
||||
#ifndef ARCH_BITS_AND
|
||||
static inline void bits_and(void *word, unsigned long mask)
|
||||
{
|
||||
*(unsigned long *)word &= mask;
|
||||
}
|
||||
#else
|
||||
#define bits_and(word, mask) arch_bits_and(word, mask)
|
||||
#endif /* ARCH_BITS_AND */
|
||||
|
||||
|
||||
/*
|
||||
* Initialize multiword bitmap
|
||||
*
|
||||
* @param map - pointer to the multiword bitmap
|
||||
* @param bitno - memory size in bits to allocate
|
||||
*
|
||||
* @return 0 on success, -1 if can't allocate memory
|
||||
*/
|
||||
int init_bitmap(bitmap_t *bitmap, int nbits);
|
||||
|
||||
/*
|
||||
* Free memory taken by multiword bitmap
|
||||
*
|
||||
* @param bitmap - bitmap to free
|
||||
*/
|
||||
void free_bitmap(bitmap_t *map);
|
||||
|
||||
/**
|
||||
* Set bit number @a bit in the bitmap @a bitmap
|
||||
*
|
||||
* @param bitmap - A pointer to the bitmap
|
||||
* @param bit - Number of bit to set
|
||||
*/
|
||||
void bit_set_multi(bitmap_t *bitmap, int bitno);
|
||||
|
||||
/**
|
||||
* test bit of a multiword bitmap
|
||||
*
|
||||
* @param bitmap - A pointer to the bitmap
|
||||
* @param bitno - The number of bit to test
|
||||
*
|
||||
* @return value of the specified bit
|
||||
*/
|
||||
int bit_test_multi(bitmap_t *bitmap, int bitno);
|
||||
|
||||
/**
|
||||
* @brief Get old value of bit with number @a bitno and set @a bitno bit in the bitmap
|
||||
*
|
||||
* This function is similar to bit_set() except it copies old bit value before
|
||||
* setting it to 1 and return that value after needed bit was setted.
|
||||
*
|
||||
* @param bitmap - A pointer to the bitmap
|
||||
* @param bitno - The number of bit to test and set
|
||||
*
|
||||
* @return Old value of bit with number @a bitno or -1 if bitno is illegal
|
||||
*/
|
||||
int bit_test_and_set_multi(bitmap_t *bitmap, int bitno);
|
||||
|
||||
/**
|
||||
* @brief Get old value of bit with number @a bitno and clear @a bitno bit in the bitmap
|
||||
*
|
||||
* This function is similar to bit_set() except it copies old bit value before
|
||||
* setting it to 1 and return that value after needed bit was setted.
|
||||
*
|
||||
* @param bitmap - A pointer to the bitmap
|
||||
* @param bitno - The number of bit to test and set
|
||||
*
|
||||
* @return Old value of bit with number @a bitno or -1 if bitno is illegal
|
||||
*/
|
||||
int bit_test_and_reset_multi(bitmap_t *bitmap, int bitno);
|
||||
|
||||
|
||||
/**
|
||||
* Clear bit number @a bit in the bitmap @a bitmap
|
||||
*
|
||||
* @param bitmap - A pointer to the bitmap
|
||||
* @param bit - Number of bit to clear
|
||||
*/
|
||||
void bit_clear_multi(bitmap_t *bitmap, int bitno);
|
||||
|
||||
/*
|
||||
* Set multiple bits in the multiword bitmap
|
||||
*
|
||||
* @param bitmap - pointer to the multimap bitmap
|
||||
* @param start_bit - bit to set from
|
||||
* int end_bit - bit to set upto
|
||||
*/
|
||||
void bitrange_set_multi(bitmap_t *bitmap, int start_bit, int end_bit);
|
||||
|
||||
/*
|
||||
* Clear multiple bits in the multiword bitmap
|
||||
*
|
||||
* @param bitmap - pointer to the multimap bitmap
|
||||
* @param start_bit - bit to clear from
|
||||
* int end_bit - bit to clear upto
|
||||
*/
|
||||
void bitrange_clear_multi(bitmap_t *bitmap, int start_bit, int end_bit);
|
||||
|
||||
/**
|
||||
* Find most significant set bit in multimap word which from the 0 bit
|
||||
* upto @end_bit
|
||||
*
|
||||
* @param word - Where to search.
|
||||
* @param end_bit - most bit to search upto
|
||||
* @return Found bit number on success, negative value on failure.
|
||||
*/
|
||||
int bit_find_msf_multi(bitmap_t *bitmap, int mbit);
|
||||
|
||||
/**
|
||||
* Find first set least significant bit.
|
||||
*
|
||||
* @param word - Where to search
|
||||
* @param sbit - least bit to search from
|
||||
* @return Found bit number on success, negative value on failure.
|
||||
*/
|
||||
int bit_find_lsf_multi(bitmap_t *bitmap, int lbit);
|
||||
|
||||
#ifndef ARCH_BIT_TEST_AND_CLEAR
|
||||
static inline int bit_test_and_clear(void *bitmap, int bitno)
|
||||
{
|
||||
int val = bit_test(bitmap, bitno);
|
||||
bit_clear(bitmap, bitno);
|
||||
return val;
|
||||
}
|
||||
#else
|
||||
#define bit_test_and_clear(bitmap, bitno) arch_bit_test_and_clear(bitmap, bitno)
|
||||
#endif
|
||||
|
||||
#endif /* __BITWISE_H__ */
|
@ -0,0 +1,42 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* cas.c
|
||||
* Copyright (C) 2015 Alexander Vdolainen <avdolainen@gmail.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#ifndef __TDATA_CTRIE_H__
|
||||
#define __TDATA_CTRIE_H__
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
/* flags */
|
||||
#define CTRIE_FLAG_RO (1 << 1)
|
||||
|
||||
/* structure Ctrie (flags is also underlying node type) */
|
||||
typedef struct __ctrie_type {
|
||||
int flags;
|
||||
void **root;
|
||||
}__attribute__((packed)) ctrie_t;
|
||||
|
||||
/* structure SNode (key-value node) */
|
||||
typedef struct __ctrie_snode {
|
||||
ct_key_t key;
|
||||
void *value;
|
||||
}__attribute__((packed)) ct_snode_t;
|
||||
|
||||
|
||||
|
||||
#endif /* __TDATA_CTRIE_H__ */
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* (c) Copyright 2006,2007,2008 MString Core Team <http://mstring.jarios.org>
|
||||
* (c) Copyright 2009 Dan Kruchinin <dan.kruchinin@gmail.com>
|
||||
* (c) Copyright 2009 Alfeiks Kaanoken <madtirra@jarios.org> (libc adaptation)
|
||||
* (c) Copyright 2009 Dmitry Gromada <gromada@jarios.org> (locking added)
|
||||
* (c) Copyright 2013 Alexander Vdolainen <vdo@askele.com> (verios changes to make it run on linux)
|
||||
*
|
||||
* (c) Copyright 2012 - 2013 Askele Oy <http://askele.com>
|
||||
*
|
||||
* Index allocator
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file include/libdata/idx_allocator.h
|
||||
* @brief Index allocator API and definitions
|
||||
*
|
||||
* Index allocator is a quite simple bitmaps based data
|
||||
* structure allowing to allocate non-negative integers
|
||||
* from an ordered continuous numbers set.
|
||||
* It may be useful for dynamic allocation of pids, uids and
|
||||
* other identifiers that must be unique.
|
||||
* Any identifier from a given set may be allocated, deallocated and reserved
|
||||
* (which prevents its allocation).
|
||||
* Note, there is no any sence to use index allocator for relatively
|
||||
* small(for example for sets containing less than 1024 items) identifier sets.
|
||||
* Allocator uses *at least* BYTES_PER_ITEM + sizeof(ulong_t) bytes for its internal bitmaps.
|
||||
*/
|
||||
|
||||
#ifndef __IDX_ALLOCATOR_H__
|
||||
#define __IDX_ALLOCATOR_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
|
||||
typedef unsigned long ulong_t;
|
||||
|
||||
#define BYTES_PER_ITEM 64 /**< Number of bytes per one entry of a second-level bitmap */
|
||||
#define WORDS_PER_ITEM (BYTES_PER_ITEM / sizeof(ulong_t)) /**< Number of machine words(ulong_t) per second-level bitmap item */
|
||||
#define IDX_INVAL ~0UL /**< Invalid index value */
|
||||
|
||||
#define ida_lock_init(lock) pthread_mutex_init(lock, NULL)
|
||||
#define ida_lock_destroy(lock) pthread_mutex_destroy(lock);
|
||||
#define ida_lock(a) pthread_mutex_lock(&a->lock)
|
||||
#define ida_unlock(a) pthread_mutex_unlock(&a->lock)
|
||||
#define ida_lockable(a) (a->lck)
|
||||
|
||||
typedef pthread_mutex_t ida_lock_t;
|
||||
|
||||
/**
|
||||
* @struct idx_allocator_t
|
||||
* @brief Index allocator structure
|
||||
*/
|
||||
typedef struct __idx_allocator {
|
||||
int size; /**< Total number of words used for second-level bitmap */
|
||||
ulong_t max_id; /**< Maximum index value(exclusive) */
|
||||
ulong_t *main_bmap; /**< First-level(main) bitmap that splits second-level bitmap on several parts */
|
||||
ulong_t *ids_bmap; /**< Second-level bitmap whose each bit corresponds to particular unique identifier */
|
||||
ida_lock_t lock;
|
||||
int lck;
|
||||
} idx_allocator_t;
|
||||
|
||||
#define idx_allocator_initialized(ida) (((idx_allocator_t*)(ida))->max_id)
|
||||
|
||||
/**
|
||||
* @brief Initialize an index allocator.
|
||||
* @param ida - A pointer to particular index allocator
|
||||
* @param idx_max - Maximum index value.
|
||||
* @lockable - flag to indicate the allocator must support locking itself
|
||||
*/
|
||||
int idx_allocator_init(idx_allocator_t *ida, ulong_t idx_max, int lockable);
|
||||
|
||||
/**
|
||||
* @brief Destroy index allocator.
|
||||
*
|
||||
* This function frees space used by allocator's internal
|
||||
* bitmaps. After it is called, allocator can not be used.
|
||||
*
|
||||
* @param ida - A pointer to praticular index allocator.
|
||||
*/
|
||||
void idx_allocator_destroy(idx_allocator_t *ida);
|
||||
|
||||
/**
|
||||
* @brief Allocate new index from an allocator's set.
|
||||
* @param ida - A pointer to target index allocator.
|
||||
* @return Valid index value on success, IDX_INVAL on error.
|
||||
* @see IDX_INVAL
|
||||
* @see idx_reserve
|
||||
* @see idx_free
|
||||
*/
|
||||
ulong_t idx_allocate(idx_allocator_t *ida);
|
||||
|
||||
/**
|
||||
* @brief Reserves particular index number.
|
||||
*
|
||||
* This action prevents named index number from
|
||||
* allocation. Index allocator skips reserved indices until
|
||||
* they are fried with idx_free
|
||||
*
|
||||
* @param ida - A pointer to particular index allocator.
|
||||
* @param idx - Number of index to reserve.
|
||||
* @see idx_free
|
||||
* @see idx_allocate
|
||||
*/
|
||||
void idx_reserve(idx_allocator_t *ida, ulong_t idx);
|
||||
|
||||
/**
|
||||
* @brief Free back index @a idx to named allocator @a ida.
|
||||
* @param ida - Allocator index will be freed back to.
|
||||
* @param idx - An index to free.
|
||||
* @see idx_allocate
|
||||
* @see idx_reserve
|
||||
*/
|
||||
void idx_free(idx_allocator_t *ida, ulong_t idx);
|
||||
|
||||
#endif /* __IDX_ALLOCATOR_H__ */
|
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Typical data structures used.
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* (c) 2013-2014, 2015 Copyright Askele, inc. <http://askele.com>
|
||||
* (c) 2013-2014, 2015 Copyright Askele Ingria, inc. <http://askele-ingria.com>
|
||||
*/
|
||||
|
||||
#ifndef __TDATA_LIST_H__
|
||||
#define __TDATA_LIST_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define __MILESTONE ((unsigned long)0x123)
|
||||
|
||||
/**
|
||||
* @def MILESTONES_SEQ(num) ((void *)__MILESTONE##num)
|
||||
* @brief Easy way to define next item in milestones sequence
|
||||
* @pararm num - number of milestone in sequence
|
||||
*/
|
||||
#define MILESTONES_SEQ(num) ((void *)(__MILESTONE + (num)))
|
||||
|
||||
/* milestones for list's next and prev pointers respectively */
|
||||
#define MLST_LIST_NEXT MILESTONES_SEQ(1)
|
||||
#define MLST_LIST_PREV MILESTONES_SEQ(2)
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(PTR, TYPE, MEMBER) \
|
||||
((TYPE *)((char *)(PTR) - offsetof(TYPE, MEMBER)))
|
||||
#endif
|
||||
|
||||
/* init root node of non containerized double linked non cyclic list */
|
||||
#define nclist_init_root(root) \
|
||||
do { \
|
||||
root->next = NULL; \
|
||||
root->prev = root; \
|
||||
} while (0)
|
||||
|
||||
/* add to tail of non containerized double linked non cyclic list */
|
||||
#define nclist_add2tail(root,node) \
|
||||
do { \
|
||||
typeof(root) __tail = (root)->prev; \
|
||||
\
|
||||
__tail->next = node; \
|
||||
node->prev = __tail; \
|
||||
node->next = NULL; \
|
||||
(root)->prev = node; \
|
||||
} while (0)
|
||||
|
||||
#define nclist_for_each(root, node) \
|
||||
for (node = root; node != NULL; node = node->next)
|
||||
|
||||
/**
|
||||
* @typedef struct __list_node list_node_t
|
||||
* @struct __list_node
|
||||
* @brief List node
|
||||
*/
|
||||
typedef struct __list_node {
|
||||
struct __list_node *next;
|
||||
struct __list_node *prev;
|
||||
} list_node_t;
|
||||
|
||||
/**
|
||||
* @typedef struct __list_head list_head_t
|
||||
* @struct __list_head
|
||||
* @brief List head
|
||||
* Actually list_head_t is the same as list_node_t, but
|
||||
* they have different types though. That was done to prevent
|
||||
* potentional errors(notice that list head is a stub, it's never
|
||||
* tied with any real data and it's used only to determine where list
|
||||
* starts and where it ends)
|
||||
*/
|
||||
typedef struct __list_head {
|
||||
list_node_t head; /**< Head element of the list */
|
||||
} list_head_t;
|
||||
|
||||
/**
|
||||
* @def LIST_DEFINE(name)
|
||||
* @brief Define and initialize list head with name @a name
|
||||
* @param name - name of variable
|
||||
*/
|
||||
#define LIST_DEFINE(name) \
|
||||
list_head_t name = { .head = { &(name).head, &(name).head } }
|
||||
|
||||
/**
|
||||
* @fn static inline void list_init_head(list_head_t *lst)
|
||||
* @brief Initialize list head
|
||||
* @param lst - a pointer to list head.
|
||||
*/
|
||||
static inline void list_init_head(list_head_t *lst)
|
||||
{
|
||||
lst->head.next = lst->head.prev = &lst->head;
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn static inline void list_init_node(list_node_t *node)
|
||||
* @brief Initialize list node
|
||||
* @param node - a pointer to free(unattached from list) node.
|
||||
*/
|
||||
static inline void list_init_node(list_node_t *node)
|
||||
{
|
||||
node->next = MLST_LIST_NEXT;
|
||||
node->prev = MLST_LIST_PREV;
|
||||
}
|
||||
|
||||
static inline bool list_node_next_isbound(list_node_t *node)
|
||||
{
|
||||
return (node->next == MLST_LIST_NEXT);
|
||||
}
|
||||
|
||||
static inline bool list_node_prev_isbound(list_node_t *node)
|
||||
{
|
||||
return (node->prev == MLST_LIST_PREV);
|
||||
}
|
||||
|
||||
/**
|
||||
* @def list_entry(lst, nptr)
|
||||
* @brief Get item that holds @a nptr node
|
||||
* @param list - A pointer to the list
|
||||
* @param nptr - A pointer to the node
|
||||
* @return A pointer to the object given node contains
|
||||
*/
|
||||
#define list_entry(node, type, member) \
|
||||
container_of(node, type, member)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @def list_head(lst)
|
||||
* @brief Get head of the list
|
||||
* @param lst - a pointer to list_head_t
|
||||
* @return A pointer to header list_node_t
|
||||
*/
|
||||
#define list_head(lst) \
|
||||
(&(lst)->head)
|
||||
|
||||
/**
|
||||
* @def list_node_first(lst)
|
||||
* @brief Get list's first node
|
||||
* @param list - A pointer to the list_head_t
|
||||
* @return A pointer to the list first node
|
||||
*/
|
||||
#define list_node_first(lst) \
|
||||
((lst)->head.next)
|
||||
|
||||
/**
|
||||
* list_first_entry - get the first element from a list
|
||||
* @lst: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_first_entry(lst, type, member) \
|
||||
list_entry((lst)->head.next, type, member)
|
||||
|
||||
/**
|
||||
* @def list_node_last(lst)
|
||||
* @brief Get list's last node
|
||||
* @param list - A pointer to the list_head_t
|
||||
* @return A pointer to the list last node
|
||||
*/
|
||||
#define list_node_last(lst) \
|
||||
((lst)->head.prev)
|
||||
|
||||
/**
|
||||
* list_last_entry - get the last element from a list
|
||||
* @lst: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_last_entry(lst, type, member) \
|
||||
list_entry((lst)->head.prev, type, member)
|
||||
|
||||
/**
|
||||
* @def list_add2head(lst, new)
|
||||
* @brief Add a node @a new to the head of the list
|
||||
* @param lst - A pointer to the list
|
||||
* @param new - A pointer to the list node
|
||||
*/
|
||||
#define list_add2head(lst, new) \
|
||||
list_add(list_node_first(lst), new)
|
||||
|
||||
/**
|
||||
* @def list_add2tail(lst, new)
|
||||
* @brief Add a node @a new to the tail of the list
|
||||
* @param lst - A pointer to the list
|
||||
* @param new - A pointer to node to add
|
||||
*/
|
||||
#define list_add2tail(lst, new) \
|
||||
list_add(list_head(lst), new)
|
||||
|
||||
/**
|
||||
* @def list_delfromhead(lst)
|
||||
* @brief Remove first element of the list
|
||||
* @param lst - A pointer to the list
|
||||
*/
|
||||
#define list_delfromhead(lst) \
|
||||
list_del(list_node_first(lst))
|
||||
|
||||
/**
|
||||
* @def list_delfromtail(lst)
|
||||
* @brief Remove the last element of the list
|
||||
* @param list - A pointer to the list
|
||||
*/
|
||||
#define list_delfromtail(lst) \
|
||||
list_del(list_node_last(lst))
|
||||
|
||||
/**
|
||||
* @def list_del(del)
|
||||
* @brief Remove node @a del from the list
|
||||
* @param del - A node to remove
|
||||
*/
|
||||
#define list_del(del) \
|
||||
(list_del_range(del, del))
|
||||
|
||||
/**
|
||||
* @def list_add(before, new, after)
|
||||
* @param after - will be the next node after @a new
|
||||
* @param new - node to insert
|
||||
*/
|
||||
#define list_add(after, new) \
|
||||
(list_add_range(new, new, (after)->prev, after))
|
||||
|
||||
/**
|
||||
* @def list_move2head(to, from)
|
||||
* @brief Move all nodes from list @a from to the head of list @a to
|
||||
* @param to - destination list
|
||||
* @param from - source list
|
||||
*/
|
||||
#define list_move2head(to, from) \
|
||||
(list_move(list_head(to), list_node_first(to), from))
|
||||
|
||||
/**
|
||||
* @def list_move2tail(to, from)
|
||||
* @brief Move all nodes from list @a from to the tail of list @a to
|
||||
* @param to - destination list
|
||||
* @param from - source list
|
||||
*/
|
||||
#define list_move2tail(to, from) \
|
||||
(list_move(list_node_last(to), list_head(to), from))
|
||||
|
||||
|
||||
/**
|
||||
* @def list_for_each(lst, liter)
|
||||
* @brief Iterate through each element of the list
|
||||
* @param lst - A pointer to list head
|
||||
* @param liter - A pointer to list which will be used for iteration
|
||||
*/
|
||||
#define list_for_each(lst, liter) \
|
||||
for (liter = list_node_first(lst); \
|
||||
(liter) != list_head(lst); (liter) = (liter)->next)
|
||||
|
||||
/**
|
||||
* @def list_for_each_safe(lst, liter, save)
|
||||
* @brief Safe iteration through the list @a lst
|
||||
*
|
||||
* This iteration wouldn't be broken even if @a liter will be removed
|
||||
* from the list
|
||||
*
|
||||
* @param lst - A pointer to the list head
|
||||
* @param liter - A pointer to list node which will be used for iteration
|
||||
* @param save - The same
|
||||
*/
|
||||
#define list_for_each_safe(lst, liter, save) \
|
||||
for (liter = list_node_first(lst), save = (liter)->next; \
|
||||
(liter) != list_head(lst); (liter) = (save), \
|
||||
(save) = (liter)->next)
|
||||
|
||||
/**
|
||||
* @def list_for_each_entry(lst, iter, member)
|
||||
* @brief Iterate through each list node member
|
||||
* @param lst - a pointer list head
|
||||
* @param iter - a pointer to list entry using as iterator
|
||||
* @param member - name of list node member in the parent structure
|
||||
*/
|
||||
#define list_for_each_entry(lst, iter, member) \
|
||||
for (iter = list_entry(list_node_first(lst), typeof(*iter), member); \
|
||||
&iter->member != list_head(lst); \
|
||||
iter = list_entry(iter->member.next, typeof(*iter), member))
|
||||
|
||||
/**
|
||||
* @def list_for_each_entry(lst, iter, member)
|
||||
* @brief Iterate through each list node member and calls specified function with argument
|
||||
* pointing to a list entry
|
||||
*
|
||||
* @param lst - a pointer list head
|
||||
* @param iter - a pointer to list entry using as iterator
|
||||
* @param member - name of list node member in the parent structure
|
||||
* @param fn - function doing some actins against each entry of the list
|
||||
*/
|
||||
#define list_do_for_each_entry(lst, type, member, fn) \
|
||||
{ \
|
||||
type *t; \
|
||||
list_node_t *node, *save; \
|
||||
\
|
||||
list_for_each_safe(lst, node, save) { \
|
||||
t = container_of(node, type, member); \
|
||||
fn(t); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn static inline int list_is_empty(list_t *list)
|
||||
* @brief Determines if list @a list is empty
|
||||
* @param list - A pointer to list to test
|
||||
* @return True if list is empty, false otherwise
|
||||
*/
|
||||
static inline int list_is_empty(list_head_t *list)
|
||||
{
|
||||
return (list_node_first(list) == list_head(list));
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn static inline void list_add_range(list_node_t *first, list_node_t *last,
|
||||
* list_node_t *prev, list_node_t *next)
|
||||
* @brief Insert a range of nodes from @a frist to @a last after @a prev and before @a last
|
||||
* @param first - first node of range
|
||||
* @param last - last node of range
|
||||
* @param prev - after this node a range will be inserted
|
||||
* @param next - before this node a range will be inserted
|
||||
*/
|
||||
static inline void list_add_range(list_node_t *first, list_node_t *last,
|
||||
list_node_t *prev, list_node_t *next)
|
||||
{
|
||||
next->prev = last;
|
||||
last->next = next;
|
||||
prev->next = first;
|
||||
first->prev = prev;
|
||||
}
|
||||
|
||||
/* for internal usage */
|
||||
static inline void __list_del_range(list_node_t *first, list_node_t *last)
|
||||
{
|
||||
first->prev->next = last->next;
|
||||
last->next->prev = first->prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn static inline list_del_range(list_node_t *first, list_node_t *last)
|
||||
* @brief Delete nodes from @a first to @a last from list.
|
||||
* @param fist - first node to delete
|
||||
* @param last - last node to delete
|
||||
*/
|
||||
static inline void list_del_range(list_node_t *first, list_node_t *last)
|
||||
{
|
||||
__list_del_range(first, last);
|
||||
first->prev = MLST_LIST_PREV;
|
||||
last->next = MLST_LIST_NEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn static inline void list_cut_sublist(list_node_t *first, list_node_t *last)
|
||||
* @brief Cut a "sublist" started from @a first and ended with @a last
|
||||
*
|
||||
* A @e "sublist" is similar to ordinary list except it hasn't a head.
|
||||
* In other words it's a cyclic list in which all nodes are equitable.
|
||||
*
|
||||
* @param first - From this node sublist will be cutted
|
||||
* @param last - The last node in the cutted sequence
|
||||
*/
|
||||
static inline void list_cut_sublist(list_node_t *first, list_node_t *last)
|
||||
{
|
||||
__list_del_range(first, last);
|
||||
first->prev = last;
|
||||
last->next = first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn static inline void list_cut_head(list_head_t *head)
|
||||
* @brief Cut a head from the list and make a "sublist"
|
||||
* @param head - List's head that will be cutted.
|
||||
* @see list_cut_sublist
|
||||
* @see list_set_head
|
||||
*/
|
||||
static inline void list_cut_head(list_head_t *head)
|
||||
{
|
||||
list_cut_sublist(list_node_first(head), list_node_last(head));
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn static inline void list_cut_head(list_head_t *head)
|
||||
* @brief Attach a head to the sublist @a cyclist
|
||||
* @param new_head - A head that will be attached
|
||||
* @param cyclist - "sublist"
|
||||
* @see list_cut_sublist
|
||||
* @see list_set_head
|
||||
*/
|
||||
static inline void list_set_head(list_head_t *new_head, list_node_t *cyclist)
|
||||
{
|
||||
list_add_range(cyclist, cyclist->prev,
|
||||
list_node_first(new_head), list_node_last(new_head));
|
||||
}
|
||||
|
||||
/**
|
||||
* @fn static inline void list_move(list_node_t *prev, list_node_t *next, list_head_t *from)
|
||||
* @brief Insert nodes of list @a from after @a prev and before @a next
|
||||
* @param prev - a node after which nodes of @a from will be inserted
|
||||
* @param next - a node before which nodes of @a from will be inserted
|
||||
*/
|
||||
static inline void list_move(list_node_t *prev, list_node_t *next, list_head_t *from)
|
||||
{
|
||||
list_add_range(list_node_first(from), list_node_last(from),
|
||||
prev, next);
|
||||
list_init_head(from);
|
||||
}
|
||||
|
||||
#endif /* __TDATA_LIST_H__ */
|
||||
|
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* macro.h
|
||||
* Copyright (C) 2006-2013 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#ifndef __MACRO_H__
|
||||
#define __MACRO_H__
|
||||
|
||||
/*this macros just for better source code look and feel*/
|
||||
|
||||
#define left usrtc_left
|
||||
#define right usrtc_right
|
||||
#define parent usrtc_parent
|
||||
#define next usrtc_right
|
||||
#define prev usrtc_left
|
||||
#define data usrtc_data
|
||||
#define key usrtc_node_key
|
||||
#define rb_color usrtc_rb_color
|
||||
#define impl_specific usrtc_impldata
|
||||
|
||||
#define futable usrtc_futable
|
||||
#define nodecount usrtc_nodecount
|
||||
#define maxcount usrtc_maxcount
|
||||
#define dupes_allowed usrtc_dupes_allowed
|
||||
#define sentinel usrtc_sentinel
|
||||
#define compare usrtc_compare
|
||||
#define node_alloc usrtc_node_alloc
|
||||
#define node_free usrtc_node_free
|
||||
#define context usrtc_context
|
||||
|
||||
#endif /*__MACRO_H__*/
|
@ -0,0 +1,47 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* tree.h
|
||||
* Copyright (C) 2006-2013 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#ifndef __TREE_H__
|
||||
#define __TREE_H__
|
||||
|
||||
#include <tdata/usrtc.h>
|
||||
|
||||
#define tree_root_priv(T) ((T)->sentinel.left)
|
||||
#define tree_null_priv(L) (&(L)->sentinel)
|
||||
#define TREE_DEPTH_MAX 64
|
||||
|
||||
/*tree functions*/
|
||||
void usrtc_tree_init(usrtc_t *us);
|
||||
void usrtc_tree_insert(usrtc_t *us, usrtc_node_t *node, const void *key);
|
||||
void usrtc_tree_delete(usrtc_t *us, usrtc_node_t *node, usrtc_node_t **pswap,
|
||||
usrtc_node_t **pchild);
|
||||
usrtc_node_t *usrtc_tree_lookup(usrtc_t *us, const void *key);
|
||||
usrtc_node_t *usrtc_tree_lower_bound(usrtc_t *us, const void *key);
|
||||
usrtc_node_t *usrtc_tree_upper_bound(usrtc_t *us, const void *key);
|
||||
usrtc_node_t *usrtc_tree_first(usrtc_t *us);
|
||||
usrtc_node_t *usrtc_tree_last(usrtc_t *us);
|
||||
usrtc_node_t *usrtc_tree_next(usrtc_t *us, usrtc_node_t *curr);
|
||||
usrtc_node_t *usrtc_tree_prev(usrtc_t *us, usrtc_node_t *curr);
|
||||
void usrtc_tree_convert_to_list(usrtc_t *us);
|
||||
void usrtc_tree_convert_from_list(usrtc_t *us);
|
||||
void usrtc_tree_rotate_left(usrtc_node_t *child, usrtc_node_t *parent);
|
||||
void usrtc_tree_rotate_right(usrtc_node_t *child, usrtc_node_t *parent);
|
||||
|
||||
|
||||
#endif /*__TREE_H__*/
|
@ -0,0 +1,136 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* usrtc.h
|
||||
* Copyright (C) 2006-2013 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#ifndef __USRTC_H__
|
||||
#define __USRTC_H__
|
||||
|
||||
#define USRTC_COUNT_T_MAX ((1 << (sizeof(unsigned long)*(sizeof(char) << 1)))-1)
|
||||
|
||||
/*count and some misc typedefs*/
|
||||
typedef unsigned long usrtc_count_t;
|
||||
typedef unsigned int usrtc_impl_id_t;
|
||||
|
||||
/* implementations ids,
|
||||
* if you want to add some
|
||||
* add the id here, don't forget to do it.
|
||||
*/
|
||||
#define USRTC_LIST 0
|
||||
#define USRTC_BST 1
|
||||
#define USRTC_REDBLACK 2
|
||||
#define USRTC_SPLAY 3
|
||||
#define USRTC_AVL 4
|
||||
|
||||
typedef enum {
|
||||
usrtc_lst,
|
||||
usrtc_bst,
|
||||
usrtc_other
|
||||
} usrtc_impltype_t;
|
||||
|
||||
typedef enum {
|
||||
usrtc_red,
|
||||
usrtc_black
|
||||
} usrtc_rb_color_t;
|
||||
typedef enum {
|
||||
usrtc_balanced,
|
||||
usrtc_leftheavy,
|
||||
usrtc_rightheavy
|
||||
} usrtc_avl_balance_t;
|
||||
|
||||
/*used for the specific implementation features*/
|
||||
typedef union {
|
||||
int usrtc_dummy;
|
||||
usrtc_rb_color_t usrtc_rb_color;
|
||||
usrtc_avl_balance_t usrtc_avl_balance;
|
||||
} usrtc_impldata_t;
|
||||
|
||||
/*universal node*/
|
||||
typedef struct __usrtc_node_t {
|
||||
struct __usrtc_node_t *usrtc_left;
|
||||
struct __usrtc_node_t *usrtc_right;
|
||||
struct __usrtc_node_t *usrtc_parent;
|
||||
void *usrtc_data;
|
||||
const void *usrtc_node_key;
|
||||
usrtc_impldata_t usrtc_impldata;
|
||||
} usrtc_node_t;
|
||||
|
||||
typedef long (*usrtc_compare_t)(const void*, const void*);
|
||||
typedef usrtc_node_t *(*usrtc_node_alloc_t)(void *);
|
||||
typedef void (*usrtc_node_free_t)(void *, usrtc_node_t *);
|
||||
|
||||
typedef struct __usrtc_t {
|
||||
struct __usrtc_functions_t *usrtc_futable;
|
||||
usrtc_count_t usrtc_nodecount;
|
||||
usrtc_count_t usrtc_maxcount;
|
||||
int usrtc_dupes_allowed;
|
||||
usrtc_node_t usrtc_sentinel;
|
||||
usrtc_compare_t usrtc_compare;
|
||||
usrtc_node_alloc_t usrtc_node_alloc;
|
||||
usrtc_node_free_t usrtc_node_free;
|
||||
void *usrtc_context;
|
||||
} usrtc_t;
|
||||
|
||||
typedef struct __usrtc_functions_t {
|
||||
void (*usrtc_init)(usrtc_t *);
|
||||
void (*usrtc_insert)(usrtc_t *, usrtc_node_t *, const void *);
|
||||
void (*usrtc_delete)(usrtc_t *, usrtc_node_t *);
|
||||
usrtc_node_t *(*usrtc_lookup)(usrtc_t *, const void *);
|
||||
usrtc_node_t *(*usrtc_lower_bound)(usrtc_t *, const void *);
|
||||
usrtc_node_t *(*usrtc_upper_bound)(usrtc_t *, const void *);
|
||||
usrtc_node_t *(*usrtc_first)(usrtc_t *);
|
||||
usrtc_node_t *(*usrtc_last)(usrtc_t *);
|
||||
usrtc_node_t *(*usrtc_next)(usrtc_t *, usrtc_node_t *);
|
||||
usrtc_node_t *(*usrtc_prev)(usrtc_t *, usrtc_node_t *);
|
||||
void (*usrtc_convert_to_list)(usrtc_t *);
|
||||
void (*usrtc_convert_from_list)(usrtc_t *);
|
||||
usrtc_impltype_t usrtc_type;
|
||||
} usrtc_functions_t;
|
||||
|
||||
/*basic rtc functions*/
|
||||
void usrtc_init(usrtc_t *us,int impl,usrtc_count_t maxcount,usrtc_compare_t compare);
|
||||
usrtc_t *usrtc_create(int impl,usrtc_count_t maxcount,usrtc_compare_t compare);
|
||||
void usrtc_destroy(usrtc_t *us);
|
||||
void usrtc_convert_to(usrtc_t *us,int impl);
|
||||
usrtc_count_t usrtc_count(usrtc_t *us);
|
||||
int usrtc_isempty(usrtc_t *us);
|
||||
int usrtc_isfull(usrtc_t *us);
|
||||
int usrtc_alloc_insert(usrtc_t *us,const void *key,void *data);
|
||||
void usrtc_delete_free(usrtc_t *us,usrtc_node_t *node);
|
||||
void usrtc_set_allocator(usrtc_t *us,usrtc_node_alloc_t alloc,usrtc_node_free_t n_free,void *context);
|
||||
void usrtc_allow_dupes(usrtc_t *ud);
|
||||
|
||||
/*basic node functions*/
|
||||
void usrtc_node_init(usrtc_node_t *node,void *data);
|
||||
usrtc_node_t *usrtc_node_create(void *data);
|
||||
void usrtc_node_destroy(usrtc_node_t *node);
|
||||
void *usrtc_node_getdata(usrtc_node_t *node);
|
||||
void usrtc_node_setdata(usrtc_node_t *node,void *data);
|
||||
const void *usrtc_node_getkey(usrtc_node_t *node);
|
||||
|
||||
/*rtc wrappers for the specific data structure functions*/
|
||||
void usrtc_insert(usrtc_t *us,usrtc_node_t *node,const void *key);
|
||||
void usrtc_delete(usrtc_t *us,usrtc_node_t *node);
|
||||
usrtc_node_t *usrtc_lookup(usrtc_t *us,const void *key);
|
||||
usrtc_node_t *usrtc_lower_bound(usrtc_t *us,const void *key);
|
||||
usrtc_node_t *usrtc_upper_bound(usrtc_t *us,const void *key);
|
||||
usrtc_node_t *usrtc_first(usrtc_t *us);
|
||||
usrtc_node_t *usrtc_last(usrtc_t *us);
|
||||
usrtc_node_t *usrtc_next(usrtc_t *us,usrtc_node_t *node);
|
||||
usrtc_node_t *usrtc_prev(usrtc_t *us,usrtc_node_t *node);
|
||||
|
||||
#endif /*__USRTC_H__*/
|
@ -0,0 +1,38 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
|
||||
-DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
|
||||
-DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \
|
||||
-I../include
|
||||
|
||||
#if WIN32
|
||||
#AM_CPPFLAGS + = -I../../include
|
||||
#endif
|
||||
|
||||
AM_CFLAGS =\
|
||||
-Wall\
|
||||
-g
|
||||
|
||||
lib_LTLIBRARIES = libsexpr.la
|
||||
|
||||
|
||||
libsexpr_la_SOURCES = \
|
||||
cstring.c event_temp.c faststack.c io.c \
|
||||
parser.c sexp.c sexp_memory.c sexp_ops.c sexp_vis.c
|
||||
|
||||
libsexpr_la_LDFLAGS =
|
||||
|
||||
libsexpr_la_LIBADD =
|
||||
|
||||
##include_HEADERS = \
|
||||
## ../include/sexpr/cstring.h ../include/sexpr/faststack.h ../include/sexpr/sexp_errors.h \
|
||||
## ../include/sexpr/sexp.h ../include/sexpr/sexp_memory.h ../include/sexpr/sexp_ops.h \
|
||||
## ../include/sexpr/sexp_vis.h
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libsexpr.pc
|
||||
|
||||
EXTRA_DIST = \
|
||||
libsexpr.pc.in
|
||||
|
@ -0,0 +1,3 @@
|
||||
1.3.1
|
||||
|
||||
|
@ -0,0 +1,220 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
/**
|
||||
* Implementation of stuff in cstring.h to make ron happy
|
||||
*/
|
||||
#include <sexpr/cstring.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sexpr/sexp_memory.h>
|
||||
#include <sexpr/sexp.h>
|
||||
|
||||
/**
|
||||
* growth size for cstrings -- default is 8k. use sgrowsize() to adjust.
|
||||
*/
|
||||
static size_t cstring_growsize = 8192;
|
||||
|
||||
void sgrowsize(size_t s) {
|
||||
if (s < 1)
|
||||
return;
|
||||
|
||||
cstring_growsize = s;
|
||||
}
|
||||
|
||||
CSTRING *snew(size_t s) {
|
||||
CSTRING *cs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
cs = (CSTRING *)sexp_malloc(sizeof(CSTRING));
|
||||
#else
|
||||
cs = sexp_malloc(sizeof(CSTRING));
|
||||
#endif
|
||||
if (cs == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cs->len = s;
|
||||
cs->curlen = 0;
|
||||
|
||||
#ifdef __cplusplus
|
||||
cs->base = (char *)sexp_calloc(sizeof(char),s);
|
||||
#else
|
||||
cs->base = sexp_calloc(sizeof(char),s);
|
||||
#endif
|
||||
if (cs->base == NULL) {
|
||||
sexp_free(cs,sizeof(CSTRING));
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
CSTRING *sadd(CSTRING *s, char *a) {
|
||||
size_t alen;
|
||||
char *newbase;
|
||||
|
||||
/* no string, so bail */
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* nothing to add, return s */
|
||||
if (a == NULL) {
|
||||
return s;
|
||||
}
|
||||
|
||||
alen = strlen(a);
|
||||
|
||||
if (s->curlen + alen >= s->len) {
|
||||
#ifdef __cplusplus
|
||||
newbase = (char *)sexp_realloc(s->base,
|
||||
s->len+cstring_growsize+alen,
|
||||
s->len);
|
||||
#else
|
||||
newbase = sexp_realloc(s->base,
|
||||
s->len+cstring_growsize+alen,
|
||||
s->len);
|
||||
#endif
|
||||
|
||||
/* do NOT destroy s anymore. if realloc fails, the original data is
|
||||
still valid, so just report the error to sexp_errno and return NULL.
|
||||
*/
|
||||
if (newbase == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->len += cstring_growsize + alen;
|
||||
s->base = newbase;
|
||||
}
|
||||
|
||||
memcpy(&s->base[s->curlen],a,alen);
|
||||
s->curlen += alen;
|
||||
s->base[s->curlen] = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
CSTRING *saddch(CSTRING *s, char a) {
|
||||
char *newbase;
|
||||
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (s->curlen + 1 >= s->len) {
|
||||
#ifdef __cplusplus
|
||||
newbase = (char *)sexp_realloc(s->base,
|
||||
s->len+cstring_growsize+1,
|
||||
s->len);
|
||||
#else
|
||||
newbase = sexp_realloc(s->base,
|
||||
s->len+cstring_growsize+1,
|
||||
s->len);
|
||||
#endif
|
||||
|
||||
/* do NOT destroy s anymore. if realloc fails, the original data is
|
||||
still valid, so just report the error to sexp_errno and return NULL.
|
||||
*/
|
||||
if (newbase == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->len += cstring_growsize+1;
|
||||
s->base = newbase;
|
||||
}
|
||||
|
||||
s->base[s->curlen] = a;
|
||||
s->curlen++;
|
||||
s->base[s->curlen] = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
CSTRING *strim(CSTRING *s) {
|
||||
char *newbase;
|
||||
|
||||
if (s == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* no trimming necessary? */
|
||||
if (s->len == s->curlen+1) {
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
newbase = (char *)sexp_realloc(s->base,
|
||||
s->curlen+1,
|
||||
s->len);
|
||||
#else
|
||||
newbase = sexp_realloc(s->base,
|
||||
s->curlen+1,
|
||||
s->len);
|
||||
#endif
|
||||
|
||||
/* do NOT destroy s anymore. if realloc fails, the original data is
|
||||
still valid, so just report the error to sexp_errno and return NULL.
|
||||
*/
|
||||
if (newbase == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->len = s->curlen+1;
|
||||
s->base = newbase;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
char *toCharPtr(CSTRING *s) {
|
||||
if (s == NULL) return NULL;
|
||||
return s->base;
|
||||
}
|
||||
|
||||
void sempty(CSTRING *s) {
|
||||
if (s == NULL) return;
|
||||
s->curlen = 0;
|
||||
}
|
||||
|
||||
void sdestroy(CSTRING *s) {
|
||||
if (s == NULL) return;
|
||||
sexp_free(s->base,s->len);
|
||||
sexp_free(s,sizeof(CSTRING));
|
||||
}
|
@ -0,0 +1,891 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#include <assert.h>
|
||||
#include <sexpr/sexp.h>
|
||||
|
||||
static size_t sexp_val_start_size = 256;
|
||||
static size_t sexp_val_grow_size = 64;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* event parser : based on cparse_sexp from v1.91 of this file. separate out
|
||||
* in the event that the parser mode is PARSER_EVENTS_ONLY.
|
||||
*/
|
||||
pcont_t *
|
||||
eparse_sexp (char *str, size_t len, pcont_t *lc)
|
||||
{
|
||||
char *t, *s;
|
||||
register size_t binexpected = 0;
|
||||
register size_t binread = 0;
|
||||
register parsermode_t mode = PARSER_NORMAL;
|
||||
register size_t val_allocated = 0;
|
||||
register unsigned int squoted = 0;
|
||||
register size_t val_used = 0;
|
||||
register unsigned int state = 1;
|
||||
register unsigned int depth = 0;
|
||||
register unsigned int qdepth = 0;
|
||||
register unsigned int elts = 0;
|
||||
register unsigned int esc = 0;
|
||||
pcont_t *cc;
|
||||
char *val, *vcur, *bindata = NULL;
|
||||
faststack_t *stack;
|
||||
char *bufEnd;
|
||||
int keepgoing = 1;
|
||||
parser_event_handlers_t *event_handlers = NULL;
|
||||
|
||||
/* make sure non-null string */
|
||||
if (str == NULL) {
|
||||
lc->error = SEXP_ERR_NULLSTRING;
|
||||
return lc;
|
||||
}
|
||||
|
||||
/* first, if we have a non null continuation passed in, restore state. */
|
||||
if (lc != NULL) {
|
||||
cc = lc;
|
||||
binexpected = cc->binexpected;
|
||||
binread = cc->binread;
|
||||
bindata = cc->bindata;
|
||||
val_used = cc->val_used;
|
||||
val_allocated = cc->val_allocated;
|
||||
squoted = cc->squoted;
|
||||
val = cc->val;
|
||||
vcur = cc->vcur;
|
||||
state = cc->state;
|
||||
depth = cc->depth;
|
||||
qdepth = cc->qdepth;
|
||||
stack = cc->stack;
|
||||
esc = cc->esc;
|
||||
mode = cc->mode;
|
||||
event_handlers = cc->event_handlers;
|
||||
s = str;
|
||||
if (cc->lastPos != NULL)
|
||||
t = cc->lastPos;
|
||||
else {
|
||||
t = s;
|
||||
cc->sbuffer = str;
|
||||
}
|
||||
} else {
|
||||
/* new continuation... */
|
||||
#ifdef __cplusplus
|
||||
cc = (pcont_t *)sexp_malloc(sizeof(pcont_t));
|
||||
#else
|
||||
cc = sexp_malloc(sizeof(pcont_t));
|
||||
#endif
|
||||
assert(cc != NULL);
|
||||
|
||||
cc->mode = mode;
|
||||
|
||||
/* allocate atom buffer */
|
||||
#ifdef __cplusplus
|
||||
cc->val = val = (char *)sexp_malloc(sizeof(char)*sexp_val_start_size);
|
||||
#else
|
||||
cc->val = val = sexp_malloc(sizeof(char)*sexp_val_start_size);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
|
||||
cc->val_used = val_used = 0;
|
||||
cc->val_allocated = val_allocated = sexp_val_start_size;
|
||||
|
||||
vcur = val;
|
||||
|
||||
/* allocate stack */
|
||||
cc->stack = stack = make_stack();
|
||||
cc->bindata = NULL;
|
||||
cc->binread = cc->binexpected = 0;
|
||||
|
||||
/* event handlers are null */
|
||||
cc->event_handlers = NULL;
|
||||
|
||||
/* t is temp pointer into s for current position */
|
||||
s = str;
|
||||
t = s;
|
||||
cc->sbuffer = str;
|
||||
}
|
||||
|
||||
bufEnd = cc->sbuffer+len;
|
||||
|
||||
/* guard for loop - see end of loop for info. Put it out here in the
|
||||
event that we're restoring state from a continuation and need to
|
||||
check before we start up. */
|
||||
if (state != 15 && t[0] == '\0') keepgoing = 0;
|
||||
|
||||
/*==================*/
|
||||
/* main parser loop */
|
||||
/*==================*/
|
||||
while (keepgoing == 1 && t != bufEnd)
|
||||
{
|
||||
|
||||
/* based on the current state in the FSM, do something */
|
||||
switch (state)
|
||||
{
|
||||
case 1:
|
||||
switch (t[0])
|
||||
{
|
||||
/* space,tab,CR,LF considered white space */
|
||||
case '\n':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
t++;
|
||||
break;
|
||||
/* semicolon starts a comment that extends until a \n is
|
||||
encountered. */
|
||||
case ';':
|
||||
t++;
|
||||
state = 11;
|
||||
break;
|
||||
/* enter state 2 for open paren */
|
||||
case '(':
|
||||
state = 2;
|
||||
t++;
|
||||
if (event_handlers != NULL &&
|
||||
event_handlers->start_sexpr != NULL)
|
||||
event_handlers->start_sexpr();
|
||||
break;
|
||||
/* enter state 3 for close paren */
|
||||
case ')':
|
||||
state = 3;
|
||||
break;
|
||||
/* begin quoted string - enter state 5 */
|
||||
case '\"':
|
||||
state = 5;
|
||||
/* set cur pointer to beginning of val buffer */
|
||||
vcur = val;
|
||||
t++;
|
||||
break;
|
||||
/* single quote - enter state 7 */
|
||||
case '\'':
|
||||
state = 7;
|
||||
t++;
|
||||
break;
|
||||
/* other characters are assumed to be atom parts */
|
||||
default:
|
||||
/* set cur pointer to beginning of val buffer */
|
||||
vcur = val;
|
||||
|
||||
/** NOTE: the following code originally required a transition
|
||||
to state 4 before processing the first atom character --
|
||||
this required two iterations for the first character
|
||||
of each atom. merging this into here allows us to process
|
||||
what we already know to be a valid atom character before
|
||||
entering state 4. **/
|
||||
vcur[0] = t[0];
|
||||
if (t[0] == '\\') esc = 1;
|
||||
else esc = 0;
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
/* if the atom starts with # and we're in inline
|
||||
binary mode, we need to go to state 12 to start
|
||||
checking for the #b# prefix. otherwise,
|
||||
if it's not a # or we're just in normal mode,
|
||||
proceed to state 4 as usual. */
|
||||
if (t[0] == '#' && mode == PARSER_INLINE_BINARY) {
|
||||
state = 12;
|
||||
} else {
|
||||
state = 4;
|
||||
}
|
||||
|
||||
t++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* open paren */
|
||||
depth++;
|
||||
|
||||
elts++;
|
||||
|
||||
if (stack->height < 1)
|
||||
stack->height++;
|
||||
|
||||
stack->height++;
|
||||
|
||||
state = 1;
|
||||
break;
|
||||
case 3:
|
||||
/** close paren **/
|
||||
|
||||
/* check for close parens that were never opened. */
|
||||
if (depth == 0) {
|
||||
cc->bindata = bindata;
|
||||
cc->binread = binread;
|
||||
cc->binexpected = binexpected;
|
||||
cc->val = val;
|
||||
cc->mode = mode;
|
||||
cc->val_used = val_used;
|
||||
cc->val_allocated = val_allocated;
|
||||
cc->vcur = vcur;
|
||||
cc->lastPos = t;
|
||||
cc->depth = depth;
|
||||
cc->qdepth = qdepth;
|
||||
cc->state = 1;
|
||||
cc->stack = stack;
|
||||
cc->esc = 0;
|
||||
cc->last_sexp = NULL;
|
||||
cc->error = SEXP_ERR_BADFORM;
|
||||
cc->event_handlers = event_handlers;
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
t++;
|
||||
depth--;
|
||||
|
||||
stack->height--;
|
||||
|
||||
if (event_handlers != NULL &&
|
||||
event_handlers->end_sexpr != NULL)
|
||||
event_handlers->end_sexpr();
|
||||
|
||||
state = 1;
|
||||
|
||||
/** if depth = 0 then we finished a sexpr, and we return **/
|
||||
if (depth == 0) {
|
||||
cc->bindata = bindata;
|
||||
cc->binread = binread;
|
||||
cc->binexpected = binexpected;
|
||||
cc->error = SEXP_ERR_OK;
|
||||
cc->mode = mode;
|
||||
cc->val = val;
|
||||
cc->val_allocated = val_allocated;
|
||||
cc->val_used = val_used;
|
||||
cc->vcur = vcur;
|
||||
cc->lastPos = t;
|
||||
cc->depth = depth;
|
||||
cc->qdepth = qdepth;
|
||||
cc->state = 1;
|
||||
cc->stack = stack;
|
||||
cc->esc = 0;
|
||||
cc->event_handlers = event_handlers;
|
||||
cc->last_sexp = NULL;
|
||||
stack->height = 0;
|
||||
|
||||
return cc;
|
||||
}
|
||||
break;
|
||||
case 4: /** parsing atom **/
|
||||
if (esc == 1 && (t[0] == '\"' || t[0] == '(' ||
|
||||
t[0] == ')' || t[0] == '\'' ||
|
||||
t[0] == '\\')) {
|
||||
vcur--; /* back up to overwrite the \ */
|
||||
vcur[0] = t[0];
|
||||
vcur++;
|
||||
t++;
|
||||
esc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* look at an ascii table - these ranges are the non-whitespace, non
|
||||
paren and quote characters that are legal in atoms */
|
||||
if (!((t[0] >= '*' && t[0] <= '~') ||
|
||||
((unsigned char)(t[0]) > 127) ||
|
||||
(t[0] == '!') ||
|
||||
(t[0] >= '#' && t[0] <= '&')))
|
||||
{
|
||||
vcur[0] = '\0';
|
||||
val_used++;
|
||||
|
||||
elts++;
|
||||
|
||||
if (event_handlers != NULL &&
|
||||
event_handlers->characters != NULL) {
|
||||
if (squoted != 0)
|
||||
event_handlers->characters(val,val_used,SEXP_SQUOTE);
|
||||
else
|
||||
event_handlers->characters(val,val_used,SEXP_BASIC);
|
||||
}
|
||||
|
||||
vcur = val;
|
||||
val_used = 0;
|
||||
|
||||
if (stack->height < 1) {
|
||||
/* looks like this expression was just a basic atom - so
|
||||
return it. */
|
||||
cc->bindata = bindata;
|
||||
cc->binread = binread;
|
||||
cc->binexpected = binexpected;
|
||||
cc->mode = mode;
|
||||
cc->error = SEXP_ERR_OK;
|
||||
cc->val = val;
|
||||
cc->val_used = val_used;
|
||||
cc->val_allocated = val_allocated;
|
||||
cc->vcur = vcur;
|
||||
cc->squoted = 0;
|
||||
cc->lastPos = t;
|
||||
cc->depth = depth;
|
||||
cc->qdepth = qdepth;
|
||||
cc->state = 1;
|
||||
cc->stack = stack;
|
||||
cc->esc = 0;
|
||||
cc->last_sexp = NULL;
|
||||
cc->event_handlers = event_handlers;
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
switch (t[0]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
/** NOTE: we know whitespace following atom, so spin ahead
|
||||
one and let state 1 do what it needs to for the next
|
||||
character. **/
|
||||
state = 1;
|
||||
t++;
|
||||
squoted = 0;
|
||||
break;
|
||||
case ')':
|
||||
squoted = 0;
|
||||
state = 3;
|
||||
break;
|
||||
default:
|
||||
squoted = 0;
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vcur[0] = t[0];
|
||||
if (t[0] == '\\') esc = 1;
|
||||
else esc = 0;
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
t++;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (esc == 1 && (t[0] == '\"' ||
|
||||
t[0] == '\'' ||
|
||||
t[0] == '(' ||
|
||||
t[0] == ')' ||
|
||||
t[0] == '\\')) {
|
||||
vcur--;
|
||||
vcur[0] = t[0];
|
||||
vcur++;
|
||||
/** NO NEED TO UPDATE VAL COUNTS **/
|
||||
t++;
|
||||
esc = 0;
|
||||
}
|
||||
|
||||
if (t[0] == '\"')
|
||||
{
|
||||
state = 6;
|
||||
|
||||
if (squoted == 1) {
|
||||
vcur[0] = '\"';
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
}
|
||||
|
||||
vcur[0] = '\0';
|
||||
|
||||
val_used++;
|
||||
elts++;
|
||||
|
||||
if (event_handlers != NULL &&
|
||||
event_handlers->characters != NULL) {
|
||||
if (squoted == 1)
|
||||
event_handlers->characters(val,val_used,SEXP_SQUOTE);
|
||||
else
|
||||
event_handlers->characters(val,val_used,SEXP_DQUOTE);
|
||||
}
|
||||
|
||||
vcur = val;
|
||||
val_used = 0;
|
||||
|
||||
if (stack->height < 1) {
|
||||
/* looks like this expression was just a basic double
|
||||
quoted atom - so return it. */
|
||||
t++; /* spin past the quote */
|
||||
|
||||
cc->bindata = bindata;
|
||||
cc->binread = binread;
|
||||
cc->binexpected = binexpected;
|
||||
cc->mode = mode;
|
||||
cc->squoted = 0;
|
||||
cc->error = SEXP_ERR_OK;
|
||||
cc->val = val;
|
||||
cc->val_used = val_used;
|
||||
cc->val_allocated = val_allocated;
|
||||
cc->vcur = vcur;
|
||||
cc->lastPos = t++;
|
||||
cc->depth = depth;
|
||||
cc->qdepth = qdepth;
|
||||
cc->state = 1;
|
||||
cc->stack = stack;
|
||||
cc->esc = 0;
|
||||
cc->last_sexp = NULL;
|
||||
cc->event_handlers = event_handlers;
|
||||
|
||||
return cc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vcur[0] = t[0];
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
if (t[0] == '\\') {
|
||||
esc = 1;
|
||||
} else
|
||||
esc = 0;
|
||||
}
|
||||
|
||||
t++;
|
||||
break;
|
||||
case 6:
|
||||
vcur = val;
|
||||
state = 1;
|
||||
break;
|
||||
case 7:
|
||||
if (t[0] == '\"')
|
||||
{
|
||||
state = 5;
|
||||
vcur = val;
|
||||
t++;
|
||||
|
||||
vcur[0] = '\"';
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
squoted = 1;
|
||||
}
|
||||
else if (t[0] == '(')
|
||||
{
|
||||
vcur = val;
|
||||
state = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
vcur = val;
|
||||
state = 4;
|
||||
squoted = 1;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (esc == 0) {
|
||||
if (t[0] == '(')
|
||||
{
|
||||
qdepth++;
|
||||
}
|
||||
else if (t[0] == ')')
|
||||
{
|
||||
qdepth--;
|
||||
state = 9;
|
||||
}
|
||||
else if (t[0] == '\"')
|
||||
{
|
||||
state = 10;
|
||||
}
|
||||
} else {
|
||||
esc = 0;
|
||||
}
|
||||
vcur[0] = t[0];
|
||||
if (t[0] == '\\') esc = 1;
|
||||
else esc = 0;
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
t++;
|
||||
/* let it fall through to state 9 if we know we're transitioning
|
||||
into that state */
|
||||
if (state != 9)
|
||||
break;
|
||||
case 9:
|
||||
if (qdepth == 0)
|
||||
{
|
||||
state = 1;
|
||||
vcur[0] = '\0';
|
||||
|
||||
elts++;
|
||||
|
||||
if (event_handlers != NULL &&
|
||||
event_handlers->characters != NULL)
|
||||
event_handlers->characters(val,val_used,SEXP_SQUOTE);
|
||||
|
||||
vcur = val;
|
||||
val_used = 0;
|
||||
|
||||
if (stack->height < 1) {
|
||||
/* looks like the whole expression was a single
|
||||
quoted value! So return it. */
|
||||
cc->bindata = bindata;
|
||||
cc->binread = binread;
|
||||
cc->binexpected = binexpected;
|
||||
cc->mode = mode;
|
||||
cc->error = SEXP_ERR_OK;
|
||||
cc->squoted = 0;
|
||||
cc->val = val;
|
||||
cc->val_used = val_used;
|
||||
cc->val_allocated = val_allocated;
|
||||
cc->vcur = vcur;
|
||||
cc->lastPos = t;
|
||||
cc->depth = depth;
|
||||
cc->qdepth = qdepth;
|
||||
cc->state = 1;
|
||||
cc->stack = stack;
|
||||
cc->esc = 0;
|
||||
cc->last_sexp = NULL;
|
||||
cc->event_handlers = event_handlers;
|
||||
|
||||
return cc;
|
||||
}
|
||||
}
|
||||
else
|
||||
state = 8;
|
||||
break;
|
||||
case 10:
|
||||
if (t[0] == '\"' && esc == 0)
|
||||
{
|
||||
state = 8;
|
||||
}
|
||||
vcur[0] = t[0];
|
||||
if (t[0] == '\\') esc = 1;
|
||||
else esc = 0;
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
t++;
|
||||
break;
|
||||
case 11:
|
||||
if (t[0] == '\n') {
|
||||
state = 1;
|
||||
}
|
||||
t++;
|
||||
break;
|
||||
case 12: /* pre: we saw a # and we're in inline binary mode */
|
||||
if (t[0] == 'b') {
|
||||
vcur[0] = t[0];
|
||||
if (t[0] == '\\') esc = 1;
|
||||
else esc = 0;
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
state = 13; /* so far, #b */
|
||||
t++;
|
||||
} else {
|
||||
state = 4; /* not #b, so plain ol' atom */
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 13: /* pre: we saw a #b and we're in inline binary mode */
|
||||
if (t[0] == '#') {
|
||||
vcur[0] = t[0];
|
||||
if (t[0] == '\\') esc = 1;
|
||||
else esc = 0;
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
state = 14; /* so far, #b# - we're definitely in binary
|
||||
land now. */
|
||||
/* reset vcur to val, overwrite #b# with the size string. */
|
||||
vcur = val;
|
||||
val_used = 0;
|
||||
t++;
|
||||
} else {
|
||||
state = 4; /* not #b#, so plain ol' atom */
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 14:
|
||||
/**
|
||||
* so far we've read #b#. Now, the steps of the process become:
|
||||
* proceed to read bytes in until we see # again. This will be
|
||||
* an ASCII representation of the size. At this point, we want
|
||||
* to read as many bytes as specified by this size string after
|
||||
* the #.
|
||||
*/
|
||||
if (t[0] == '#') { /* done with size string */
|
||||
t++;
|
||||
state = 15;
|
||||
vcur[0] = '\0';
|
||||
|
||||
binexpected = (size_t) atoi(val);
|
||||
assert(binexpected > 0);
|
||||
binread = 0;
|
||||
#ifdef __cplusplus
|
||||
bindata = (char *)sexp_malloc(sizeof(char)*binexpected);
|
||||
#else
|
||||
bindata = sexp_malloc(sizeof(char)*binexpected);
|
||||
#endif
|
||||
assert(bindata != NULL);
|
||||
} else { /* still reading size string */
|
||||
vcur[0] = t[0];
|
||||
if (t[0] == '\\') esc = 1;
|
||||
else esc = 0;
|
||||
val_used++;
|
||||
|
||||
if (val_used == val_allocated) {
|
||||
#ifdef __cplusplus
|
||||
val = (char *)sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#else
|
||||
val = sexp_realloc(val,
|
||||
val_allocated+sexp_val_grow_size,
|
||||
val_allocated);
|
||||
#endif
|
||||
assert(val != NULL);
|
||||
vcur = val + val_used;
|
||||
val_allocated += sexp_val_grow_size;
|
||||
} else vcur++;
|
||||
|
||||
t++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 15: /* reading binary blob */
|
||||
bindata[binread] = t[0];
|
||||
binread++;
|
||||
t++;
|
||||
|
||||
if (binread == binexpected) {
|
||||
/* state = 1 -- create a sexp_t and head back */
|
||||
|
||||
elts++;
|
||||
|
||||
if (event_handlers != NULL &&
|
||||
event_handlers->binary != NULL)
|
||||
event_handlers->binary(bindata, binread);
|
||||
|
||||
sexp_free(bindata,binread);
|
||||
bindata = NULL;
|
||||
binread = binexpected = 0;
|
||||
|
||||
state = 1;
|
||||
|
||||
val_used = 0;
|
||||
vcur = val;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf (stderr, "eparse_sexp: unknown parser state %d.\n", state);
|
||||
break;
|
||||
}
|
||||
|
||||
/* the null check used to be part of the guard on the while loop.
|
||||
unfortunately, if we're in state 15, null is considered a
|
||||
perfectly valid byte. This means the length passed in better
|
||||
be accurate for the parser to not walk off the end of the
|
||||
string! */
|
||||
if (state != 15 && t[0] == '\0') keepgoing = 0;
|
||||
}
|
||||
|
||||
if (depth == 0 && elts > 0) {
|
||||
cc->bindata = bindata;
|
||||
cc->binread = binread;
|
||||
cc->binexpected = binexpected;
|
||||
cc->mode = mode;
|
||||
cc->error = SEXP_ERR_OK;
|
||||
cc->val = val;
|
||||
cc->squoted = squoted;
|
||||
cc->val_used = val_used;
|
||||
cc->val_allocated = val_allocated;
|
||||
cc->vcur = vcur;
|
||||
cc->lastPos = t;
|
||||
cc->depth = depth;
|
||||
cc->qdepth = qdepth;
|
||||
cc->state = 1;
|
||||
cc->stack = stack;
|
||||
cc->esc = 0;
|
||||
cc->event_handlers = event_handlers;
|
||||
stack->height = 0;
|
||||
cc->last_sexp = NULL;
|
||||
} else {
|
||||
cc->bindata = bindata;
|
||||
cc->binread = binread;
|
||||
cc->binexpected = binexpected;
|
||||
cc->mode = mode;
|
||||
cc->val = val;
|
||||
cc->esc = esc;
|
||||
cc->squoted = squoted;
|
||||
cc->vcur = vcur;
|
||||
cc->val_allocated = val_allocated;
|
||||
cc->val_used = val_used;
|
||||
if (t[0] == '\0' || t == bufEnd)
|
||||
cc->lastPos = NULL;
|
||||
else
|
||||
cc->lastPos = t;
|
||||
cc->depth = depth;
|
||||
cc->qdepth = qdepth;
|
||||
cc->state = state;
|
||||
cc->stack = stack;
|
||||
cc->last_sexp = NULL;
|
||||
cc->event_handlers = event_handlers;
|
||||
cc->error = SEXP_ERR_OK;
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
/**
|
||||
* faststack.c : implementation of fast stack.
|
||||
*
|
||||
* matt sottile / matt@lanl.gov
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sexpr/faststack.h>
|
||||
#include <sexpr/sexp.h>
|
||||
|
||||
/**
|
||||
* create an empty stack.
|
||||
*/
|
||||
faststack_t *
|
||||
make_stack ()
|
||||
{
|
||||
faststack_t *s;
|
||||
|
||||
#ifdef __cplusplus
|
||||
s = (faststack_t *)sexp_malloc (sizeof (faststack_t));
|
||||
#else
|
||||
s = sexp_malloc (sizeof (faststack_t));
|
||||
#endif
|
||||
|
||||
if (s == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->top = s->bottom = NULL;
|
||||
s->height = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* free all levels of a stack
|
||||
*/
|
||||
void
|
||||
destroy_stack (faststack_t * s)
|
||||
{
|
||||
stack_lvl_t *sl;
|
||||
|
||||
/* return if stack is null. no error condition - just return. */
|
||||
if (s == NULL)
|
||||
return;
|
||||
|
||||
/* start at the bottom */
|
||||
sl = s->bottom;
|
||||
|
||||
/* if bottom is null, no levels to free. just free stack itself then. */
|
||||
if (sl == NULL) {
|
||||
sexp_free(s, sizeof(faststack_t));
|
||||
return;
|
||||
}
|
||||
|
||||
/* go up to the top of the allocated stack */
|
||||
while (sl->above != NULL)
|
||||
sl = sl->above;
|
||||
|
||||
/* until we get to the bottom (where below is null), free the data
|
||||
at each level and the level itself. */
|
||||
while (sl->below != NULL)
|
||||
{
|
||||
sl = sl->below;
|
||||
sexp_free (sl->above, sizeof(stack_lvl_t));
|
||||
}
|
||||
|
||||
/* free the bottom level */
|
||||
sexp_free (sl, sizeof(stack_lvl_t));
|
||||
|
||||
/* free the stack wrapper itself. */
|
||||
sexp_free (s, sizeof(faststack_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* push a level onto the cur_stack. reuse levels that have
|
||||
* been previously allocated, allocate a new one if none
|
||||
* are available.
|
||||
*/
|
||||
faststack_t *
|
||||
push (faststack_t * cur_stack, void *data)
|
||||
{
|
||||
stack_lvl_t *top, *tmp;
|
||||
|
||||
if (cur_stack == NULL) {
|
||||
sexp_errno = SEXP_ERR_BAD_STACK;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
top = cur_stack->top;
|
||||
|
||||
/* if top isn't null, try to push above it. */
|
||||
if (top != NULL)
|
||||
{
|
||||
/* if above isn't null, set the stack top to it and set the
|
||||
data */
|
||||
if (top->above != NULL)
|
||||
{
|
||||
top = cur_stack->top = cur_stack->top->above;
|
||||
top->data = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise, allocate a new level. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
tmp = top->above = (stack_level *)sexp_malloc (sizeof (stack_lvl_t));
|
||||
#else
|
||||
tmp = top->above = sexp_malloc (sizeof (stack_lvl_t));
|
||||
#endif
|
||||
|
||||
if (tmp == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmp->below = cur_stack->top;
|
||||
tmp->above = NULL;
|
||||
cur_stack->top = tmp;
|
||||
tmp->data = data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cur_stack->bottom != NULL)
|
||||
{
|
||||
cur_stack->top = cur_stack->bottom;
|
||||
cur_stack->top->data = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
tmp = cur_stack->top =
|
||||
(stack_lvl_t *)sexp_malloc (sizeof (stack_lvl_t));
|
||||
#else
|
||||
tmp = cur_stack->top = sexp_malloc (sizeof (stack_lvl_t));
|
||||
#endif
|
||||
if (tmp == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cur_stack->bottom = tmp;
|
||||
tmp->above = NULL;
|
||||
tmp->below = NULL;
|
||||
tmp->data = data;
|
||||
}
|
||||
}
|
||||
|
||||
cur_stack->height++;
|
||||
|
||||
return cur_stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* pop the top of the stack, return the stack level that was
|
||||
* popped of.
|
||||
*/
|
||||
stack_lvl_t *
|
||||
pop (faststack_t * s)
|
||||
{
|
||||
stack_lvl_t *top;
|
||||
|
||||
if (s == NULL) {
|
||||
sexp_errno = SEXP_ERR_BAD_STACK;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
top = s->top;
|
||||
|
||||
/* if stack top isn't null, set the top pointer to the next
|
||||
level down and return the old top. */
|
||||
if (top != NULL && s->height > 0)
|
||||
{
|
||||
s->top = s->top->below;
|
||||
s->height--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->height < 1) return NULL;
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#include <fcntl.h>
|
||||
#ifndef WIN32
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# define ssize_t int
|
||||
# include <io.h>
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sexpr/sexp.h>
|
||||
|
||||
/**
|
||||
* initialize an io-wrapper
|
||||
*/
|
||||
sexp_iowrap_t *init_iowrap(int fd) {
|
||||
sexp_iowrap_t *iow;
|
||||
|
||||
#ifdef __cplusplus
|
||||
iow = (sexp_iowrap_t *)sexp_calloc(1,sizeof(sexp_iowrap_t));
|
||||
#else
|
||||
iow = sexp_calloc(1,sizeof(sexp_iowrap_t));
|
||||
#endif
|
||||
|
||||
if (iow == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iow->cc = NULL;
|
||||
iow->fd = fd;
|
||||
iow->cnt = 0;
|
||||
iow->buf[0] = '\0';
|
||||
|
||||
return iow;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void destroy_iowrap(sexp_iowrap_t *iow) {
|
||||
if (iow == NULL) return; /* idiot */
|
||||
|
||||
destroy_continuation(iow->cc);
|
||||
sexp_free(iow, sizeof(sexp_iowrap_t));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
sexp_t *read_one_sexp(sexp_iowrap_t *iow) {
|
||||
sexp_t *sx = NULL;
|
||||
|
||||
if (iow == NULL)
|
||||
return NULL;
|
||||
|
||||
/* check if we have more to parse from the continuation. */
|
||||
if (iow->cc != NULL && iow->cc->lastPos != NULL) {
|
||||
iow->cc = cparse_sexp(iow->buf, iow->cnt, iow->cc);
|
||||
|
||||
if (iow->cc == NULL) return NULL; /* cparse_sexp set sexp_errno */
|
||||
if (iow->cc->last_sexp != NULL) {
|
||||
sx = iow->cc->last_sexp;
|
||||
iow->cc->last_sexp = NULL;
|
||||
return sx;
|
||||
}
|
||||
iow->cnt = 0;
|
||||
}
|
||||
|
||||
if (iow->cnt == 0) {
|
||||
iow->cnt = (size_t) read(iow->fd,iow->buf,BUFSIZ);
|
||||
|
||||
if (iow->cnt == 0) {
|
||||
sexp_errno = SEXP_ERR_IO_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
iow->cc = cparse_sexp(iow->buf,iow->cnt,iow->cc);
|
||||
|
||||
while (iow->cc->last_sexp == NULL) {
|
||||
if (iow->cc->error != SEXP_ERR_OK) {
|
||||
sexp_errno = iow->cc->error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iow->cnt = (size_t) read(iow->fd,iow->buf,BUFSIZ);
|
||||
|
||||
if (iow->cnt == 0) {
|
||||
sexp_errno = SEXP_ERR_IO_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iow->cc = cparse_sexp(iow->buf,iow->cnt,iow->cc);
|
||||
iow->cnt = 0;
|
||||
}
|
||||
|
||||
sx = iow->cc->last_sexp;
|
||||
iow->cc->last_sexp = NULL;
|
||||
|
||||
return sx;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
datarootdir=@datarootdir@
|
||||
datadir=@datadir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libsexpr
|
||||
Description: Small, fast s-expression handling library (so called sexpr).
|
||||
Version: @LIBSEXPR_VERSION@
|
||||
Requires:
|
||||
Libs: -L${libdir} -lsexpr
|
||||
Cflags: -I${includedir}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,589 @@
|
||||
/**
|
||||
@Cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sexpr/sexp.h>
|
||||
#include <sexpr/faststack.h>
|
||||
|
||||
/*
|
||||
* global error code that can be set by sexp library calls. default
|
||||
* is SEXP_ERR_OK.
|
||||
*/
|
||||
sexp_errcode_t sexp_errno = SEXP_ERR_OK;
|
||||
|
||||
void reset_sexp_errno() {
|
||||
sexp_errno = SEXP_ERR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively walk an s-expression and free it.
|
||||
*/
|
||||
void
|
||||
destroy_sexp (sexp_t * s)
|
||||
{
|
||||
if (s == NULL)
|
||||
return;
|
||||
|
||||
if (s->ty == SEXP_LIST) {
|
||||
destroy_sexp (s->list);
|
||||
} else if (s->ty == SEXP_VALUE) {
|
||||
if (s->aty == SEXP_BINARY && s->bindata != NULL) {
|
||||
sexp_free(s->bindata, s->binlength);
|
||||
} else if (s->val != NULL) {
|
||||
sexp_free(s->val, s->val_allocated);
|
||||
}
|
||||
}
|
||||
|
||||
s->val = NULL;
|
||||
s->bindata = NULL;
|
||||
|
||||
destroy_sexp (s->next);
|
||||
|
||||
s->next = s->list = NULL;
|
||||
|
||||
sexp_t_deallocate(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterative method to walk sx and turn it back into the string
|
||||
* representation of the s-expression. Fills the buffer.
|
||||
*/
|
||||
int
|
||||
print_sexp (char *buf, size_t size, const sexp_t * sx)
|
||||
{
|
||||
int retval;
|
||||
size_t sz;
|
||||
char *b = buf, *tc;
|
||||
size_t left = size;
|
||||
int depth = 0;
|
||||
faststack_t *stack;
|
||||
stack_lvl_t *top;
|
||||
sexp_t *tdata;
|
||||
sexp_t *fakehead;
|
||||
sexp_t tmp;
|
||||
|
||||
if (sx == NULL) {
|
||||
buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = *sx;
|
||||
tmp.next = tmp.list = NULL;
|
||||
|
||||
fakehead = copy_sexp(&tmp);
|
||||
|
||||
if (fakehead == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fakehead->list = sx->list;
|
||||
fakehead->next = NULL; /* this is the important part of fakehead */
|
||||
|
||||
stack = make_stack ();
|
||||
if (stack == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
sexp_t_deallocate(fakehead);
|
||||
return -1;
|
||||
}
|
||||
|
||||
push (stack, fakehead);
|
||||
|
||||
while (stack->top != NULL)
|
||||
{
|
||||
top = stack->top;
|
||||
tdata = (sexp_t *) top->data;
|
||||
|
||||
if (tdata == NULL)
|
||||
{
|
||||
pop (stack);
|
||||
|
||||
if (depth > 0)
|
||||
{
|
||||
b[0] = ')';
|
||||
b++;
|
||||
left--;
|
||||
depth--;
|
||||
if (left == 0)
|
||||
{
|
||||
sexp_errno = SEXP_ERR_BUFFER_FULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack->top == NULL)
|
||||
break;
|
||||
|
||||
top = stack->top;
|
||||
top->data = ((sexp_t *) top->data)->next;
|
||||
if (top->data != NULL)
|
||||
{
|
||||
b[0] = ' ';
|
||||
b++;
|
||||
left--;
|
||||
if (left == 0)
|
||||
{
|
||||
sexp_errno = SEXP_ERR_BUFFER_FULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tdata->ty == SEXP_VALUE)
|
||||
{
|
||||
if (tdata->aty == SEXP_DQUOTE)
|
||||
{
|
||||
b[0] = '\"';
|
||||
b++;
|
||||
left--;
|
||||
}
|
||||
else if (tdata->aty == SEXP_SQUOTE)
|
||||
{
|
||||
b[0] = '\'';
|
||||
b++;
|
||||
left--;
|
||||
}
|
||||
|
||||
if (tdata->aty != SEXP_BINARY && tdata->val_used > 0) {
|
||||
tc = tdata->val;
|
||||
/* copy value into string */
|
||||
while (tc[0] != 0 && left > 0)
|
||||
{
|
||||
/* escape characters that need escaping. */
|
||||
if ((tc[0] == '\"' || tc[0] == '\\') &&
|
||||
tdata->aty == SEXP_DQUOTE)
|
||||
{
|
||||
b[0] = '\\';
|
||||
b++;
|
||||
left--;
|
||||
if (left == 0) break;
|
||||
}
|
||||
|
||||
b[0] = tc[0];
|
||||
b++;
|
||||
tc++;
|
||||
left--;
|
||||
if (left == 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (left > 3) {
|
||||
b[0] = '#'; b[1] = 'b'; b[2] = '#';
|
||||
b+=3;
|
||||
left-=3;
|
||||
|
||||
#ifndef WIN32
|
||||
if ((size_t)(sz = snprintf(b,left,"%lu#",(unsigned long)tdata->binlength)) >= left) {
|
||||
#else
|
||||
if ((sz = _snprintf(b,left,"%lu#",tdata->binlength)) >= left) {
|
||||
#endif
|
||||
left = 0;
|
||||
break;
|
||||
}
|
||||
b += sz;
|
||||
left -= sz;
|
||||
|
||||
if (left < tdata->binlength) {
|
||||
left = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tdata->binlength > 0) {
|
||||
memcpy(b,tdata->bindata,tdata->binlength);
|
||||
left -= tdata->binlength;
|
||||
b+=tdata->binlength;
|
||||
}
|
||||
|
||||
b[0] = ' ';
|
||||
left--;
|
||||
|
||||
} else {
|
||||
left = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tdata->aty == SEXP_DQUOTE && left > 0)
|
||||
{
|
||||
b[0] = '\"';
|
||||
b++;
|
||||
left--;
|
||||
}
|
||||
|
||||
if (left == 0)
|
||||
{
|
||||
sexp_errno = SEXP_ERR_BUFFER_FULL;
|
||||
break;
|
||||
}
|
||||
|
||||
top->data = ((sexp_t *) top->data)->next;
|
||||
|
||||
if (top->data != NULL)
|
||||
{
|
||||
b[0] = ' ';
|
||||
b++;
|
||||
left--;
|
||||
if (left == 0)
|
||||
{
|
||||
sexp_errno = SEXP_ERR_BUFFER_FULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tdata->ty == SEXP_LIST)
|
||||
{
|
||||
depth++;
|
||||
b[0] = '(';
|
||||
b++;
|
||||
left--;
|
||||
if (left == 0)
|
||||
{
|
||||
sexp_errno = SEXP_ERR_BUFFER_FULL;
|
||||
break;
|
||||
}
|
||||
|
||||
push (stack, tdata->list);
|
||||
}
|
||||
else
|
||||
{
|
||||
sexp_errno = SEXP_ERR_BADCONTENT;
|
||||
destroy_stack (stack);
|
||||
sexp_t_deallocate(fakehead);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
while (depth != 0)
|
||||
{
|
||||
b[0] = ')';
|
||||
b++;
|
||||
left--;
|
||||
depth--;
|
||||
if (left == 0)
|
||||
{
|
||||
sexp_errno = SEXP_ERR_BUFFER_FULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (left != 0) {
|
||||
b[0] = 0;
|
||||
retval = (int) (size-left);
|
||||
} else {
|
||||
b--;
|
||||
b[0] = 0;
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
destroy_stack (stack);
|
||||
sexp_t_deallocate(fakehead);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterative method to walk sx and turn it back into the string
|
||||
* representation of the s-expression. Fills the CSTRING that is
|
||||
* passed in. If *s == NULL (new CSTRING, never used), snew() is called
|
||||
* and passed back. If *s != NULL, *s is used as the CSTRING to print
|
||||
* into. In the last case, the recycled CSTRING must have sempty() called
|
||||
* to reset the allocated vs. used counters to make it appear to be empty.
|
||||
* the code will assume that sempty() was called by the user!
|
||||
*/
|
||||
int
|
||||
print_sexp_cstr (CSTRING **s, const sexp_t *sx, size_t ss)
|
||||
{
|
||||
int retval;
|
||||
char *tc;
|
||||
int depth = 0;
|
||||
faststack_t *stack;
|
||||
stack_lvl_t *top;
|
||||
sexp_t *tdata;
|
||||
sexp_t *fakehead;
|
||||
CSTRING *_s = NULL;
|
||||
char sbuf[32];
|
||||
unsigned int i;
|
||||
sexp_t tmp;
|
||||
|
||||
if (sx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*s == NULL)
|
||||
_s = snew(ss);
|
||||
else
|
||||
_s = *s;
|
||||
|
||||
tmp = *sx;
|
||||
tmp.next = tmp.list = NULL;
|
||||
|
||||
fakehead = copy_sexp(&tmp);
|
||||
|
||||
if (fakehead == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fakehead->list = sx->list;
|
||||
fakehead->next = NULL; /* this is the important part of fakehead */
|
||||
|
||||
stack = make_stack ();
|
||||
if (stack == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
sexp_t_deallocate(fakehead);
|
||||
return -1;
|
||||
}
|
||||
|
||||
push (stack, fakehead);
|
||||
|
||||
while (stack->top != NULL)
|
||||
{
|
||||
top = stack->top;
|
||||
tdata = (sexp_t *) top->data;
|
||||
|
||||
if (tdata == NULL)
|
||||
{
|
||||
pop (stack);
|
||||
|
||||
if (depth > 0)
|
||||
{
|
||||
_s = saddch(_s, ')');
|
||||
depth--;
|
||||
}
|
||||
|
||||
if (stack->top == NULL)
|
||||
break;
|
||||
|
||||
top = stack->top;
|
||||
top->data = ((sexp_t *) top->data)->next;
|
||||
if (top->data != NULL)
|
||||
{
|
||||
_s = saddch(_s, ' ');
|
||||
}
|
||||
}
|
||||
else if (tdata->ty == SEXP_VALUE)
|
||||
{
|
||||
if (tdata->aty == SEXP_DQUOTE)
|
||||
{
|
||||
_s = saddch(_s,'\"');
|
||||
}
|
||||
else if (tdata->aty == SEXP_SQUOTE)
|
||||
{
|
||||
_s = saddch(_s,'\'');
|
||||
}
|
||||
|
||||
if (tdata->aty == SEXP_BINARY) {
|
||||
sprintf(sbuf,"#b#%lu#",(unsigned long)tdata->binlength);
|
||||
|
||||
_s = sadd(_s,sbuf);
|
||||
|
||||
for (i=0;i<tdata->binlength;i++)
|
||||
_s = saddch(_s,tdata->bindata[i]);
|
||||
_s = saddch(_s,' ');
|
||||
} else {
|
||||
if (tdata->val_used > 0) {
|
||||
tc = tdata->val;
|
||||
|
||||
/* copy value into string */
|
||||
while (tc[0] != 0)
|
||||
{
|
||||
/* escape characters that need escaping. */
|
||||
if ((tc[0] == '\"' ||
|
||||
tc[0] == '\\') && tdata->aty == SEXP_DQUOTE)
|
||||
{
|
||||
_s = saddch(_s,'\\');
|
||||
}
|
||||
|
||||
_s = saddch(_s,tc[0]);
|
||||
tc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tdata->aty == SEXP_DQUOTE)
|
||||
{
|
||||
_s = saddch(_s,'\"');
|
||||
}
|
||||
|
||||
top->data = ((sexp_t *) top->data)->next;
|
||||
|
||||
if (top->data != NULL)
|
||||
{
|
||||
_s = saddch(_s,' ');
|
||||
}
|
||||
}
|
||||
else if (tdata->ty == SEXP_LIST)
|
||||
{
|
||||
depth++;
|
||||
_s = saddch(_s,'(');
|
||||
push (stack, tdata->list);
|
||||
}
|
||||
else
|
||||
{
|
||||
sexp_errno = SEXP_ERR_BADCONTENT;
|
||||
destroy_stack (stack);
|
||||
sexp_t_deallocate(fakehead);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
while (depth != 0)
|
||||
{
|
||||
_s = saddch(_s,')');
|
||||
depth--;
|
||||
}
|
||||
|
||||
*s = _s;
|
||||
if (_s == NULL)
|
||||
retval = 0;
|
||||
else
|
||||
retval = (int) _s->curlen;
|
||||
|
||||
destroy_stack (stack);
|
||||
sexp_t_deallocate(fakehead);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new sexp_t element representing a list.
|
||||
*/
|
||||
sexp_t *new_sexp_list(sexp_t *l) {
|
||||
sexp_t *sx = sexp_t_allocate();
|
||||
|
||||
if (sx == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sx->ty = SEXP_LIST;
|
||||
|
||||
sx->list = l;
|
||||
sx->next = NULL;
|
||||
|
||||
sx->val = NULL;
|
||||
sx->val_used = sx->val_allocated = 0;
|
||||
|
||||
return sx;
|
||||
}
|
||||
|
||||
/**
|
||||
* allocate a new sexp_t element representing a raw binary value
|
||||
*/
|
||||
sexp_t *new_sexp_binary_atom(char *data, size_t binlength) {
|
||||
sexp_t *sx = sexp_t_allocate();
|
||||
|
||||
if (sx == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sx->ty = SEXP_VALUE;
|
||||
sx->next = sx->list = NULL;
|
||||
sx->aty = SEXP_BINARY;
|
||||
sx->bindata = data;
|
||||
sx->binlength = binlength;
|
||||
sx->val = NULL;
|
||||
sx->val_used = sx->val_allocated = 0;
|
||||
|
||||
return sx;
|
||||
}
|
||||
|
||||
/**
|
||||
* allocate a new sexp_t element representing a value
|
||||
*/
|
||||
sexp_t *new_sexp_atom(const char *buf, size_t bs, atom_t aty) {
|
||||
sexp_t *sx = NULL;
|
||||
|
||||
if (aty == SEXP_BINARY) {
|
||||
sexp_errno = SEXP_ERR_BAD_CONSTRUCTOR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sx = sexp_t_allocate();
|
||||
|
||||
if (sx == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sx->ty = SEXP_VALUE;
|
||||
sx->aty = aty;
|
||||
|
||||
#ifdef __cplusplus
|
||||
sx->val = (char *)sexp_malloc(sizeof(char)*(bs+1));
|
||||
#else
|
||||
sx->val = sexp_malloc(sizeof(char)*(bs+1));
|
||||
#endif
|
||||
|
||||
if (sx->val == NULL) {
|
||||
sexp_t_deallocate(sx);
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sx->val_used = sx->val_allocated = bs+1;
|
||||
|
||||
strcpy(sx->val,buf);
|
||||
|
||||
sx->list = sx->next = NULL;
|
||||
|
||||
return sx;
|
||||
}
|
||||
|
||||
/* sexp helpers */
|
||||
int sexp_list_car(sexp_t *expr, sexp_t **sx)
|
||||
{
|
||||
if (!SEXP_IS_LIST(expr) || expr->list->ty != SEXP_VALUE) return 1;
|
||||
|
||||
*sx = expr->list;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sexp_list_cdr(sexp_t *expr, sexp_t **sx)
|
||||
{
|
||||
/* Dummy function. Can we do cdr properly? */
|
||||
if (!SEXP_IS_LIST(expr) || expr->list->ty != SEXP_VALUE) return 1;
|
||||
|
||||
if (!expr->list->next) *sx = NULL;
|
||||
else *sx = expr->list->next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,125 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sexpr/sexp.h>
|
||||
#include <sexpr/sexp_errors.h>
|
||||
#include <sexpr/sexp_memory.h>
|
||||
|
||||
#ifdef _SEXP_LIMIT_MEMORY_
|
||||
|
||||
static size_t sexp_max_memory = 32*1024*1024; /* default: 32MB */
|
||||
static size_t sexp_used_memory = 0;
|
||||
|
||||
size_t get_sexp_max_memory() {
|
||||
return sexp_max_memory;
|
||||
}
|
||||
|
||||
size_t get_sexp_used_memory() {
|
||||
return sexp_used_memory;
|
||||
}
|
||||
|
||||
int set_sexp_max_memory(size_t newsize) {
|
||||
if (newsize > 0) {
|
||||
if (newsize < sexp_used_memory) {
|
||||
sexp_errno = SEXP_ERR_BAD_PARAM;
|
||||
return -1;
|
||||
} else {
|
||||
sexp_max_memory = newsize;
|
||||
}
|
||||
} else {
|
||||
sexp_errno = SEXP_ERR_BAD_PARAM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sexp_max_memory;
|
||||
}
|
||||
|
||||
void *sexp_malloc(size_t size) {
|
||||
void *ptr;
|
||||
|
||||
if (sexp_used_memory+size > sexp_max_memory) {
|
||||
sexp_errno = SEXP_ERR_MEM_LIMIT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = malloc(size);
|
||||
if (ptr != NULL) sexp_used_memory += size;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *sexp_calloc(size_t count, size_t size) {
|
||||
void *ptr;
|
||||
|
||||
if (sexp_used_memory+(size*count) > sexp_max_memory) {
|
||||
sexp_errno = SEXP_ERR_MEM_LIMIT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = calloc(count, size);
|
||||
if (ptr != NULL) sexp_used_memory += size*count;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void sexp_free(void *ptr, size_t size) {
|
||||
if (sexp_used_memory < size) {
|
||||
fprintf(stderr,"ERROR: sexp_free called too many times!\n");
|
||||
} else {
|
||||
sexp_used_memory -= size;
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void *sexp_realloc(void *ptr, size_t size, size_t oldsize) {
|
||||
void *p;
|
||||
|
||||
if (sexp_used_memory+(size-oldsize) > sexp_max_memory) {
|
||||
sexp_errno = SEXP_ERR_MEM_LIMIT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = realloc(ptr,size);
|
||||
if (p != NULL) sexp_used_memory += size-oldsize;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif /* _SEXP_LIMIT_MEMORY_ */
|
@ -0,0 +1,224 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sexpr/sexp_ops.h>
|
||||
|
||||
/**
|
||||
* Given an s-expression, find the atom inside of it with the
|
||||
* value matchine name, and return a reference to it. If the atom
|
||||
* doesn't occur inside start, return NULL.
|
||||
*/
|
||||
sexp_t *
|
||||
find_sexp (const char *name, sexp_t * start)
|
||||
{
|
||||
sexp_t *temp;
|
||||
|
||||
if (start == NULL)
|
||||
return NULL;
|
||||
|
||||
if (start->ty == SEXP_LIST)
|
||||
{
|
||||
temp = find_sexp (name, start->list);
|
||||
if (temp == NULL)
|
||||
return find_sexp (name, start->next);
|
||||
else
|
||||
return temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (start->val != NULL && strcmp (start->val, name) == 0)
|
||||
return start;
|
||||
else
|
||||
return find_sexp (name, start->next);
|
||||
}
|
||||
|
||||
return NULL; /* shouldn't get here */
|
||||
}
|
||||
|
||||
/**
|
||||
* Breadth first search - look at ->next before ->list when seeing list
|
||||
* elements of an expression.
|
||||
*/
|
||||
sexp_t *bfs_find_sexp(const char *str, sexp_t *sx) {
|
||||
sexp_t *t = sx;
|
||||
sexp_t *rt;
|
||||
|
||||
if (sx == NULL) return NULL;
|
||||
|
||||
while (t != NULL) {
|
||||
if (t->ty == SEXP_VALUE) {
|
||||
if (t->val != NULL) {
|
||||
if (strcmp(t->val,str) == 0) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
t = sx;
|
||||
while (t != NULL) {
|
||||
if (t->ty == SEXP_LIST) {
|
||||
rt = bfs_find_sexp(str,t->list);
|
||||
if (rt != NULL) return rt;
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the length of a s-expression list.
|
||||
*/
|
||||
int sexp_list_length(const sexp_t *sx) {
|
||||
int len = 0;
|
||||
const sexp_t *t;
|
||||
|
||||
if (sx == NULL) return 0;
|
||||
|
||||
if (sx->ty == SEXP_VALUE) return 1;
|
||||
|
||||
t = sx->list;
|
||||
|
||||
while (t != NULL) {
|
||||
len++;
|
||||
t = t->next;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy an s-expression.
|
||||
*/
|
||||
sexp_t *copy_sexp(const sexp_t *s) {
|
||||
sexp_t *s_new;
|
||||
|
||||
if (s == NULL) return NULL;
|
||||
|
||||
s_new = sexp_t_allocate();
|
||||
if (s_new == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* initialize fields to null and zero, and fill in only those necessary. */
|
||||
s_new->val_allocated = s_new->val_used = 0;
|
||||
s_new->val = NULL;
|
||||
s_new->list = s_new->next = NULL;
|
||||
s_new->bindata = NULL;
|
||||
s_new->binlength = 0;
|
||||
|
||||
/* now start copying in data and setting appropriate fields. */
|
||||
s_new->ty = s->ty;
|
||||
|
||||
/* values */
|
||||
if (s_new->ty == SEXP_VALUE) {
|
||||
s_new->aty = s->aty;
|
||||
|
||||
/* binary */
|
||||
if (s_new->aty == SEXP_BINARY) {
|
||||
if (s->bindata == NULL && s->binlength > 0) {
|
||||
sexp_errno = SEXP_ERR_BADCONTENT;
|
||||
sexp_t_deallocate(s_new);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s_new->binlength = s->binlength;
|
||||
|
||||
if (s->bindata == NULL) {
|
||||
s_new->bindata = NULL;
|
||||
} else {
|
||||
/** allocate space **/
|
||||
#ifdef __cplusplus
|
||||
s_new->bindata = (char *)sexp_malloc(sizeof(char)*s->binlength);
|
||||
#else
|
||||
s_new->bindata = sexp_malloc(sizeof(char)*s->binlength);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (s_new->bindata == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
sexp_t_deallocate(s_new);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(s_new->bindata,s->bindata,s->binlength*sizeof(char));
|
||||
|
||||
/* non-binary */
|
||||
} else {
|
||||
if (s->val == NULL && (s->val_used > 0 || s->val_allocated > 0)) {
|
||||
sexp_errno = SEXP_ERR_BADCONTENT;
|
||||
sexp_t_deallocate(s_new);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s_new->val_used = s->val_used;
|
||||
s_new->val_allocated = s->val_allocated;
|
||||
|
||||
if (s->val == NULL) {
|
||||
s_new->val = NULL;
|
||||
} else {
|
||||
/** allocate space **/
|
||||
#ifdef __cplusplus
|
||||
s_new->val = (char *)sexp_calloc(1,sizeof(char)*s->val_allocated);
|
||||
#else
|
||||
s_new->val = sexp_calloc(1,sizeof(char)*s->val_allocated);
|
||||
#endif
|
||||
|
||||
if (s_new->val == NULL) {
|
||||
sexp_errno = SEXP_ERR_MEMORY;
|
||||
sexp_t_deallocate(s_new);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(s_new->val, s->val, sizeof(char)*s->val_used);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s_new->list = copy_sexp(s->list);
|
||||
}
|
||||
|
||||
s_new->next = copy_sexp(s->next);
|
||||
|
||||
return s_new;
|
||||
}
|
||||
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
@cond IGNORE
|
||||
|
||||
======================================================
|
||||
SFSEXP: Small, Fast S-Expression Library version 1.2
|
||||
Written by Matthew Sottile (mjsottile@gmail.com)
|
||||
======================================================
|
||||
|
||||
Copyright (2003-2006). The Regents of the University of California. This
|
||||
material was produced under U.S. Government contract W-7405-ENG-36 for Los
|
||||
Alamos National Laboratory, which is operated by the University of
|
||||
California for the U.S. Department of Energy. The U.S. Government has rights
|
||||
to use, reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR
|
||||
THE UNIVERSITY MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
|
||||
LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified to produce
|
||||
derivative works, such modified software should be clearly marked, so as not
|
||||
to confuse it with the version available from LANL.
|
||||
|
||||
Additionally, this library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this library; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U SA
|
||||
|
||||
LA-CC-04-094
|
||||
|
||||
@endcond
|
||||
**/
|
||||
#include <sexpr/faststack.h>
|
||||
#include <sexpr/sexp.h>
|
||||
|
||||
void _sexp_to_dotfile(const sexp_t *sx, FILE *fp) {
|
||||
const sexp_t *tmp;
|
||||
|
||||
tmp = sx;
|
||||
|
||||
while (tmp != NULL) {
|
||||
fprintf(fp," sx%lu [shape=record,label=\"",(unsigned long)tmp);
|
||||
if (tmp->ty == SEXP_VALUE) {
|
||||
fprintf(fp,"{ <type> SEXP_VALUE | ");
|
||||
switch (tmp->aty) {
|
||||
case SEXP_BASIC:
|
||||
fprintf(fp,"SEXP_BASIC }");
|
||||
break;
|
||||
case SEXP_SQUOTE:
|
||||
fprintf(fp,"SEXP_SQUOTE }");
|
||||
break;
|
||||
case SEXP_DQUOTE:
|
||||
fprintf(fp,"SEXP_DQUOTE }");
|
||||
break;
|
||||
case SEXP_BINARY:
|
||||
fprintf(fp,"SEXP_BINARY }");
|
||||
break;
|
||||
default:
|
||||
fprintf(fp,"ATY Unknown }");
|
||||
break;
|
||||
}
|
||||
} else
|
||||
fprintf(fp,"<type> SEXP_LIST");
|
||||
|
||||
if (tmp->ty == SEXP_LIST) {
|
||||
fprintf(fp,"| <list> list | <next> next\"];\n");
|
||||
|
||||
if (tmp->list != NULL) {
|
||||
fprintf(fp," sx%lu:list -> sx%lu:type;\n",
|
||||
(unsigned long)tmp,
|
||||
(unsigned long)tmp->list);
|
||||
_sexp_to_dotfile(tmp->list,fp);
|
||||
if (tmp->next != NULL)
|
||||
fprintf(fp," sx%lu:next -> sx%lu:type;\n",
|
||||
(unsigned long)tmp,
|
||||
(unsigned long)tmp->next);
|
||||
tmp = tmp->next;
|
||||
}
|
||||
} else {
|
||||
if (tmp->aty == SEXP_BINARY)
|
||||
fprintf(fp,"| binlength=%lu | <next> next\"];\n",
|
||||
(unsigned long)tmp->binlength);
|
||||
else
|
||||
fprintf(fp,"| { va=%lu | vu=%lu } | val=%s | <next> next\"];\n",
|
||||
(unsigned long)tmp->val_allocated,
|
||||
(unsigned long)tmp->val_used,
|
||||
tmp->val);
|
||||
|
||||
if (tmp->next != NULL)
|
||||
fprintf(fp," sx%lu:next -> sx%lu:type;\n",
|
||||
(unsigned long)tmp,
|
||||
(unsigned long)tmp->next);
|
||||
tmp = tmp->next;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sexp_errcode_t sexp_to_dotfile(const sexp_t *sx, const char *fname) {
|
||||
FILE *fp;
|
||||
|
||||
if (sx == NULL || fname == NULL) {
|
||||
return SEXP_ERR_NULLSTRING;
|
||||
}
|
||||
|
||||
fp = fopen(fname,"w+");
|
||||
if (fp == NULL) {
|
||||
return SEXP_ERR_IO;
|
||||
}
|
||||
|
||||
fprintf(fp,"digraph sexp {\n");
|
||||
|
||||
_sexp_to_dotfile(sx,fp);
|
||||
|
||||
fprintf(fp,"}\n");
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return SEXP_ERR_OK;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
|
||||
-DPACKAGE_SRC_DIR=\""$(srcdir)"\" \
|
||||
-DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \
|
||||
$(LIBTDATA_CFLAGS) -I../include
|
||||
|
||||
AM_CFLAGS =\
|
||||
-Wall\
|
||||
-g
|
||||
|
||||
lib_LTLIBRARIES = libtdata.la
|
||||
|
||||
|
||||
libtdata_la_SOURCES = \
|
||||
avl.c lslist.c redblack.c splay.c \
|
||||
tree.c usrtc.c bitwise.c idx_allocator.c \
|
||||
cas.c
|
||||
|
||||
libtdata_la_LDFLAGS =
|
||||
|
||||
libtdata_la_LIBADD =
|
||||
|
||||
##include_HEADERS = \
|
||||
## ../include/tdata/macro.h ../include/tdata/tree.h ../include/tdata/usrtc.h \
|
||||
## ../include/tdata/bitwise.h ../include/tdata/idx_allocator.h
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libtdata.pc
|
||||
|
||||
EXTRA_DIST = \
|
||||
libtdata.pc.in
|
||||
|
@ -0,0 +1,3 @@
|
||||
0.2.3
|
||||
|
||||
|
@ -0,0 +1,328 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* avl.c
|
||||
* Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com>
|
||||
* Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#include <tdata/usrtc.h>
|
||||
#include <tdata/macro.h>
|
||||
#include <tdata/tree.h>
|
||||
|
||||
#define balance usrtc_impldata.usrtc_avl_balance
|
||||
#define BALANCED usrtc_balanced
|
||||
#define LEFTHEAVY usrtc_leftheavy
|
||||
#define RIGHTHEAVY usrtc_rightheavy
|
||||
|
||||
/*local functions prototypes*/
|
||||
static void avl_init(usrtc_t *);
|
||||
static void avl_insert(usrtc_t *,usrtc_node_t *,const void *);
|
||||
static void avl_delete(usrtc_t *,usrtc_node_t *);
|
||||
static void avl_convert_from_list(usrtc_t *);
|
||||
|
||||
usrtc_functions_t usrtc_avl_fu = {
|
||||
avl_init,
|
||||
avl_insert,
|
||||
avl_delete,
|
||||
usrtc_tree_lookup,
|
||||
usrtc_tree_lower_bound,
|
||||
usrtc_tree_upper_bound,
|
||||
usrtc_tree_first,
|
||||
usrtc_tree_last,
|
||||
usrtc_tree_next,
|
||||
usrtc_tree_prev,
|
||||
usrtc_tree_convert_to_list,
|
||||
avl_convert_from_list,
|
||||
usrtc_bst
|
||||
};
|
||||
|
||||
/*internal use*/
|
||||
static void rotate_left(usrtc_node_t **);
|
||||
static void rotate_right(usrtc_node_t **);
|
||||
static void fix_balance(usrtc_node_t **,usrtc_avl_balance_t );
|
||||
static int insert(usrtc_t *,usrtc_node_t *,usrtc_node_t **,usrtc_node_t *);
|
||||
static usrtc_node_t *make_tree(usrtc_node_t **,usrtc_count_t ,int *,usrtc_node_t *);
|
||||
|
||||
/*implementation*/
|
||||
static void avl_init(usrtc_t *us)
|
||||
{
|
||||
usrtc_tree_init(us);
|
||||
us->sentinel.balance=BALANCED;
|
||||
}
|
||||
|
||||
static void avl_insert(usrtc_t *us,usrtc_node_t *node,const void *key)
|
||||
{
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
|
||||
node->key=key;
|
||||
node->left=nil;
|
||||
node->right=nil;
|
||||
node->balance=BALANCED;
|
||||
|
||||
if(insert(us,node,&nil->left,nil)) {
|
||||
nil->balance=LEFTHEAVY;
|
||||
}
|
||||
|
||||
us->nodecount++;
|
||||
}
|
||||
|
||||
static void avl_delete(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *swap;
|
||||
usrtc_node_t *child;
|
||||
usrtc_node_t *parent;
|
||||
|
||||
/*basic deletion*/
|
||||
usrtc_tree_delete(us,node,&swap,&child);
|
||||
|
||||
/*implementation specific*/
|
||||
swap->balance=node->balance;
|
||||
parent=child->parent;
|
||||
|
||||
if(parent==nil) {
|
||||
if(child==nil) {
|
||||
parent->balance=BALANCED;
|
||||
}
|
||||
}
|
||||
|
||||
while(parent!=nil) {
|
||||
if((parent->left==nil) && (parent->right==nil)) {
|
||||
if(child!=nil)
|
||||
return;
|
||||
if(parent==BALANCED)
|
||||
return;
|
||||
parent->balance=BALANCED;
|
||||
}
|
||||
else {
|
||||
usrtc_node_t **pparent;
|
||||
if(parent==parent->parent->left)
|
||||
pparent=&parent->parent->left;
|
||||
else
|
||||
pparent=&parent->parent->right;
|
||||
|
||||
if(child==parent->left)
|
||||
fix_balance(pparent,RIGHTHEAVY);
|
||||
else {
|
||||
if(child!=parent->right)
|
||||
return;
|
||||
|
||||
fix_balance(pparent,LEFTHEAVY);
|
||||
}
|
||||
|
||||
parent=*pparent;
|
||||
}
|
||||
|
||||
if(parent->balance==BALANCED) {
|
||||
child=parent;
|
||||
parent=child->parent;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void avl_convert_from_list(usrtc_t *us)
|
||||
{
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *root;
|
||||
int height;
|
||||
|
||||
if(us->nodecount==0) {
|
||||
nil->balance=BALANCED;
|
||||
return;
|
||||
}
|
||||
|
||||
root=make_tree(&nil->next,us->nodecount,&height,nil);
|
||||
|
||||
if(nil->next!=nil)
|
||||
return;
|
||||
|
||||
nil->left=root;
|
||||
root->parent=nil;
|
||||
nil->balance=LEFTHEAVY;
|
||||
}
|
||||
|
||||
/*---*/
|
||||
static void rotate_left(usrtc_node_t **top)
|
||||
{
|
||||
usrtc_node_t *parent=*top;
|
||||
usrtc_node_t *child=parent->right;
|
||||
|
||||
child->parent=parent->parent;
|
||||
parent->right=child->left;
|
||||
parent->right->parent=parent;
|
||||
child->left=parent;
|
||||
parent->parent=child;
|
||||
*top=child;
|
||||
}
|
||||
|
||||
static void rotate_right(usrtc_node_t **top)
|
||||
{
|
||||
usrtc_node_t *parent=*top;
|
||||
usrtc_node_t *child=parent->left;
|
||||
|
||||
child->parent=parent->parent;
|
||||
parent->left=child->right;
|
||||
parent->left->parent=parent;
|
||||
child->right=parent;
|
||||
parent->parent=child;
|
||||
*top=child;
|
||||
}
|
||||
|
||||
static void fix_balance(usrtc_node_t **pnode,usrtc_avl_balance_t bal)
|
||||
{
|
||||
usrtc_node_t *node=*pnode;
|
||||
usrtc_node_t *child;
|
||||
usrtc_node_t *grandchild;
|
||||
|
||||
if(node->balance==BALANCED)
|
||||
node->balance=bal;
|
||||
else if(node->balance!=bal)
|
||||
node->balance=BALANCED;
|
||||
else {
|
||||
if(node->balance!=bal)
|
||||
return;
|
||||
|
||||
if(bal==LEFTHEAVY) {
|
||||
child=node->left;
|
||||
if(child->balance==LEFTHEAVY) {
|
||||
node->balance=BALANCED;
|
||||
child->balance=BALANCED;
|
||||
rotate_right(pnode);
|
||||
}
|
||||
else if(child->balance==BALANCED) {
|
||||
node->balance=LEFTHEAVY;
|
||||
child->balance=RIGHTHEAVY;
|
||||
rotate_right(pnode);
|
||||
}
|
||||
else {
|
||||
grandchild=child->right;
|
||||
if(grandchild->balance==LEFTHEAVY) {
|
||||
node->balance=RIGHTHEAVY;
|
||||
child->balance=BALANCED;
|
||||
}
|
||||
else if(grandchild->balance==RIGHTHEAVY) {
|
||||
node->balance=BALANCED;
|
||||
child->balance=LEFTHEAVY;
|
||||
}
|
||||
else {
|
||||
node->balance=BALANCED;
|
||||
child->balance=BALANCED;
|
||||
}
|
||||
grandchild->balance=BALANCED;
|
||||
rotate_left(&node->left);
|
||||
rotate_right(pnode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
child=node->right;
|
||||
if(child->balance==RIGHTHEAVY) {
|
||||
node->balance=BALANCED;
|
||||
child->balance=BALANCED;
|
||||
rotate_left(pnode);
|
||||
}
|
||||
else if(child->balance==BALANCED) {
|
||||
node->balance=RIGHTHEAVY;
|
||||
child->balance=LEFTHEAVY;
|
||||
rotate_left(pnode);
|
||||
}
|
||||
else {
|
||||
grandchild=child->left;
|
||||
if(grandchild->balance==RIGHTHEAVY) {
|
||||
node->balance=LEFTHEAVY;
|
||||
child->balance=BALANCED;
|
||||
}
|
||||
else if(grandchild->balance==LEFTHEAVY) {
|
||||
node->balance=BALANCED;
|
||||
child->balance=RIGHTHEAVY;
|
||||
}
|
||||
else {
|
||||
node->balance=BALANCED;
|
||||
child->balance=BALANCED;
|
||||
}
|
||||
grandchild->balance=BALANCED;
|
||||
rotate_right(&node->right);
|
||||
rotate_left(pnode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int insert(usrtc_t *us,usrtc_node_t *what,usrtc_node_t **where,usrtc_node_t *parent)
|
||||
{
|
||||
usrtc_node_t *here=*where;
|
||||
int result;
|
||||
|
||||
if(here==tree_null_priv(us)) {
|
||||
*where=what;
|
||||
what->parent=parent;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
result=us->compare(what->key,here->key);
|
||||
|
||||
if(result < 0) {
|
||||
if(insert(us,what,&here->left,here)) {
|
||||
fix_balance(where,LEFTHEAVY);
|
||||
return ((*where)->balance!=BALANCED);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(insert(us,what,&here->right,here)) {
|
||||
fix_balance(where,RIGHTHEAVY);
|
||||
return ((*where)->balance!=BALANCED);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static usrtc_node_t *make_tree(usrtc_node_t **pnode,usrtc_count_t count,
|
||||
int *pheight,usrtc_node_t *nil)
|
||||
{
|
||||
usrtc_count_t leftcount;
|
||||
int leftheight, rightheight;
|
||||
usrtc_node_t *root;
|
||||
usrtc_node_t *leftroot;
|
||||
|
||||
if(count==0) {
|
||||
*pheight=0;
|
||||
return nil;
|
||||
}
|
||||
|
||||
leftcount=(count-1)/2;
|
||||
leftroot=make_tree(pnode,leftcount,&leftheight,nil);
|
||||
count-=leftcount;
|
||||
|
||||
root=*pnode;
|
||||
*pnode=root->next;
|
||||
--count;
|
||||
|
||||
root->left=leftroot;
|
||||
leftroot->parent=root;
|
||||
root->right=make_tree(pnode,count,&rightheight,nil);
|
||||
root->right->parent=root;
|
||||
|
||||
if(leftheight>rightheight)
|
||||
return (void *)0;
|
||||
|
||||
*pheight=rightheight+1;
|
||||
root->balance=(leftheight==rightheight) ? BALANCED : RIGHTHEAVY;
|
||||
|
||||
return root;
|
||||
}
|
||||
|
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* (c) Copyright 2006,2007,2008 Jari OS Core Team <http://jarios.org>
|
||||
* (c) Copyright 2008 Dmitry Gromada <gromada82@gmail.com>
|
||||
* (c) Copyright 2010 Alexander Vdolainen <vdo@askele.com>
|
||||
*
|
||||
* (c) Copyright 2012 - 2013, 2014 Askele Oy <http://askele.com>
|
||||
*
|
||||
* Implements bitwise operations with multiword bitmaps
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tdata/bitwise.h>
|
||||
|
||||
/* operation equivalent to division modulo number of power 2 */
|
||||
#define MOD_POW2(var, pow) ((var) & ((pow) - 1))
|
||||
|
||||
int init_bitmap(bitmap_t *bitmap, int nbits)
|
||||
{
|
||||
int ret = 0;
|
||||
int size = nbits >> TYPE_LONG_SHIFT;
|
||||
|
||||
if (nbits < 0)
|
||||
return -1;
|
||||
|
||||
if (size << TYPE_LONG_SHIFT != nbits)
|
||||
size++;
|
||||
|
||||
bitmap->map = (unsigned long*)malloc(size * sizeof(unsigned long));
|
||||
if (bitmap->map == NULL)
|
||||
ret = -1;
|
||||
else
|
||||
bitmap->nwords = size;
|
||||
|
||||
memset(bitmap->map, 0, size * sizeof(unsigned long));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void free_bitmap(bitmap_t *bitmap)
|
||||
{
|
||||
if (bitmap->map) {
|
||||
free(bitmap->map);
|
||||
bitmap->map = NULL;
|
||||
}
|
||||
bitmap->nwords = 0;
|
||||
}
|
||||
|
||||
|
||||
void bit_set_multi(bitmap_t *bitmap, int bitno)
|
||||
{
|
||||
int i = bitno >> TYPE_LONG_SHIFT;
|
||||
|
||||
return bit_set( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) );
|
||||
}
|
||||
|
||||
int bit_test_and_set_multi(bitmap_t *bitmap, int bitno)
|
||||
{
|
||||
int i = bitno >> TYPE_LONG_SHIFT;
|
||||
|
||||
return bit_test_and_set( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) );
|
||||
}
|
||||
|
||||
int bit_test_and_reset_multi(bitmap_t *bitmap, int bitno)
|
||||
{
|
||||
int i = bitno >> TYPE_LONG_SHIFT;
|
||||
|
||||
return bit_test_and_reset( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) );
|
||||
}
|
||||
|
||||
void bit_clear_multi(bitmap_t *bitmap, int bitno)
|
||||
{
|
||||
int i = bitno >> TYPE_LONG_SHIFT;
|
||||
|
||||
return bit_clear( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) );
|
||||
}
|
||||
|
||||
int bit_find_msf_multi(bitmap_t *bitmap, int mbit)
|
||||
{
|
||||
int i, r;
|
||||
unsigned long word;
|
||||
|
||||
if (mbit < 0)
|
||||
return -1;
|
||||
else if (mbit >= bitmap->nwords * BITS_PER_LONG)
|
||||
mbit = bitmap->nwords * BITS_PER_LONG - 1;
|
||||
|
||||
i = mbit >> TYPE_LONG_SHIFT;
|
||||
word = bitmap->map[i] & (~0UL >> ( BITS_PER_LONG - 1 - MOD_POW2(mbit, BITS_PER_LONG) ));
|
||||
r = bit_find_msf(word);
|
||||
|
||||
while ((r == -1) && (--i >= 0)) {
|
||||
if (bitmap->map[i])
|
||||
r = bit_find_msf(bitmap->map[i]);
|
||||
}
|
||||
|
||||
r = (r == -1) ? r : (i * BITS_PER_LONG + r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int bit_find_lsf_multi(bitmap_t *bitmap, int lbit)
|
||||
{
|
||||
int i, r;
|
||||
unsigned long word;
|
||||
|
||||
if (lbit >= bitmap->nwords * BITS_PER_LONG)
|
||||
return -1;
|
||||
else if (lbit < 0)
|
||||
lbit = 0;
|
||||
|
||||
i = lbit >> TYPE_LONG_SHIFT;
|
||||
word = bitmap->map[i] & (~0UL << MOD_POW2(lbit, BITS_PER_LONG));
|
||||
r = bit_find_lsf(word);
|
||||
|
||||
while ((r == -1) && (++i < bitmap->nwords)) {
|
||||
if (bitmap->map[i])
|
||||
r = bit_find_lsf(bitmap->map[i]);
|
||||
}
|
||||
|
||||
r = (r == -1) ? r : (i * BITS_PER_LONG + r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int bit_test_multi(bitmap_t *bitmap, int bitno)
|
||||
{
|
||||
int i = bitno >> TYPE_LONG_SHIFT;
|
||||
|
||||
return bit_test( bitmap->map + i, MOD_POW2(bitno, BITS_PER_LONG) );
|
||||
}
|
||||
|
||||
void bitrange_set_multi(bitmap_t *bitmap, int start_bit, int end_bit)
|
||||
{
|
||||
int i1, i2;
|
||||
unsigned long mask1, mask2, *p = bitmap->map;
|
||||
|
||||
if (start_bit > end_bit)
|
||||
return;
|
||||
|
||||
i1 = start_bit >> TYPE_LONG_SHIFT;
|
||||
mask1 = ~0UL << MOD_POW2(start_bit, BITS_PER_LONG);
|
||||
|
||||
i2 = end_bit >> TYPE_LONG_SHIFT;
|
||||
mask2 = ~0UL >> (BITS_PER_LONG - 1 - MOD_POW2(end_bit, BITS_PER_LONG));
|
||||
|
||||
if (i1 == i2)
|
||||
p[i1] |= mask1 & mask2;
|
||||
else {
|
||||
p[i1++] |= mask1;
|
||||
|
||||
if (i2 - i1 > 0)
|
||||
memset( p + i1, 0xFF, (i2 - i1) * sizeof(unsigned long) );
|
||||
|
||||
p[i2] |= mask2;
|
||||
}
|
||||
}
|
||||
|
||||
void bitrange_clear_multi(bitmap_t *bitmap, int start_bit, int end_bit)
|
||||
{
|
||||
int i1, i2;
|
||||
unsigned long mask1, mask2, *p = bitmap->map;
|
||||
|
||||
if (start_bit > end_bit)
|
||||
return;
|
||||
|
||||
i1 = start_bit >> TYPE_LONG_SHIFT;
|
||||
mask1 = ( 1UL << (start_bit & MOD_POW2(start_bit, BITS_PER_LONG)) ) - 1;
|
||||
|
||||
i2 = end_bit >> TYPE_LONG_SHIFT;
|
||||
mask2 = ~0UL << (MOD_POW2(end_bit, BITS_PER_LONG) + 1);
|
||||
|
||||
if (i1 == i2)
|
||||
p[i1] &= mask1 | mask2;
|
||||
else {
|
||||
p[i1++] &= mask1;
|
||||
|
||||
if (i2 - i1 > 0)
|
||||
memset(p + i1, 0, (i2 - i1) * sizeof(unsigned long));
|
||||
|
||||
p[i2] &= mask2;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* cas.c
|
||||
* Copyright (C) 2015 Alexander Vdolainen <avdolainen@gmail.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#if !defined (HAVE__SYNC_BOOL_COMPARE_AND_SWAP_8)
|
||||
#include <pthread.h>
|
||||
static pthread_mutex_t __sync_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE__SYNC_BOOL_COMPARE_AND_SWAP_8
|
||||
_Bool __sync_bool_compare_and_swap_8 (uint64_t*, uint64_t, uint64_t)
|
||||
__attribute__ ((visibility ("hidden")));
|
||||
|
||||
_Bool __sync_bool_compare_and_swap_8 (uint64_t* ptr, uint64_t old, uint64_t new)
|
||||
{
|
||||
int i;
|
||||
_Bool ret;
|
||||
|
||||
i = pthread_mutex_lock(&__sync_lock);
|
||||
|
||||
if(*ptr != old) ret = 0;
|
||||
else {
|
||||
*ptr = new;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
i = pthread_mutex_unlock(&__sync_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* (c) Copyright 2006,2007,2008 MString Core Team <http://mstring.jarios.org>
|
||||
* (c) Copyright 2009 Dan Kruchinin <dan.kruchinin@gmail.com>
|
||||
* (c) Copyright 2009 Alexander Vdolainen <madtirra@jarios.org> (libc adaptation)
|
||||
* (c) Copyright 2009 Dmitry Gromada <gromada@jarios.org> (locking added)
|
||||
* (c) Copyright 2013 Alexander Vdolainen <vdo@askele.com> (verios changes to make it run on linux)
|
||||
*
|
||||
* (c) Copyright 2012 - 2013, 2014 Askele Oy <http://askele.com>
|
||||
*
|
||||
* Index allocator
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <tdata/bitwise.h>
|
||||
#include <tdata/idx_allocator.h>
|
||||
|
||||
/*
|
||||
* Main idea of index allocator is quite simple:
|
||||
* There is a group of tasks that requires dynamic allocation
|
||||
* of unique non-negative integer identifiers. Where a set of such
|
||||
* integers is relatively big (thousands of numbers), index allocator
|
||||
* becomes a nifty solution.
|
||||
* The core of allocator is two bitmaps. One of them called "indices bitmap"
|
||||
* or "second level bitmap". Each bit of that bitmap corresponds to particular unique
|
||||
* index. Since second-level bitmap is a large portion of continuous memory, searching
|
||||
* of set/zero bit in it becomes relatively slow. For speeding-up search process we invented
|
||||
* a first-level bitmap. Second-level array is splitted on groups each of them contains BYTES_PER_ITEM bytes.
|
||||
* First-level(or main) bitmap establishes corresponding between particular group and its
|
||||
* state(group may have free indices or not).
|
||||
* So index allocation assumes at first searching of group index in a the first-level bitmap and only
|
||||
* then searching an index in the second level bitmap starting from a group index.
|
||||
*/
|
||||
|
||||
#define MIN_IDA_SIZE (WORDS_PER_ITEM * sizeof(ulong_t))
|
||||
#define MAX_UNLOCKED_ATTEMPTS 3
|
||||
|
||||
/* there macros defined only on new glibc (from 12-jul-2013), let's use our own */
|
||||
#ifndef is_powerof2
|
||||
#define is_powerof2(num) (((num) & ~((num) - 1)) == (num))
|
||||
#endif
|
||||
#ifndef round_up_pow2
|
||||
#define round_up_pow2(x) (!is_powerof2(x) ? (1 << (bit_find_msf(x) + 1)) : (x) )
|
||||
#endif
|
||||
|
||||
static inline size_t __get_main_bmap_size(idx_allocator_t *ida)
|
||||
{
|
||||
if (ida->ids_bmap != NULL)
|
||||
return (round_up_pow2((ida->size * sizeof(ulong_t)) / BYTES_PER_ITEM));
|
||||
|
||||
return ida->size;
|
||||
}
|
||||
|
||||
ulong_t idx_allocate(idx_allocator_t *ida)
|
||||
{
|
||||
ulong_t id = IDX_INVAL;
|
||||
long fnfi = 0;
|
||||
size_t i, main_offs = 0, main_sz;
|
||||
int natm = 0; /* attempt number */
|
||||
|
||||
main_sz = __get_main_bmap_size(ida) / sizeof(ulong_t);
|
||||
i = 0;
|
||||
|
||||
if (ida->ids_bmap != NULL) {
|
||||
for (;;) {
|
||||
while (i < main_sz) {
|
||||
fnfi = zero_bit_find_lsf(ida->main_bmap[i]);
|
||||
if (fnfi >= 0) {
|
||||
fnfi = (fnfi * WORDS_PER_ITEM) + i * WORDS_PER_ITEM * BITS_PER_LONG;
|
||||
main_offs = i;
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
if ((fnfi >= 0) && (fnfi < ida->size)) {
|
||||
int res_id, j, total_sz;
|
||||
|
||||
total_sz = fnfi + WORDS_PER_ITEM;
|
||||
j = fnfi;
|
||||
while (j < total_sz) {
|
||||
res_id = zero_bit_find_lsf(ida->ids_bmap[j]);
|
||||
if (res_id < 0) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ida_lockable(ida) /*&& atomic_test_and_set_bit(ida->ids_bmap + j, res_id)*/) {
|
||||
natm++;
|
||||
if (natm == MAX_UNLOCKED_ATTEMPTS)
|
||||
ida_lock(ida);
|
||||
} else {
|
||||
bit_set(ida->ids_bmap + j, res_id);
|
||||
}
|
||||
|
||||
id = res_id + j * BITS_PER_LONG;
|
||||
if (id >= ida->max_id) {
|
||||
bit_clear(ida->ids_bmap + j, res_id);
|
||||
id = IDX_INVAL;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
bit_set(ida->main_bmap + main_offs,
|
||||
(fnfi - (main_offs * WORDS_PER_ITEM * BITS_PER_LONG)) / WORDS_PER_ITEM);
|
||||
if ((ida->main_bmap[i] & ~0UL) == ~0UL)
|
||||
i++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (i < main_sz) {
|
||||
fnfi = zero_bit_find_lsf(ida->main_bmap[i]);
|
||||
if (fnfi >= 0) {
|
||||
bit_set(ida->main_bmap + i, fnfi);
|
||||
id = fnfi + i * BITS_PER_LONG;
|
||||
if (id >= ida->max_id) {
|
||||
bit_clear(ida->main_bmap + i, fnfi);
|
||||
id = IDX_INVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (natm == MAX_UNLOCKED_ATTEMPTS)
|
||||
ida_unlock(ida);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void idx_reserve(idx_allocator_t *ida, ulong_t idx)
|
||||
{
|
||||
int start_id, bitno;
|
||||
ulong_t *ptr;
|
||||
|
||||
start_id = idx / BITS_PER_LONG;
|
||||
bitno = idx - start_id * BITS_PER_LONG;
|
||||
if (ida->ids_bmap != NULL)
|
||||
ptr = ida->ids_bmap + start_id;
|
||||
else
|
||||
ptr = ida->main_bmap + start_id;
|
||||
|
||||
if (bit_test_and_set(ptr, bitno)) {
|
||||
printf("[libc warning] Detected an attempt to reserve already busy index %ld "
|
||||
"[function: %s]!\n", idx, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
void idx_free(idx_allocator_t *ida, ulong_t idx)
|
||||
{
|
||||
int start_id, bitno, main_id, main_bitno;
|
||||
ulong_t *ptr;
|
||||
|
||||
start_id = idx / BITS_PER_LONG;
|
||||
bitno = idx - start_id * BITS_PER_LONG;
|
||||
if (ida->ids_bmap != NULL) {
|
||||
ptr = ida->ids_bmap + start_id;
|
||||
main_id = start_id / WORDS_PER_ITEM;
|
||||
main_bitno = start_id - main_id * WORDS_PER_ITEM;
|
||||
bit_clear(ida->main_bmap + main_id, main_bitno);
|
||||
}
|
||||
else
|
||||
ptr = ida->main_bmap + start_id;
|
||||
|
||||
if (!bit_test_and_clear(ptr, bitno)) {
|
||||
printf("[libc warning] Detected an attempt to free already fried index %ld "
|
||||
"[function: %s]!\n", idx, __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
int idx_allocator_init(idx_allocator_t *ida, ulong_t idx_max, int lockable)
|
||||
{
|
||||
size_t bmap_sz;
|
||||
int err = -ENOMEM;
|
||||
|
||||
bmap_sz = (round_up_pow2(idx_max) >> 3);
|
||||
memset(ida, 0, sizeof(*ida));
|
||||
ida->size = bmap_sz / sizeof(ulong_t);
|
||||
if (ida->size >= MIN_IDA_SIZE) {
|
||||
ida->ids_bmap = malloc(bmap_sz);
|
||||
if (!ida->ids_bmap) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(ida->ids_bmap, 0, bmap_sz);
|
||||
}
|
||||
else
|
||||
ida->size = (ida->size > 0) ? (ida->size * sizeof(ulong_t)) : sizeof(ulong_t);
|
||||
|
||||
ida->main_bmap = malloc(__get_main_bmap_size(ida));
|
||||
if (!ida->main_bmap) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (lockable && ida_lock_init(&ida->lock))
|
||||
goto error;
|
||||
#endif
|
||||
ida->lck = 0; /* cutty, we don't use the lockable due to the very arch specifics */
|
||||
|
||||
memset(ida->main_bmap, 0, __get_main_bmap_size(ida));
|
||||
ida->max_id = idx_max;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (ida->ids_bmap) {
|
||||
free(ida->ids_bmap);
|
||||
}
|
||||
if (ida->main_bmap) {
|
||||
free(ida->main_bmap);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void idx_allocator_destroy(idx_allocator_t *ida)
|
||||
{
|
||||
if (ida->ids_bmap != NULL)
|
||||
free(ida->ids_bmap);
|
||||
|
||||
free(ida->main_bmap);
|
||||
|
||||
if (ida_lockable(ida))
|
||||
ida_lock_destroy(&ida->lock);
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
datarootdir=@datarootdir@
|
||||
datadir=@datadir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libtdata
|
||||
Description: Data structures C implementation.
|
||||
Version: @LIBTDATA_VERSION@
|
||||
Requires:
|
||||
Libs: -L${libdir} -ltdata
|
||||
Cflags: -I${includedir}
|
@ -0,0 +1,174 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* lslist.c
|
||||
* Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com>
|
||||
* Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <tdata/macro.h>
|
||||
#include <tdata/usrtc.h>
|
||||
|
||||
#define list_first_priv(L) ((L)->sentinel.next)
|
||||
#define list_last_priv(L) ((L)->sentinel.prev)
|
||||
#define list_null_priv(L) (&(L)->sentinel)
|
||||
|
||||
/*function prototypes*/
|
||||
static void list_init(usrtc_t *);
|
||||
static void list_insert(usrtc_t *,usrtc_node_t *,const void *);
|
||||
static void list_delete(usrtc_t *,usrtc_node_t *);
|
||||
static usrtc_node_t *list_lookup(usrtc_t *,const void *);
|
||||
static usrtc_node_t *list_lower_bound(usrtc_t *,const void *);
|
||||
static usrtc_node_t *list_upper_bound(usrtc_t *,const void *);
|
||||
static usrtc_node_t *list_first(usrtc_t *);
|
||||
static usrtc_node_t *list_last(usrtc_t *);
|
||||
static usrtc_node_t *list_next(usrtc_t *, usrtc_node_t *);
|
||||
static usrtc_node_t *list_prev(usrtc_t *, usrtc_node_t *);
|
||||
static void list_convert_to_list(usrtc_t *);
|
||||
static void list_convert_from_list(usrtc_t *);
|
||||
|
||||
usrtc_functions_t usrtc_list_fu = {
|
||||
list_init,
|
||||
list_insert,
|
||||
list_delete,
|
||||
list_lookup,
|
||||
list_lower_bound,
|
||||
list_upper_bound,
|
||||
list_first,
|
||||
list_last,
|
||||
list_next,
|
||||
list_prev,
|
||||
list_convert_to_list,
|
||||
list_convert_from_list,
|
||||
usrtc_lst
|
||||
};
|
||||
|
||||
static void insert_before(usrtc_t *,usrtc_node_t *,usrtc_node_t *);
|
||||
|
||||
/*implementation*/
|
||||
static void list_init(usrtc_t *us)
|
||||
{
|
||||
us->sentinel.next=&us->sentinel;
|
||||
us->sentinel.prev=&us->sentinel;
|
||||
}
|
||||
|
||||
static void list_insert(usrtc_t *us,usrtc_node_t *newnode,const void *key)
|
||||
{
|
||||
usrtc_node_t *succ;
|
||||
|
||||
newnode->key=key;
|
||||
|
||||
for(succ=list_first_priv(us);succ!=list_null_priv(us);succ=succ->next) {
|
||||
if(us->compare(succ->key,key)>0)
|
||||
break;
|
||||
}
|
||||
|
||||
insert_before(us,newnode,succ);
|
||||
}
|
||||
|
||||
static void list_delete(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
usrtc_node_t *pred=node->prev;
|
||||
usrtc_node_t *succ=node->next;
|
||||
|
||||
pred->next=succ;
|
||||
succ->prev=pred;
|
||||
/*check node count*/
|
||||
us->nodecount--;
|
||||
}
|
||||
|
||||
static usrtc_node_t *list_lookup(usrtc_t *us,const void *key)
|
||||
{
|
||||
usrtc_node_t *node;
|
||||
|
||||
for(node=list_first_priv(us);node!=list_null_priv(us);node=node->next) {
|
||||
if(us->compare(node->key,key)==0)
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static usrtc_node_t *list_lower_bound(usrtc_t *us,const void *key)
|
||||
{
|
||||
usrtc_node_t *node;
|
||||
|
||||
for(node=list_first_priv(us);node!=list_null_priv(us);node=node->next) {
|
||||
if(us->compare(node->key,key) >= 0)
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static usrtc_node_t *list_upper_bound(usrtc_t *us,const void *key)
|
||||
{
|
||||
usrtc_node_t *node;
|
||||
|
||||
for(node=list_first_priv(us);node!=list_null_priv(us);node=node->prev) {
|
||||
if(us->compare(node->key,key) >= 0)
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static usrtc_node_t *list_first(usrtc_t *us)
|
||||
{
|
||||
return (list_first_priv(us) == list_null_priv(us)) ? 0 : list_first_priv(us);
|
||||
}
|
||||
|
||||
static usrtc_node_t *list_last(usrtc_t *us)
|
||||
{
|
||||
return (list_last_priv(us) == list_null_priv(us)) ? 0 : list_last_priv(us);
|
||||
}
|
||||
|
||||
static usrtc_node_t *list_next(usrtc_t *us, usrtc_node_t *node)
|
||||
{
|
||||
return (node->next == list_null_priv(us)) ? 0 : node->next;
|
||||
}
|
||||
|
||||
static usrtc_node_t *list_prev(usrtc_t *us, usrtc_node_t *node)
|
||||
{
|
||||
return (node->prev == list_null_priv(us)) ? 0 : node->prev;
|
||||
}
|
||||
|
||||
static void list_convert_to_list(usrtc_t *us)
|
||||
{
|
||||
/*dummy*/
|
||||
}
|
||||
|
||||
static void list_convert_from_list(usrtc_t *us)
|
||||
{
|
||||
/*dummy*/
|
||||
}
|
||||
|
||||
/*internal function*/
|
||||
static void insert_before(usrtc_t *us,usrtc_node_t *newnode,usrtc_node_t *succ)
|
||||
{
|
||||
usrtc_node_t *pred=succ->prev;
|
||||
|
||||
newnode->prev=pred;
|
||||
newnode->next=succ;
|
||||
|
||||
pred->next=newnode;
|
||||
succ->prev=newnode;
|
||||
|
||||
/*TODO: check for maxcount*/
|
||||
us->nodecount++;
|
||||
}
|
||||
|
@ -0,0 +1,310 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* redblack.c
|
||||
* Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com>
|
||||
* Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <tdata/usrtc.h>
|
||||
#include <tdata/macro.h>
|
||||
#include <tdata/tree.h>
|
||||
|
||||
#define color usrtc_impldata.usrtc_rb_color
|
||||
|
||||
/*function prototypes*/
|
||||
static void redblack_init(usrtc_t *);
|
||||
static void redblack_insert(usrtc_t *, usrtc_node_t *, const void *);
|
||||
static void redblack_delete(usrtc_t *, usrtc_node_t *);
|
||||
static void redblack_convert_from_list(usrtc_t *);
|
||||
|
||||
usrtc_functions_t usrtc_redblack_fu = {
|
||||
redblack_init,
|
||||
redblack_insert,
|
||||
redblack_delete,
|
||||
usrtc_tree_lookup,
|
||||
usrtc_tree_lower_bound,
|
||||
usrtc_tree_upper_bound,
|
||||
usrtc_tree_first,
|
||||
usrtc_tree_last,
|
||||
usrtc_tree_next,
|
||||
usrtc_tree_prev,
|
||||
usrtc_tree_convert_to_list,
|
||||
redblack_convert_from_list,
|
||||
usrtc_bst
|
||||
};
|
||||
|
||||
/*implementation*/
|
||||
static void redblack_init(usrtc_t *us)
|
||||
{
|
||||
usrtc_tree_init(us);
|
||||
us->sentinel.color = usrtc_black;
|
||||
}
|
||||
|
||||
static void redblack_insert(usrtc_t *us, usrtc_node_t *node, const void *key)
|
||||
{
|
||||
usrtc_node_t *parent;
|
||||
|
||||
/* simple bt insert */
|
||||
usrtc_tree_insert(us,node,key);
|
||||
|
||||
/* implementation specific insert */
|
||||
node->color = usrtc_red;
|
||||
parent=node->parent;
|
||||
|
||||
while(parent->color==usrtc_red) {
|
||||
usrtc_node_t *grandpa=parent->parent;
|
||||
|
||||
if(parent==grandpa->left) {
|
||||
usrtc_node_t *uncle=grandpa->right;
|
||||
if(uncle->color==usrtc_red) { /*red parent->red uncle*/
|
||||
parent->color=usrtc_black;
|
||||
uncle->color=usrtc_black;
|
||||
grandpa->color=usrtc_red;
|
||||
node=grandpa;
|
||||
parent=grandpa->parent;
|
||||
} else { /*red parent->black uncle */
|
||||
if(node==parent->right) {
|
||||
usrtc_tree_rotate_left(node,parent);
|
||||
parent=node;
|
||||
if(grandpa!=parent->parent)
|
||||
return;
|
||||
}
|
||||
parent->color=usrtc_black;
|
||||
grandpa->color=usrtc_red;
|
||||
usrtc_tree_rotate_right(parent,grandpa);
|
||||
break;
|
||||
}
|
||||
} else { /*ooh,parent == parent->parent->right*/
|
||||
usrtc_node_t *uncle=grandpa->left;
|
||||
if(uncle->color==usrtc_red) {
|
||||
parent->color=usrtc_black;
|
||||
uncle->color=usrtc_black;
|
||||
grandpa->color=usrtc_red;
|
||||
node=grandpa;
|
||||
parent=grandpa->parent;
|
||||
} else {
|
||||
if(node==parent->left) {
|
||||
usrtc_tree_rotate_right(node,parent);
|
||||
parent=node;
|
||||
|
||||
if(grandpa!=parent->parent)
|
||||
return;
|
||||
}
|
||||
parent->color=usrtc_black;
|
||||
grandpa->color=usrtc_red;
|
||||
usrtc_tree_rotate_left(parent,grandpa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tree_root_priv(us)->color=usrtc_black;
|
||||
}
|
||||
|
||||
static void redblack_delete(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
usrtc_node_t *swap;
|
||||
usrtc_node_t *child;
|
||||
usrtc_rb_color_t savecolor;
|
||||
|
||||
/*basic bt delete*/
|
||||
usrtc_tree_delete(us,node,&swap,&child);
|
||||
|
||||
/*implementation specific deletion*/
|
||||
savecolor=node->color;
|
||||
node->color=swap->color;
|
||||
swap->color=savecolor;
|
||||
|
||||
if(node->color==usrtc_black) { /*black*/
|
||||
usrtc_node_t *parent;
|
||||
usrtc_node_t *sister;
|
||||
|
||||
tree_root_priv(us)->color=usrtc_red;
|
||||
|
||||
while(child->color==usrtc_black) {
|
||||
parent=child->parent;
|
||||
if(child==parent->left) {
|
||||
sister=parent->right;
|
||||
if(sister==tree_null_priv(us))
|
||||
return;
|
||||
|
||||
if(sister->color==usrtc_red) {
|
||||
sister->color=usrtc_black;
|
||||
parent->color=usrtc_red;
|
||||
usrtc_tree_rotate_left(sister,parent);
|
||||
sister=parent->right;
|
||||
|
||||
if(sister==tree_null_priv(us))
|
||||
return;
|
||||
}
|
||||
if(sister->left->color==usrtc_black && sister->right->color==usrtc_black) {
|
||||
sister->color=usrtc_red;
|
||||
child=parent;
|
||||
} else {
|
||||
if(sister->right->color==usrtc_black) {
|
||||
if(sister->left->color!=usrtc_red)
|
||||
return;
|
||||
|
||||
sister->left->color=usrtc_black;
|
||||
sister->color=usrtc_red;
|
||||
usrtc_tree_rotate_right(sister->left,sister);
|
||||
sister=parent->right;
|
||||
|
||||
if(sister==tree_null_priv(us))
|
||||
return;
|
||||
}
|
||||
sister->color=parent->color;
|
||||
sister->right->color=usrtc_black;
|
||||
parent->color=usrtc_black;
|
||||
usrtc_tree_rotate_left(sister,parent);
|
||||
break;
|
||||
}
|
||||
} else { /*!child == child->parent->right*/
|
||||
if(child!=parent->right)
|
||||
return;
|
||||
|
||||
sister=parent->left;
|
||||
|
||||
if(sister==tree_null_priv(us))
|
||||
return;
|
||||
|
||||
if(sister->color==usrtc_red) {
|
||||
sister->color=usrtc_black;
|
||||
parent->color=usrtc_red;
|
||||
usrtc_tree_rotate_right(sister,parent);
|
||||
sister = parent->left;
|
||||
|
||||
if(sister==tree_null_priv(us))
|
||||
return;
|
||||
}
|
||||
if(sister->right->color==usrtc_black && sister->left->color==usrtc_black) {
|
||||
sister->color=usrtc_red;
|
||||
child=parent;
|
||||
} else {
|
||||
if(sister->left->color == usrtc_black) {
|
||||
if(sister->right->color!=usrtc_red)
|
||||
return;
|
||||
|
||||
sister->right->color=usrtc_black;
|
||||
sister->color=usrtc_red;
|
||||
usrtc_tree_rotate_left(sister->right, sister);
|
||||
sister=parent->left;
|
||||
|
||||
if(sister==tree_null_priv(us))
|
||||
return;
|
||||
}
|
||||
sister->color=parent->color;
|
||||
sister->left->color=usrtc_black;
|
||||
parent->color=usrtc_black;
|
||||
usrtc_tree_rotate_right(sister,parent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
child->color=usrtc_black;
|
||||
tree_root_priv(us)->color=usrtc_black;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void redblack_convert_from_list(usrtc_t *us)
|
||||
{
|
||||
usrtc_node_t *tree[TREE_DEPTH_MAX] = { NULL };
|
||||
usrtc_node_t *curr;
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *next;
|
||||
usrtc_node_t *complete=NULL;
|
||||
usrtc_count_t fullcount=(usrtc_count_t)USRTC_COUNT_T_MAX;
|
||||
usrtc_count_t nodecount=us->nodecount;
|
||||
usrtc_count_t botrowcount;
|
||||
unsigned int baselevel=0;
|
||||
unsigned int level=0;
|
||||
unsigned int i;
|
||||
|
||||
if(usrtc_red!=0 && usrtc_black!=1)
|
||||
return;
|
||||
|
||||
while(fullcount>=nodecount && fullcount) /*calc*/
|
||||
fullcount >>= 1;
|
||||
|
||||
botrowcount=nodecount-fullcount;
|
||||
|
||||
for(curr=nil->next;curr!=nil;curr=next) {
|
||||
next=curr->next;
|
||||
|
||||
if(complete==NULL && botrowcount--==0) {
|
||||
baselevel=level=1;
|
||||
complete=tree[0];
|
||||
|
||||
if(complete!=NULL) {
|
||||
tree[0]=NULL;
|
||||
complete->right=nil;
|
||||
while(tree[level]!=0) {
|
||||
tree[level]->right=complete;
|
||||
complete->parent=tree[level];
|
||||
complete=tree[level];
|
||||
tree[level++]=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(complete==NULL) {
|
||||
curr->left=nil;
|
||||
curr->right=nil;
|
||||
curr->color=level%2;
|
||||
complete=curr;
|
||||
|
||||
if(level!=baselevel)
|
||||
return;
|
||||
|
||||
while(tree[level]!=NULL) {
|
||||
tree[level]->right=complete;
|
||||
complete->parent=tree[level];
|
||||
complete=tree[level];
|
||||
tree[level++]=NULL;
|
||||
}
|
||||
} else {
|
||||
curr->left=complete;
|
||||
curr->color=(level+1)%2;
|
||||
complete->parent=curr;
|
||||
tree[level]=curr;
|
||||
complete=NULL;
|
||||
level=baselevel;
|
||||
}
|
||||
}
|
||||
|
||||
if(complete==NULL)
|
||||
complete=nil;
|
||||
|
||||
for (i=0;i<TREE_DEPTH_MAX;i++) {
|
||||
if (tree[i]!=NULL) {
|
||||
tree[i]->right=complete;
|
||||
complete->parent=tree[i];
|
||||
complete=tree[i];
|
||||
}
|
||||
}
|
||||
|
||||
nil->right=nil;
|
||||
nil->left=complete;
|
||||
nil->color=usrtc_black;
|
||||
complete->parent=nil;
|
||||
complete->color=usrtc_black;
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,143 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* splay.c
|
||||
* Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com>
|
||||
* Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#include <tdata/usrtc.h>
|
||||
#include <tdata/macro.h>
|
||||
#include <tdata/tree.h>
|
||||
|
||||
/*prototypes*/
|
||||
static void splay_insert(usrtc_t *,usrtc_node_t *,const void *);
|
||||
static void splay_delete(usrtc_t *,usrtc_node_t *);
|
||||
static usrtc_node_t *splay_lookup(usrtc_t *,const void *);
|
||||
|
||||
usrtc_functions_t usrtc_splay_fu = {
|
||||
usrtc_tree_init,
|
||||
splay_insert,
|
||||
splay_delete,
|
||||
splay_lookup,
|
||||
usrtc_tree_lower_bound,
|
||||
usrtc_tree_upper_bound,
|
||||
usrtc_tree_first,
|
||||
usrtc_tree_last,
|
||||
usrtc_tree_next,
|
||||
usrtc_tree_prev,
|
||||
usrtc_tree_convert_to_list,
|
||||
usrtc_tree_convert_from_list,
|
||||
usrtc_bst
|
||||
};
|
||||
|
||||
static void right_zig_zig(usrtc_node_t *,usrtc_node_t *,usrtc_node_t *);
|
||||
static void left_zig_zig(usrtc_node_t *,usrtc_node_t *,usrtc_node_t *);
|
||||
static void right_zig_zag(usrtc_node_t *,usrtc_node_t *,usrtc_node_t *);
|
||||
static void left_zig_zag(usrtc_node_t *,usrtc_node_t *,usrtc_node_t *);
|
||||
static void splay_node(usrtc_t *,usrtc_node_t *);
|
||||
|
||||
/*implementation*/
|
||||
|
||||
static void splay_insert(usrtc_t *us,usrtc_node_t *node,const void *key)
|
||||
{
|
||||
usrtc_tree_insert(us,node,key);
|
||||
|
||||
while(node!=tree_root_priv(us))
|
||||
splay_node(us,node);
|
||||
}
|
||||
|
||||
static void splay_delete(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
usrtc_node_t *dummy;
|
||||
usrtc_tree_delete(us,node,&dummy,&dummy);
|
||||
}
|
||||
|
||||
static usrtc_node_t *splay_lookup(usrtc_t *us,const void *key)
|
||||
{
|
||||
usrtc_node_t *node=usrtc_tree_lookup(us,key);
|
||||
|
||||
if(node)
|
||||
while(node!=tree_root_priv(us))
|
||||
splay_node(us,node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void right_zig_zig(usrtc_node_t *child,usrtc_node_t *parent,usrtc_node_t *grandpa)
|
||||
{
|
||||
usrtc_tree_rotate_right(parent,grandpa);
|
||||
usrtc_tree_rotate_right(child,parent);
|
||||
}
|
||||
|
||||
static void left_zig_zig(usrtc_node_t *child,usrtc_node_t *parent,usrtc_node_t *grandpa)
|
||||
{
|
||||
usrtc_tree_rotate_left(parent,grandpa);
|
||||
usrtc_tree_rotate_left(child,parent);
|
||||
}
|
||||
|
||||
static void right_zig_zag(usrtc_node_t *child,usrtc_node_t *parent,usrtc_node_t *grandpa)
|
||||
{
|
||||
usrtc_tree_rotate_right(child,parent);
|
||||
usrtc_tree_rotate_left(child,grandpa);
|
||||
}
|
||||
|
||||
static void left_zig_zag(usrtc_node_t *child,usrtc_node_t *parent,usrtc_node_t *grandpa)
|
||||
{
|
||||
usrtc_tree_rotate_left(child,parent);
|
||||
usrtc_tree_rotate_right(child,grandpa);
|
||||
}
|
||||
|
||||
static void splay_node(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
usrtc_node_t *root=tree_root_priv(us);
|
||||
usrtc_node_t *parent=node->parent;
|
||||
|
||||
if(parent->left==node) {
|
||||
if(parent==root) {
|
||||
usrtc_tree_rotate_right(node,parent);
|
||||
} else {
|
||||
usrtc_node_t *grandpa=parent->parent;
|
||||
|
||||
if(grandpa->left==parent)
|
||||
right_zig_zig(node,parent,grandpa);
|
||||
else {
|
||||
if(grandpa->right!=parent)
|
||||
return;
|
||||
|
||||
right_zig_zag(node,parent,grandpa);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(parent->right!=node)
|
||||
return;
|
||||
|
||||
if(parent==root) {
|
||||
usrtc_tree_rotate_left(node,parent);
|
||||
} else {
|
||||
usrtc_node_t *grandpa=parent->parent;
|
||||
|
||||
if(grandpa->right==parent) {
|
||||
left_zig_zig(node,parent,grandpa);
|
||||
} else {
|
||||
if(grandpa->left!=parent)
|
||||
return;
|
||||
|
||||
left_zig_zag(node,parent,grandpa);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,492 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* tree.c
|
||||
* Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com>
|
||||
* Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <tdata/usrtc.h>
|
||||
#include <tdata/macro.h>
|
||||
#include <tdata/tree.h>
|
||||
|
||||
/*local functions prototypes*/
|
||||
static void tree_delete(usrtc_t *, usrtc_node_t *);
|
||||
|
||||
usrtc_functions_t usrtc_tree_fu = {
|
||||
usrtc_tree_init,
|
||||
usrtc_tree_insert,
|
||||
tree_delete,
|
||||
usrtc_tree_lookup,
|
||||
usrtc_tree_lower_bound,
|
||||
usrtc_tree_upper_bound,
|
||||
usrtc_tree_first,
|
||||
usrtc_tree_last,
|
||||
usrtc_tree_next,
|
||||
usrtc_tree_prev,
|
||||
usrtc_tree_convert_to_list,
|
||||
usrtc_tree_convert_from_list,
|
||||
usrtc_bst
|
||||
};
|
||||
|
||||
/*implementation*/
|
||||
|
||||
void usrtc_tree_init(usrtc_t *us)
|
||||
{
|
||||
us->sentinel.left=&us->sentinel;
|
||||
us->sentinel.right=&us->sentinel;
|
||||
us->sentinel.parent=&us->sentinel;
|
||||
|
||||
us->sentinel.impl_specific.usrtc_dummy=0;
|
||||
us->sentinel.data=0;
|
||||
us->sentinel.key=0;
|
||||
}
|
||||
|
||||
void usrtc_tree_insert(usrtc_t *us,usrtc_node_t *node,const void *key)
|
||||
{
|
||||
usrtc_node_t *where=tree_root_priv(us);
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *parent=nil;
|
||||
long res=-1;
|
||||
|
||||
node->key=key;
|
||||
|
||||
while(where!=nil) {
|
||||
parent=where;
|
||||
res=us->compare(key,where->key);
|
||||
|
||||
if(us->dupes_allowed && !res) /*trying to put duplicate to the disabled dupe tree*/
|
||||
return;
|
||||
|
||||
if(res<0)
|
||||
where=where->left;
|
||||
else
|
||||
where=where->right;
|
||||
}
|
||||
|
||||
/*assert(where==nil);*/
|
||||
|
||||
if(res<0)
|
||||
parent->left=node;
|
||||
else
|
||||
parent->right=node;
|
||||
|
||||
node->parent=parent;
|
||||
node->left=nil;
|
||||
node->right=nil;
|
||||
|
||||
us->nodecount++;
|
||||
}
|
||||
|
||||
void usrtc_tree_delete(usrtc_t *us,usrtc_node_t *node,usrtc_node_t **pswap,usrtc_node_t **pchild)
|
||||
{
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *child;
|
||||
usrtc_node_t *delparent=node->parent;
|
||||
usrtc_node_t *next=node;
|
||||
usrtc_node_t *nextparent;
|
||||
|
||||
if(node->left!=nil && node->right!=nil) {
|
||||
next=usrtc_tree_next(us,node);
|
||||
nextparent=next->parent;
|
||||
|
||||
/*if(next!=nil && next->parent!=nil && next->parent==nil)
|
||||
return;*/
|
||||
|
||||
child=next->right;
|
||||
child->parent=nextparent;
|
||||
|
||||
if(nextparent->left==next)
|
||||
nextparent->left=child;
|
||||
else {
|
||||
//if(nextparent->right!=next)
|
||||
//return;
|
||||
nextparent->right=child;
|
||||
}
|
||||
|
||||
next->parent=delparent;
|
||||
next->left=node->left;
|
||||
next->right=node->right;
|
||||
next->left->parent=next;
|
||||
next->right->parent=next;
|
||||
|
||||
if(delparent->left==node) {
|
||||
delparent->left=next;
|
||||
} else {
|
||||
//if(delparent->right!=node)
|
||||
// return;
|
||||
delparent->right = next;
|
||||
}
|
||||
|
||||
} else {
|
||||
/*if(node==nil)
|
||||
return;
|
||||
if(node->left!=nil && node->right!=nil)
|
||||
return;*/
|
||||
|
||||
child=(node->left!=nil) ? node->left : node->right;
|
||||
|
||||
child->parent=delparent=node->parent;
|
||||
|
||||
if(node==delparent->left) {
|
||||
delparent->left=child;
|
||||
} else {
|
||||
/*if(node!=delparent->right)
|
||||
return;*/
|
||||
delparent->right=child;
|
||||
}
|
||||
}
|
||||
|
||||
node->parent=0;
|
||||
node->right=0;
|
||||
node->left=0;
|
||||
|
||||
us->nodecount--;
|
||||
|
||||
*pswap = next;
|
||||
*pchild = child;
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_tree_lookup(usrtc_t *us,const void *key)
|
||||
{
|
||||
usrtc_node_t *root=tree_root_priv(us);
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *saved;
|
||||
long res;
|
||||
|
||||
while (root!=nil) {
|
||||
res=us->compare(key,root->key);
|
||||
if(res<0)
|
||||
root=root->left;
|
||||
else if(res>0)
|
||||
root=root->right;
|
||||
else {
|
||||
if(!us->dupes_allowed)
|
||||
return root; /*no duplicates*/
|
||||
else { /*duplicate, then find left occurence*/
|
||||
do {
|
||||
saved=root;
|
||||
root=root->left;
|
||||
while(root!=nil && us->compare(key,root->key))
|
||||
root=root->right;
|
||||
} while(root!=nil);
|
||||
return saved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_tree_lower_bound(usrtc_t *us,const void *key)
|
||||
{
|
||||
usrtc_node_t *root=tree_root_priv(us);
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *tentative=NULL;
|
||||
long res;
|
||||
|
||||
while(root!=nil) {
|
||||
res=us->compare(key,root->key);
|
||||
|
||||
if(res>0) {
|
||||
root=root->right;
|
||||
} else if(res<0) {
|
||||
tentative=root;
|
||||
root=root->left;
|
||||
} else {
|
||||
if (!us->dupes_allowed)
|
||||
return root;
|
||||
else {
|
||||
tentative=root;
|
||||
root=root->left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tentative;
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_tree_upper_bound(usrtc_t *us,const void *key)
|
||||
{
|
||||
usrtc_node_t *root=tree_root_priv(us);
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *tentative=NULL;
|
||||
long res;
|
||||
|
||||
while(root!=nil) {
|
||||
res=us->compare(key,root->key);
|
||||
|
||||
if(res>0) {
|
||||
root=root->left;
|
||||
} else if(res<0) {
|
||||
tentative=root;
|
||||
root=root->right;
|
||||
} else {
|
||||
if (!us->dupes_allowed)
|
||||
return root;
|
||||
else {
|
||||
tentative=root;
|
||||
root=root->right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tentative;
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_tree_first(usrtc_t *us)
|
||||
{
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *root=tree_root_priv(us);
|
||||
usrtc_node_t *left;
|
||||
|
||||
if(root!=nil)
|
||||
while((left=root->left)!=nil)
|
||||
root=left;
|
||||
|
||||
return (root==nil) ? NULL : root;
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_tree_last(usrtc_t *us)
|
||||
{
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *root=tree_root_priv(us);
|
||||
usrtc_node_t *right;
|
||||
|
||||
if(root!=nil)
|
||||
while((right=root->right)!=nil)
|
||||
root=right;
|
||||
|
||||
return (root==nil) ? NULL : root;
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_tree_next(usrtc_t *us, usrtc_node_t *curr)
|
||||
{
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *parent;
|
||||
usrtc_node_t *left;
|
||||
|
||||
if(curr->right!=nil) {
|
||||
curr=curr->right;
|
||||
while((left=curr->left)!=nil)
|
||||
curr=left;
|
||||
return curr;
|
||||
}
|
||||
|
||||
parent=curr->parent;
|
||||
|
||||
while(parent!=nil && curr==parent->right) {
|
||||
curr=parent;
|
||||
parent=curr->parent;
|
||||
}
|
||||
|
||||
return (parent==nil) ? NULL : parent;
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_tree_prev(usrtc_t *us, usrtc_node_t *curr)
|
||||
{
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *parent;
|
||||
usrtc_node_t *right;
|
||||
|
||||
if(curr->left!=nil) {
|
||||
curr=curr->left;
|
||||
while((right=curr->right)!=nil)
|
||||
curr=right;
|
||||
return curr;
|
||||
}
|
||||
|
||||
parent=curr->parent;
|
||||
|
||||
while(parent!=nil && curr==parent->left) {
|
||||
curr=parent;
|
||||
parent=curr->parent;
|
||||
}
|
||||
|
||||
return (parent==nil) ? NULL : parent;
|
||||
}
|
||||
|
||||
/*uff, convertation between trees and lists*/
|
||||
void usrtc_tree_convert_to_list(usrtc_t *us)
|
||||
{
|
||||
usrtc_node_t *node;
|
||||
usrtc_node_t tempsentinel;
|
||||
usrtc_node_t *nil=&tempsentinel;
|
||||
usrtc_node_t *tail,*next;
|
||||
usrtc_node_t *treenil=tree_null_priv(us);
|
||||
|
||||
if(us->nodecount==0) /* no nodes */
|
||||
return;
|
||||
|
||||
tempsentinel.next=nil;
|
||||
tempsentinel.prev=nil;
|
||||
|
||||
/* two passes */
|
||||
for(tail=nil,node=usrtc_tree_first(us);node!=0;tail=node,node=next) {
|
||||
next=usrtc_tree_next(us,node);
|
||||
node->prev=tail;
|
||||
}
|
||||
|
||||
nil->prev=tail;
|
||||
|
||||
for(tail=nil,node=nil->prev;node!=nil;tail=node,node=node->prev)
|
||||
node->next=tail;
|
||||
|
||||
nil->next=tail;
|
||||
|
||||
us->sentinel.next=tempsentinel.next;
|
||||
us->sentinel.prev=tempsentinel.prev;
|
||||
us->sentinel.next->prev=treenil;
|
||||
us->sentinel.prev->next=treenil;
|
||||
}
|
||||
|
||||
void usrtc_tree_convert_from_list(usrtc_t *us)
|
||||
{
|
||||
usrtc_node_t *tree[TREE_DEPTH_MAX]={ 0 };
|
||||
usrtc_node_t *curr;
|
||||
usrtc_node_t *nil=tree_null_priv(us);
|
||||
usrtc_node_t *next;
|
||||
usrtc_node_t *complete=NULL;
|
||||
usrtc_count_t fullcount=(usrtc_count_t)USRTC_COUNT_T_MAX;
|
||||
usrtc_count_t nodecount=us->nodecount;
|
||||
usrtc_count_t botrowcount;
|
||||
int baselevel=0;
|
||||
int level=0;
|
||||
int i=0;
|
||||
|
||||
while (fullcount>=nodecount && fullcount) /* calc */
|
||||
fullcount>>=1;
|
||||
|
||||
botrowcount=nodecount-fullcount;
|
||||
|
||||
for(curr=nil->next;curr!=nil;curr=next) {
|
||||
next=curr->next;
|
||||
|
||||
if(complete==NULL && botrowcount-- ==0) {
|
||||
baselevel=level=1;
|
||||
complete=tree[0];
|
||||
|
||||
if(complete!=NULL) {
|
||||
tree[0]=0;
|
||||
complete->right=nil;
|
||||
while(tree[level]!=NULL) {
|
||||
tree[level]->right=complete;
|
||||
complete->parent=tree[level];
|
||||
complete=tree[level];
|
||||
tree[level++]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(complete==NULL) {
|
||||
curr->left=nil;
|
||||
curr->right=nil;
|
||||
complete=curr;
|
||||
|
||||
if(level!=baselevel)
|
||||
return;
|
||||
while(tree[level]!=NULL) {
|
||||
tree[level]->right=complete;
|
||||
complete->parent=tree[level];
|
||||
complete=tree[level];
|
||||
tree[level++]=0;
|
||||
}
|
||||
} else {
|
||||
curr->left=complete;
|
||||
complete->parent=curr;
|
||||
tree[level]=curr;
|
||||
complete=NULL;
|
||||
level=baselevel;
|
||||
}
|
||||
}
|
||||
|
||||
if(complete==NULL)
|
||||
complete=nil;
|
||||
|
||||
for(i=0;i<TREE_DEPTH_MAX;i++) {
|
||||
if(tree[i]!=NULL) {
|
||||
tree[i]->right=complete;
|
||||
complete->parent=tree[i];
|
||||
complete=tree[i];
|
||||
}
|
||||
}
|
||||
|
||||
nil->right=nil;
|
||||
nil->left=complete;
|
||||
complete->parent=nil;
|
||||
|
||||
}
|
||||
|
||||
void usrtc_tree_rotate_left(usrtc_node_t *child,usrtc_node_t *parent)
|
||||
{
|
||||
usrtc_node_t *leftgrandchild;
|
||||
usrtc_node_t *grandpa;
|
||||
|
||||
if(parent->right!=child)
|
||||
return;
|
||||
|
||||
child=parent->right;
|
||||
parent->right=leftgrandchild=child->left;
|
||||
leftgrandchild->parent=parent;
|
||||
|
||||
child->parent=grandpa=parent->parent;
|
||||
|
||||
if(parent==grandpa->left) {
|
||||
grandpa->left=child;
|
||||
} else {
|
||||
if(parent!=grandpa->right)
|
||||
return;
|
||||
grandpa->right=child;
|
||||
}
|
||||
|
||||
child->left=parent;
|
||||
parent->parent=child;
|
||||
}
|
||||
|
||||
void usrtc_tree_rotate_right(usrtc_node_t *child,usrtc_node_t *parent)
|
||||
{
|
||||
usrtc_node_t *rightgrandchild;
|
||||
usrtc_node_t *grandpa;
|
||||
|
||||
if(parent->left!=child)
|
||||
return;
|
||||
|
||||
parent->left=rightgrandchild=child->right;
|
||||
rightgrandchild->parent=parent;
|
||||
|
||||
child->parent=grandpa=parent->parent;
|
||||
|
||||
if(parent==grandpa->right) {
|
||||
grandpa->right=child;
|
||||
} else {
|
||||
if(parent!=grandpa->left)
|
||||
return;
|
||||
grandpa->left=child;
|
||||
}
|
||||
|
||||
child->right=parent;
|
||||
parent->parent=child;
|
||||
}
|
||||
|
||||
/* local functions */
|
||||
static void tree_delete(usrtc_t *us, usrtc_node_t *node)
|
||||
{
|
||||
usrtc_node_t *dummy;
|
||||
|
||||
usrtc_tree_delete(us, node, &dummy, &dummy);
|
||||
}
|
||||
|
@ -0,0 +1,244 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
|
||||
/*
|
||||
* usrtc.c
|
||||
* Copyright (C) 2006, 2013 Alexander Vdolainen <avdolainen@gmail.com>
|
||||
* Copyright (C) 2006-2013, 2014 Askele inc. <http://askele.com>
|
||||
*
|
||||
* libtdata is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* libtdata is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <tdata/usrtc.h>
|
||||
#include <tdata/macro.h>
|
||||
|
||||
/* so, if you want to add your implementation of the data
|
||||
* structure please add this here, like the following.
|
||||
*/
|
||||
|
||||
#define MAX_IMPL 4
|
||||
|
||||
extern usrtc_functions_t usrtc_list_fu;
|
||||
extern usrtc_functions_t usrtc_tree_fu;
|
||||
extern usrtc_functions_t usrtc_redblack_fu;
|
||||
extern usrtc_functions_t usrtc_splay_fu;
|
||||
extern usrtc_functions_t usrtc_avl_fu;
|
||||
|
||||
static usrtc_functions_t *impl_table[] = {
|
||||
&usrtc_list_fu,&usrtc_tree_fu,
|
||||
&usrtc_redblack_fu,&usrtc_splay_fu,
|
||||
&usrtc_avl_fu };
|
||||
|
||||
static usrtc_node_t *default_node_alloc(void *context)
|
||||
{
|
||||
return malloc(sizeof *default_node_alloc(context));
|
||||
}
|
||||
|
||||
static void default_node_free(void *context,usrtc_node_t *node)
|
||||
{
|
||||
free(node);
|
||||
}
|
||||
|
||||
void usrtc_init(usrtc_t *us,int impl,usrtc_count_t maxcount,usrtc_compare_t compare)
|
||||
{
|
||||
if(!us)
|
||||
return;
|
||||
if(impl>MAX_IMPL)
|
||||
return;
|
||||
|
||||
us->nodecount=0;
|
||||
us->maxcount=maxcount;
|
||||
us->dupes_allowed=0;
|
||||
us->compare=compare;
|
||||
us->node_alloc=default_node_alloc;
|
||||
us->node_free=default_node_free;
|
||||
us->context=0;
|
||||
us->futable=impl_table[impl];
|
||||
us->futable->usrtc_init(us);
|
||||
}
|
||||
|
||||
usrtc_t *usrtc_create(int impl,usrtc_count_t maxcount,usrtc_compare_t compare)
|
||||
{
|
||||
usrtc_t *newrtc=(usrtc_t*)malloc(sizeof *newrtc);
|
||||
|
||||
if(newrtc)
|
||||
usrtc_init(newrtc,impl,maxcount,compare);
|
||||
|
||||
return newrtc;
|
||||
}
|
||||
|
||||
void usrtc_destroy(usrtc_t *us)
|
||||
{
|
||||
/*assert(usrtc_isempty(us));*/
|
||||
if(!us)
|
||||
return;
|
||||
|
||||
free(us);
|
||||
}
|
||||
|
||||
void usrtc_convert_to(usrtc_t *us,int impl)
|
||||
{
|
||||
if(impl_table[impl]==us->futable)
|
||||
return;
|
||||
|
||||
if(us->futable->usrtc_type==usrtc_bst && (impl==USRTC_BST || impl==USRTC_SPLAY)) {
|
||||
us->futable=impl_table[impl];
|
||||
return;
|
||||
}
|
||||
|
||||
us->futable->usrtc_convert_to_list(us);
|
||||
us->futable=impl_table[impl];
|
||||
|
||||
if(impl_table[impl]->usrtc_type==usrtc_lst)
|
||||
return;
|
||||
|
||||
us->futable->usrtc_convert_from_list(us);
|
||||
}
|
||||
|
||||
usrtc_count_t usrtc_count(usrtc_t *us)
|
||||
{
|
||||
return us->nodecount;
|
||||
}
|
||||
|
||||
int usrtc_isempty(usrtc_t *us)
|
||||
{
|
||||
return us->nodecount == 0;
|
||||
}
|
||||
|
||||
int usrtc_isfull(usrtc_t *us)
|
||||
{
|
||||
return us->nodecount == us->maxcount;
|
||||
}
|
||||
|
||||
int usrtc_alloc_insert(usrtc_t *us,const void *key,void *data)
|
||||
{
|
||||
usrtc_node_t *newnode=us->node_alloc(us->context);
|
||||
|
||||
if(newnode!=NULL) {
|
||||
newnode->data=data;
|
||||
us->futable->usrtc_insert(us,newnode,key);
|
||||
}
|
||||
|
||||
return newnode!=NULL;
|
||||
}
|
||||
|
||||
void usrtc_delete_free(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
us->futable->usrtc_delete(us,node);
|
||||
us->node_free(us->context,node);
|
||||
}
|
||||
|
||||
void usrtc_set_allocator(usrtc_t *us,usrtc_node_alloc_t alloc,usrtc_node_free_t n_free,void *context)
|
||||
{
|
||||
us->node_alloc=alloc;
|
||||
us->node_free=n_free;
|
||||
us->context=context;
|
||||
}
|
||||
|
||||
void usrtc_allow_dupes(usrtc_t *us)
|
||||
{
|
||||
/*assert(us->nodecount == 0);*/
|
||||
if(!us->nodecount)
|
||||
return;
|
||||
|
||||
us->dupes_allowed=1;
|
||||
}
|
||||
|
||||
void usrtc_node_init(usrtc_node_t *node,void *data)
|
||||
{
|
||||
node->data=data;
|
||||
node->impl_specific.usrtc_dummy=0;
|
||||
node->left=NULL;
|
||||
node->right=NULL;
|
||||
node->parent=NULL;
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_node_create(void *data)
|
||||
{
|
||||
usrtc_node_t *newnode=(usrtc_node_t*)malloc(sizeof *newnode);
|
||||
|
||||
if(newnode!=NULL)
|
||||
newnode->data=data;
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
void usrtc_node_destroy(usrtc_node_t *node)
|
||||
{
|
||||
free(node);
|
||||
}
|
||||
|
||||
void *usrtc_node_getdata(usrtc_node_t *node)
|
||||
{
|
||||
return node->data;
|
||||
}
|
||||
|
||||
void usrtc_node_setdata(usrtc_node_t *node,void *data)
|
||||
{
|
||||
node->data=data;
|
||||
}
|
||||
|
||||
const void *usrtc_node_getkey(usrtc_node_t *node)
|
||||
{
|
||||
return node->key;
|
||||
}
|
||||
|
||||
void usrtc_insert(usrtc_t *us,usrtc_node_t *node,const void *key)
|
||||
{
|
||||
us->futable->usrtc_insert(us,node,key);
|
||||
}
|
||||
|
||||
void usrtc_delete(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
us->futable->usrtc_delete(us,node);
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_lookup(usrtc_t *us,const void *key)
|
||||
{
|
||||
return us->futable->usrtc_lookup(us,key);
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_lower_bound(usrtc_t *us,const void *key)
|
||||
{
|
||||
return us->futable->usrtc_lower_bound(us,key);
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_upper_bound(usrtc_t *us,const void *key)
|
||||
{
|
||||
return us->futable->usrtc_upper_bound(us,key);
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_first(usrtc_t *us)
|
||||
{
|
||||
return us->futable->usrtc_first(us);
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_last(usrtc_t *us)
|
||||
{
|
||||
return us->futable->usrtc_last(us);
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_next(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
return us->futable->usrtc_next(us,node);
|
||||
}
|
||||
|
||||
usrtc_node_t *usrtc_prev(usrtc_t *us,usrtc_node_t *node)
|
||||
{
|
||||
return us->futable->usrtc_prev(us,node);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue