move util library into ddsrt
As was the plan with the introduction of ddsrt; this includes renaming the identifiers to match the capitalization style and removes old junk. Signed-off-by: Erik Boasson <eb@ilities.com>
This commit is contained in:
		
							parent
							
								
									42500e7fb8
								
							
						
					
					
						commit
						712ca3149f
					
				
					 62 changed files with 1702 additions and 1869 deletions
				
			
		| 
						 | 
				
			
			@ -78,6 +78,21 @@ list(APPEND sources
 | 
			
		|||
  "${source_path}/strtod.c"
 | 
			
		||||
  "${source_path}/strtol.c")
 | 
			
		||||
 | 
			
		||||
list(APPEND headers
 | 
			
		||||
  "${source_path}/dds/ddsrt/avl.h"
 | 
			
		||||
  "${source_path}/dds/ddsrt/expand_envvars.h"
 | 
			
		||||
  "${source_path}/dds/ddsrt/fibheap.h"
 | 
			
		||||
  "${source_path}/dds/ddsrt/hopscotch.h"
 | 
			
		||||
  "${source_path}/dds/ddsrt/thread_pool.h")
 | 
			
		||||
 | 
			
		||||
list(APPEND sources
 | 
			
		||||
  "${source_path}/avl.c"
 | 
			
		||||
  "${source_path}/expand_envvars.c"
 | 
			
		||||
  "${source_path}/fibheap.c"
 | 
			
		||||
  "${source_path}/hopscotch.c"
 | 
			
		||||
  "${source_path}/thread_pool.c"
 | 
			
		||||
  "${source_path}/xmlparser.c")
 | 
			
		||||
 | 
			
		||||
# Not every target offers the same set of features. For embedded targets the
 | 
			
		||||
# set of features may even be different between builds. e.g. a FreeRTOS build
 | 
			
		||||
# could use the lightweight IP stack, but later change to FreeRTOS+TCP.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										359
									
								
								src/ddsrt/include/dds/ddsrt/avl.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								src/ddsrt/include/dds/ddsrt/avl.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,359 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSRT_AVL_H
 | 
			
		||||
#define DDSRT_AVL_H
 | 
			
		||||
 | 
			
		||||
/* The tree library never performs memory allocations or deallocations internally.
 | 
			
		||||
 | 
			
		||||
   - Treedef_t: defines the properties of the tree, offsets,
 | 
			
		||||
     comparison functions, augmented structures, flags -- these are
 | 
			
		||||
     related to the code/data structure in which the tree is embedded,
 | 
			
		||||
     and in nearly all cases known at compile time.
 | 
			
		||||
   - avlTree_t: represents the tree, i.e., pointer to the root.
 | 
			
		||||
   - avlNode_t: contains the administrative data for a single node in
 | 
			
		||||
     the tree.
 | 
			
		||||
 | 
			
		||||
   For a tree node:
 | 
			
		||||
     struct T {
 | 
			
		||||
       avlNode_t avlnode;
 | 
			
		||||
       int key;
 | 
			
		||||
     };
 | 
			
		||||
   by definition, avlnodeoffset == offsetof(struct T, avlnode) and
 | 
			
		||||
   keyoffset = offsetof(struct T, key). The user of the library only
 | 
			
		||||
   ever deals in pointers to (in this case) struct T, never with
 | 
			
		||||
   pointers to the avlNode_t, and the compare function operations on
 | 
			
		||||
   pointers to keys, in this case pointers to "int"s. If you wish, you
 | 
			
		||||
   can also do: keyoffset = 0, in which case the compare function
 | 
			
		||||
   would be operating on struct T's.
 | 
			
		||||
 | 
			
		||||
   The compare function is assumed to behave just like all compare
 | 
			
		||||
   functions in the C library: < 0, =0, >0 for left argument less
 | 
			
		||||
   than, equal to or greater than the right argument.
 | 
			
		||||
 | 
			
		||||
   The "augment" function is automatically called whenever some of the
 | 
			
		||||
   children of a node change, as well as when the "augment" function
 | 
			
		||||
   has been called on some of the children. It allows you to maintain
 | 
			
		||||
   a "summary" of the subtree -- currently only used in ddsi2e, in one
 | 
			
		||||
   spot.
 | 
			
		||||
 | 
			
		||||
   Trees come in various "variants", configured through "treedef"
 | 
			
		||||
   flags:
 | 
			
		||||
   - direct/indirect key: direct meaning the key value is embedded in
 | 
			
		||||
     the structure containing the avlNode_t, indirect meaning a
 | 
			
		||||
     pointer to the key value is. The compare function doesn't deal
 | 
			
		||||
     with tree nodes, but with key values.
 | 
			
		||||
   - re-entrant: in the style of the C library, meaning, the
 | 
			
		||||
     comparison function gets a user-supplied 3rd argument (in
 | 
			
		||||
     particular used by mmstat).
 | 
			
		||||
   - unique keys/duplicate keys: when keys must be unique, some
 | 
			
		||||
     optimizations apply; it is up to the caller to ensure one doesn't
 | 
			
		||||
     violate the uniqueness of the keys (it'll happily crash in insert
 | 
			
		||||
     if you don't); when duplicate keys are allowed, a forward scan of
 | 
			
		||||
     the tree will visit them in the order of insertion.
 | 
			
		||||
 | 
			
		||||
   For a tree node:
 | 
			
		||||
     struct T {
 | 
			
		||||
       avlnode_t avlnode;
 | 
			
		||||
      char *key;
 | 
			
		||||
     };
 | 
			
		||||
   you could set the "indirect" flag, and then you simply use
 | 
			
		||||
   strcmp(), avoiding the need for passing templates in looking up key
 | 
			
		||||
   values. Much nicer.
 | 
			
		||||
 | 
			
		||||
   There is also an orthogonal variant that is enforced through the
 | 
			
		||||
   type system -- note that would be possible for all of the above as
 | 
			
		||||
   well, but the number of cases simply explodes and none of the above
 | 
			
		||||
   flags affects the dynamically changing data structures (just the
 | 
			
		||||
   tree definition), unlike this one.
 | 
			
		||||
 | 
			
		||||
   - the "C" variant keeps track of the number of nodes in the tree to
 | 
			
		||||
     support a "count" operation in O(1) time, but is otherwise
 | 
			
		||||
     identical.
 | 
			
		||||
 | 
			
		||||
   The various initializer macros and TreedefInit functions should
 | 
			
		||||
   make sense with this.
 | 
			
		||||
 | 
			
		||||
   All functions for looking up nodes return NULL if there is no node
 | 
			
		||||
   satisfying the requirements.
 | 
			
		||||
 | 
			
		||||
   - Init: initializes a tree (really just: root = NULL, perhaps count = 0)
 | 
			
		||||
   - Free: calls "freefun" on each node, which may free the node
 | 
			
		||||
   - FreeArg: as "Free", but with an extra, user-supplied, argument
 | 
			
		||||
   - Root: returns the root node
 | 
			
		||||
   - Lookup: returns a node with key value "key" (ref allowdups flag)
 | 
			
		||||
   - LookupIPath: like Lookup, but also filling an IPath_t structure
 | 
			
		||||
     for efficient insertion in case of a failed lookup (or inserting
 | 
			
		||||
     duplicates)
 | 
			
		||||
   - LookupDPath: like Lookup, but also filling a DPath_t structure
 | 
			
		||||
     that helps with deleting a node
 | 
			
		||||
   - LookupPredEq: locates the node with the greatest key value <= "key"
 | 
			
		||||
   - LookupSuccEq: similar, but smallest key value >= "key"
 | 
			
		||||
   - LookupPred: similar, < "key"
 | 
			
		||||
   - LookupSucc: similar, > "key"
 | 
			
		||||
   - Insert: convenience function: LookupIPath ; InsertIPath
 | 
			
		||||
   - Delete: convenience function: LookupDPath ; DeleteDPath
 | 
			
		||||
   - InsertIPath: insert node based on the "path" obtained from LookupIPath
 | 
			
		||||
   - DeleteDPath: delete node, using information in "path" to do so efficiently
 | 
			
		||||
   - SwapNode: replace "oldn" by "newn" without modifying the tree
 | 
			
		||||
     structure (the key need not be equal, but must be
 | 
			
		||||
     FindPred(oldn).key < newn.key < FindSucc(oldn).key, where a
 | 
			
		||||
     non-existing predecessor has key -inf and a non-existing
 | 
			
		||||
     successor has key +inf, and where it is understood that the <
 | 
			
		||||
     operator becomes <= if allowdups is set
 | 
			
		||||
   - AugmentUpdate: to be called when something in "node" changes that
 | 
			
		||||
     affects the subtree "summary" computed by the configured
 | 
			
		||||
     "augment" function
 | 
			
		||||
   - IsEmpty: returns 1 if tree is empty, 0 if not
 | 
			
		||||
   - IsSingleton: returns 1 if tree contains exactly one node, 0 if not
 | 
			
		||||
   - FindMin: returns the node with the smallest key value in the tree
 | 
			
		||||
   - FindMax: similar, largest key value
 | 
			
		||||
   - FindPred: preceding node in in-order treewalk
 | 
			
		||||
   - FindSucc: similar, following node
 | 
			
		||||
 | 
			
		||||
   - Walk: calls "f" with user-supplied argument "a" once for each
 | 
			
		||||
     node, starting at FindMin and ending at FindMax
 | 
			
		||||
   - ConstWalk: same, but with a const tree
 | 
			
		||||
   - WalkRange: like Walk, but only visiting nodes with key values in
 | 
			
		||||
     range [min,max] (that's inclusive)
 | 
			
		||||
   - ConstWalkRange: same, but with a const tree
 | 
			
		||||
   - WalkRangeReverse: like WalkRange, but in the reverse direction
 | 
			
		||||
   - ConstWalkRangeReverse: same, but with a const tree
 | 
			
		||||
   - IterFirst: starts forward iteration, starting at (and returning) FindMin
 | 
			
		||||
   - IterSuccEq: similar, starting at LookupSuccEq
 | 
			
		||||
   - IterSucc: similar, starting at LookupSucc
 | 
			
		||||
   - IterNext: returns FindSucc(last returned node); may not be called
 | 
			
		||||
     if preceding IterXXX call on same "iter" returned NULL
 | 
			
		||||
 | 
			
		||||
   That's all there is to it.
 | 
			
		||||
 | 
			
		||||
   Note that all calls to Walk(f,a) can be rewritten as:
 | 
			
		||||
     for(n=IterFirst(&it); n; n=IterNext(&it)) { f(n,a) }
 | 
			
		||||
   or as
 | 
			
		||||
     for(n=FindMin(); n; n=FindSucc(n)) { f(n,a) }
 | 
			
		||||
 | 
			
		||||
   The walk functions and iterators may not alter the tree
 | 
			
		||||
   structure. If that is desired, the latter can easily be rewritten
 | 
			
		||||
   as:
 | 
			
		||||
     n=FindMin() ; while(n) { nn=FindSucc(n); f(n,a); n=nn }
 | 
			
		||||
   because FindMin/FindSucc doesn't store any information to allow
 | 
			
		||||
   fast processing. That'll allow every operation, with the obvious
 | 
			
		||||
   exception of f(n) calling Delete(FindSucc(n)).
 | 
			
		||||
 | 
			
		||||
   Currently, all trees maintain parent pointers, but it may be worth
 | 
			
		||||
   doing a separate set without it, as it reduces the size of
 | 
			
		||||
   avlNode_t. But in that case, the FindMin/FindSucc option would no
 | 
			
		||||
   longer be a reasonable option because it would be prohibitively
 | 
			
		||||
   expensive, whereas the IterFirst/IterNext option are alway
 | 
			
		||||
   efficiently. If one were to do a threaded tree variant, the
 | 
			
		||||
   implemetantion of IterFirst/IterNext would become absolute trivial
 | 
			
		||||
   and faster still, but at the cost of significantly more overhead in
 | 
			
		||||
   memory and updates. */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
#include "dds/ddsrt/attributes.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DDSRT_AVL_MAX_TREEHEIGHT (12 * sizeof (void *))
 | 
			
		||||
 | 
			
		||||
typedef int (*ddsrt_avl_compare_t) (const void *a, const void *b);
 | 
			
		||||
typedef int (*ddsrt_avl_compare_r_t) (const void *a, const void *b, void *arg);
 | 
			
		||||
typedef void (*ddsrt_avl_augment_t) (void *node, const void *left, const void *right);
 | 
			
		||||
typedef void (*ddsrt_avl_walk_t) (void *node, void *arg);
 | 
			
		||||
typedef void (*ddsrt_avl_const_walk_t) (const void *node, void *arg);
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_node {
 | 
			
		||||
    struct ddsrt_avl_node *cs[2]; /* 0 = left, 1 = right */
 | 
			
		||||
    struct ddsrt_avl_node *parent;
 | 
			
		||||
    int height;
 | 
			
		||||
} ddsrt_avl_node_t;
 | 
			
		||||
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_FLAG_INDKEY 1
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_FLAG_R 2
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_FLAG_ALLOWDUPS 4
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_treedef {
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
    ddsrt_avl_treedef() {}
 | 
			
		||||
#endif
 | 
			
		||||
    size_t avlnodeoffset;
 | 
			
		||||
    size_t keyoffset;
 | 
			
		||||
    union {
 | 
			
		||||
        ddsrt_avl_compare_t comparekk;
 | 
			
		||||
        ddsrt_avl_compare_r_t comparekk_r;
 | 
			
		||||
    } u;
 | 
			
		||||
    ddsrt_avl_augment_t augment;
 | 
			
		||||
    uint32_t flags;
 | 
			
		||||
    void *cmp_arg; /* for _r variant */
 | 
			
		||||
} ddsrt_avl_treedef_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_ctreedef {
 | 
			
		||||
    ddsrt_avl_treedef_t t;
 | 
			
		||||
} ddsrt_avl_ctreedef_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_tree {
 | 
			
		||||
    ddsrt_avl_node_t *root;
 | 
			
		||||
} ddsrt_avl_tree_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_ctree {
 | 
			
		||||
    ddsrt_avl_tree_t t;
 | 
			
		||||
    size_t count;
 | 
			
		||||
} ddsrt_avl_ctree_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_path {
 | 
			
		||||
    int depth; /* total depth of path */
 | 
			
		||||
    int pnodeidx;
 | 
			
		||||
    ddsrt_avl_node_t *parent; /* (nodeidx == 0 ? NULL : *(path[nodeidx-1])) */
 | 
			
		||||
    ddsrt_avl_node_t **pnode[DDSRT_AVL_MAX_TREEHEIGHT];
 | 
			
		||||
} ddsrt_avl_path_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_ipath {
 | 
			
		||||
    ddsrt_avl_path_t p;
 | 
			
		||||
} ddsrt_avl_ipath_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_dpath {
 | 
			
		||||
    ddsrt_avl_path_t p;
 | 
			
		||||
} ddsrt_avl_dpath_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_iter {
 | 
			
		||||
    const ddsrt_avl_treedef_t *td;
 | 
			
		||||
    ddsrt_avl_node_t *right;
 | 
			
		||||
    ddsrt_avl_node_t **todop;
 | 
			
		||||
    ddsrt_avl_node_t *todo[1+DDSRT_AVL_MAX_TREEHEIGHT];
 | 
			
		||||
} ddsrt_avl_iter_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_avl_citer {
 | 
			
		||||
    ddsrt_avl_iter_t t;
 | 
			
		||||
} ddsrt_avl_citer_t;
 | 
			
		||||
 | 
			
		||||
/* avlnodeoffset and keyoffset must both be in [0,2**31-1] */
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_INITIALIZER(avlnodeoffset, keyoffset, comparekk_, augment) { (avlnodeoffset), (keyoffset), { .comparekk = (comparekk_) }, (augment), 0, 0 }
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY(avlnodeoffset, keyoffset, comparekk_, augment) { (avlnodeoffset), (keyoffset), { .comparekk = (comparekk_) }, (augment), DDSRT_AVL_TREEDEF_FLAG_INDKEY, 0 }
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_INITIALIZER_ALLOWDUPS(avlnodeoffset, keyoffset, comparekk_, augment) { (avlnodeoffset), (keyoffset), { .comparekk = (comparekk_) }, (augment), DDSRT_AVL_TREEDEF_FLAG_ALLOWDUPS, 0 }
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY_ALLOWDUPS(avlnodeoffset, keyoffset, comparekk_, augment) { (avlnodeoffset), (keyoffset), { .comparekk = (comparekk_) }, (augment), DDSRT_AVL_TREEDEF_FLAG_INDKEY|DDSRT_AVL_TREEDEF_FLAG_ALLOWDUPS, 0 }
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_INITIALIZER_R(avlnodeoffset, keyoffset, comparekk_, cmparg, augment) { (avlnodeoffset), (keyoffset), { .comparekk_r = (comparekk_) }, (augment), DDSRT_AVL_TREEDEF_FLAG_R, (cmparg) }
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY_R(avlnodeoffset, keyoffset, comparekk_, cmparg, augment) { (avlnodeoffset), (keyoffset), { .comparekk_r = (comparekk_) }, (augment), DDSRT_AVL_TREEDEF_FLAG_INDKEY|DDSRT_AVL_TREEDEF_FLAG_R, (cmparg) }
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_INITIALIZER_R_ALLOWDUPS(avlnodeoffset, keyoffset, comparekk_, cmparg, augment) { (avlnodeoffset), (keyoffset), { .comparekk_r = (comparekk_) }, (augment), DDSRT_AVL_TREEDEF_FLAG_R|DDSRT_AVL_TREEDEF_FLAG_ALLOWDUPS, (cmparg) }
 | 
			
		||||
#define DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY_R_ALLOWDUPS(avlnodeoffset, keyoffset, comparekk_, cmparg, augment) { (avlnodeoffset), (keyoffset), { .comparekk_r = (comparekk_) }, (augment), DDSRT_AVL_TREEDEF_FLAG_INDKEY|DDSRT_AVL_TREEDEF_FLAG_R|DDSRT_AVL_TREEDEF_FLAG_ALLOWDUPS, (cmparg) }
 | 
			
		||||
 | 
			
		||||
/* Not maintaining # nodes */
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_treedef_init (ddsrt_avl_treedef_t *td, size_t avlnodeoffset, size_t keyoffset, ddsrt_avl_compare_t comparekk, ddsrt_avl_augment_t augment, uint32_t flags) ddsrt_nonnull((1,4));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_treedef_init_r (ddsrt_avl_treedef_t *td, size_t avlnodeoffset, size_t keyoffset, ddsrt_avl_compare_r_t comparekk_r, void *cmp_arg, ddsrt_avl_augment_t augment, uint32_t flags) ddsrt_nonnull((1,4));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_init (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_free (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, void (*freefun) (void *node)) ddsrt_nonnull((1,2));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_free_arg (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, void (*freefun) (void *node, void *arg), void *arg) ddsrt_nonnull((1,2));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_root (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_root_non_empty (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_lookup (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_lookup_ipath (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *key, ddsrt_avl_ipath_t *path) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_lookup_dpath (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *key, ddsrt_avl_dpath_t *path) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_lookup_pred_eq (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_lookup_succ_eq (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_lookup_pred (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_lookup_succ (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_insert (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, void *node) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_delete (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, void *node) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_insert_ipath (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, void *node, ddsrt_avl_ipath_t *path) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_delete_dpath (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, void *node, ddsrt_avl_dpath_t *path) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_swap_node (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, void *oldn, void *newn) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_augment_update (const ddsrt_avl_treedef_t *td, void *node) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT int ddsrt_avl_is_empty (const ddsrt_avl_tree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT int ddsrt_avl_is_singleton (const ddsrt_avl_tree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_find_min (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_find_max (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_find_pred (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *vnode) ddsrt_nonnull((1,2));
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_find_succ (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *vnode) ddsrt_nonnull((1,2));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_walk (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, ddsrt_avl_walk_t f, void *a) ddsrt_nonnull((1,2,3));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_const_walk (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, ddsrt_avl_const_walk_t f, void *a) ddsrt_nonnull((1,2,3));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_walk_range (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, const void *min, const void *max, ddsrt_avl_walk_t f, void *a)  ddsrt_nonnull((1,2,3,4,5));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_const_walk_range (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *min, const void *max, ddsrt_avl_const_walk_t f, void *a) ddsrt_nonnull((1,2,3,4,5));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_walk_range_reverse (const ddsrt_avl_treedef_t *td, ddsrt_avl_tree_t *tree, const void *min, const void *max, ddsrt_avl_walk_t f, void *a) ddsrt_nonnull((1,2,3));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_const_walk_range_reverse (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, const void *min, const void *max, ddsrt_avl_const_walk_t f, void *a) ddsrt_nonnull((1,2,3));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_iter_first (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, ddsrt_avl_iter_t *iter) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_iter_succ_eq (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, ddsrt_avl_iter_t *iter, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_iter_succ (const ddsrt_avl_treedef_t *td, const ddsrt_avl_tree_t *tree, ddsrt_avl_iter_t *iter, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_iter_next (ddsrt_avl_iter_t *iter) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
/* Maintaining # nodes */
 | 
			
		||||
 | 
			
		||||
#define DDSRT_AVL_CTREEDEF_INITIALIZER(avlnodeoffset, keyoffset, comparekk, augment) { DDSRT_AVL_TREEDEF_INITIALIZER (avlnodeoffset, keyoffset, comparekk, augment) }
 | 
			
		||||
#define DDSRT_AVL_CTREEDEF_INITIALIZER_INDKEY(avlnodeoffset, keyoffset, comparekk, augment) { DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY (avlnodeoffset, keyoffset, comparekk, augment) }
 | 
			
		||||
#define DDSRT_AVL_CTREEDEF_INITIALIZER_ALLOWDUPS(avlnodeoffset, keyoffset, comparekk, augment) { DDSRT_AVL_TREEDEF_INITIALIZER_ALLOWDUPS (avlnodeoffset, keyoffset, comparekk, augment) }
 | 
			
		||||
#define DDSRT_AVL_CTREEDEF_INITIALIZER_INDKEY_ALLOWDUPS(avlnodeoffset, keyoffset, comparekk, augment) { DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY_ALLOWDUPS (avlnodeoffset, keyoffset, comparekk, augment) }
 | 
			
		||||
#define DDSRT_AVL_CTREEDEF_INITIALIZER_R(avlnodeoffset, keyoffset, comparekk, cmparg, augment) { DDSRT_AVL_TREEDEF_INITIALIZER_R (avlnodeoffset, keyoffset, comparekk, cmparg, augment) }
 | 
			
		||||
#define DDSRT_AVL_CTREEDEF_INITIALIZER_INDKEY_R(avlnodeoffset, keyoffset, comparekk, cmparg, augment) { DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY_R (avlnodeoffset, keyoffset, comparekk, cmparg, augment) }
 | 
			
		||||
#define DDSRT_AVL_CTREEDEF_INITIALIZER_R_ALLOWDUPS(avlnodeoffset, keyoffset, comparekk, cmparg, augment) { DDSRT_AVL_TREEDEF_INITIALIZER_R_ALLOWDUPS (avlnodeoffset, keyoffset, comparekk, cmparg, augment) }
 | 
			
		||||
#define DDSRT_AVL_CTREEDEF_INITIALIZER_INDKEY_R_ALLOWDUPS(avlnodeoffset, keyoffset, comparekk, cmparg, augment) { DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY_R_ALLOWDUPS (avlnodeoffset, keyoffset, comparekk, cmparg, augment) }
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_ctreedef_init (ddsrt_avl_ctreedef_t *td, size_t avlnodeoffset, size_t keyoffset, ddsrt_avl_compare_t comparekk, ddsrt_avl_augment_t augment, uint32_t flags) ddsrt_nonnull((1,4));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_ctreedef_init_r (ddsrt_avl_ctreedef_t *td, size_t avlnodeoffset, size_t keyoffset, ddsrt_avl_compare_r_t comparekk_r, void *cmp_arg, ddsrt_avl_augment_t augment, uint32_t flags) ddsrt_nonnull((1,4));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cinit (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cfree (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, void (*freefun) (void *node)) ddsrt_nonnull((1,2));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cfree_arg (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, void (*freefun) (void *node, void *arg), void *arg) ddsrt_nonnull((1,2));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_croot (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_croot_non_empty (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_clookup (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_clookup_ipath (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *key, ddsrt_avl_ipath_t *path) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_clookup_dpath (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *key, ddsrt_avl_dpath_t *path) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_clookup_pred_eq (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_clookup_succ_eq (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_clookup_pred (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_clookup_succ (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cinsert (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, void *node) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cdelete (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, void *node) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cinsert_ipath (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, void *node, ddsrt_avl_ipath_t *path) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cdelete_dpath (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, void *node, ddsrt_avl_dpath_t *path) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cswap_node (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, void *oldn, void *newn) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_caugment_update (const ddsrt_avl_ctreedef_t *td, void *node) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT int ddsrt_avl_cis_empty (const ddsrt_avl_ctree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT int ddsrt_avl_cis_singleton (const ddsrt_avl_ctree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT size_t ddsrt_avl_ccount (const ddsrt_avl_ctree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_cfind_min (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_cfind_max (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_cfind_pred (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *vnode) ddsrt_nonnull((1,2));
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_cfind_succ (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *vnode) ddsrt_nonnull((1,2));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cwalk (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, ddsrt_avl_walk_t f, void *a) ddsrt_nonnull((1,2,3));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cconst_walk (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, ddsrt_avl_const_walk_t f, void *a) ddsrt_nonnull((1,2,3));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cwalk_range (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, const void *min, const void *max, ddsrt_avl_walk_t f, void *a) ddsrt_nonnull((1,2,3,4,5));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cconst_walk_range (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *min, const void *max, ddsrt_avl_const_walk_t f, void *a) ddsrt_nonnull((1,2,3,4,5));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cwalk_range_reverse (const ddsrt_avl_ctreedef_t *td, ddsrt_avl_ctree_t *tree, const void *min, const void *max, ddsrt_avl_walk_t f, void *a) ddsrt_nonnull((1,2,3,4,5));
 | 
			
		||||
DDS_EXPORT void ddsrt_avl_cconst_walk_range_reverse (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, const void *min, const void *max, ddsrt_avl_const_walk_t f, void *a) ddsrt_nonnull((1,2,3,4,5));
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_citer_first (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, ddsrt_avl_citer_t *iter) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_citer_succ_eq (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, ddsrt_avl_citer_t *iter, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_citer_succ (const ddsrt_avl_ctreedef_t *td, const ddsrt_avl_ctree_t *tree, ddsrt_avl_citer_t *iter, const void *key) ddsrt_nonnull_all;
 | 
			
		||||
DDS_EXPORT void *ddsrt_avl_citer_next (ddsrt_avl_citer_t *iter) ddsrt_nonnull_all;
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* DDSRT_AVL_H */
 | 
			
		||||
							
								
								
									
										31
									
								
								src/ddsrt/include/dds/ddsrt/expand_envvars.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/ddsrt/include/dds/ddsrt/expand_envvars.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSRT_EXPAND_ENVVARS_H
 | 
			
		||||
#define DDSRT_EXPAND_ENVVARS_H
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X */
 | 
			
		||||
    DDS_EXPORT char *ddsrt_expand_envvars(const char *string);
 | 
			
		||||
 | 
			
		||||
    /* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, $ and \ can be escaped with \ */
 | 
			
		||||
    DDS_EXPORT char *ddsrt_expand_envvars_sh(const char *string);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										54
									
								
								src/ddsrt/include/dds/ddsrt/fibheap.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/ddsrt/include/dds/ddsrt/fibheap.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSRT_FIBHEAP_H
 | 
			
		||||
#define DDSRT_FIBHEAP_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_fibheap_node {
 | 
			
		||||
  struct ddsrt_fibheap_node *parent, *children;
 | 
			
		||||
  struct ddsrt_fibheap_node *prev, *next;
 | 
			
		||||
  unsigned mark: 1;
 | 
			
		||||
  unsigned degree: 31;
 | 
			
		||||
} ddsrt_fibheap_node_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_fibheap_def {
 | 
			
		||||
    uintptr_t offset;
 | 
			
		||||
    int (*cmp) (const void *va, const void *vb);
 | 
			
		||||
} ddsrt_fibheap_def_t;
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_fibheap {
 | 
			
		||||
  ddsrt_fibheap_node_t *roots; /* points to root with min key value */
 | 
			
		||||
} ddsrt_fibheap_t;
 | 
			
		||||
 | 
			
		||||
#define DDSRT_FIBHEAPDEF_INITIALIZER(offset, cmp) { (offset), (cmp) }
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_fibheap_def_init (ddsrt_fibheap_def_t *fhdef, uintptr_t offset, int (*cmp) (const void *va, const void *vb));
 | 
			
		||||
DDS_EXPORT void ddsrt_fibheap_init (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh);
 | 
			
		||||
DDS_EXPORT void *ddsrt_fibheap_min (const ddsrt_fibheap_def_t *fhdef, const ddsrt_fibheap_t *fh);
 | 
			
		||||
DDS_EXPORT void ddsrt_fibheap_merge (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *a, ddsrt_fibheap_t *b);
 | 
			
		||||
DDS_EXPORT void ddsrt_fibheap_insert (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh, const void *vnode);
 | 
			
		||||
DDS_EXPORT void ddsrt_fibheap_delete (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh, const void *vnode);
 | 
			
		||||
DDS_EXPORT void *ddsrt_fibheap_extract_min (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh);
 | 
			
		||||
DDS_EXPORT void ddsrt_fibheap_decrease_key (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh, const void *vnode); /* to be called AFTER decreasing the key */
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* DDSRT_FIBHEAP_H */
 | 
			
		||||
							
								
								
									
										104
									
								
								src/ddsrt/include/dds/ddsrt/hopscotch.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/ddsrt/include/dds/ddsrt/hopscotch.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,104 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSRT_HOPSCOTCH_H
 | 
			
		||||
#define DDSRT_HOPSCOTCH_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Concurrent version */
 | 
			
		||||
struct ddsrt_chh;
 | 
			
		||||
struct ddsrt_chh_bucket;
 | 
			
		||||
struct ddsrt_chh_iter {
 | 
			
		||||
  struct ddsrt_chh_bucket *bs;
 | 
			
		||||
  uint32_t size;
 | 
			
		||||
  uint32_t cursor;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The hopscotch hash table is dependent on a proper functioning hash.
 | 
			
		||||
 * If the hash function generates a lot of hash collisions, then it will
 | 
			
		||||
 * not be able to handle that by design.
 | 
			
		||||
 * It is capable of handling some collisions, but not more than 32 per
 | 
			
		||||
 * bucket (less, when other hash values are clustered around the
 | 
			
		||||
 * collision value).
 | 
			
		||||
 * When proper distributed hash values are generated, then hopscotch
 | 
			
		||||
 * works nice and quickly.
 | 
			
		||||
 */
 | 
			
		||||
typedef uint32_t (*ddsrt_hh_hash_fn) (const void *);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Hopscotch needs to be able to compare two elements.
 | 
			
		||||
 * Returns 0 when not equal.
 | 
			
		||||
 */
 | 
			
		||||
typedef int (*ddsrt_hh_equals_fn) (const void *, const void *);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Hopscotch is will resize its internal buckets list when needed. It will
 | 
			
		||||
 * call this garbage collection function with the old buckets list. The
 | 
			
		||||
 * caller has to delete the list when it deems it safe to do so.
 | 
			
		||||
 */
 | 
			
		||||
typedef void (*ddsrt_hh_buckets_gc_fn) (void *);
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets);
 | 
			
		||||
DDS_EXPORT void ddsrt_chh_free (struct ddsrt_chh * __restrict hh);
 | 
			
		||||
DDS_EXPORT void *ddsrt_chh_lookup (struct ddsrt_chh * __restrict rt, const void * __restrict template);
 | 
			
		||||
DDS_EXPORT int ddsrt_chh_add (struct ddsrt_chh * __restrict rt, const void * __restrict data);
 | 
			
		||||
DDS_EXPORT int ddsrt_chh_remove (struct ddsrt_chh * __restrict rt, const void * __restrict template);
 | 
			
		||||
DDS_EXPORT void ddsrt_chh_enum_unsafe (struct ddsrt_chh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg); /* may delete a */
 | 
			
		||||
void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict rt, struct ddsrt_chh_iter *it);
 | 
			
		||||
void *ddsrt_chh_iter_next (struct ddsrt_chh_iter *it);
 | 
			
		||||
 | 
			
		||||
/* Sequential version */
 | 
			
		||||
struct ddsrt_hh;
 | 
			
		||||
 | 
			
		||||
struct ddsrt_hh_iter {
 | 
			
		||||
    struct ddsrt_hh *hh;
 | 
			
		||||
    uint32_t cursor;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT struct ddsrt_hh *ddsrt_hh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals);
 | 
			
		||||
DDS_EXPORT void ddsrt_hh_free (struct ddsrt_hh * __restrict hh);
 | 
			
		||||
DDS_EXPORT void *ddsrt_hh_lookup (const struct ddsrt_hh * __restrict rt, const void * __restrict template);
 | 
			
		||||
DDS_EXPORT int ddsrt_hh_add (struct ddsrt_hh * __restrict rt, const void * __restrict data);
 | 
			
		||||
DDS_EXPORT int ddsrt_hh_remove (struct ddsrt_hh * __restrict rt, const void * __restrict template);
 | 
			
		||||
DDS_EXPORT void ddsrt_hh_enum (struct ddsrt_hh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg); /* may delete a */
 | 
			
		||||
DDS_EXPORT void *ddsrt_hh_iter_first (struct ddsrt_hh * __restrict rt, struct ddsrt_hh_iter * __restrict iter); /* may delete nodes */
 | 
			
		||||
DDS_EXPORT void *ddsrt_hh_iter_next (struct ddsrt_hh_iter * __restrict iter);
 | 
			
		||||
 | 
			
		||||
/* Sequential version, embedded data */
 | 
			
		||||
struct ddsrt_ehh;
 | 
			
		||||
 | 
			
		||||
struct ddsrt_ehh_iter {
 | 
			
		||||
    struct ddsrt_ehh *hh;
 | 
			
		||||
    uint32_t cursor;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT struct ddsrt_ehh *ddsrt_ehh_new (size_t elemsz, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals);
 | 
			
		||||
DDS_EXPORT void ddsrt_ehh_free (struct ddsrt_ehh * __restrict hh);
 | 
			
		||||
DDS_EXPORT void *ddsrt_ehh_lookup (const struct ddsrt_ehh * __restrict rt, const void * __restrict template);
 | 
			
		||||
DDS_EXPORT int ddsrt_ehh_add (struct ddsrt_ehh * __restrict rt, const void * __restrict data);
 | 
			
		||||
DDS_EXPORT int ddsrt_ehh_remove (struct ddsrt_ehh * __restrict rt, const void * __restrict template);
 | 
			
		||||
DDS_EXPORT void ddsrt_ehh_enum (struct ddsrt_ehh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg); /* may delete a */
 | 
			
		||||
DDS_EXPORT void *ddsrt_ehh_iter_first (struct ddsrt_ehh * __restrict rt, struct ddsrt_ehh_iter * __restrict iter); /* may delete nodes */
 | 
			
		||||
DDS_EXPORT void *ddsrt_ehh_iter_next (struct ddsrt_ehh_iter * __restrict iter);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										69
									
								
								src/ddsrt/include/dds/ddsrt/thread_pool.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/ddsrt/include/dds/ddsrt/thread_pool.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSRT_THREAD_POOL_H
 | 
			
		||||
#define DDSRT_THREAD_POOL_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
#include "dds/ddsrt/sync.h"
 | 
			
		||||
#include "dds/ddsrt/threads.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct ddsrt_thread_pool_s *ddsrt_thread_pool;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  ddsrt_thread_pool_new: Creates a new thread pool. Returns NULL if
 | 
			
		||||
  cannot create initial set of threads. Threads are created with
 | 
			
		||||
  the optional atribute argument. Additional threads may be created
 | 
			
		||||
  on demand up to max_threads.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT ddsrt_thread_pool ddsrt_thread_pool_new
 | 
			
		||||
(
 | 
			
		||||
  uint32_t threads,     /* Initial number of threads in pool (can be 0) */
 | 
			
		||||
  uint32_t max_threads, /* Maximum number of threads in pool (0 == infinite) */
 | 
			
		||||
  uint32_t max_queue,   /* Maximum number of queued requests (0 == infinite) */
 | 
			
		||||
  ddsrt_threadattr_t * attr   /* Attributes used to create pool threads (can be NULL) */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/* ddsrt_thread_pool_free: Frees pool, destroying threads. */
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_thread_pool_free (ddsrt_thread_pool pool);
 | 
			
		||||
 | 
			
		||||
/* ddsrt_thread_pool_purge: Purge threads from pool back to initial set. */
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT void ddsrt_thread_pool_purge (ddsrt_thread_pool pool);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  ddsrt_thread_pool_submit: Submit a thread function and associated argument
 | 
			
		||||
  to be invoked by a thread from the pool. If no threads are available a
 | 
			
		||||
  new thread will be created on demand to handle the function unless the
 | 
			
		||||
  pool thread maximum has been reached, in which case the function is queued.
 | 
			
		||||
  Note that if the pool queue has reached it's maximum DDS_RETCODE_TRY_AGAIN is returned.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
DDS_EXPORT dds_retcode_t ddsrt_thread_pool_submit
 | 
			
		||||
(
 | 
			
		||||
  ddsrt_thread_pool pool,  /* Thread pool instance */
 | 
			
		||||
  void (*fn) (void *arg),  /* Function to be invoked by thread from pool */
 | 
			
		||||
  void * arg            /* Argument passed to invoked function */
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* DDSRT_THREAD_POOL_H */
 | 
			
		||||
							
								
								
									
										52
									
								
								src/ddsrt/include/dds/ddsrt/xmlparser.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/ddsrt/include/dds/ddsrt/xmlparser.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#ifndef DDSRT_XMLPARSER_H
 | 
			
		||||
#define DDSRT_XMLPARSER_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/export.h"
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    typedef int (*ddsrt_xmlp_proc_elem_open_t) (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name);
 | 
			
		||||
    typedef int (*ddsrt_xmlp_proc_attr_t) (void *varg, uintptr_t eleminfo, const char *name, const char *value);
 | 
			
		||||
    typedef int (*ddsrt_xmlp_proc_elem_data_t) (void *varg, uintptr_t eleminfo, const char *data);
 | 
			
		||||
    typedef int (*ddsrt_xmlp_proc_elem_close_t) (void *varg, uintptr_t eleminfo);
 | 
			
		||||
    typedef void (*ddsrt_xmlp_error) (void *varg, const char *msg, int line);
 | 
			
		||||
 | 
			
		||||
    struct ddsrt_xmlp_callbacks {
 | 
			
		||||
        ddsrt_xmlp_proc_elem_open_t elem_open;
 | 
			
		||||
        ddsrt_xmlp_proc_attr_t attr;
 | 
			
		||||
        ddsrt_xmlp_proc_elem_data_t elem_data;
 | 
			
		||||
        ddsrt_xmlp_proc_elem_close_t elem_close;
 | 
			
		||||
        ddsrt_xmlp_error error;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct ddsrt_xmlp_state;
 | 
			
		||||
 | 
			
		||||
    DDS_EXPORT struct ddsrt_xmlp_state *ddsrt_xmlp_new_file (FILE *fp, void *varg, const struct ddsrt_xmlp_callbacks *cb);
 | 
			
		||||
    DDS_EXPORT struct ddsrt_xmlp_state *ddsrt_xmlp_new_string (const char *string, void *varg, const struct ddsrt_xmlp_callbacks *cb);
 | 
			
		||||
    DDS_EXPORT void ddsrt_xmlp_set_requireEOF (struct ddsrt_xmlp_state *st, int require_eof);
 | 
			
		||||
    DDS_EXPORT size_t ddsrt_xmlp_get_bufpos (const struct ddsrt_xmlp_state *st);
 | 
			
		||||
    DDS_EXPORT void ddsrt_xmlp_free (struct ddsrt_xmlp_state *st);
 | 
			
		||||
    DDS_EXPORT int ddsrt_xmlp_parse (struct ddsrt_xmlp_state *st);
 | 
			
		||||
 | 
			
		||||
    DDS_EXPORT int ddsrt_xmlUnescapeInsitu (char *buffer, size_t *n);
 | 
			
		||||
 | 
			
		||||
#if defined (__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1148
									
								
								src/ddsrt/src/avl.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1148
									
								
								src/ddsrt/src/avl.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										232
									
								
								src/ddsrt/src/expand_envvars.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								src/ddsrt/src/expand_envvars.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,232 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/environ.h"
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds/ddsrt/log.h"
 | 
			
		||||
#include "dds/ddsrt/string.h"
 | 
			
		||||
#include "dds/ddsrt/expand_envvars.h"
 | 
			
		||||
 | 
			
		||||
typedef char * (*expand_fn)(const char *src0);
 | 
			
		||||
 | 
			
		||||
static void expand_append (char **dst, size_t *sz, size_t *pos, char c)
 | 
			
		||||
{
 | 
			
		||||
    if (*pos == *sz) {
 | 
			
		||||
        *sz += 1024;
 | 
			
		||||
        *dst = ddsrt_realloc (*dst, *sz);
 | 
			
		||||
    }
 | 
			
		||||
    (*dst)[*pos] = c;
 | 
			
		||||
    (*pos)++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *expand_env (const char *name, char op, const char *alt, expand_fn expand)
 | 
			
		||||
{
 | 
			
		||||
    char *env = NULL;
 | 
			
		||||
    (void)ddsrt_getenv (name, &env);
 | 
			
		||||
    switch (op)
 | 
			
		||||
    {
 | 
			
		||||
        case 0:
 | 
			
		||||
            return ddsrt_strdup (env ? env : "");
 | 
			
		||||
        case '-':
 | 
			
		||||
            return env && *env ? ddsrt_strdup (env) : expand (alt);
 | 
			
		||||
        case '?':
 | 
			
		||||
            if (env && *env) {
 | 
			
		||||
                return ddsrt_strdup (env);
 | 
			
		||||
            } else {
 | 
			
		||||
                char *altx = expand (alt);
 | 
			
		||||
                DDS_ERROR("%s: %s\n", name, altx);
 | 
			
		||||
                ddsrt_free (altx);
 | 
			
		||||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
        case '+':
 | 
			
		||||
            return env && *env ? expand (alt) : ddsrt_strdup ("");
 | 
			
		||||
        default:
 | 
			
		||||
            abort ();
 | 
			
		||||
            return NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *expand_envbrace (const char **src, expand_fn expand)
 | 
			
		||||
{
 | 
			
		||||
    const char *start = *src + 1;
 | 
			
		||||
    char *name, *x;
 | 
			
		||||
    assert (**src == '{');
 | 
			
		||||
    (*src)++;
 | 
			
		||||
    while (**src && **src != ':' && **src != '}') {
 | 
			
		||||
        (*src)++;
 | 
			
		||||
    }
 | 
			
		||||
    if (**src == 0) {
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
    name = ddsrt_malloc ((size_t) (*src - start) + 1);
 | 
			
		||||
    memcpy (name, start, (size_t) (*src - start));
 | 
			
		||||
    name[*src - start] = 0;
 | 
			
		||||
    if (**src == '}') {
 | 
			
		||||
        (*src)++;
 | 
			
		||||
        x = expand_env (name, 0, NULL, expand);
 | 
			
		||||
        ddsrt_free (name);
 | 
			
		||||
        return x;
 | 
			
		||||
    } else {
 | 
			
		||||
        const char *altstart;
 | 
			
		||||
        char *alt;
 | 
			
		||||
        char op;
 | 
			
		||||
        int nest = 0;
 | 
			
		||||
        assert (**src == ':');
 | 
			
		||||
        (*src)++;
 | 
			
		||||
        switch (**src) {
 | 
			
		||||
            case '-': case '+': case '?':
 | 
			
		||||
                op = **src;
 | 
			
		||||
                (*src)++;
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                ddsrt_free(name);
 | 
			
		||||
                goto err;
 | 
			
		||||
        }
 | 
			
		||||
        altstart = *src;
 | 
			
		||||
        while (**src && (**src != '}' || nest > 0)) {
 | 
			
		||||
            if (**src == '{') {
 | 
			
		||||
                nest++;
 | 
			
		||||
            } else if (**src == '}') {
 | 
			
		||||
                assert (nest > 0);
 | 
			
		||||
                nest--;
 | 
			
		||||
            } else if (**src == '\\') {
 | 
			
		||||
                (*src)++;
 | 
			
		||||
                if (**src == 0) {
 | 
			
		||||
                    ddsrt_free(name);
 | 
			
		||||
                    goto err;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            (*src)++;
 | 
			
		||||
        }
 | 
			
		||||
        if (**src == 0) {
 | 
			
		||||
            ddsrt_free(name);
 | 
			
		||||
            goto err;
 | 
			
		||||
        }
 | 
			
		||||
        assert (**src == '}');
 | 
			
		||||
        alt = ddsrt_malloc ((size_t) (*src - altstart) + 1);
 | 
			
		||||
        memcpy (alt, altstart, (size_t) (*src - altstart));
 | 
			
		||||
        alt[*src - altstart] = 0;
 | 
			
		||||
        (*src)++;
 | 
			
		||||
        x = expand_env (name, op, alt, expand);
 | 
			
		||||
        ddsrt_free (alt);
 | 
			
		||||
        ddsrt_free (name);
 | 
			
		||||
        return x;
 | 
			
		||||
    }
 | 
			
		||||
err:
 | 
			
		||||
    DDS_ERROR("%*.*s: invalid expansion\n", (int) (*src - start), (int) (*src - start), start);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *expand_envsimple (const char **src, expand_fn expand)
 | 
			
		||||
{
 | 
			
		||||
    const char *start = *src;
 | 
			
		||||
    char *name, *x;
 | 
			
		||||
    while (**src && (isalnum ((unsigned char) **src) || **src == '_')) {
 | 
			
		||||
        (*src)++;
 | 
			
		||||
    }
 | 
			
		||||
    assert (*src > start);
 | 
			
		||||
    name = ddsrt_malloc ((size_t) (*src - start) + 1);
 | 
			
		||||
    memcpy (name, start, (size_t) (*src - start));
 | 
			
		||||
    name[*src - start] = 0;
 | 
			
		||||
    x = expand_env (name, 0, NULL, expand);
 | 
			
		||||
    ddsrt_free (name);
 | 
			
		||||
    return x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *expand_envchar (const char **src, expand_fn expand)
 | 
			
		||||
{
 | 
			
		||||
    char name[2];
 | 
			
		||||
    assert (**src);
 | 
			
		||||
    name[0] = **src;
 | 
			
		||||
    name[1] = 0;
 | 
			
		||||
    (*src)++;
 | 
			
		||||
    return expand_env (name, 0, NULL, expand);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ddsrt_expand_envvars_sh (const char *src0)
 | 
			
		||||
{
 | 
			
		||||
    /* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms; $ and \ can be escaped with \ */
 | 
			
		||||
    const char *src = src0;
 | 
			
		||||
    size_t sz = strlen (src) + 1, pos = 0;
 | 
			
		||||
    char *dst = ddsrt_malloc (sz);
 | 
			
		||||
    while (*src) {
 | 
			
		||||
        if (*src == '\\') {
 | 
			
		||||
            src++;
 | 
			
		||||
            if (*src == 0) {
 | 
			
		||||
                DDS_ERROR("%s: incomplete escape at end of string\n", src0);
 | 
			
		||||
                ddsrt_free(dst);
 | 
			
		||||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
            expand_append (&dst, &sz, &pos, *src++);
 | 
			
		||||
        } else if (*src == '$') {
 | 
			
		||||
            char *x, *xp;
 | 
			
		||||
            src++;
 | 
			
		||||
            if (*src == 0) {
 | 
			
		||||
                DDS_ERROR("%s: incomplete variable expansion at end of string\n", src0);
 | 
			
		||||
                ddsrt_free(dst);
 | 
			
		||||
                return NULL;
 | 
			
		||||
            } else if (*src == '{') {
 | 
			
		||||
                x = expand_envbrace (&src, &ddsrt_expand_envvars_sh);
 | 
			
		||||
            } else if (isalnum ((unsigned char) *src) || *src == '_') {
 | 
			
		||||
                x = expand_envsimple (&src, &ddsrt_expand_envvars_sh);
 | 
			
		||||
            } else {
 | 
			
		||||
                x = expand_envchar (&src, &ddsrt_expand_envvars_sh);
 | 
			
		||||
            }
 | 
			
		||||
            if (x == NULL) {
 | 
			
		||||
                ddsrt_free(dst);
 | 
			
		||||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
            xp = x;
 | 
			
		||||
            while (*xp) {
 | 
			
		||||
                expand_append (&dst, &sz, &pos, *xp++);
 | 
			
		||||
            }
 | 
			
		||||
            ddsrt_free (x);
 | 
			
		||||
        } else {
 | 
			
		||||
            expand_append (&dst, &sz, &pos, *src++);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    expand_append (&dst, &sz, &pos, 0);
 | 
			
		||||
    return dst;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ddsrt_expand_envvars (const char *src0)
 | 
			
		||||
{
 | 
			
		||||
    /* Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X */
 | 
			
		||||
    const char *src = src0;
 | 
			
		||||
    size_t sz = strlen (src) + 1, pos = 0;
 | 
			
		||||
    char *dst = ddsrt_malloc (sz);
 | 
			
		||||
    while (*src) {
 | 
			
		||||
        if (*src == '$' && *(src + 1) == '{') {
 | 
			
		||||
            char *x, *xp;
 | 
			
		||||
            src++;
 | 
			
		||||
            x = expand_envbrace (&src, &ddsrt_expand_envvars);
 | 
			
		||||
            if (x == NULL) {
 | 
			
		||||
                ddsrt_free(dst);
 | 
			
		||||
                return NULL;
 | 
			
		||||
            }
 | 
			
		||||
            xp = x;
 | 
			
		||||
            while (*xp) {
 | 
			
		||||
                expand_append (&dst, &sz, &pos, *xp++);
 | 
			
		||||
            }
 | 
			
		||||
            ddsrt_free (x);
 | 
			
		||||
        } else {
 | 
			
		||||
            expand_append (&dst, &sz, &pos, *src++);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    expand_append (&dst, &sz, &pos, 0);
 | 
			
		||||
    return dst;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										304
									
								
								src/ddsrt/src/fibheap.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								src/ddsrt/src/fibheap.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,304 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/misc.h"
 | 
			
		||||
#include "dds/ddsrt/fibheap.h"
 | 
			
		||||
 | 
			
		||||
/* max degree: n >= F_{d+2} >= \phi^d ==> d <= log_\phi n, where \phi
 | 
			
		||||
   (as usual) is the golden ratio ~= 1.618.  We know n <= (size of
 | 
			
		||||
   address space) / sizeof (fh_node), log_\phi 2 ~= 1.44, sizeof
 | 
			
		||||
   (fh_node) >= 4, therefore max degree < log_2 (size of address
 | 
			
		||||
   space). */
 | 
			
		||||
#define MAX_DEGREE ((unsigned) (sizeof (void *) * CHAR_BIT - 1))
 | 
			
		||||
 | 
			
		||||
static int cmp (const ddsrt_fibheap_def_t *fhdef, const ddsrt_fibheap_node_t *a, const ddsrt_fibheap_node_t *b)
 | 
			
		||||
{
 | 
			
		||||
    return fhdef->cmp ((const char *) a - fhdef->offset, (const char *) b - fhdef->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_fibheap_def_init (ddsrt_fibheap_def_t *fhdef, uintptr_t offset, int (*cmp) (const void *va, const void *vb))
 | 
			
		||||
{
 | 
			
		||||
    fhdef->offset = offset;
 | 
			
		||||
    fhdef->cmp = cmp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_fibheap_init (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh)
 | 
			
		||||
{
 | 
			
		||||
    DDSRT_UNUSED_ARG(fhdef);
 | 
			
		||||
    fh->roots = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_fibheap_min (const ddsrt_fibheap_def_t *fhdef, const ddsrt_fibheap_t *fh)
 | 
			
		||||
{
 | 
			
		||||
    if (fh->roots) {
 | 
			
		||||
        return (void *) ((char *) fh->roots - fhdef->offset);
 | 
			
		||||
    } else {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_fibheap_merge_nonempty_list (ddsrt_fibheap_node_t **markptr, ddsrt_fibheap_node_t *list)
 | 
			
		||||
{
 | 
			
		||||
    assert (list != NULL);
 | 
			
		||||
 | 
			
		||||
    if (*markptr == NULL) {
 | 
			
		||||
        *markptr = list;
 | 
			
		||||
    } else {
 | 
			
		||||
        ddsrt_fibheap_node_t * const mark = *markptr;
 | 
			
		||||
        ddsrt_fibheap_node_t * const old_mark_next = mark->next;
 | 
			
		||||
        ddsrt_fibheap_node_t * const old_list_prev = list->prev;
 | 
			
		||||
        mark->next = list;
 | 
			
		||||
        old_mark_next->prev = old_list_prev;
 | 
			
		||||
        list->prev = mark;
 | 
			
		||||
        old_list_prev->next = old_mark_next;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_fibheap_merge_into (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *a, ddsrt_fibheap_node_t * const br)
 | 
			
		||||
{
 | 
			
		||||
    if (br == NULL) {
 | 
			
		||||
        return;
 | 
			
		||||
    } else if (a->roots == NULL) {
 | 
			
		||||
        a->roots = br;
 | 
			
		||||
    } else {
 | 
			
		||||
        const int c = cmp (fhdef, br, a->roots);
 | 
			
		||||
        ddsrt_fibheap_merge_nonempty_list (&a->roots, br);
 | 
			
		||||
        if (c < 0)
 | 
			
		||||
            a->roots = br;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_fibheap_merge (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *a, ddsrt_fibheap_t *b)
 | 
			
		||||
{
 | 
			
		||||
    /* merges nodes from b into a, thereafter, b is empty */
 | 
			
		||||
    ddsrt_fibheap_merge_into (fhdef, a, b->roots);
 | 
			
		||||
    b->roots = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_fibheap_insert (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh, const void *vnode)
 | 
			
		||||
{
 | 
			
		||||
    /* fibheap node is opaque => nothing in node changes as far as
 | 
			
		||||
     caller is concerned => declare as const argument, then drop the
 | 
			
		||||
     const qualifier */
 | 
			
		||||
    ddsrt_fibheap_node_t *node = (ddsrt_fibheap_node_t *) ((char *) vnode + fhdef->offset);
 | 
			
		||||
 | 
			
		||||
    /* new heap of degree 0 (i.e., only containing NODE) */
 | 
			
		||||
    node->parent = node->children = NULL;
 | 
			
		||||
    node->prev = node->next = node;
 | 
			
		||||
    node->mark = 0;
 | 
			
		||||
    node->degree = 0;
 | 
			
		||||
 | 
			
		||||
    /* then merge it in */
 | 
			
		||||
    ddsrt_fibheap_merge_into (fhdef, fh, node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_fibheap_add_as_child (ddsrt_fibheap_node_t *parent, ddsrt_fibheap_node_t *child)
 | 
			
		||||
{
 | 
			
		||||
    parent->degree++;
 | 
			
		||||
    child->parent = parent;
 | 
			
		||||
    child->prev = child->next = child;
 | 
			
		||||
    ddsrt_fibheap_merge_nonempty_list (&parent->children, child);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_fibheap_delete_one_from_list (ddsrt_fibheap_node_t **markptr, ddsrt_fibheap_node_t *node)
 | 
			
		||||
{
 | 
			
		||||
    if (node->next == node) {
 | 
			
		||||
        *markptr = NULL;
 | 
			
		||||
    } else {
 | 
			
		||||
        ddsrt_fibheap_node_t * const node_prev = node->prev;
 | 
			
		||||
        ddsrt_fibheap_node_t * const node_next = node->next;
 | 
			
		||||
        node_prev->next = node_next;
 | 
			
		||||
        node_next->prev = node_prev;
 | 
			
		||||
        if (*markptr == node) {
 | 
			
		||||
            *markptr = node_next;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_fibheap_extract_min (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh)
 | 
			
		||||
{
 | 
			
		||||
    ddsrt_fibheap_node_t *roots[MAX_DEGREE + 1];
 | 
			
		||||
    ddsrt_fibheap_node_t * const min = fh->roots;
 | 
			
		||||
    unsigned min_degree_noninit = 0;
 | 
			
		||||
 | 
			
		||||
    /* empty heap => return that, alternative would be to require the
 | 
			
		||||
       heap to contain at least one element, but this is probably nicer
 | 
			
		||||
       in practice */
 | 
			
		||||
    if (min == NULL) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* singleton heap => no work remaining */
 | 
			
		||||
    if (min->next == min && min->children == NULL) {
 | 
			
		||||
        fh->roots = NULL;
 | 
			
		||||
        return (void *) ((char *) min - fhdef->offset);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* remove min from fh->roots */
 | 
			
		||||
    ddsrt_fibheap_delete_one_from_list (&fh->roots, min);
 | 
			
		||||
 | 
			
		||||
    /* FIXME: can speed up by combining a few things & improving
 | 
			
		||||
       locality of reference by scanning lists only once */
 | 
			
		||||
 | 
			
		||||
    /* insert min'schildren as new roots -- must fix parent pointers,
 | 
			
		||||
       and reset marks because roots are always unmarked */
 | 
			
		||||
    if (min->children) {
 | 
			
		||||
        ddsrt_fibheap_node_t * const mark = min->children;
 | 
			
		||||
        ddsrt_fibheap_node_t *n = mark;
 | 
			
		||||
        do {
 | 
			
		||||
            n->parent = NULL;
 | 
			
		||||
            n->mark = 0;
 | 
			
		||||
            n = n->next;
 | 
			
		||||
        } while (n != mark);
 | 
			
		||||
 | 
			
		||||
        ddsrt_fibheap_merge_nonempty_list (&fh->roots, min->children);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* iteratively merge roots of equal degree, completely messing up
 | 
			
		||||
       fh->roots, ... */
 | 
			
		||||
    {
 | 
			
		||||
        ddsrt_fibheap_node_t *const mark = fh->roots;
 | 
			
		||||
        ddsrt_fibheap_node_t *n = mark;
 | 
			
		||||
        do {
 | 
			
		||||
            ddsrt_fibheap_node_t * const n1 = n->next;
 | 
			
		||||
 | 
			
		||||
            /* if n is first root with this high a degree, there's certainly
 | 
			
		||||
               not going to be another root to merge with yet */
 | 
			
		||||
            while (n->degree < min_degree_noninit && roots[n->degree]) {
 | 
			
		||||
                unsigned const degree = n->degree;
 | 
			
		||||
                ddsrt_fibheap_node_t *u, *v;
 | 
			
		||||
 | 
			
		||||
                if (cmp (fhdef, roots[degree], n) < 0) {
 | 
			
		||||
                    u = roots[degree]; v = n;
 | 
			
		||||
                } else {
 | 
			
		||||
                    u = n; v = roots[degree];
 | 
			
		||||
                }
 | 
			
		||||
                roots[degree] = NULL;
 | 
			
		||||
                ddsrt_fibheap_add_as_child (u, v);
 | 
			
		||||
                n = u;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* n may have changed, hence need to retest whether or not
 | 
			
		||||
               enough of roots has been initialised -- note that
 | 
			
		||||
               initialising roots[n->degree] is unnecessary, but easier */
 | 
			
		||||
            assert (n->degree <= MAX_DEGREE);
 | 
			
		||||
            while (min_degree_noninit <= n->degree) {
 | 
			
		||||
                roots[min_degree_noninit++] = NULL;
 | 
			
		||||
            }
 | 
			
		||||
            roots[n->degree] = n;
 | 
			
		||||
            n = n1;
 | 
			
		||||
        } while (n != mark);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* ... but we don't mind because we have roots[], we can scan linear
 | 
			
		||||
       memory at an astonishing rate, and we need to compare the root
 | 
			
		||||
       keys anyway to find the minimum */
 | 
			
		||||
    {
 | 
			
		||||
        ddsrt_fibheap_node_t *mark, *cursor, *newmin;
 | 
			
		||||
        unsigned i;
 | 
			
		||||
        for (i = 0; roots[i] == NULL; i++) {
 | 
			
		||||
            assert (i+1 < min_degree_noninit);
 | 
			
		||||
        }
 | 
			
		||||
        newmin = roots[i];
 | 
			
		||||
        assert (newmin != NULL);
 | 
			
		||||
        mark = cursor = roots[i];
 | 
			
		||||
        for (++i; i < min_degree_noninit; i++) {
 | 
			
		||||
            if (roots[i]) {
 | 
			
		||||
                ddsrt_fibheap_node_t * const r = roots[i];
 | 
			
		||||
                if (cmp (fhdef, r, newmin) < 0)
 | 
			
		||||
                    newmin = r;
 | 
			
		||||
                r->prev = cursor;
 | 
			
		||||
                cursor->next = r;
 | 
			
		||||
                cursor = r;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        mark->prev = cursor;
 | 
			
		||||
        cursor->next = mark;
 | 
			
		||||
 | 
			
		||||
        fh->roots = newmin;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (void *) ((char *) min - fhdef->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_fibheap_cutnode (ddsrt_fibheap_t *fh, ddsrt_fibheap_node_t *node)
 | 
			
		||||
{
 | 
			
		||||
    /* by marking the node, we ensure it gets cut */
 | 
			
		||||
    node->mark = 1;
 | 
			
		||||
 | 
			
		||||
    /* traverse towards the root, cutting marked nodes on the way */
 | 
			
		||||
    while (node->parent && node->mark) {
 | 
			
		||||
        ddsrt_fibheap_node_t *parent = node->parent;
 | 
			
		||||
 | 
			
		||||
        assert (parent->degree > 0);
 | 
			
		||||
        ddsrt_fibheap_delete_one_from_list (&parent->children, node);
 | 
			
		||||
        parent->degree--;
 | 
			
		||||
 | 
			
		||||
        node->mark = 0;
 | 
			
		||||
        node->parent = NULL;
 | 
			
		||||
        node->next = node->prev = node;
 | 
			
		||||
 | 
			
		||||
        /* we assume heap properties haven't been violated, and therefore
 | 
			
		||||
           none of the nodes we cut can become the new minimum */
 | 
			
		||||
        ddsrt_fibheap_merge_nonempty_list (&fh->roots, node);
 | 
			
		||||
 | 
			
		||||
        node = parent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* if we stopped because we hit an unmarked interior node, we must
 | 
			
		||||
       mark it */
 | 
			
		||||
    if (node->parent) {
 | 
			
		||||
        node->mark = 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_fibheap_decrease_key (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh, const void *vnode)
 | 
			
		||||
{
 | 
			
		||||
    /* fibheap node is opaque => nothing in node changes as far as
 | 
			
		||||
       caller is concerned => declare as const argument, then drop the
 | 
			
		||||
       const qualifier */
 | 
			
		||||
    ddsrt_fibheap_node_t *node = (ddsrt_fibheap_node_t *) ((char *) vnode + fhdef->offset);
 | 
			
		||||
 | 
			
		||||
    if (node->parent && cmp (fhdef, node->parent, node) <= 0) {
 | 
			
		||||
        /* heap property not violated, do nothing */
 | 
			
		||||
    } else {
 | 
			
		||||
        if (node->parent) {
 | 
			
		||||
            /* heap property violated by decreasing the key, but we cut it
 | 
			
		||||
               pretending nothing has happened yet, then fix up the minimum if
 | 
			
		||||
               this node is the new minimum */
 | 
			
		||||
            ddsrt_fibheap_cutnode (fh, node);
 | 
			
		||||
        }
 | 
			
		||||
        if (cmp (fhdef, node, fh->roots) < 0) {
 | 
			
		||||
            fh->roots = node;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_fibheap_delete (const ddsrt_fibheap_def_t *fhdef, ddsrt_fibheap_t *fh, const void *vnode)
 | 
			
		||||
{
 | 
			
		||||
    /* fibheap node is opaque => nothing in node changes as far as
 | 
			
		||||
       caller is concerned => declare as const argument, then drop the
 | 
			
		||||
       const qualifier */
 | 
			
		||||
    ddsrt_fibheap_node_t *node = (ddsrt_fibheap_node_t *) ((char *) vnode + fhdef->offset);
 | 
			
		||||
    
 | 
			
		||||
    /* essentially decreasekey(node);extractmin while pretending the
 | 
			
		||||
       node key is -infinity.  That means we can't directly call
 | 
			
		||||
       decreasekey, because it considers the actual value of the key. */
 | 
			
		||||
    if (node->parent != NULL) {
 | 
			
		||||
        ddsrt_fibheap_cutnode (fh, node);
 | 
			
		||||
    }
 | 
			
		||||
    fh->roots = node;
 | 
			
		||||
    (void) ddsrt_fibheap_extract_min (fhdef, fh);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										943
									
								
								src/ddsrt/src/hopscotch.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										943
									
								
								src/ddsrt/src/hopscotch.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,943 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/atomics.h"
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds/ddsrt/sync.h"
 | 
			
		||||
#include "dds/ddsrt/hopscotch.h"
 | 
			
		||||
 | 
			
		||||
#define HH_HOP_RANGE 32
 | 
			
		||||
#define HH_ADD_RANGE 64
 | 
			
		||||
 | 
			
		||||
#define NOT_A_BUCKET (~(uint32_t)0)
 | 
			
		||||
 | 
			
		||||
/********** CONCURRENT VERSION ************/
 | 
			
		||||
 | 
			
		||||
#define N_BACKING_LOCKS 32
 | 
			
		||||
#define N_RESIZE_LOCKS 8
 | 
			
		||||
 | 
			
		||||
struct ddsrt_chh_bucket {
 | 
			
		||||
    ddsrt_atomic_uint32_t hopinfo;
 | 
			
		||||
    ddsrt_atomic_uint32_t timestamp;
 | 
			
		||||
    ddsrt_atomic_uint32_t lock;
 | 
			
		||||
    ddsrt_atomic_voidp_t data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ddsrt_chh_bucket_array {
 | 
			
		||||
    uint32_t size; /* power of 2 */
 | 
			
		||||
    struct ddsrt_chh_bucket bs[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ddsrt_chh_backing_lock {
 | 
			
		||||
    ddsrt_mutex_t lock;
 | 
			
		||||
    ddsrt_cond_t cv;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ddsrt_chh {
 | 
			
		||||
    ddsrt_atomic_voidp_t buckets; /* struct ddsrt_chh_bucket_array * */
 | 
			
		||||
    struct ddsrt_chh_backing_lock backingLocks[N_BACKING_LOCKS];
 | 
			
		||||
    ddsrt_hh_hash_fn hash;
 | 
			
		||||
    ddsrt_hh_equals_fn equals;
 | 
			
		||||
    ddsrt_rwlock_t resize_locks[N_RESIZE_LOCKS];
 | 
			
		||||
    ddsrt_hh_buckets_gc_fn gc_buckets;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define CHH_MAX_TRIES 4
 | 
			
		||||
#define CHH_BUSY ((void *) 1)
 | 
			
		||||
 | 
			
		||||
static int ddsrt_chh_data_valid_p (void *data)
 | 
			
		||||
{
 | 
			
		||||
    return data != NULL && data != CHH_BUSY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ddsrt_chh_init (struct ddsrt_chh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t size;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
    struct ddsrt_chh_bucket_array *buckets;
 | 
			
		||||
 | 
			
		||||
    size = HH_HOP_RANGE;
 | 
			
		||||
    while (size < init_size) {
 | 
			
		||||
        size *= 2;
 | 
			
		||||
    }
 | 
			
		||||
    rt->hash = hash;
 | 
			
		||||
    rt->equals = equals;
 | 
			
		||||
    rt->gc_buckets = gc_buckets;
 | 
			
		||||
 | 
			
		||||
    buckets = ddsrt_malloc (offsetof (struct ddsrt_chh_bucket_array, bs) + size * sizeof (*buckets->bs));
 | 
			
		||||
    ddsrt_atomic_stvoidp (&rt->buckets, buckets);
 | 
			
		||||
    buckets->size = size;
 | 
			
		||||
    for (i = 0; i < size; i++) {
 | 
			
		||||
        struct ddsrt_chh_bucket *b = &buckets->bs[i];
 | 
			
		||||
        ddsrt_atomic_st32 (&b->hopinfo, 0);
 | 
			
		||||
        ddsrt_atomic_st32 (&b->timestamp, 0);
 | 
			
		||||
        ddsrt_atomic_st32 (&b->lock, 0);
 | 
			
		||||
        ddsrt_atomic_stvoidp (&b->data, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < N_BACKING_LOCKS; i++) {
 | 
			
		||||
        struct ddsrt_chh_backing_lock *s = &rt->backingLocks[i];
 | 
			
		||||
        ddsrt_mutex_init (&s->lock);
 | 
			
		||||
        ddsrt_cond_init (&s->cv);
 | 
			
		||||
    }
 | 
			
		||||
    for (i = 0; i < N_RESIZE_LOCKS; i++) {
 | 
			
		||||
        ddsrt_rwlock_init (&rt->resize_locks[i]);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_chh_fini (struct ddsrt_chh *rt)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    ddsrt_free (ddsrt_atomic_ldvoidp (&rt->buckets));
 | 
			
		||||
    for (i = 0; i < N_BACKING_LOCKS; i++) {
 | 
			
		||||
        struct ddsrt_chh_backing_lock *s = &rt->backingLocks[i];
 | 
			
		||||
        ddsrt_cond_destroy (&s->cv);
 | 
			
		||||
        ddsrt_mutex_destroy (&s->lock);
 | 
			
		||||
    }
 | 
			
		||||
    for (i = 0; i < N_RESIZE_LOCKS; i++) {
 | 
			
		||||
        ddsrt_rwlock_destroy (&rt->resize_locks[i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ddsrt_chh *ddsrt_chh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals, ddsrt_hh_buckets_gc_fn gc_buckets)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_chh *hh = ddsrt_malloc (sizeof (*hh));
 | 
			
		||||
    if (ddsrt_chh_init (hh, init_size, hash, equals, gc_buckets) < 0) {
 | 
			
		||||
        ddsrt_free (hh);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    } else {
 | 
			
		||||
        return hh;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_chh_free (struct ddsrt_chh * __restrict hh)
 | 
			
		||||
{
 | 
			
		||||
    ddsrt_chh_fini (hh);
 | 
			
		||||
    ddsrt_free (hh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define LOCKBIT ((uint32_t)1 << 31)
 | 
			
		||||
 | 
			
		||||
static void ddsrt_chh_lock_bucket (struct ddsrt_chh *rt, uint32_t bidx)
 | 
			
		||||
{
 | 
			
		||||
    /* Lock: MSB <=> LOCKBIT, LSBs <=> wait count; note that
 | 
			
		||||
       (o&LOCKBIT)==0 means a thread can sneak in when there are
 | 
			
		||||
       already waiters, changing it to o==0 would avoid that. */
 | 
			
		||||
    struct ddsrt_chh_bucket_array * const bsary = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
    struct ddsrt_chh_bucket * const b = &bsary->bs[bidx];
 | 
			
		||||
    struct ddsrt_chh_backing_lock * const s = &rt->backingLocks[bidx % N_BACKING_LOCKS];
 | 
			
		||||
    uint32_t o, n;
 | 
			
		||||
 fastpath_retry:
 | 
			
		||||
    o = ddsrt_atomic_ld32 (&b->lock);
 | 
			
		||||
    if ((o & LOCKBIT) == 0) {
 | 
			
		||||
        n = o | LOCKBIT;
 | 
			
		||||
    } else {
 | 
			
		||||
        n = o + 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (!ddsrt_atomic_cas32 (&b->lock, o, n)) {
 | 
			
		||||
        goto fastpath_retry;
 | 
			
		||||
    }
 | 
			
		||||
    if ((o & LOCKBIT) == 0) {
 | 
			
		||||
        ddsrt_atomic_fence ();
 | 
			
		||||
    } else {
 | 
			
		||||
        ddsrt_mutex_lock (&s->lock);
 | 
			
		||||
        do {
 | 
			
		||||
            while ((o = ddsrt_atomic_ld32 (&b->lock)) & LOCKBIT) {
 | 
			
		||||
                ddsrt_cond_wait (&s->cv, &s->lock);
 | 
			
		||||
            }
 | 
			
		||||
        } while (!ddsrt_atomic_cas32 (&b->lock, o, (o - 1) | LOCKBIT));
 | 
			
		||||
        ddsrt_mutex_unlock (&s->lock);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_chh_unlock_bucket (struct ddsrt_chh *rt, uint32_t bidx)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_chh_bucket_array * const bsary = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
    struct ddsrt_chh_bucket * const b = &bsary->bs[bidx];
 | 
			
		||||
    struct ddsrt_chh_backing_lock * const s = &rt->backingLocks[bidx % N_BACKING_LOCKS];
 | 
			
		||||
    uint32_t o, n;
 | 
			
		||||
 retry:
 | 
			
		||||
    o = ddsrt_atomic_ld32 (&b->lock);
 | 
			
		||||
    assert (o & LOCKBIT);
 | 
			
		||||
    n = o & ~LOCKBIT;
 | 
			
		||||
    if (!ddsrt_atomic_cas32 (&b->lock, o, n)) {
 | 
			
		||||
        goto retry;
 | 
			
		||||
    }
 | 
			
		||||
    if (n == 0) {
 | 
			
		||||
        ddsrt_atomic_fence ();
 | 
			
		||||
    } else {
 | 
			
		||||
        ddsrt_mutex_lock (&s->lock);
 | 
			
		||||
        /* Need to broadcast because the CV is shared by multiple buckets
 | 
			
		||||
           and the kernel wakes an arbitrary thread, it may be a thread
 | 
			
		||||
           waiting for another bucket's lock that gets woken up, and that
 | 
			
		||||
           can result in all threads waiting with all locks unlocked.
 | 
			
		||||
           Broadcast avoids that, and with significantly more CVs than
 | 
			
		||||
           cores, it shouldn't happen often. */
 | 
			
		||||
        ddsrt_cond_broadcast (&s->cv);
 | 
			
		||||
        ddsrt_mutex_unlock (&s->lock);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *ddsrt_chh_lookup_internal (struct ddsrt_chh_bucket_array const * const bsary, ddsrt_hh_equals_fn equals, const uint32_t bucket, const void *template)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_chh_bucket const * const bs = bsary->bs;
 | 
			
		||||
    const uint32_t idxmask = bsary->size - 1;
 | 
			
		||||
    uint32_t timestamp;
 | 
			
		||||
    int try_counter = 0;
 | 
			
		||||
    uint32_t idx;
 | 
			
		||||
    do {
 | 
			
		||||
        uint32_t hopinfo;
 | 
			
		||||
        timestamp = ddsrt_atomic_ld32 (&bs[bucket].timestamp);
 | 
			
		||||
        ddsrt_atomic_fence_ldld ();
 | 
			
		||||
        hopinfo = ddsrt_atomic_ld32 (&bs[bucket].hopinfo);
 | 
			
		||||
        for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
 | 
			
		||||
            const uint32_t bidx = (bucket + idx) & idxmask;
 | 
			
		||||
            void *data = ddsrt_atomic_ldvoidp (&bs[bidx].data);
 | 
			
		||||
            if (ddsrt_chh_data_valid_p (data) && equals (data, template)) {
 | 
			
		||||
                return data;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ddsrt_atomic_fence_ldld ();
 | 
			
		||||
    } while (timestamp != ddsrt_atomic_ld32 (&bs[bucket].timestamp) && ++try_counter < CHH_MAX_TRIES);
 | 
			
		||||
    if (try_counter == CHH_MAX_TRIES) {
 | 
			
		||||
        /* Note: try_counter would not have been incremented to
 | 
			
		||||
           CHH_MAX_TRIES if we ended the loop because the two timestamps
 | 
			
		||||
           were equal, but this avoids loading the timestamp again */
 | 
			
		||||
        for (idx = 0; idx < HH_HOP_RANGE; idx++) {
 | 
			
		||||
            const uint32_t bidx = (bucket + idx) & idxmask;
 | 
			
		||||
            void *data = ddsrt_atomic_ldvoidp (&bs[bidx].data);
 | 
			
		||||
            if (ddsrt_chh_data_valid_p (data) && equals (data, template)) {
 | 
			
		||||
                return data;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ddsrt_atomic_rmw32_nonatomic(var_, tmp_, expr_) do {                 \
 | 
			
		||||
        ddsrt_atomic_uint32_t *var__ = (var_);                               \
 | 
			
		||||
        uint32_t tmp_ = ddsrt_atomic_ld32 (var__);                          \
 | 
			
		||||
        ddsrt_atomic_st32 (var__, (expr_));                                  \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
void *ddsrt_chh_lookup (struct ddsrt_chh * __restrict rt, const void * __restrict template)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_chh_bucket_array const * const bsary = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
    const uint32_t hash = rt->hash (template);
 | 
			
		||||
    const uint32_t idxmask = bsary->size - 1;
 | 
			
		||||
    const uint32_t bucket = hash & idxmask;
 | 
			
		||||
    return ddsrt_chh_lookup_internal (bsary, rt->equals, bucket, template);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t ddsrt_chh_find_closer_free_bucket (struct ddsrt_chh *rt, uint32_t free_bucket, uint32_t *free_distance)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_chh_bucket_array * const bsary = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
    struct ddsrt_chh_bucket * const bs = bsary->bs;
 | 
			
		||||
    const uint32_t idxmask = bsary->size - 1;
 | 
			
		||||
    uint32_t move_bucket, free_dist;
 | 
			
		||||
    move_bucket = (free_bucket - (HH_HOP_RANGE - 1)) & idxmask;
 | 
			
		||||
    for (free_dist = HH_HOP_RANGE - 1; free_dist > 0; free_dist--) {
 | 
			
		||||
        uint32_t start_hop_info = ddsrt_atomic_ld32 (&bs[move_bucket].hopinfo);
 | 
			
		||||
        uint32_t move_free_distance = NOT_A_BUCKET;
 | 
			
		||||
        uint32_t mask = 1;
 | 
			
		||||
        uint32_t i;
 | 
			
		||||
        for (i = 0; i < free_dist; i++, mask <<= 1) {
 | 
			
		||||
            if (mask & start_hop_info) {
 | 
			
		||||
                move_free_distance = i;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (move_free_distance != NOT_A_BUCKET) {
 | 
			
		||||
            ddsrt_chh_lock_bucket (rt, move_bucket);
 | 
			
		||||
            if (start_hop_info == ddsrt_atomic_ld32 (&bs[move_bucket].hopinfo))
 | 
			
		||||
            {
 | 
			
		||||
                uint32_t new_free_bucket = (move_bucket + move_free_distance) & idxmask;
 | 
			
		||||
                ddsrt_atomic_rmw32_nonatomic (&bs[move_bucket].hopinfo, x, x | (1u << free_dist));
 | 
			
		||||
                ddsrt_atomic_stvoidp (&bs[free_bucket].data, ddsrt_atomic_ldvoidp (&bs[new_free_bucket].data));
 | 
			
		||||
                ddsrt_atomic_rmw32_nonatomic (&bs[move_bucket].timestamp, x, x + 1);
 | 
			
		||||
                ddsrt_atomic_fence ();
 | 
			
		||||
                ddsrt_atomic_stvoidp (&bs[new_free_bucket].data, CHH_BUSY);
 | 
			
		||||
                ddsrt_atomic_rmw32_nonatomic (&bs[move_bucket].hopinfo, x, x & ~(1u << move_free_distance));
 | 
			
		||||
 | 
			
		||||
                *free_distance -= free_dist - move_free_distance;
 | 
			
		||||
                ddsrt_chh_unlock_bucket (rt, move_bucket);
 | 
			
		||||
                return new_free_bucket;
 | 
			
		||||
            }
 | 
			
		||||
            ddsrt_chh_unlock_bucket (rt, move_bucket);
 | 
			
		||||
        }
 | 
			
		||||
        move_bucket = (move_bucket + 1) & idxmask;
 | 
			
		||||
    }
 | 
			
		||||
    return NOT_A_BUCKET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_chh_resize (struct ddsrt_chh *rt)
 | 
			
		||||
{
 | 
			
		||||
    /* doubles the size => bucket index gains one bit at the msb =>
 | 
			
		||||
       start bucket is unchanged or moved into the added half of the set
 | 
			
		||||
       => those for which the (new) msb is 0 are guaranteed to fit, and
 | 
			
		||||
       so are those for which the (new) msb is 1 => never have to resize
 | 
			
		||||
       recursively */
 | 
			
		||||
    struct ddsrt_chh_bucket_array * const bsary0 = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
    struct ddsrt_chh_bucket * const bs0 = bsary0->bs;
 | 
			
		||||
    struct ddsrt_chh_bucket_array *bsary1;
 | 
			
		||||
    struct ddsrt_chh_bucket *bs1;
 | 
			
		||||
    uint32_t i, idxmask0, idxmask1;
 | 
			
		||||
 | 
			
		||||
    assert (bsary0->size > 0);
 | 
			
		||||
    bsary1 = ddsrt_malloc (offsetof (struct ddsrt_chh_bucket_array, bs) + 2 * bsary0->size * sizeof (*bsary1->bs));
 | 
			
		||||
    bsary1->size = 2 * bsary0->size;
 | 
			
		||||
    bs1 = bsary1->bs;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < bsary1->size; i++) {
 | 
			
		||||
        ddsrt_atomic_st32 (&bs1[i].hopinfo, 0);
 | 
			
		||||
        ddsrt_atomic_st32 (&bs1[i].timestamp, 0);
 | 
			
		||||
        ddsrt_atomic_st32 (&bs1[i].lock, 0);
 | 
			
		||||
        ddsrt_atomic_stvoidp (&bs1[i].data, NULL);
 | 
			
		||||
    }
 | 
			
		||||
    idxmask0 = bsary0->size - 1;
 | 
			
		||||
    idxmask1 = bsary1->size - 1;
 | 
			
		||||
    for (i = 0; i < bsary0->size; i++) {
 | 
			
		||||
        void *data = ddsrt_atomic_ldvoidp (&bs0[i].data);
 | 
			
		||||
        if (data && data != CHH_BUSY) {
 | 
			
		||||
            const uint32_t hash = rt->hash (data);
 | 
			
		||||
            const uint32_t old_start_bucket = hash & idxmask0;
 | 
			
		||||
            const uint32_t new_start_bucket = hash & idxmask1;
 | 
			
		||||
            const uint32_t dist = (i >= old_start_bucket) ? (i - old_start_bucket) : (bsary0->size + i - old_start_bucket);
 | 
			
		||||
            const uint32_t newb = (new_start_bucket + dist) & idxmask1;
 | 
			
		||||
            assert (dist < HH_HOP_RANGE);
 | 
			
		||||
            ddsrt_atomic_rmw32_nonatomic (&bs1[new_start_bucket].hopinfo, x, x | (1u << dist));
 | 
			
		||||
            ddsrt_atomic_stvoidp (&bs1[newb].data, data);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_atomic_fence ();
 | 
			
		||||
    ddsrt_atomic_stvoidp (&rt->buckets, bsary1);
 | 
			
		||||
    rt->gc_buckets (bsary0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ddsrt_chh_add (struct ddsrt_chh * __restrict rt, const void * __restrict data)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t hash = rt->hash (data);
 | 
			
		||||
    uint32_t size;
 | 
			
		||||
    ddsrt_rwlock_read (&rt->resize_locks[hash % N_RESIZE_LOCKS]);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        struct ddsrt_chh_bucket_array * const bsary = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
        struct ddsrt_chh_bucket * const bs = bsary->bs;
 | 
			
		||||
        uint32_t idxmask;
 | 
			
		||||
        uint32_t start_bucket, free_distance, free_bucket;
 | 
			
		||||
 | 
			
		||||
        size = bsary->size;
 | 
			
		||||
        idxmask = size - 1;
 | 
			
		||||
        start_bucket = hash & idxmask;
 | 
			
		||||
 | 
			
		||||
        ddsrt_chh_lock_bucket (rt, start_bucket);
 | 
			
		||||
        if (ddsrt_chh_lookup_internal (bsary, rt->equals, start_bucket, data)) {
 | 
			
		||||
            ddsrt_chh_unlock_bucket (rt, start_bucket);
 | 
			
		||||
            ddsrt_rwlock_unlock (&rt->resize_locks[hash % N_RESIZE_LOCKS]);
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        free_bucket = start_bucket;
 | 
			
		||||
        for (free_distance = 0; free_distance < HH_ADD_RANGE; free_distance++) {
 | 
			
		||||
            if (ddsrt_atomic_ldvoidp (&bs[free_bucket].data) == NULL &&
 | 
			
		||||
                ddsrt_atomic_casvoidp (&bs[free_bucket].data, NULL, CHH_BUSY)) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            free_bucket = (free_bucket + 1) & idxmask;
 | 
			
		||||
        }
 | 
			
		||||
        if (free_distance < HH_ADD_RANGE) {
 | 
			
		||||
            do {
 | 
			
		||||
                if (free_distance < HH_HOP_RANGE) {
 | 
			
		||||
                    assert (free_bucket == ((start_bucket + free_distance) & idxmask));
 | 
			
		||||
                    ddsrt_atomic_rmw32_nonatomic (&bs[start_bucket].hopinfo, x, x | (1u << free_distance));
 | 
			
		||||
                    ddsrt_atomic_fence ();
 | 
			
		||||
                    ddsrt_atomic_stvoidp (&bs[free_bucket].data, (void *) data);
 | 
			
		||||
                    ddsrt_chh_unlock_bucket (rt, start_bucket);
 | 
			
		||||
                    ddsrt_rwlock_unlock (&rt->resize_locks[hash % N_RESIZE_LOCKS]);
 | 
			
		||||
                    return 1;
 | 
			
		||||
                }
 | 
			
		||||
                free_bucket = ddsrt_chh_find_closer_free_bucket (rt, free_bucket, &free_distance);
 | 
			
		||||
                assert (free_bucket == NOT_A_BUCKET || free_bucket <= idxmask);
 | 
			
		||||
            } while (free_bucket != NOT_A_BUCKET);
 | 
			
		||||
        }
 | 
			
		||||
        ddsrt_chh_unlock_bucket (rt, start_bucket);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_rwlock_unlock (&rt->resize_locks[hash % N_RESIZE_LOCKS]);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        int i;
 | 
			
		||||
        struct ddsrt_chh_bucket_array *bsary1;
 | 
			
		||||
        for (i = 0; i < N_RESIZE_LOCKS; i++) {
 | 
			
		||||
            ddsrt_rwlock_write (&rt->resize_locks[i]);
 | 
			
		||||
        }
 | 
			
		||||
        /* another thread may have sneaked past and grown the hash table */
 | 
			
		||||
        bsary1 = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
        if (bsary1->size == size) {
 | 
			
		||||
            ddsrt_chh_resize (rt);
 | 
			
		||||
        }
 | 
			
		||||
        for (i = 0; i < N_RESIZE_LOCKS; i++) {
 | 
			
		||||
            ddsrt_rwlock_unlock (&rt->resize_locks[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ddsrt_chh_add (rt, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ddsrt_chh_remove (struct ddsrt_chh * __restrict rt, const void * __restrict template)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t hash = rt->hash (template);
 | 
			
		||||
    ddsrt_rwlock_read (&rt->resize_locks[hash % N_RESIZE_LOCKS]);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        struct ddsrt_chh_bucket_array * const bsary = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
        struct ddsrt_chh_bucket * const bs = bsary->bs;
 | 
			
		||||
        const uint32_t size = bsary->size;
 | 
			
		||||
        const uint32_t idxmask = size - 1;
 | 
			
		||||
        const uint32_t bucket = hash & idxmask;
 | 
			
		||||
        uint32_t hopinfo;
 | 
			
		||||
        uint32_t idx;
 | 
			
		||||
        ddsrt_chh_lock_bucket (rt, bucket);
 | 
			
		||||
        hopinfo = ddsrt_atomic_ld32 (&bs[bucket].hopinfo);
 | 
			
		||||
        for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
 | 
			
		||||
            if (hopinfo & 1) {
 | 
			
		||||
                const uint32_t bidx = (bucket + idx) & idxmask;
 | 
			
		||||
                void *data = ddsrt_atomic_ldvoidp (&bs[bidx].data);
 | 
			
		||||
                if (ddsrt_chh_data_valid_p (data) && rt->equals (data, template)) {
 | 
			
		||||
                    ddsrt_atomic_stvoidp (&bs[bidx].data, NULL);
 | 
			
		||||
                    ddsrt_atomic_rmw32_nonatomic (&bs[bucket].hopinfo, x, x & ~(1u << idx));
 | 
			
		||||
                    ddsrt_chh_unlock_bucket (rt, bucket);
 | 
			
		||||
                    ddsrt_rwlock_unlock (&rt->resize_locks[hash % N_RESIZE_LOCKS]);
 | 
			
		||||
                    return 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ddsrt_chh_unlock_bucket (rt, bucket);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_rwlock_unlock (&rt->resize_locks[hash % N_RESIZE_LOCKS]);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_chh_enum_unsafe (struct ddsrt_chh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_chh_bucket_array * const bsary = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
    struct ddsrt_chh_bucket * const bs = bsary->bs;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
    for (i = 0; i < bsary->size; i++) {
 | 
			
		||||
        void *data = ddsrt_atomic_ldvoidp (&bs[i].data);
 | 
			
		||||
        if (data && data != CHH_BUSY) {
 | 
			
		||||
            f (data, f_arg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_chh_iter_next (struct ddsrt_chh_iter *it)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t i;
 | 
			
		||||
  for (i = it->cursor; i < it->size; i++) {
 | 
			
		||||
    void *data = ddsrt_atomic_ldvoidp (&it->bs[i].data);
 | 
			
		||||
    if (data && data != CHH_BUSY) {
 | 
			
		||||
      it->cursor = i+1;
 | 
			
		||||
      return data;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_chh_iter_first (struct ddsrt_chh * __restrict rt, struct ddsrt_chh_iter *it)
 | 
			
		||||
{
 | 
			
		||||
  struct ddsrt_chh_bucket_array * const bsary = ddsrt_atomic_ldvoidp (&rt->buckets);
 | 
			
		||||
  it->bs = bsary->bs;
 | 
			
		||||
  it->size = bsary->size;
 | 
			
		||||
  it->cursor = 0;
 | 
			
		||||
  return ddsrt_chh_iter_next (it);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/************* SEQUENTIAL VERSION ***************/
 | 
			
		||||
 | 
			
		||||
struct ddsrt_hh_bucket {
 | 
			
		||||
    uint32_t hopinfo;
 | 
			
		||||
    void *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ddsrt_hh {
 | 
			
		||||
    uint32_t size; /* power of 2 */
 | 
			
		||||
    struct ddsrt_hh_bucket *buckets;
 | 
			
		||||
    ddsrt_hh_hash_fn hash;
 | 
			
		||||
    ddsrt_hh_equals_fn equals;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void ddsrt_hh_init (struct ddsrt_hh *rt, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t size = HH_HOP_RANGE;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
    while (size < init_size) {
 | 
			
		||||
        size *= 2;
 | 
			
		||||
    }
 | 
			
		||||
    rt->hash = hash;
 | 
			
		||||
    rt->equals = equals;
 | 
			
		||||
    rt->size = size;
 | 
			
		||||
    rt->buckets = ddsrt_malloc (size * sizeof (*rt->buckets));
 | 
			
		||||
    for (i = 0; i < size; i++) {
 | 
			
		||||
        rt->buckets[i].hopinfo = 0;
 | 
			
		||||
        rt->buckets[i].data = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_hh_fini (struct ddsrt_hh *rt)
 | 
			
		||||
{
 | 
			
		||||
    ddsrt_free (rt->buckets);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ddsrt_hh *ddsrt_hh_new (uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_hh *hh = ddsrt_malloc (sizeof (*hh));
 | 
			
		||||
    ddsrt_hh_init (hh, init_size, hash, equals);
 | 
			
		||||
    return hh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_hh_free (struct ddsrt_hh * __restrict hh)
 | 
			
		||||
{
 | 
			
		||||
    ddsrt_hh_fini (hh);
 | 
			
		||||
    ddsrt_free (hh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *ddsrt_hh_lookup_internal (const struct ddsrt_hh *rt, const uint32_t bucket, const void *template)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    uint32_t hopinfo = rt->buckets[bucket].hopinfo;
 | 
			
		||||
    uint32_t idx;
 | 
			
		||||
    for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
 | 
			
		||||
        const uint32_t bidx = (bucket + idx) & idxmask;
 | 
			
		||||
        void *data = rt->buckets[bidx].data;
 | 
			
		||||
        if (data && rt->equals (data, template))
 | 
			
		||||
            return data;
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_hh_lookup (const struct ddsrt_hh * __restrict rt, const void * __restrict template)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t hash = rt->hash (template);
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    const uint32_t bucket = hash & idxmask;
 | 
			
		||||
    return ddsrt_hh_lookup_internal (rt, bucket, template);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t ddsrt_hh_find_closer_free_bucket (struct ddsrt_hh *rt, uint32_t free_bucket, uint32_t *free_distance)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    uint32_t move_bucket, free_dist;
 | 
			
		||||
    move_bucket = (free_bucket - (HH_HOP_RANGE - 1)) & idxmask;
 | 
			
		||||
    for (free_dist = HH_HOP_RANGE - 1; free_dist > 0; free_dist--) {
 | 
			
		||||
        uint32_t move_free_distance = NOT_A_BUCKET;
 | 
			
		||||
        uint32_t mask = 1;
 | 
			
		||||
        uint32_t i;
 | 
			
		||||
        for (i = 0; i < free_dist; i++, mask <<= 1) {
 | 
			
		||||
            if (mask & rt->buckets[move_bucket].hopinfo) {
 | 
			
		||||
                move_free_distance = i;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (move_free_distance != NOT_A_BUCKET) {
 | 
			
		||||
            uint32_t new_free_bucket = (move_bucket + move_free_distance) & idxmask;
 | 
			
		||||
            rt->buckets[move_bucket].hopinfo |= 1u << free_dist;
 | 
			
		||||
            rt->buckets[free_bucket].data = rt->buckets[new_free_bucket].data;
 | 
			
		||||
            rt->buckets[new_free_bucket].data = NULL;
 | 
			
		||||
            rt->buckets[move_bucket].hopinfo &= ~(1u << move_free_distance);
 | 
			
		||||
            *free_distance -= free_dist - move_free_distance;
 | 
			
		||||
            return new_free_bucket;
 | 
			
		||||
        }
 | 
			
		||||
        move_bucket = (move_bucket + 1) & idxmask;
 | 
			
		||||
    }
 | 
			
		||||
    return NOT_A_BUCKET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_hh_resize (struct ddsrt_hh *rt)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_hh_bucket *bs1;
 | 
			
		||||
    uint32_t i, idxmask0, idxmask1;
 | 
			
		||||
 | 
			
		||||
    bs1 = ddsrt_malloc (2 * rt->size * sizeof (*rt->buckets));
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < 2 * rt->size; i++) {
 | 
			
		||||
        bs1[i].hopinfo = 0;
 | 
			
		||||
        bs1[i].data = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    idxmask0 = rt->size - 1;
 | 
			
		||||
    idxmask1 = 2 * rt->size - 1;
 | 
			
		||||
    for (i = 0; i < rt->size; i++) {
 | 
			
		||||
        void *data = rt->buckets[i].data;
 | 
			
		||||
        if (data) {
 | 
			
		||||
            const uint32_t hash = rt->hash (data);
 | 
			
		||||
            const uint32_t old_start_bucket = hash & idxmask0;
 | 
			
		||||
            const uint32_t new_start_bucket = hash & idxmask1;
 | 
			
		||||
            const uint32_t dist = (i >= old_start_bucket) ? (i - old_start_bucket) : (rt->size + i - old_start_bucket);
 | 
			
		||||
            const uint32_t newb = (new_start_bucket + dist) & idxmask1;
 | 
			
		||||
            assert (dist < HH_HOP_RANGE);
 | 
			
		||||
            bs1[new_start_bucket].hopinfo |= 1u << dist;
 | 
			
		||||
            bs1[newb].data = data;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_free (rt->buckets);
 | 
			
		||||
    rt->size *= 2;
 | 
			
		||||
    rt->buckets = bs1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ddsrt_hh_add (struct ddsrt_hh * __restrict rt, const void * __restrict data)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t hash = rt->hash (data);
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    const uint32_t start_bucket = hash & idxmask;
 | 
			
		||||
    uint32_t free_distance, free_bucket;
 | 
			
		||||
 | 
			
		||||
    if (ddsrt_hh_lookup_internal (rt, start_bucket, data)) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free_bucket = start_bucket;
 | 
			
		||||
    for (free_distance = 0; free_distance < HH_ADD_RANGE; free_distance++) {
 | 
			
		||||
        if (rt->buckets[free_bucket].data == NULL)
 | 
			
		||||
            break;
 | 
			
		||||
        free_bucket = (free_bucket + 1) & idxmask;
 | 
			
		||||
    }
 | 
			
		||||
    if (free_distance < HH_ADD_RANGE) {
 | 
			
		||||
        do {
 | 
			
		||||
            if (free_distance < HH_HOP_RANGE) {
 | 
			
		||||
                assert ((uint32_t) free_bucket == ((start_bucket + free_distance) & idxmask));
 | 
			
		||||
                rt->buckets[start_bucket].hopinfo |= 1u << free_distance;
 | 
			
		||||
                rt->buckets[free_bucket].data = (void *) data;
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
            free_bucket = ddsrt_hh_find_closer_free_bucket (rt, free_bucket, &free_distance);
 | 
			
		||||
            assert (free_bucket == NOT_A_BUCKET || free_bucket <= idxmask);
 | 
			
		||||
        } while (free_bucket != NOT_A_BUCKET);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_hh_resize (rt);
 | 
			
		||||
    return ddsrt_hh_add (rt, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ddsrt_hh_remove (struct ddsrt_hh * __restrict rt, const void * __restrict template)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t hash = rt->hash (template);
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    const uint32_t bucket = hash & idxmask;
 | 
			
		||||
    uint32_t hopinfo;
 | 
			
		||||
    uint32_t idx;
 | 
			
		||||
    hopinfo = rt->buckets[bucket].hopinfo;
 | 
			
		||||
    for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
 | 
			
		||||
        if (hopinfo & 1) {
 | 
			
		||||
            const uint32_t bidx = (bucket + idx) & idxmask;
 | 
			
		||||
            void *data = rt->buckets[bidx].data;
 | 
			
		||||
            if (data && rt->equals (data, template)) {
 | 
			
		||||
                rt->buckets[bidx].data = NULL;
 | 
			
		||||
                rt->buckets[bucket].hopinfo &= ~(1u << idx);
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_hh_enum (struct ddsrt_hh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
    for (i = 0; i < rt->size; i++) {
 | 
			
		||||
        void *data = rt->buckets[i].data;
 | 
			
		||||
        if (data) {
 | 
			
		||||
            f (data, f_arg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_hh_iter_first (struct ddsrt_hh * __restrict rt, struct ddsrt_hh_iter * __restrict iter)
 | 
			
		||||
{
 | 
			
		||||
    iter->hh = rt;
 | 
			
		||||
    iter->cursor = 0;
 | 
			
		||||
    return ddsrt_hh_iter_next (iter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_hh_iter_next (struct ddsrt_hh_iter * __restrict iter)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_hh *rt = iter->hh;
 | 
			
		||||
    while (iter->cursor < rt->size) {
 | 
			
		||||
        void *data = rt->buckets[iter->cursor].data;
 | 
			
		||||
        iter->cursor++;
 | 
			
		||||
        if (data) {
 | 
			
		||||
            return data;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/************* SEQUENTIAL VERSION WITH EMBEDDED DATA ***************/
 | 
			
		||||
 | 
			
		||||
struct ddsrt_ehh_bucket {
 | 
			
		||||
    uint32_t hopinfo;
 | 
			
		||||
    uint32_t inuse;
 | 
			
		||||
    char data[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ddsrt_ehh {
 | 
			
		||||
    uint32_t size; /* power of 2 */
 | 
			
		||||
    size_t elemsz;
 | 
			
		||||
    size_t bucketsz;
 | 
			
		||||
    char *buckets; /* ehhBucket, but embedded data messes up the layout */
 | 
			
		||||
    ddsrt_hh_hash_fn hash;
 | 
			
		||||
    ddsrt_hh_equals_fn equals;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void ddsrt_ehh_init (struct ddsrt_ehh *rt, size_t elemsz, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t size = HH_HOP_RANGE;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
    while (size < init_size) {
 | 
			
		||||
        size *= 2;
 | 
			
		||||
    }
 | 
			
		||||
    rt->hash = hash;
 | 
			
		||||
    rt->equals = equals;
 | 
			
		||||
    rt->size = size;
 | 
			
		||||
    rt->elemsz = elemsz;
 | 
			
		||||
    rt->bucketsz = sizeof (struct ddsrt_ehh_bucket) + ((elemsz+7) & ~(size_t)7);
 | 
			
		||||
    rt->buckets = ddsrt_malloc (size * rt->bucketsz);
 | 
			
		||||
    for (i = 0; i < size; i++) {
 | 
			
		||||
        struct ddsrt_ehh_bucket *b = (struct ddsrt_ehh_bucket *) (rt->buckets + i * rt->bucketsz);
 | 
			
		||||
        b->hopinfo = 0;
 | 
			
		||||
        b->inuse = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_ehh_fini (struct ddsrt_ehh *rt)
 | 
			
		||||
{
 | 
			
		||||
    ddsrt_free (rt->buckets);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ddsrt_ehh *ddsrt_ehh_new (size_t elemsz, uint32_t init_size, ddsrt_hh_hash_fn hash, ddsrt_hh_equals_fn equals)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_ehh *hh = ddsrt_malloc (sizeof (*hh));
 | 
			
		||||
    ddsrt_ehh_init (hh, elemsz, init_size, hash, equals);
 | 
			
		||||
    return hh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_ehh_free (struct ddsrt_ehh * __restrict hh)
 | 
			
		||||
{
 | 
			
		||||
    ddsrt_ehh_fini (hh);
 | 
			
		||||
    ddsrt_free (hh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *ddsrt_ehh_lookup_internal (const struct ddsrt_ehh *rt, uint32_t bucket, const void *template)
 | 
			
		||||
{
 | 
			
		||||
    const struct ddsrt_ehh_bucket *b = (const struct ddsrt_ehh_bucket *) (rt->buckets + bucket * rt->bucketsz);
 | 
			
		||||
    uint32_t hopinfo = b->hopinfo;
 | 
			
		||||
 | 
			
		||||
    if (hopinfo & 1) {
 | 
			
		||||
        if (b->inuse && rt->equals (b->data, template)) {
 | 
			
		||||
            return (void *) b->data;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        hopinfo >>= 1;
 | 
			
		||||
        if (++bucket == rt->size) {
 | 
			
		||||
            bucket = 0;
 | 
			
		||||
        }
 | 
			
		||||
        if (hopinfo & 1) {
 | 
			
		||||
            b = (const struct ddsrt_ehh_bucket *) (rt->buckets + bucket * rt->bucketsz);
 | 
			
		||||
            if (b->inuse && rt->equals (b->data, template)) {
 | 
			
		||||
                return (void *) b->data;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } while (hopinfo != 0);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_ehh_lookup (const struct ddsrt_ehh * __restrict rt, const void * __restrict template)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t hash = rt->hash (template);
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    const uint32_t bucket = hash & idxmask;
 | 
			
		||||
    return ddsrt_ehh_lookup_internal (rt, bucket, template);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t ddsrt_ehh_find_closer_free_bucket (struct ddsrt_ehh *rt, uint32_t free_bucket, uint32_t *free_distance)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    uint32_t move_bucket, free_dist;
 | 
			
		||||
    move_bucket = (free_bucket - (HH_HOP_RANGE - 1)) & idxmask;
 | 
			
		||||
    for (free_dist = HH_HOP_RANGE - 1; free_dist > 0; free_dist--) {
 | 
			
		||||
        struct ddsrt_ehh_bucket * const mb = (struct ddsrt_ehh_bucket *) (rt->buckets + move_bucket * rt->bucketsz);
 | 
			
		||||
        uint32_t move_free_distance = NOT_A_BUCKET;
 | 
			
		||||
        uint32_t mask = 1;
 | 
			
		||||
        uint32_t i;
 | 
			
		||||
        for (i = 0; i < free_dist; i++, mask <<= 1) {
 | 
			
		||||
            if (mask & mb->hopinfo) {
 | 
			
		||||
                move_free_distance = i;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (move_free_distance != NOT_A_BUCKET) {
 | 
			
		||||
            uint32_t new_free_bucket = (move_bucket + move_free_distance) & idxmask;
 | 
			
		||||
            struct ddsrt_ehh_bucket * const fb = (struct ddsrt_ehh_bucket *) (rt->buckets + free_bucket * rt->bucketsz);
 | 
			
		||||
            struct ddsrt_ehh_bucket * const nfb = (struct ddsrt_ehh_bucket *) (rt->buckets + new_free_bucket * rt->bucketsz);
 | 
			
		||||
            mb->hopinfo |= 1u << free_dist;
 | 
			
		||||
            fb->inuse = 1;
 | 
			
		||||
            memcpy (fb->data, nfb->data, rt->elemsz);
 | 
			
		||||
            nfb->inuse = 0;
 | 
			
		||||
            mb->hopinfo &= ~(1u << move_free_distance);
 | 
			
		||||
            *free_distance -= free_dist - move_free_distance;
 | 
			
		||||
            return new_free_bucket;
 | 
			
		||||
        }
 | 
			
		||||
        move_bucket = (move_bucket + 1) & idxmask;
 | 
			
		||||
    }
 | 
			
		||||
    return NOT_A_BUCKET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_ehh_resize (struct ddsrt_ehh *rt)
 | 
			
		||||
{
 | 
			
		||||
    char *bs1;
 | 
			
		||||
    uint32_t i, idxmask0, idxmask1;
 | 
			
		||||
 | 
			
		||||
    bs1 = ddsrt_malloc (2 * rt->size * rt->bucketsz);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < 2 * rt->size; i++) {
 | 
			
		||||
        struct ddsrt_ehh_bucket *b = (struct ddsrt_ehh_bucket *) (bs1 + i * rt->bucketsz);
 | 
			
		||||
        b->hopinfo = 0;
 | 
			
		||||
        b->inuse = 0;
 | 
			
		||||
    }
 | 
			
		||||
    idxmask0 = rt->size - 1;
 | 
			
		||||
    idxmask1 = 2 * rt->size - 1;
 | 
			
		||||
    for (i = 0; i < rt->size; i++) {
 | 
			
		||||
        struct ddsrt_ehh_bucket const * const b = (struct ddsrt_ehh_bucket *) (rt->buckets + i * rt->bucketsz);
 | 
			
		||||
        if (b->inuse) {
 | 
			
		||||
            const uint32_t hash = rt->hash (b->data);
 | 
			
		||||
            const uint32_t old_start_bucket = hash & idxmask0;
 | 
			
		||||
            const uint32_t new_start_bucket = hash & idxmask1;
 | 
			
		||||
            const uint32_t dist = (i >= old_start_bucket) ? (i - old_start_bucket) : (rt->size + i - old_start_bucket);
 | 
			
		||||
            const uint32_t newb = (new_start_bucket + dist) & idxmask1;
 | 
			
		||||
            struct ddsrt_ehh_bucket * const nsb = (struct ddsrt_ehh_bucket *) (bs1 + new_start_bucket * rt->bucketsz);
 | 
			
		||||
            struct ddsrt_ehh_bucket * const nb = (struct ddsrt_ehh_bucket *) (bs1 + newb * rt->bucketsz);
 | 
			
		||||
            assert (dist < HH_HOP_RANGE);
 | 
			
		||||
            assert (!nb->inuse);
 | 
			
		||||
            nsb->hopinfo |= 1u << dist;
 | 
			
		||||
            nb->inuse = 1;
 | 
			
		||||
            memcpy (nb->data, b->data, rt->elemsz);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_free (rt->buckets);
 | 
			
		||||
    rt->size *= 2;
 | 
			
		||||
    rt->buckets = bs1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ddsrt_ehh_add (struct ddsrt_ehh * __restrict rt, const void * __restrict data)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t hash = rt->hash (data);
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    const uint32_t start_bucket = hash & idxmask;
 | 
			
		||||
    uint32_t free_distance, free_bucket;
 | 
			
		||||
 | 
			
		||||
    if (ddsrt_ehh_lookup_internal (rt, start_bucket, data)) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free_bucket = start_bucket;
 | 
			
		||||
    for (free_distance = 0; free_distance < HH_ADD_RANGE; free_distance++) {
 | 
			
		||||
        struct ddsrt_ehh_bucket const * const fb = (struct ddsrt_ehh_bucket *) (rt->buckets + free_bucket * rt->bucketsz);
 | 
			
		||||
        if (!fb->inuse) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        free_bucket = (free_bucket + 1) & idxmask;
 | 
			
		||||
    }
 | 
			
		||||
    if (free_distance < HH_ADD_RANGE) {
 | 
			
		||||
        do {
 | 
			
		||||
            if (free_distance < HH_HOP_RANGE) {
 | 
			
		||||
                struct ddsrt_ehh_bucket * const sb = (struct ddsrt_ehh_bucket *) (rt->buckets + start_bucket * rt->bucketsz);
 | 
			
		||||
                struct ddsrt_ehh_bucket * const fb = (struct ddsrt_ehh_bucket *) (rt->buckets + free_bucket * rt->bucketsz);
 | 
			
		||||
                assert ((uint32_t) free_bucket == ((start_bucket + free_distance) & idxmask));
 | 
			
		||||
                sb->hopinfo |= 1u << free_distance;
 | 
			
		||||
                fb->inuse = 1;
 | 
			
		||||
                memcpy (fb->data, data, rt->elemsz);
 | 
			
		||||
                assert (ddsrt_ehh_lookup_internal (rt, start_bucket, data));
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
            free_bucket = ddsrt_ehh_find_closer_free_bucket (rt, free_bucket, &free_distance);
 | 
			
		||||
            assert (free_bucket == NOT_A_BUCKET || free_bucket <= idxmask);
 | 
			
		||||
        } while (free_bucket != NOT_A_BUCKET);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_ehh_resize (rt);
 | 
			
		||||
    return ddsrt_ehh_add (rt, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ddsrt_ehh_remove (struct ddsrt_ehh * __restrict rt, const void * __restrict template)
 | 
			
		||||
{
 | 
			
		||||
    const uint32_t hash = rt->hash (template);
 | 
			
		||||
    const uint32_t idxmask = rt->size - 1;
 | 
			
		||||
    const uint32_t bucket = hash & idxmask;
 | 
			
		||||
    uint32_t hopinfo;
 | 
			
		||||
    struct ddsrt_ehh_bucket *sb;
 | 
			
		||||
    uint32_t idx;
 | 
			
		||||
    sb = (struct ddsrt_ehh_bucket *) (rt->buckets + bucket * rt->bucketsz);
 | 
			
		||||
    hopinfo = sb->hopinfo;
 | 
			
		||||
    for (idx = 0; hopinfo != 0; hopinfo >>= 1, idx++) {
 | 
			
		||||
        if (hopinfo & 1) {
 | 
			
		||||
            const uint32_t bidx = (bucket + idx) & idxmask;
 | 
			
		||||
            struct ddsrt_ehh_bucket *b = (struct ddsrt_ehh_bucket *) (rt->buckets + bidx * rt->bucketsz);
 | 
			
		||||
            if (b->inuse && rt->equals (b->data, template)) {
 | 
			
		||||
                assert (ddsrt_ehh_lookup_internal(rt, bucket, template));
 | 
			
		||||
                b->inuse = 0;
 | 
			
		||||
                sb->hopinfo &= ~(1u << idx);
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    assert (!ddsrt_ehh_lookup_internal(rt, bucket, template));
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_ehh_enum (struct ddsrt_ehh * __restrict rt, void (*f) (void *a, void *f_arg), void *f_arg)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
    for (i = 0; i < rt->size; i++) {
 | 
			
		||||
        struct ddsrt_ehh_bucket *b = (struct ddsrt_ehh_bucket *) (rt->buckets + i * rt->bucketsz);
 | 
			
		||||
        if (b->inuse) {
 | 
			
		||||
            f (b->data, f_arg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_ehh_iter_first (struct ddsrt_ehh * __restrict rt, struct ddsrt_ehh_iter * __restrict iter)
 | 
			
		||||
{
 | 
			
		||||
    iter->hh = rt;
 | 
			
		||||
    iter->cursor = 0;
 | 
			
		||||
    return ddsrt_ehh_iter_next (iter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *ddsrt_ehh_iter_next (struct ddsrt_ehh_iter * __restrict iter)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_ehh *rt = iter->hh;
 | 
			
		||||
    while (iter->cursor < rt->size) {
 | 
			
		||||
        struct ddsrt_ehh_bucket *b = (struct ddsrt_ehh_bucket *) (rt->buckets + iter->cursor * rt->bucketsz);
 | 
			
		||||
        iter->cursor++;
 | 
			
		||||
        if (b->inuse) {
 | 
			
		||||
            return b->data;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										285
									
								
								src/ddsrt/src/thread_pool.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								src/ddsrt/src/thread_pool.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,285 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/io.h"
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds/ddsrt/sync.h"
 | 
			
		||||
#include "dds/ddsrt/threads.h"
 | 
			
		||||
#include "dds/ddsrt/thread_pool.h"
 | 
			
		||||
 | 
			
		||||
typedef struct ddsi_work_queue_job
 | 
			
		||||
{
 | 
			
		||||
    struct ddsi_work_queue_job * m_next_job; /* Jobs list pointer */
 | 
			
		||||
    void (*m_fn) (void *arg);                   /* Thread function */
 | 
			
		||||
    void * m_arg;                            /* Thread function argument */
 | 
			
		||||
}
 | 
			
		||||
* ddsi_work_queue_job_t;
 | 
			
		||||
 | 
			
		||||
struct ddsrt_thread_pool_s
 | 
			
		||||
{
 | 
			
		||||
    ddsi_work_queue_job_t m_jobs;      /* Job queue */
 | 
			
		||||
    ddsi_work_queue_job_t m_jobs_tail; /* Tail of job queue */
 | 
			
		||||
    ddsi_work_queue_job_t m_free;      /* Job free list */
 | 
			
		||||
    uint32_t m_thread_max;            /* Maximum number of threads */
 | 
			
		||||
    uint32_t m_thread_min;            /* Minimum number of threads */
 | 
			
		||||
    uint32_t m_threads;               /* Current number of threads */
 | 
			
		||||
    uint32_t m_waiting;               /* Number of threads waiting for a job */
 | 
			
		||||
    uint32_t m_job_count;             /* Number of queued jobs */
 | 
			
		||||
    uint32_t m_job_max;               /* Maximum number of jobs to queue */
 | 
			
		||||
    unsigned short m_count;            /* Counter for thread name */
 | 
			
		||||
    ddsrt_threadattr_t m_attr;              /* Thread creation attribute */
 | 
			
		||||
    ddsrt_cond_t m_cv;                    /* Thread wait semaphore */
 | 
			
		||||
    ddsrt_mutex_t m_mutex;                  /* Pool guard mutex */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint32_t ddsrt_thread_start_fn (void * arg)
 | 
			
		||||
{
 | 
			
		||||
    ddsi_work_queue_job_t job;
 | 
			
		||||
    ddsrt_thread_pool pool = (ddsrt_thread_pool) arg;
 | 
			
		||||
 | 
			
		||||
    /* Thread loops, pulling jobs from queue */
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_lock (&pool->m_mutex);
 | 
			
		||||
 | 
			
		||||
    while (pool->m_jobs != NULL) {
 | 
			
		||||
        /* Wait for job */
 | 
			
		||||
        ddsrt_cond_wait (&pool->m_cv, &pool->m_mutex);
 | 
			
		||||
 | 
			
		||||
        /* Check if pool deleted or being purged */
 | 
			
		||||
 | 
			
		||||
        if (pool->m_jobs) {
 | 
			
		||||
            /* Take job from queue head */
 | 
			
		||||
 | 
			
		||||
            pool->m_waiting--;
 | 
			
		||||
            job = pool->m_jobs;
 | 
			
		||||
            pool->m_jobs = job->m_next_job;
 | 
			
		||||
            pool->m_job_count--;
 | 
			
		||||
 | 
			
		||||
            ddsrt_mutex_unlock (&pool->m_mutex);
 | 
			
		||||
 | 
			
		||||
            /* Do job */
 | 
			
		||||
 | 
			
		||||
            (job->m_fn) (job->m_arg);
 | 
			
		||||
 | 
			
		||||
            /* Put job back on free list */
 | 
			
		||||
 | 
			
		||||
            ddsrt_mutex_lock (&pool->m_mutex);
 | 
			
		||||
            pool->m_waiting++;
 | 
			
		||||
            job->m_next_job = pool->m_free;
 | 
			
		||||
            pool->m_free = job;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (--pool->m_threads) {
 | 
			
		||||
        /* last to leave triggers thread_pool_free */
 | 
			
		||||
        ddsrt_cond_broadcast (&pool->m_cv);
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_mutex_unlock (&pool->m_mutex);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static dds_retcode_t ddsrt_thread_pool_new_thread (ddsrt_thread_pool pool)
 | 
			
		||||
{
 | 
			
		||||
    static unsigned char pools = 0; /* Pool counter - TODO make atomic */
 | 
			
		||||
 | 
			
		||||
    char name [64];
 | 
			
		||||
    ddsrt_thread_t id;
 | 
			
		||||
    dds_retcode_t res;
 | 
			
		||||
 | 
			
		||||
    (void) snprintf (name, sizeof (name), "OSPL-%u-%u", pools++, pool->m_count++);
 | 
			
		||||
    res = ddsrt_thread_create (&id, name, &pool->m_attr, &ddsrt_thread_start_fn, pool);
 | 
			
		||||
 | 
			
		||||
    if (res == DDS_RETCODE_OK)
 | 
			
		||||
    {
 | 
			
		||||
        ddsrt_mutex_lock (&pool->m_mutex);
 | 
			
		||||
        pool->m_threads++;
 | 
			
		||||
        pool->m_waiting++;
 | 
			
		||||
        ddsrt_mutex_unlock (&pool->m_mutex);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ddsrt_thread_pool ddsrt_thread_pool_new (uint32_t threads, uint32_t max_threads, uint32_t max_queue, ddsrt_threadattr_t * attr)
 | 
			
		||||
{
 | 
			
		||||
    ddsrt_thread_pool pool;
 | 
			
		||||
    ddsi_work_queue_job_t job;
 | 
			
		||||
 | 
			
		||||
    /* Sanity check QoS */
 | 
			
		||||
 | 
			
		||||
    if (max_threads && (max_threads < threads))
 | 
			
		||||
    {
 | 
			
		||||
        max_threads = threads;
 | 
			
		||||
    }
 | 
			
		||||
    if (max_queue && (max_queue < threads))
 | 
			
		||||
    {
 | 
			
		||||
        max_queue = threads;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pool = ddsrt_malloc (sizeof (*pool));
 | 
			
		||||
    memset (pool, 0, sizeof (*pool));
 | 
			
		||||
    pool->m_thread_min = threads;
 | 
			
		||||
    pool->m_thread_max = max_threads;
 | 
			
		||||
    pool->m_job_max = max_queue;
 | 
			
		||||
    ddsrt_threadattr_init (&pool->m_attr);
 | 
			
		||||
    ddsrt_mutex_init (&pool->m_mutex);
 | 
			
		||||
    ddsrt_cond_init (&pool->m_cv);
 | 
			
		||||
 | 
			
		||||
    if (attr)
 | 
			
		||||
    {
 | 
			
		||||
        pool->m_attr = *attr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Create initial threads and jobs */
 | 
			
		||||
 | 
			
		||||
    while (threads--)
 | 
			
		||||
    {
 | 
			
		||||
        if (ddsrt_thread_pool_new_thread (pool) != DDS_RETCODE_OK)
 | 
			
		||||
        {
 | 
			
		||||
            ddsrt_thread_pool_free (pool);
 | 
			
		||||
            pool = NULL;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        job = ddsrt_malloc (sizeof (*job));
 | 
			
		||||
        job->m_next_job = pool->m_free;
 | 
			
		||||
        pool->m_free = job;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return pool;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_thread_pool_free (ddsrt_thread_pool pool)
 | 
			
		||||
{
 | 
			
		||||
    ddsi_work_queue_job_t job;
 | 
			
		||||
 | 
			
		||||
    if (pool == NULL)
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_lock (&pool->m_mutex);
 | 
			
		||||
 | 
			
		||||
    /* Delete all pending jobs from queue */
 | 
			
		||||
 | 
			
		||||
    while (pool->m_jobs)
 | 
			
		||||
    {
 | 
			
		||||
        job = pool->m_jobs;
 | 
			
		||||
        pool->m_jobs = job->m_next_job;
 | 
			
		||||
        ddsrt_free (job);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Wake all waiting threads */
 | 
			
		||||
 | 
			
		||||
    ddsrt_cond_broadcast (&pool->m_cv);
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_unlock (&pool->m_mutex);
 | 
			
		||||
 | 
			
		||||
    /* Wait for threads to complete */
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_lock (&pool->m_mutex);
 | 
			
		||||
    while (pool->m_threads != 0)
 | 
			
		||||
        ddsrt_cond_wait (&pool->m_cv, &pool->m_mutex);
 | 
			
		||||
    ddsrt_mutex_unlock (&pool->m_mutex);
 | 
			
		||||
 | 
			
		||||
    /* Delete all free jobs from queue */
 | 
			
		||||
 | 
			
		||||
    while (pool->m_free)
 | 
			
		||||
    {
 | 
			
		||||
        job = pool->m_free;
 | 
			
		||||
        pool->m_free = job->m_next_job;
 | 
			
		||||
        ddsrt_free (job);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_cond_destroy (&pool->m_cv);
 | 
			
		||||
    ddsrt_mutex_destroy (&pool->m_mutex);
 | 
			
		||||
    ddsrt_free (pool);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dds_retcode_t ddsrt_thread_pool_submit (ddsrt_thread_pool pool, void (*fn) (void *arg), void * arg)
 | 
			
		||||
{
 | 
			
		||||
    dds_retcode_t res = DDS_RETCODE_OK;
 | 
			
		||||
    ddsi_work_queue_job_t job;
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_lock (&pool->m_mutex);
 | 
			
		||||
 | 
			
		||||
    if (pool->m_job_max && pool->m_job_count >= pool->m_job_max)
 | 
			
		||||
    {
 | 
			
		||||
        /* Maximum number of jobs reached */
 | 
			
		||||
 | 
			
		||||
        res = DDS_RETCODE_TRY_AGAIN;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        /* Get or create new job */
 | 
			
		||||
 | 
			
		||||
        if (pool->m_free)
 | 
			
		||||
        {
 | 
			
		||||
            job = pool->m_free;
 | 
			
		||||
            pool->m_free = job->m_next_job;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            job = ddsrt_malloc (sizeof (*job));
 | 
			
		||||
        }
 | 
			
		||||
        job->m_next_job = NULL;
 | 
			
		||||
        job->m_fn = fn;
 | 
			
		||||
        job->m_arg = arg;
 | 
			
		||||
 | 
			
		||||
        /* Add new job to end of queue */
 | 
			
		||||
 | 
			
		||||
        if (pool->m_jobs)
 | 
			
		||||
        {
 | 
			
		||||
            pool->m_jobs_tail->m_next_job = job;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            pool->m_jobs = job;
 | 
			
		||||
        }
 | 
			
		||||
        pool->m_jobs_tail = job;
 | 
			
		||||
        pool->m_job_count++;
 | 
			
		||||
 | 
			
		||||
        /* Allocate thread if more jobs than waiting threads and within maximum */
 | 
			
		||||
 | 
			
		||||
        if (pool->m_waiting < pool->m_job_count)
 | 
			
		||||
        {
 | 
			
		||||
            if ((pool->m_thread_max == 0) || (pool->m_threads < pool->m_thread_max))
 | 
			
		||||
            {
 | 
			
		||||
                /* OK if fails as have queued job */
 | 
			
		||||
                (void) ddsrt_thread_pool_new_thread (pool);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Wakeup processing thread */
 | 
			
		||||
 | 
			
		||||
        ddsrt_cond_signal (&pool->m_cv);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_unlock (&pool->m_mutex);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_thread_pool_purge (ddsrt_thread_pool pool)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t total;
 | 
			
		||||
 | 
			
		||||
    ddsrt_mutex_lock (&pool->m_mutex);
 | 
			
		||||
    total = pool->m_threads;
 | 
			
		||||
    while (pool->m_waiting && (total > pool->m_thread_min))
 | 
			
		||||
    {
 | 
			
		||||
        pool->m_waiting--;
 | 
			
		||||
        total--;
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_cond_broadcast (&pool->m_cv);
 | 
			
		||||
    ddsrt_mutex_unlock (&pool->m_mutex);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										722
									
								
								src/ddsrt/src/xmlparser.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										722
									
								
								src/ddsrt/src/xmlparser.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,722 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
 | 
			
		||||
 *
 | 
			
		||||
 * This program and the accompanying materials are made available under the
 | 
			
		||||
 * terms of the Eclipse Public License v. 2.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
 | 
			
		||||
 * v. 1.0 which is available at
 | 
			
		||||
 * http://www.eclipse.org/org/documents/edl-v10.php.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include "dds/ddsrt/heap.h"
 | 
			
		||||
#include "dds/ddsrt/misc.h"
 | 
			
		||||
#include "dds/ddsrt/string.h"
 | 
			
		||||
#include "dds/ddsrt/xmlparser.h"
 | 
			
		||||
 | 
			
		||||
#define TOK_EOF -1
 | 
			
		||||
#define TOK_OPEN_TAG -2
 | 
			
		||||
#define TOK_ID -3
 | 
			
		||||
#define TOK_STRING -4
 | 
			
		||||
#define TOK_CLOSE_TAG -5
 | 
			
		||||
#define TOK_SHORTHAND_CLOSE_TAG -6
 | 
			
		||||
#define TOK_ERROR -7
 | 
			
		||||
 | 
			
		||||
#define NOMARKER (~(size_t)0)
 | 
			
		||||
 | 
			
		||||
struct ddsrt_xmlp_state {
 | 
			
		||||
    size_t cbufp; /* current position in cbuf */
 | 
			
		||||
    size_t cbufn; /* number of bytes in cbuf (cbufp <= cbufn) */
 | 
			
		||||
    size_t cbufmax; /* allocated size of cbuf (cbufn <= cbufmax) */
 | 
			
		||||
    size_t cbufmark; /* NORMARKER or marker position (cbufmark <= cbufp) for rewinding */
 | 
			
		||||
    char *cbuf; /* parser input buffer */
 | 
			
		||||
    FILE *fp; /* file to refill cbuf from, or NULL if parsing a string */
 | 
			
		||||
    int line; /* current line number */
 | 
			
		||||
    int prevline; /* line number at last token */
 | 
			
		||||
    int linemark; /* line number at marker */
 | 
			
		||||
    int peektok; /* token lookahead (peek token when no next token available) */
 | 
			
		||||
    char *peekpayload; /* payload associated with lookahead */
 | 
			
		||||
    int error; /* error flag to call error callback only once */
 | 
			
		||||
    size_t tpp; /* length of token payload */
 | 
			
		||||
    size_t tpsz; /* allocated size of tp */
 | 
			
		||||
    char *tp; /* token payload buffer */
 | 
			
		||||
    size_t tpescp; /* still escape sequences in tpescp .. tpp */
 | 
			
		||||
    int nest; /* current nesting level */
 | 
			
		||||
    void *varg; /* user argument to callback functions */
 | 
			
		||||
    int require_eof; /* if false, junk may follow top-level closing tag */
 | 
			
		||||
    struct ddsrt_xmlp_callbacks cb; /* user-supplied callbacks (or stubs) */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int cb_null_elem_open (void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name)
 | 
			
		||||
{
 | 
			
		||||
    DDSRT_UNUSED_ARG (varg);
 | 
			
		||||
    DDSRT_UNUSED_ARG (parentinfo);
 | 
			
		||||
    DDSRT_UNUSED_ARG (eleminfo);
 | 
			
		||||
    DDSRT_UNUSED_ARG (name);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cb_null_attr (void *varg, uintptr_t eleminfo, const char *name, const char *value)
 | 
			
		||||
{
 | 
			
		||||
    DDSRT_UNUSED_ARG (varg);
 | 
			
		||||
    DDSRT_UNUSED_ARG (eleminfo);
 | 
			
		||||
    DDSRT_UNUSED_ARG (name);
 | 
			
		||||
    DDSRT_UNUSED_ARG (value);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cb_null_elem_data (void *varg, uintptr_t eleminfo, const char *data)
 | 
			
		||||
{
 | 
			
		||||
    DDSRT_UNUSED_ARG (varg);
 | 
			
		||||
    DDSRT_UNUSED_ARG (eleminfo);
 | 
			
		||||
    DDSRT_UNUSED_ARG (data);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cb_null_elem_close (void *varg, uintptr_t eleminfo)
 | 
			
		||||
{
 | 
			
		||||
    DDSRT_UNUSED_ARG (varg);
 | 
			
		||||
    DDSRT_UNUSED_ARG (eleminfo);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cb_null_error (void *varg, const char *msg, int line)
 | 
			
		||||
{
 | 
			
		||||
    DDSRT_UNUSED_ARG (varg);
 | 
			
		||||
    DDSRT_UNUSED_ARG (msg);
 | 
			
		||||
    DDSRT_UNUSED_ARG (line);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_xmlp_new_common (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    st->cbufp = 0;
 | 
			
		||||
    st->cbufmark = NOMARKER;
 | 
			
		||||
    st->tpp = 0;
 | 
			
		||||
    st->tpescp = 0;
 | 
			
		||||
    st->tpsz = 1024;
 | 
			
		||||
    st->tp = ddsrt_malloc (st->tpsz);
 | 
			
		||||
    st->line = 1;
 | 
			
		||||
    st->prevline = 1;
 | 
			
		||||
    st->linemark = 0;
 | 
			
		||||
    st->peektok = 0;
 | 
			
		||||
    st->peekpayload = NULL;
 | 
			
		||||
    st->nest = 0;
 | 
			
		||||
    st->error = 0;
 | 
			
		||||
    st->require_eof = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ddsrt_xmlp_new_setCB (struct ddsrt_xmlp_state *st, void *varg, const struct ddsrt_xmlp_callbacks *cb)
 | 
			
		||||
{
 | 
			
		||||
    st->varg = varg;
 | 
			
		||||
    st->cb = *cb;
 | 
			
		||||
    if (st->cb.attr == 0) st->cb.attr = cb_null_attr;
 | 
			
		||||
    if (st->cb.elem_open == 0) st->cb.elem_open = cb_null_elem_open;
 | 
			
		||||
    if (st->cb.elem_data == 0) st->cb.elem_data = cb_null_elem_data;
 | 
			
		||||
    if (st->cb.elem_close == 0) st->cb.elem_close = cb_null_elem_close;
 | 
			
		||||
    if (st->cb.error == 0) st->cb.error = cb_null_error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ddsrt_xmlp_state *ddsrt_xmlp_new_file (FILE *fp, void *varg, const struct ddsrt_xmlp_callbacks *cb)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_xmlp_state *st;
 | 
			
		||||
    st = ddsrt_malloc (sizeof (*st));
 | 
			
		||||
    st->cbufn = 0;
 | 
			
		||||
    st->cbufmax = 8192;
 | 
			
		||||
    st->cbuf = ddsrt_malloc (st->cbufmax);
 | 
			
		||||
    st->fp = fp;
 | 
			
		||||
    ddsrt_xmlp_new_common (st);
 | 
			
		||||
    ddsrt_xmlp_new_setCB (st, varg, cb);
 | 
			
		||||
    return st;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ddsrt_xmlp_state *ddsrt_xmlp_new_string (const char *string, void *varg, const struct ddsrt_xmlp_callbacks *cb)
 | 
			
		||||
{
 | 
			
		||||
    struct ddsrt_xmlp_state *st;
 | 
			
		||||
    st = ddsrt_malloc (sizeof (*st));
 | 
			
		||||
    st->cbufn = strlen (string);
 | 
			
		||||
    st->cbufmax = st->cbufn;
 | 
			
		||||
    st->cbuf = (char *) string;
 | 
			
		||||
    st->fp = NULL;
 | 
			
		||||
    ddsrt_xmlp_new_common (st);
 | 
			
		||||
    ddsrt_xmlp_new_setCB (st, varg, cb);
 | 
			
		||||
    return st;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_xmlp_set_requireEOF (struct ddsrt_xmlp_state *st, int require_eof)
 | 
			
		||||
{
 | 
			
		||||
    st->require_eof = require_eof;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t ddsrt_xmlp_get_bufpos (const struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    return st->cbufp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ddsrt_xmlp_free (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    if (st->fp != NULL) {
 | 
			
		||||
        ddsrt_free (st->cbuf);
 | 
			
		||||
    }
 | 
			
		||||
    ddsrt_free (st->tp);
 | 
			
		||||
    ddsrt_free (st);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int make_chars_available (struct ddsrt_xmlp_state *st, size_t nmin)
 | 
			
		||||
{
 | 
			
		||||
    size_t n, pos;
 | 
			
		||||
    pos = (st->cbufmark != NOMARKER) ? st->cbufmark : st->cbufp;
 | 
			
		||||
    assert (st->cbufn >= st->cbufp);
 | 
			
		||||
    assert (st->cbufmax >= st->cbufn);
 | 
			
		||||
    assert (st->cbufmark == NOMARKER || st->cbufmark <= st->cbufp);
 | 
			
		||||
    /* fast-path available chars */
 | 
			
		||||
    if (st->cbufn - st->cbufp >= nmin) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    /* ensure buffer space is available */
 | 
			
		||||
    if (pos + nmin > st->cbufmax) {
 | 
			
		||||
        memmove (st->cbuf, st->cbuf + pos, st->cbufn - pos);
 | 
			
		||||
        st->cbufn -= pos;
 | 
			
		||||
        st->cbufp -= pos;
 | 
			
		||||
        if (st->cbufmark != NOMARKER) {
 | 
			
		||||
            st->cbufmark -= pos;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    /* buffer is owned by caller if fp = NULL, and by us if fp != NULL */
 | 
			
		||||
    if (st->cbufp + st->cbufmax < nmin && st->fp != NULL) {
 | 
			
		||||
        st->cbufmax = st->cbufp + nmin;
 | 
			
		||||
        st->cbuf = ddsrt_realloc (st->cbuf, st->cbufmax);
 | 
			
		||||
    }
 | 
			
		||||
    /* try to refill buffer if a backing file is present; eof (or end-of-string) is
 | 
			
		||||
       reached when this doesn't add any bytes to the buffer */
 | 
			
		||||
    if (st->fp != NULL) {
 | 
			
		||||
        n = fread (st->cbuf + st->cbufn, 1, st->cbufmax - st->cbufn, st->fp);
 | 
			
		||||
        st->cbufn += n;
 | 
			
		||||
    }
 | 
			
		||||
    return (st->cbufn - st->cbufp >= nmin);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_input_marker (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    assert (st->cbufmark == NOMARKER);
 | 
			
		||||
    st->cbufmark = st->cbufp;
 | 
			
		||||
    st->linemark = st->line;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void discard_input_marker (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    assert (st->cbufmark != NOMARKER);
 | 
			
		||||
    st->cbufmark = NOMARKER;
 | 
			
		||||
    st->linemark = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rewind_to_input_marker (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    assert (st->cbufmark != NOMARKER);
 | 
			
		||||
    st->cbufp = st->cbufmark;
 | 
			
		||||
    st->line = st->linemark;
 | 
			
		||||
    discard_input_marker (st);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int next_char (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    char c;
 | 
			
		||||
    if (!make_chars_available (st, 1)) {
 | 
			
		||||
        return TOK_EOF;
 | 
			
		||||
    }
 | 
			
		||||
    c = st->cbuf[st->cbufp++];
 | 
			
		||||
    if (c == '\n') {
 | 
			
		||||
        st->line++;
 | 
			
		||||
    }
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int peek_char (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    if (!make_chars_available (st, 1)) {
 | 
			
		||||
        return TOK_EOF;
 | 
			
		||||
    }
 | 
			
		||||
    return st->cbuf[st->cbufp];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int peek_chars (struct ddsrt_xmlp_state *st, const char *seq, int consume)
 | 
			
		||||
{
 | 
			
		||||
    size_t n = strlen (seq);
 | 
			
		||||
    if (!make_chars_available (st, n)) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (memcmp (st->cbuf + st->cbufp, seq, n) != 0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (consume) st->cbufp += n;
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qq_isspace (int x)
 | 
			
		||||
{
 | 
			
		||||
    return x == ' ' || x == '\t' || x == '\v' || x == '\r' || x == '\n';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qq_isidentfirst (int x)
 | 
			
		||||
{
 | 
			
		||||
    return (x >= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int qq_isidentcont (int x)
 | 
			
		||||
{
 | 
			
		||||
    return qq_isidentfirst (x) || (x >= '0' && x <= '9') || x == '_' || x == '-' || x == ':';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *unescape_into_utf8 (char *dst, unsigned cp)
 | 
			
		||||
{
 | 
			
		||||
    if (cp < 0x80) {
 | 
			
		||||
        *dst++ = (char) cp;
 | 
			
		||||
    } else if (cp <= 0x7ff) {
 | 
			
		||||
        *dst++ = (char) ((cp >> 6) + 0xc0);
 | 
			
		||||
        *dst++ = (char) ((cp & 0x3f) + 0x80);
 | 
			
		||||
    } else if (cp <= 0xffff) {
 | 
			
		||||
        *dst++ = (char) ((cp >> 12) + 0xe0);
 | 
			
		||||
        *dst++ = (char) (((cp >> 6) & 0x3f) + 0x80);
 | 
			
		||||
        *dst++ = (char) ((cp & 0x3f) + 0x80);
 | 
			
		||||
    } else if (cp <= 0x10ffff) {
 | 
			
		||||
        *dst++ = (char) ((cp >> 18) + 0xf0);
 | 
			
		||||
        *dst++ = (char) (((cp >> 12) & 0x3f) + 0x80);
 | 
			
		||||
        *dst++ = (char) (((cp >> 6) & 0x3f) + 0x80);
 | 
			
		||||
        *dst++ = (char) ((cp & 0x3f) + 0x80);
 | 
			
		||||
    } else {
 | 
			
		||||
        dst = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return dst;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DDSRT_WARNING_MSVC_OFF(4996);
 | 
			
		||||
static int unescape_insitu (char *buffer, size_t *n)
 | 
			
		||||
{
 | 
			
		||||
    const char *src = buffer;
 | 
			
		||||
    char const * const srcend = buffer + *n;
 | 
			
		||||
    char *dst = buffer;
 | 
			
		||||
    while (src < srcend)
 | 
			
		||||
    {
 | 
			
		||||
        if (*src != '&') {
 | 
			
		||||
            *dst++ = *src++;
 | 
			
		||||
        } else if (src + 1 == srcend) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        } else {
 | 
			
		||||
            char tmp[16], *ptmp = tmp;
 | 
			
		||||
            src++;
 | 
			
		||||
            while (ptmp < tmp + sizeof (tmp) && src < srcend) {
 | 
			
		||||
                char c = *src++;
 | 
			
		||||
                *ptmp++ = c;
 | 
			
		||||
                if (c == ';') {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (ptmp == tmp || *(ptmp-1) != ';') {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
            *--ptmp = 0;
 | 
			
		||||
            if (tmp[0] == '#') {
 | 
			
		||||
                unsigned cp;
 | 
			
		||||
                int pos;
 | 
			
		||||
                if (sscanf (tmp, "#x%x%n", &cp, &pos) == 1 && tmp[pos] == 0) {
 | 
			
		||||
                    ;
 | 
			
		||||
                } else if (sscanf (tmp, "#%u%n", &cp, &pos) == 1 && tmp[pos] == 0) {
 | 
			
		||||
                    ;
 | 
			
		||||
                } else {
 | 
			
		||||
                    return -1;
 | 
			
		||||
                }
 | 
			
		||||
                if ((dst = unescape_into_utf8(dst, cp)) == NULL) {
 | 
			
		||||
                    return -1;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (strcmp (tmp, "lt") == 0) {
 | 
			
		||||
                *dst++ = '<';
 | 
			
		||||
            } else if (strcmp (tmp, "gt") == 0) {
 | 
			
		||||
                *dst++ = '>';
 | 
			
		||||
            } else if (strcmp (tmp, "amp") == 0) {
 | 
			
		||||
                *dst++ = '&';
 | 
			
		||||
            } else if (strcmp (tmp, "apos") == 0) {
 | 
			
		||||
                *dst++ = '\'';
 | 
			
		||||
            } else if (strcmp (tmp, "quot") == 0) {
 | 
			
		||||
                *dst++ = '"';
 | 
			
		||||
            } else {
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    *n = (size_t) (dst - buffer);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
DDSRT_WARNING_MSVC_ON(4996);
 | 
			
		||||
 | 
			
		||||
static void discard_payload (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    st->tpp = 0;
 | 
			
		||||
    st->tpescp = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int append_to_payload (struct ddsrt_xmlp_state *st, int c, int islit)
 | 
			
		||||
{
 | 
			
		||||
    if (!islit) {
 | 
			
		||||
        st->tp[st->tpp++] = (char) c;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (st->tpescp < st->tpp) {
 | 
			
		||||
            size_t n = st->tpp - st->tpescp;
 | 
			
		||||
            if (unescape_insitu (st->tp + st->tpescp, &n) < 0) {
 | 
			
		||||
                discard_payload (st);
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
            st->tpp = st->tpescp + n;
 | 
			
		||||
        }
 | 
			
		||||
        st->tp[st->tpp++] = (char) c;
 | 
			
		||||
        st->tpescp = st->tpp;
 | 
			
		||||
    }
 | 
			
		||||
    if (st->tpp == st->tpsz) {
 | 
			
		||||
        st->tpsz += 1024;
 | 
			
		||||
        st->tp = ddsrt_realloc (st->tp, st->tpsz);
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int save_payload (char **payload, struct ddsrt_xmlp_state *st, int trim)
 | 
			
		||||
{
 | 
			
		||||
    char *p;
 | 
			
		||||
    if (st->tpescp < st->tpp) {
 | 
			
		||||
        size_t n = st->tpp - st->tpescp;
 | 
			
		||||
        if (unescape_insitu (st->tp + st->tpescp, &n) < 0) {
 | 
			
		||||
            discard_payload (st);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        st->tpp = st->tpescp + n;
 | 
			
		||||
    }
 | 
			
		||||
    if (payload == NULL) {
 | 
			
		||||
        p = NULL;
 | 
			
		||||
    } else if (st->tpp == 0) {
 | 
			
		||||
        p = ddsrt_strdup("");
 | 
			
		||||
    } else {
 | 
			
		||||
        size_t first = 0, last = st->tpp - 1;
 | 
			
		||||
        if (trim) {
 | 
			
		||||
            while (first <= last && qq_isspace (st->tp[first])) {
 | 
			
		||||
                first++;
 | 
			
		||||
            }
 | 
			
		||||
            while (first <= last && qq_isspace (st->tp[last]) && last > 0) {
 | 
			
		||||
                last--;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (first > last) {
 | 
			
		||||
            p = ddsrt_strdup("");
 | 
			
		||||
        } else {
 | 
			
		||||
            p = ddsrt_malloc (last - first + 2);
 | 
			
		||||
            /* Could be improved, parser error will be "invalid char sequence" if malloc fails. */
 | 
			
		||||
            memcpy (p, st->tp + first, last - first + 1);
 | 
			
		||||
            p[last - first + 1] = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    discard_payload (st);
 | 
			
		||||
    if (payload) {
 | 
			
		||||
        *payload = p;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int next_token_ident (struct ddsrt_xmlp_state *st, char **payload)
 | 
			
		||||
{
 | 
			
		||||
    while (qq_isidentcont (peek_char (st))) {
 | 
			
		||||
        if (append_to_payload (st, next_char (st), 0) < 0) {
 | 
			
		||||
            return TOK_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (save_payload (payload, st, 0) < 0) {
 | 
			
		||||
        return TOK_ERROR;
 | 
			
		||||
    } else {
 | 
			
		||||
        return TOK_ID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int next_token_tag_withoutclose (struct ddsrt_xmlp_state *st, char **payload)
 | 
			
		||||
{
 | 
			
		||||
    if (peek_chars (st, "<![CDATA[", 0)) {
 | 
			
		||||
        return next_char (st);
 | 
			
		||||
    } else {
 | 
			
		||||
        int tok = TOK_OPEN_TAG;
 | 
			
		||||
        /* pre: peek_char(st) == '<' */
 | 
			
		||||
        next_char (st);
 | 
			
		||||
        if (peek_char (st) == '/') {
 | 
			
		||||
            tok = TOK_CLOSE_TAG;
 | 
			
		||||
            next_char (st);
 | 
			
		||||
        }
 | 
			
		||||
        /* we only do tag names that are identifiers */
 | 
			
		||||
        if (!qq_isidentfirst (peek_char (st))) {
 | 
			
		||||
            return TOK_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
        next_token_ident (st, payload);
 | 
			
		||||
        return tok;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int next_token_string (struct ddsrt_xmlp_state *st, char **payload)
 | 
			
		||||
{
 | 
			
		||||
    /* pre: peek_char(st) == ('"' or '\'') */
 | 
			
		||||
    int endm = next_char (st);
 | 
			
		||||
    while (peek_char (st) != endm && peek_char (st) != TOK_EOF) {
 | 
			
		||||
        if (append_to_payload (st, next_char (st), 0) < 0) {
 | 
			
		||||
            return TOK_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (next_char (st) != endm) {
 | 
			
		||||
        discard_payload (st);
 | 
			
		||||
        return TOK_ERROR;
 | 
			
		||||
    } else if (save_payload (payload, st, 0) < 0) {
 | 
			
		||||
        return TOK_ERROR;
 | 
			
		||||
    } else {
 | 
			
		||||
        return TOK_STRING;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int skip_comment (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    if (!peek_chars (st, "<!--", 1)) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    while ((peek_char (st) != TOK_EOF && peek_char (st) != '-') || !peek_chars (st, "-->", 0)) {
 | 
			
		||||
        next_char (st);
 | 
			
		||||
    }
 | 
			
		||||
    if (peek_chars (st, "-->", 1)) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    } else {
 | 
			
		||||
        return TOK_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void processing_instruction (struct ddsrt_xmlp_state *st, const char *end)
 | 
			
		||||
{
 | 
			
		||||
    /* just after <?; skip everything up to and include ?> */
 | 
			
		||||
    while (peek_char (st) != TOK_EOF && !peek_chars (st, end, 1)) {
 | 
			
		||||
        next_char (st);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void drop_peek_token (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    st->peektok = 0;
 | 
			
		||||
    if (st->peekpayload) {
 | 
			
		||||
        ddsrt_free (st->peekpayload);
 | 
			
		||||
        st->peekpayload = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int next_token (struct ddsrt_xmlp_state *st, char **payload)
 | 
			
		||||
{
 | 
			
		||||
    /* Always return a valid pointer to allocated memory or a null
 | 
			
		||||
     pointer, regardless of token type */
 | 
			
		||||
    if (payload) {
 | 
			
		||||
        *payload = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (st->error) {
 | 
			
		||||
        return TOK_ERROR;
 | 
			
		||||
    } else if (st->peektok) {
 | 
			
		||||
        int tok = st->peektok;
 | 
			
		||||
        st->peektok = 0;
 | 
			
		||||
        if (payload) {
 | 
			
		||||
            *payload = st->peekpayload;
 | 
			
		||||
        } else if (st->peekpayload) {
 | 
			
		||||
            ddsrt_free (st->peekpayload);
 | 
			
		||||
            st->peekpayload = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        return tok;
 | 
			
		||||
    } else {
 | 
			
		||||
        int cmt, tok;
 | 
			
		||||
        st->prevline = st->line;
 | 
			
		||||
        do {
 | 
			
		||||
            while (qq_isspace (peek_char (st))) {
 | 
			
		||||
                next_char (st);
 | 
			
		||||
            }
 | 
			
		||||
        } while ((cmt = skip_comment (st)) > 0);
 | 
			
		||||
        if (cmt == TOK_ERROR) {
 | 
			
		||||
            tok = TOK_ERROR;
 | 
			
		||||
        } else if (peek_chars (st, "<?", 1)) {
 | 
			
		||||
            processing_instruction (st, "?>");
 | 
			
		||||
            return next_token (st, payload);
 | 
			
		||||
        } else if (peek_chars (st, "<!", 1)) {
 | 
			
		||||
            processing_instruction (st, ">");
 | 
			
		||||
            return next_token (st, payload);
 | 
			
		||||
        } else {
 | 
			
		||||
            int n = peek_char (st);
 | 
			
		||||
            if (n == '<') {
 | 
			
		||||
                tok = next_token_tag_withoutclose (st, payload);
 | 
			
		||||
            } else if (n == '"' || n == '\'') {
 | 
			
		||||
                tok = next_token_string (st, payload);
 | 
			
		||||
            } else if (qq_isidentfirst (n)) {
 | 
			
		||||
                tok = next_token_ident (st, payload);
 | 
			
		||||
            } else if (peek_chars (st, "/>", 1)) {
 | 
			
		||||
                tok = TOK_SHORTHAND_CLOSE_TAG;
 | 
			
		||||
            } else {
 | 
			
		||||
                tok = next_char (st);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (tok == TOK_ERROR) {
 | 
			
		||||
            st->error = 1;
 | 
			
		||||
        }
 | 
			
		||||
        return tok;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int peek_token (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    int tok;
 | 
			
		||||
    char *payload;
 | 
			
		||||
    tok = next_token (st, &payload);
 | 
			
		||||
    st->peektok = tok;
 | 
			
		||||
    st->peekpayload = payload;
 | 
			
		||||
    return tok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo)
 | 
			
		||||
{
 | 
			
		||||
#define PE_ERROR2(c,c1,c2) do { errc = (c); errc1 = (c1); errc2 = (c2); goto err; } while (0)
 | 
			
		||||
#define PE_ERROR(c,c1) PE_ERROR2(c,c1,0)
 | 
			
		||||
#define PE_LOCAL_ERROR(c,c1) do { ret = -1; PE_ERROR ((c), (c1)); } while (0)
 | 
			
		||||
    char *name = NULL, *aname = NULL, *ename = NULL;
 | 
			
		||||
    const char *errc = NULL, *errc1 = NULL, *errc2 = NULL;
 | 
			
		||||
    uintptr_t eleminfo;
 | 
			
		||||
    int ret = 0, tok;
 | 
			
		||||
 | 
			
		||||
    if (next_token (st, &name) != TOK_OPEN_TAG) {
 | 
			
		||||
        PE_LOCAL_ERROR ("expecting '<'", 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((ret = st->cb.elem_open (st->varg, parentinfo, &eleminfo, name)) < 0) {
 | 
			
		||||
        PE_ERROR ("failed in element open callback", name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (peek_token (st) == TOK_ID) {
 | 
			
		||||
        char *content;
 | 
			
		||||
        next_token (st, &aname);
 | 
			
		||||
        if (next_token (st, NULL) != '=') {
 | 
			
		||||
            PE_LOCAL_ERROR ("expecting '=' following attribute name", aname);
 | 
			
		||||
        }
 | 
			
		||||
        if (next_token (st, &content) != TOK_STRING) {
 | 
			
		||||
            ddsrt_free (content);
 | 
			
		||||
            PE_LOCAL_ERROR ("expecting string value for attribute", aname);
 | 
			
		||||
        }
 | 
			
		||||
        ret = st->cb.attr (st->varg, eleminfo, aname, content);
 | 
			
		||||
        ddsrt_free (content);
 | 
			
		||||
        if (ret < 0) {
 | 
			
		||||
            PE_ERROR2 ("failed in attribute callback", name, aname);
 | 
			
		||||
        }
 | 
			
		||||
        ddsrt_free (aname);
 | 
			
		||||
        aname = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tok = next_token (st, NULL);
 | 
			
		||||
    switch (tok)
 | 
			
		||||
    {
 | 
			
		||||
        case TOK_SHORTHAND_CLOSE_TAG:
 | 
			
		||||
            ret = st->cb.elem_close (st->varg, eleminfo);
 | 
			
		||||
            goto ok;
 | 
			
		||||
        case '>':
 | 
			
		||||
            st->nest++;
 | 
			
		||||
            set_input_marker (st);
 | 
			
		||||
            if (peek_token (st) == TOK_OPEN_TAG) {
 | 
			
		||||
                /* child elements */
 | 
			
		||||
                discard_input_marker (st);
 | 
			
		||||
                while (peek_token (st) == TOK_OPEN_TAG) {
 | 
			
		||||
                    if ((ret = parse_element (st, eleminfo)) < 0) {
 | 
			
		||||
                        PE_ERROR ("parse children", 0);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                /* text */
 | 
			
		||||
                static const char *cdata_magic = "<![CDATA[";
 | 
			
		||||
                char *content;
 | 
			
		||||
                int cmt = 0;
 | 
			
		||||
                rewind_to_input_marker (st);
 | 
			
		||||
                drop_peek_token (st);
 | 
			
		||||
                do {
 | 
			
		||||
                    /* gobble up content until EOF or markup */
 | 
			
		||||
                    while (peek_char (st) != '<' && peek_char (st) != TOK_EOF) {
 | 
			
		||||
                        if (append_to_payload (st, next_char (st), 0) < 0) {
 | 
			
		||||
                            PE_LOCAL_ERROR ("invalid character sequence", 0);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    /* if the mark-up happens to be a CDATA, consume it, and gobble up characters
 | 
			
		||||
                       until the closing marker is reached, which then also gets consumed */
 | 
			
		||||
                    if (peek_chars (st, cdata_magic, 1)) {
 | 
			
		||||
                        while (!peek_chars (st, "]]>", 1) && peek_char (st) != TOK_EOF) {
 | 
			
		||||
                            if (append_to_payload (st, next_char (st), 1) < 0) {
 | 
			
		||||
                                PE_LOCAL_ERROR ("invalid character sequence", 0);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    /* then, if the markup is a comment, skip it and try again */
 | 
			
		||||
                } while ((peek_char (st) != '<' || (cmt = skip_comment (st)) > 0) && make_chars_available (st, sizeof(cdata_magic) - 1));
 | 
			
		||||
                if (cmt == TOK_ERROR) {
 | 
			
		||||
                    discard_payload (st);
 | 
			
		||||
                    PE_LOCAL_ERROR ("invalid comment", 0);
 | 
			
		||||
                }
 | 
			
		||||
                if (save_payload (&content, st, 1) < 0) {
 | 
			
		||||
                    PE_ERROR ("invalid character sequence", 0);
 | 
			
		||||
                } else if (content != NULL) {
 | 
			
		||||
                    if(*content != '\0') {
 | 
			
		||||
                        ret = st->cb.elem_data (st->varg, eleminfo, content);
 | 
			
		||||
                        ddsrt_free (content);
 | 
			
		||||
                        if (ret < 0) {
 | 
			
		||||
                            PE_ERROR ("failed in data callback", 0);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        ddsrt_free (content);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            st->nest--;
 | 
			
		||||
            if (next_token (st, &ename) != TOK_CLOSE_TAG || next_char (st) != '>') {
 | 
			
		||||
                PE_LOCAL_ERROR ("expecting closing tag", name);
 | 
			
		||||
            }
 | 
			
		||||
            if (strcmp (name, ename) != 0) {
 | 
			
		||||
                PE_LOCAL_ERROR ("open/close tag mismatch", ename);
 | 
			
		||||
            }
 | 
			
		||||
            ret = st->cb.elem_close (st->varg, eleminfo);
 | 
			
		||||
            goto ok;
 | 
			
		||||
        default:
 | 
			
		||||
            PE_LOCAL_ERROR ("expecting '/>' or '>'", 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
    if (!st->error) {
 | 
			
		||||
        char msg[512];
 | 
			
		||||
        (void) snprintf (msg, sizeof (msg), "%s (%s%s%s)", errc, errc1 ? errc1 : "", errc1 && errc2 ? ", " : "", errc2 ? errc2 : "");
 | 
			
		||||
        st->cb.error (st->varg, msg, st->prevline);
 | 
			
		||||
        st->error = 1;
 | 
			
		||||
    }
 | 
			
		||||
ok:
 | 
			
		||||
    ddsrt_free (name);
 | 
			
		||||
    ddsrt_free (aname);
 | 
			
		||||
    ddsrt_free (ename);
 | 
			
		||||
    return ret;
 | 
			
		||||
#undef PE_LOCAL_ERROR
 | 
			
		||||
#undef PE_ERROR
 | 
			
		||||
#undef PE_ERROR2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ddsrt_xmlp_parse (struct ddsrt_xmlp_state *st)
 | 
			
		||||
{
 | 
			
		||||
    if (peek_token (st) == TOK_EOF) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        int ret = parse_element (st, 0);
 | 
			
		||||
        if (ret < 0|| !st->require_eof || next_token (st, NULL) == TOK_EOF ) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        } else {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ddsrt_xmlUnescapeInsitu (char *buffer, size_t *n) {
 | 
			
		||||
    return unescape_insitu (buffer, n);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue