Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Update libucl to 0.7.1
Baptiste Daroussin committed 11 years ago
commit edee29877a00bf3292291d095315ccfc4ea13f79
parent 573f777
20 files changed +1483 -210
modified external/Makefile.am
@@ -48,6 +48,8 @@ noinst_HEADERS= expat/amiga/expat_68k.h \
		libmachista/hashmap.h \
		libmachista/libmachista.h \
		libsbuf/sys/sbuf.h \
+
		libucl/klib/kvec.h \
+
		libucl/klib/khash.h \
		libucl/include/ucl.h \
		libucl/src/xxhash.h \
		libucl/src/ucl_internal.h \
@@ -170,9 +172,10 @@ libsbuf_static_la_SOURCES= ${libsbuf_la_SOURCES}
libsbuf_static_la_CFLAGS=	$(sbuf_common_CFLAGS) -static
libsbuf_static_la_LDFLAGS=	-all-static

-
ucl_common_cflags=	-I$(top_srcdir)/external//libucl/uthash \
+
ucl_common_cflags=	-I$(top_srcdir)/external/libucl/uthash \
+
			-I$(top_srcdir)/external/libucl/klib \
			-I$(top_srcdir)/external/libucl/include  \
-
			-I$(top_srcdir)/external//libucl/src \
+
			-I$(top_srcdir)/external/libucl/src \
			-Wno-unused-parameter -Wno-pointer-sign
libucl_la_SOURCES=	libucl/src/ucl_emitter.c \
			libucl/src/ucl_emitter_utils.c \
modified external/libucl/ChangeLog.md
@@ -20,3 +20,11 @@
### Libucl 0.6.1

- Various utilities fixes
+

+
### Libucl 0.7.0
+

+
- Move to klib library from uthash to reduce memory overhead and increase performance
+

+
### Libucl 0.7.1
+

+
- Added safe iterators API
modified external/libucl/Makefile.am
@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
-
EXTRA_DIST = uthash README.md
+
EXTRA_DIST = uthash klib README.md

pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libucl.pc
modified external/libucl/cmake/CMakeLists.txt
@@ -82,6 +82,7 @@ ENDIF(ENABLE_URL_SIGN MATCHES "ON")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../src")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../include")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../uthash")
+
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../klib")

SET(UCLSRC            ../src/ucl_util.c
                      ../src/ucl_parser.c
modified external/libucl/configure.ac
@@ -1,7 +1,7 @@
m4_define([maj_ver], [0])
-
m4_define([med_ver], [6])
+
m4_define([med_ver], [7])
m4_define([min_ver], [1])
-
m4_define([so_version], [3:0:1])
+
m4_define([so_version], [5:0:0])
m4_define([ucl_version], [maj_ver.med_ver.min_ver])

AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
modified external/libucl/doc/Makefile.am
@@ -4,5 +4,6 @@ dist_man_MANS = libucl.3

gen-man: @PANDOC@
	tail -n +$$(grep -n '# Synopsis' api.md | cut -d':' -f1) api.md | \
-
	cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' | \
+
	cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' \ 
+
	-e "s/%%date%%/$$(LANG=C date +'%d %B, %Y')/" | \
	@PANDOC@ -s -f markdown -t man -o libucl.3 

\ No newline at end of file
modified external/libucl/doc/api.md
@@ -377,7 +377,9 @@ If parsing operations fail then the resulting UCL object will be a `UCL_STRING`.

# Iteration functions

-
Iteration are used to iterate over UCL compound types: arrays and objects. Moreover, iterations could be performed over the keys with multiple values (implicit arrays). To iterate over an object, an array or a key with multiple values there is a function `ucl_iterate_object`.
+
Iteration are used to iterate over UCL compound types: arrays and objects. Moreover, iterations could be performed over the keys with multiple values (implicit arrays).
+
There are two types of iterators API: old and unsafe one via `ucl_iterate_object` and the proposed interface of safe iterators.
+


## ucl_iterate_object
~~~C
@@ -402,6 +404,60 @@ while ((obj = ucl_iterate_object (top, &it, true))) {
}
~~~

+
## Safe iterators API
+

+
Safe iterators are defined to clarify iterating over UCL objects and simplify flattening of UCL objects in non-trivial cases.
+
For example, if there is an implicit array that contains another array and a boolean value it is extremely unclear how to iterate over
+
such an object. Safe iterators are desinged to define two sorts of iteration:
+

+
1. Iteration over complex objects with expanding all values
+
2. Iteration over complex objects without expanding of values
+

+
The following example demonstrates the difference between these two types of iteration:
+

+
~~~
+
key = 1;
+
key = [2, 3, 4];
+

+
Iteration with expansion:
+

+
1, 2, 3, 4
+

+
Iteration without expansion:
+

+
1, [2, 3, 4]
+
~~~
+

+
UCL defines the following functions to manage safe iterators:
+

+
- `ucl_object_iterate_new` - creates new safe iterator
+
- `ucl_object_iterate_reset` - resets iterator to a new object
+
- `ucl_object_iterate_safe` - safely iterate the object inside iterator
+
- `ucl_object_iterate_free` - free memory associated with the safe iterator
+

+
Please note that unlike unsafe iterators, safe iterators *must* be explicitly initialized and freed.
+
An assert is likely generated if you use uninitialized or `NULL` iterator in all safe iterators functions.
+

+
~~~C
+
ucl_object_iter_t it;
+
const ucl_object_t *cur;
+

+
it = ucl_object_iterate_new (obj);
+

+
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
+
	/* Do something */
+
}
+

+
/* Switch to another object */
+
it = ucl_object_iterate_reset (it, another_obj);
+

+
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
+
	/* Do something else */
+
}
+

+
ucl_object_iterate_free (it);
+
~~~
+

# Validation functions

Currently, there is only one validation function called `ucl_object_validate`. It performs validation of object using the specified schema. This function is defined as following:
modified external/libucl/doc/libucl.3
@@ -1,4 +1,4 @@
-
.TH "LIBUCL" "3" "July 26, 2014" "Libucl manual" ""
+
.TH "LIBUCL" "3" "27 December, 2014" "Libucl manual" ""
.SH NAME
.PP
\f[B]ucl_parser_new\f[], \f[B]ucl_parser_register_macro\f[],
@@ -528,8 +528,9 @@ Iteration are used to iterate over UCL compound types: arrays and
objects.
Moreover, iterations could be performed over the keys with multiple
values (implicit arrays).
-
To iterate over an object, an array or a key with multiple values there
-
is a function \f[C]ucl_iterate_object\f[].
+
There are two types of iterators API: old and unsafe one via
+
\f[C]ucl_iterate_object\f[] and the proposed interface of safe
+
iterators.
.SS ucl_iterate_object
.IP
.nf
@@ -578,6 +579,75 @@ while\ ((obj\ =\ ucl_iterate_object\ (top,\ &it,\ true)))\ {
}
\f[]
.fi
+
.SS Safe iterators API
+
.PP
+
Safe iterators are defined to clarify iterating over UCL objects and
+
simplify flattening of UCL objects in non\-trivial cases.
+
For example, if there is an implicit array that contains another array
+
and a boolean value it is extremely unclear how to iterate over such an
+
object.
+
Safe iterators are desinged to define two sorts of iteration:
+
.IP "1." 3
+
Iteration over complex objects with expanding all values
+
.IP "2." 3
+
Iteration over complex objects without expanding of values
+
.PP
+
The following example demonstrates the difference between these two
+
types of iteration:
+
.IP
+
.nf
+
\f[C]
+
key\ =\ 1;
+
key\ =\ [2,\ 3,\ 4];
+

+
Iteration\ with\ expansion:
+

+
1,\ 2,\ 3,\ 4
+

+
Iteration\ without\ expansion:
+

+
1,\ [2,\ 3,\ 4]
+
\f[]
+
.fi
+
.PP
+
UCL defines the following functions to manage safe iterators:
+
.IP \[bu] 2
+
\f[C]ucl_object_iterate_new\f[] \- creates new safe iterator
+
.IP \[bu] 2
+
\f[C]ucl_object_iterate_reset\f[] \- resets iterator to a new object
+
.IP \[bu] 2
+
\f[C]ucl_object_iterate_safe\f[] \- safely iterate the object inside
+
iterator
+
.IP \[bu] 2
+
\f[C]ucl_object_iterate_free\f[] \- free memory associated with the safe
+
iterator
+
.PP
+
Please note that unlike unsafe iterators, safe iterators \f[I]must\f[]
+
be explicitly initialized and freed.
+
An assert is likely generated if you use uninitialized or \f[C]NULL\f[]
+
iterator in all safe iterators functions.
+
.IP
+
.nf
+
\f[C]
+
ucl_object_iter_t\ it;
+
const\ ucl_object_t\ *cur;
+

+
it\ =\ ucl_object_iterate_new\ (obj);
+

+
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
+
\ \ \ \ /*\ Do\ something\ */
+
}
+

+
/*\ Switch\ to\ another\ object\ */
+
it\ =\ ucl_object_iterate_reset\ (it,\ another_obj);
+

+
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
+
\ \ \ \ /*\ Do\ something\ else\ */
+
}
+

+
ucl_object_iterate_free\ (it);
+
\f[]
+
.fi
.SH VALIDATION FUNCTIONS
.PP
Currently, there is only one validation function called
modified external/libucl/doc/pandoc.template
@@ -1,6 +1,6 @@
% LIBUCL(3) Libucl manual
% Vsevolod Stakhov <vsevolod@highsecure.ru>
-
% July 26, 2014
+
% %%date%%

# Name

modified external/libucl/include/ucl.h
@@ -192,7 +192,7 @@ typedef struct ucl_object_s {
		int64_t iv;							/**< Int value of an object */
		const char *sv;					/**< String value of an object */
		double dv;							/**< Double value of an object */
-
		struct ucl_object_s *av;			/**< Array					*/
+
		void *av;							/**< Array					*/
		void *ov;							/**< Object					*/
		void* ud;							/**< Opaque user data		*/
	} value;
@@ -715,6 +715,37 @@ typedef void* ucl_object_iter_t;
 */
UCL_EXTERN const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj,
		ucl_object_iter_t *iter, bool expand_values);
+

+
/**
+
 * Create new safe iterator for the specified object
+
 * @param obj object to iterate
+
 * @return new iterator object that should be used with safe iterators API only
+
 */
+
UCL_EXTERN ucl_object_iter_t ucl_object_iterate_new (const ucl_object_t *obj)
+
	UCL_WARN_UNUSED_RESULT;
+
/**
+
 * Reset initialized iterator to a new object
+
 * @param obj new object to iterate
+
 * @return modified iterator object
+
 */
+
UCL_EXTERN ucl_object_iter_t ucl_object_iterate_reset (ucl_object_iter_t it,
+
		const ucl_object_t *obj);
+

+
/**
+
 * Get the next object from the `obj`. This fucntion iterates over arrays, objects
+
 * and implicit arrays
+
 * @param iter safe iterator
+
 * @return the next object in sequence
+
 */
+
UCL_EXTERN const ucl_object_t* ucl_object_iterate_safe (ucl_object_iter_t iter,
+
		bool expand_values);
+

+
/**
+
 * Free memory associated with the safe iterator
+
 * @param it safe iterator object
+
 */
+
UCL_EXTERN void ucl_object_iterate_free (ucl_object_iter_t it);
+

/** @} */


@@ -854,6 +885,13 @@ UCL_EXTERN ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser);
 * @param parser parser object
 */
UCL_EXTERN const char *ucl_parser_get_error(struct ucl_parser *parser);
+

+
/**
+
 * Clear the error in the parser
+
 * @param parser parser object
+
 */
+
UCL_EXTERN void ucl_parser_clear_error(struct ucl_parser *parser);
+

/**
 * Free ucl parser object
 * @param parser parser object
added external/libucl/klib/khash.h
@@ -0,0 +1,627 @@
+
/* The MIT License
+

+
   Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
+

+
   Permission is hereby granted, free of charge, to any person obtaining
+
   a copy of this software and associated documentation files (the
+
   "Software"), to deal in the Software without restriction, including
+
   without limitation the rights to use, copy, modify, merge, publish,
+
   distribute, sublicense, and/or sell copies of the Software, and to
+
   permit persons to whom the Software is furnished to do so, subject to
+
   the following conditions:
+

+
   The above copyright notice and this permission notice shall be
+
   included in all copies or substantial portions of the Software.
+

+
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+
   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+
   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+
   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+
   SOFTWARE.
+
*/
+

+
/*
+
  An example:
+

+
#include "khash.h"
+
KHASH_MAP_INIT_INT(32, char)
+
int main() {
+
	int ret, is_missing;
+
	khiter_t k;
+
	khash_t(32) *h = kh_init(32);
+
	k = kh_put(32, h, 5, &ret);
+
	kh_value(h, k) = 10;
+
	k = kh_get(32, h, 10);
+
	is_missing = (k == kh_end(h));
+
	k = kh_get(32, h, 5);
+
	kh_del(32, h, k);
+
	for (k = kh_begin(h); k != kh_end(h); ++k)
+
		if (kh_exist(h, k)) kh_value(h, k) = 1;
+
	kh_destroy(32, h);
+
	return 0;
+
}
+
*/
+

+
/*
+
  2013-05-02 (0.2.8):
+

+
	* Use quadratic probing. When the capacity is power of 2, stepping function
+
	  i*(i+1)/2 guarantees to traverse each bucket. It is better than double
+
	  hashing on cache performance and is more robust than linear probing.
+

+
	  In theory, double hashing should be more robust than quadratic probing.
+
	  However, my implementation is probably not for large hash tables, because
+
	  the second hash function is closely tied to the first hash function,
+
	  which reduce the effectiveness of double hashing.
+

+
	Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
+

+
  2011-12-29 (0.2.7):
+

+
    * Minor code clean up; no actual effect.
+

+
  2011-09-16 (0.2.6):
+

+
	* The capacity is a power of 2. This seems to dramatically improve the
+
	  speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
+

+
	   - http://code.google.com/p/ulib/
+
	   - http://nothings.org/computer/judy/
+

+
	* Allow to optionally use linear probing which usually has better
+
	  performance for random input. Double hashing is still the default as it
+
	  is more robust to certain non-random input.
+

+
	* Added Wang's integer hash function (not used by default). This hash
+
	  function is more robust to certain non-random input.
+

+
  2011-02-14 (0.2.5):
+

+
    * Allow to declare global functions.
+

+
  2009-09-26 (0.2.4):
+

+
    * Improve portability
+

+
  2008-09-19 (0.2.3):
+

+
	* Corrected the example
+
	* Improved interfaces
+

+
  2008-09-11 (0.2.2):
+

+
	* Improved speed a little in kh_put()
+

+
  2008-09-10 (0.2.1):
+

+
	* Added kh_clear()
+
	* Fixed a compiling error
+

+
  2008-09-02 (0.2.0):
+

+
	* Changed to token concatenation which increases flexibility.
+

+
  2008-08-31 (0.1.2):
+

+
	* Fixed a bug in kh_get(), which has not been tested previously.
+

+
  2008-08-31 (0.1.1):
+

+
	* Added destructor
+
*/
+

+

+
#ifndef __AC_KHASH_H
+
#define __AC_KHASH_H
+

+
/*!
+
  @header
+

+
  Generic hash table library.
+
 */
+

+
#define AC_VERSION_KHASH_H "0.2.8"
+

+
#include <stdlib.h>
+
#include <string.h>
+
#include <limits.h>
+

+
/* compiler specific configuration */
+

+
#if UINT_MAX == 0xffffffffu
+
typedef unsigned int khint32_t;
+
#elif ULONG_MAX == 0xffffffffu
+
typedef unsigned long khint32_t;
+
#endif
+

+
#if ULONG_MAX == ULLONG_MAX
+
typedef unsigned long khint64_t;
+
#else
+
typedef unsigned long long khint64_t;
+
#endif
+

+
#ifndef kh_inline
+
#ifdef _MSC_VER
+
#define kh_inline __inline
+
#else
+
#define kh_inline inline
+
#endif
+
#endif /* kh_inline */
+

+
#ifndef kh_unused
+
# ifdef __GNUC__
+
#   define kh_unused(x) __attribute__((__unused__)) x
+
# else
+
#   define kh_unused(x) x
+
# endif
+
#endif
+

+
typedef khint32_t khint_t;
+
typedef khint_t khiter_t;
+

+
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
+
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
+
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
+
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
+
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
+
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
+
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
+

+
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
+

+
#ifndef kroundup32
+
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
+
#endif
+

+
#ifndef kcalloc
+
#define kcalloc(N,Z) calloc(N,Z)
+
#endif
+
#ifndef kmalloc
+
#define kmalloc(Z) malloc(Z)
+
#endif
+
#ifndef krealloc
+
#define krealloc(P,Z) realloc(P,Z)
+
#endif
+
#ifndef kfree
+
#define kfree(P) free(P)
+
#endif
+

+
static const double __ac_HASH_UPPER = 0.77;
+

+
#define __KHASH_TYPE(name, khkey_t, khval_t) \
+
	typedef struct kh_##name##_s { \
+
		khint_t n_buckets, size, n_occupied, upper_bound; \
+
		khint32_t *flags; \
+
		khkey_t *keys; \
+
		khval_t *vals; \
+
	} kh_##name##_t;
+

+
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t)	 						\
+
	extern kh_##name##_t * kh_init_##name(void);							\
+
	extern void kh_destroy_##name(kh_##name##_t *h);						\
+
	extern void kh_clear_##name(kh_##name##_t *h);							\
+
	extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); 		\
+
	extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); 	\
+
	extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); 	\
+
	extern void kh_del_##name(kh_##name##_t *h, khint_t x);
+

+
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
+
	SCOPE kh_##name##_t *kh_init_##name(void) {							\
+
		return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t));		\
+
	}																	\
+
	SCOPE void kh_destroy_##name(kh_##name##_t *h)						\
+
	{																	\
+
		if (h) {														\
+
			kfree((void *)h->keys); kfree(h->flags);					\
+
			kfree((void *)h->vals);										\
+
			kfree(h);													\
+
		}																\
+
	}																	\
+
	SCOPE void kh_unused(kh_clear_##name)(kh_##name##_t *h)				\
+
	{																	\
+
		if (h && h->flags) {											\
+
			memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
+
			h->size = h->n_occupied = 0;								\
+
		}																\
+
	}																	\
+
	SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) 	\
+
	{																	\
+
		if (h->n_buckets) {												\
+
			khint_t k, i, last, mask, step = 0; \
+
			mask = h->n_buckets - 1;									\
+
			k = __hash_func(key); i = k & mask;							\
+
			last = i; \
+
			while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
+
				i = (i + (++step)) & mask; \
+
				if (i == last) return h->n_buckets;						\
+
			}															\
+
			return __ac_iseither(h->flags, i)? h->n_buckets : i;		\
+
		} else return 0;												\
+
	}																	\
+
	SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
+
	{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
+
		khint32_t *new_flags = 0;										\
+
		khint_t j = 1;													\
+
		{																\
+
			kroundup32(new_n_buckets); 									\
+
			if (new_n_buckets < 4) new_n_buckets = 4;					\
+
			if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0;	/* requested size is too small */ \
+
			else { /* hash table size to be changed (shrink or expand); rehash */ \
+
				new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t));	\
+
				if (!new_flags) return -1;								\
+
				memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
+
				if (h->n_buckets < new_n_buckets) {	/* expand */		\
+
					khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
+
					if (!new_keys) { kfree(new_flags); return -1; }		\
+
					h->keys = new_keys;									\
+
					if (kh_is_map) {									\
+
						khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
+
						if (!new_vals) { kfree(new_flags); return -1; }	\
+
						h->vals = new_vals;								\
+
					}													\
+
				} /* otherwise shrink */								\
+
			}															\
+
		}																\
+
		if (j) { /* rehashing is needed */								\
+
			for (j = 0; j != h->n_buckets; ++j) {						\
+
				if (__ac_iseither(h->flags, j) == 0) {					\
+
					khkey_t key = h->keys[j];							\
+
					khval_t val;										\
+
					khint_t new_mask;									\
+
					new_mask = new_n_buckets - 1; 						\
+
					if (kh_is_map) val = h->vals[j];					\
+
					__ac_set_isdel_true(h->flags, j);					\
+
					while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
+
						khint_t k, i, step = 0; \
+
						k = __hash_func(key);							\
+
						i = k & new_mask;								\
+
						while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
+
						__ac_set_isempty_false(new_flags, i);			\
+
						if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
+
							{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
+
							if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
+
							__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
+
						} else { /* write the element and jump out of the loop */ \
+
							h->keys[i] = key;							\
+
							if (kh_is_map) h->vals[i] = val;			\
+
							break;										\
+
						}												\
+
					}													\
+
				}														\
+
			}															\
+
			if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
+
				h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
+
				if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
+
			}															\
+
			kfree(h->flags); /* free the working space */				\
+
			h->flags = new_flags;										\
+
			h->n_buckets = new_n_buckets;								\
+
			h->n_occupied = h->size;									\
+
			h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
+
		}																\
+
		return 0;														\
+
	}																	\
+
	SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
+
	{																	\
+
		khint_t x;														\
+
		if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
+
			if (h->n_buckets > (h->size<<1)) {							\
+
				if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
+
					*ret = -1; return h->n_buckets;						\
+
				}														\
+
			} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
+
				*ret = -1; return h->n_buckets;							\
+
			}															\
+
		} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
+
		{																\
+
			khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
+
			x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
+
			if (__ac_isempty(h->flags, i)) x = i; /* for speed up */	\
+
			else {														\
+
				last = i; \
+
				while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
+
					if (__ac_isdel(h->flags, i)) site = i;				\
+
					i = (i + (++step)) & mask; \
+
					if (i == last) { x = site; break; }					\
+
				}														\
+
				if (x == h->n_buckets) {								\
+
					if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
+
					else x = i;											\
+
				}														\
+
			}															\
+
		}																\
+
		if (__ac_isempty(h->flags, x)) { /* not present at all */		\
+
			h->keys[x] = key;											\
+
			__ac_set_isboth_false(h->flags, x);							\
+
			++h->size; ++h->n_occupied;									\
+
			*ret = 1;													\
+
		} else if (__ac_isdel(h->flags, x)) { /* deleted */				\
+
			h->keys[x] = key;											\
+
			__ac_set_isboth_false(h->flags, x);							\
+
			++h->size;													\
+
			*ret = 2;													\
+
		} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
+
		return x;														\
+
	}																	\
+
	SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x)				\
+
	{																	\
+
		if (x != h->n_buckets && !__ac_iseither(h->flags, x)) {			\
+
			__ac_set_isdel_true(h->flags, x);							\
+
			--h->size;													\
+
		}																\
+
	}
+

+
#define KHASH_DECLARE(name, khkey_t, khval_t)		 					\
+
	__KHASH_TYPE(name, khkey_t, khval_t) 								\
+
	__KHASH_PROTOTYPES(name, khkey_t, khval_t)
+

+
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
+
	__KHASH_TYPE(name, khkey_t, khval_t) 								\
+
	__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
+

+
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
+
	KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
+

+
/* --- BEGIN OF HASH FUNCTIONS --- */
+

+
/*! @function
+
  @abstract     Integer hash function
+
  @param  key   The integer [khint32_t]
+
  @return       The hash value [khint_t]
+
 */
+
#define kh_int_hash_func(key) (khint32_t)(key)
+
/*! @function
+
  @abstract     Integer comparison function
+
 */
+
#define kh_int_hash_equal(a, b) ((a) == (b))
+
/*! @function
+
  @abstract     64-bit integer hash function
+
  @param  key   The integer [khint64_t]
+
  @return       The hash value [khint_t]
+
 */
+
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
+
/*! @function
+
  @abstract     64-bit integer comparison function
+
 */
+
#define kh_int64_hash_equal(a, b) ((a) == (b))
+
/*! @function
+
  @abstract     const char* hash function
+
  @param  s     Pointer to a null terminated string
+
  @return       The hash value
+
 */
+
static kh_inline khint_t __ac_X31_hash_string(const char *s)
+
{
+
	khint_t h = (khint_t)*s;
+
	if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
+
	return h;
+
}
+
/*! @function
+
  @abstract     Another interface to const char* hash function
+
  @param  key   Pointer to a null terminated string [const char*]
+
  @return       The hash value [khint_t]
+
 */
+
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
+
/*! @function
+
  @abstract     Const char* comparison function
+
 */
+
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
+

+
static kh_inline khint_t __ac_Wang_hash(khint_t key)
+
{
+
    key += ~(key << 15);
+
    key ^=  (key >> 10);
+
    key +=  (key << 3);
+
    key ^=  (key >> 6);
+
    key += ~(key << 11);
+
    key ^=  (key >> 16);
+
    return key;
+
}
+
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
+

+
/* --- END OF HASH FUNCTIONS --- */
+

+
/* Other convenient macros... */
+

+
/*!
+
  @abstract Type of the hash table.
+
  @param  name  Name of the hash table [symbol]
+
 */
+
#define khash_t(name) kh_##name##_t
+

+
/*! @function
+
  @abstract     Initiate a hash table.
+
  @param  name  Name of the hash table [symbol]
+
  @return       Pointer to the hash table [khash_t(name)*]
+
 */
+
#define kh_init(name) kh_init_##name()
+

+
/*! @function
+
  @abstract     Destroy a hash table.
+
  @param  name  Name of the hash table [symbol]
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
 */
+
#define kh_destroy(name, h) kh_destroy_##name(h)
+

+
/*! @function
+
  @abstract     Reset a hash table without deallocating memory.
+
  @param  name  Name of the hash table [symbol]
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
 */
+
#define kh_clear(name, h) kh_clear_##name(h)
+

+
/*! @function
+
  @abstract     Resize a hash table.
+
  @param  name  Name of the hash table [symbol]
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  s     New size [khint_t]
+
 */
+
#define kh_resize(name, h, s) kh_resize_##name(h, s)
+

+
/*! @function
+
  @abstract     Insert a key to the hash table.
+
  @param  name  Name of the hash table [symbol]
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  k     Key [type of keys]
+
  @param  r     Extra return code: -1 if the operation failed;
+
                0 if the key is present in the hash table;
+
                1 if the bucket is empty (never used); 2 if the element in
+
				the bucket has been deleted [int*]
+
  @return       Iterator to the inserted element [khint_t]
+
 */
+
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
+

+
/*! @function
+
  @abstract     Retrieve a key from the hash table.
+
  @param  name  Name of the hash table [symbol]
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  k     Key [type of keys]
+
  @return       Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
+
 */
+
#define kh_get(name, h, k) kh_get_##name(h, k)
+

+
/*! @function
+
  @abstract     Remove a key from the hash table.
+
  @param  name  Name of the hash table [symbol]
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  k     Iterator to the element to be deleted [khint_t]
+
 */
+
#define kh_del(name, h, k) kh_del_##name(h, k)
+

+
/*! @function
+
  @abstract     Test whether a bucket contains data.
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  x     Iterator to the bucket [khint_t]
+
  @return       1 if containing data; 0 otherwise [int]
+
 */
+
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
+

+
/*! @function
+
  @abstract     Get key given an iterator
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  x     Iterator to the bucket [khint_t]
+
  @return       Key [type of keys]
+
 */
+
#define kh_key(h, x) ((h)->keys[x])
+

+
/*! @function
+
  @abstract     Get value given an iterator
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  x     Iterator to the bucket [khint_t]
+
  @return       Value [type of values]
+
  @discussion   For hash sets, calling this results in segfault.
+
 */
+
#define kh_val(h, x) ((h)->vals[x])
+

+
/*! @function
+
  @abstract     Alias of kh_val()
+
 */
+
#define kh_value(h, x) ((h)->vals[x])
+

+
/*! @function
+
  @abstract     Get the start iterator
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @return       The start iterator [khint_t]
+
 */
+
#define kh_begin(h) (khint_t)(0)
+

+
/*! @function
+
  @abstract     Get the end iterator
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @return       The end iterator [khint_t]
+
 */
+
#define kh_end(h) ((h)->n_buckets)
+

+
/*! @function
+
  @abstract     Get the number of elements in the hash table
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @return       Number of elements in the hash table [khint_t]
+
 */
+
#define kh_size(h) ((h)->size)
+

+
/*! @function
+
  @abstract     Get the number of buckets in the hash table
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @return       Number of buckets in the hash table [khint_t]
+
 */
+
#define kh_n_buckets(h) ((h)->n_buckets)
+

+
/*! @function
+
  @abstract     Iterate over the entries in the hash table
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  kvar  Variable to which key will be assigned
+
  @param  vvar  Variable to which value will be assigned
+
  @param  code  Block of code to execute
+
 */
+
#define kh_foreach(h, kvar, vvar, code) { khint_t __i;		\
+
	for (__i = kh_begin(h); __i != kh_end(h); ++__i) {		\
+
		if (!kh_exist(h,__i)) continue;						\
+
		(kvar) = kh_key(h,__i);								\
+
		(vvar) = kh_val(h,__i);								\
+
		code;												\
+
	} }
+

+
/*! @function
+
  @abstract     Iterate over the values in the hash table
+
  @param  h     Pointer to the hash table [khash_t(name)*]
+
  @param  vvar  Variable to which value will be assigned
+
  @param  code  Block of code to execute
+
 */
+
#define kh_foreach_value(h, vvar, code) { khint_t __i;		\
+
	for (__i = kh_begin(h); __i != kh_end(h); ++__i) {		\
+
		if (!kh_exist(h,__i)) continue;						\
+
		(vvar) = kh_val(h,__i);								\
+
		code;												\
+
	} }
+

+
/* More conenient interfaces */
+

+
/*! @function
+
  @abstract     Instantiate a hash set containing integer keys
+
  @param  name  Name of the hash table [symbol]
+
 */
+
#define KHASH_SET_INIT_INT(name)										\
+
	KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
+

+
/*! @function
+
  @abstract     Instantiate a hash map containing integer keys
+
  @param  name  Name of the hash table [symbol]
+
  @param  khval_t  Type of values [type]
+
 */
+
#define KHASH_MAP_INIT_INT(name, khval_t)								\
+
	KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
+

+
/*! @function
+
  @abstract     Instantiate a hash map containing 64-bit integer keys
+
  @param  name  Name of the hash table [symbol]
+
 */
+
#define KHASH_SET_INIT_INT64(name)										\
+
	KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
+

+
/*! @function
+
  @abstract     Instantiate a hash map containing 64-bit integer keys
+
  @param  name  Name of the hash table [symbol]
+
  @param  khval_t  Type of values [type]
+
 */
+
#define KHASH_MAP_INIT_INT64(name, khval_t)								\
+
	KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
+

+
typedef const char *kh_cstr_t;
+
/*! @function
+
  @abstract     Instantiate a hash map containing const char* keys
+
  @param  name  Name of the hash table [symbol]
+
 */
+
#define KHASH_SET_INIT_STR(name)										\
+
	KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
+

+
/*! @function
+
  @abstract     Instantiate a hash map containing const char* keys
+
  @param  name  Name of the hash table [symbol]
+
  @param  khval_t  Type of values [type]
+
 */
+
#define KHASH_MAP_INIT_STR(name, khval_t)								\
+
	KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
+

+
#endif /* __AC_KHASH_H */
added external/libucl/klib/kvec.h
@@ -0,0 +1,103 @@
+
/* The MIT License
+

+
   Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk>
+

+
   Permission is hereby granted, free of charge, to any person obtaining
+
   a copy of this software and associated documentation files (the
+
   "Software"), to deal in the Software without restriction, including
+
   without limitation the rights to use, copy, modify, merge, publish,
+
   distribute, sublicense, and/or sell copies of the Software, and to
+
   permit persons to whom the Software is furnished to do so, subject to
+
   the following conditions:
+

+
   The above copyright notice and this permission notice shall be
+
   included in all copies or substantial portions of the Software.
+

+
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+
   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+
   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+
   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+
   SOFTWARE.
+
*/
+

+
/*
+
  An example:
+

+
#include "kvec.h"
+
int main() {
+
	kvec_t(int) array;
+
	kv_init(array);
+
	kv_push(int, array, 10); // append
+
	kv_a(int, array, 20) = 5; // dynamic
+
	kv_A(array, 20) = 4; // static
+
	kv_destroy(array);
+
	return 0;
+
}
+
*/
+

+
/*
+
  2008-09-22 (0.1.0):
+

+
	* The initial version.
+

+
*/
+

+
#ifndef AC_KVEC_H
+
#define AC_KVEC_H
+

+
#include <stdlib.h>
+

+
#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
+

+
#define kvec_t(type) struct { size_t n, m; type *a; }
+
#define kv_init(v) ((v).n = (v).m = 0, (v).a = 0)
+
#define kv_destroy(v) free((v).a)
+
#define kv_A(v, i) ((v).a[(i)])
+
#define kv_pop(v) ((v).a[--(v).n])
+
#define kv_size(v) ((v).n)
+
#define kv_max(v) ((v).m)
+

+
#define kv_resize(type, v, s)  ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
+
#define kv_grow_factor 1.5
+
#define kv_grow(type, v)  ((v).m = ((v).m > 1 ? (v).m * kv_grow_factor : 2), \
+
		(v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
+

+
#define kv_copy(type, v1, v0) do {											\
+
		if ((v1).m < (v0).n) kv_resize(type, v1, (v0).n);					\
+
		(v1).n = (v0).n;													\
+
		memcpy((v1).a, (v0).a, sizeof(type) * (v0).n);						\
+
	} while (0)																\
+

+
#define kv_push(type, v, x) do {											\
+
		if ((v).n == (v).m) {												\
+
			kv_grow(type, v);												\
+
		}																	\
+
		(v).a[(v).n++] = (x);												\
+
	} while (0)
+

+
#define kv_prepend(type, v, x) do {											\
+
	if ((v).n == (v).m) {													\
+
		kv_grow(type, v);													\
+
	}																		\
+
	memmove((v).a + 1, (v).a, sizeof(type) * (v).n);							\
+
	(v).a[0] = (x);															\
+
	(v).n ++;																\
+
} while (0)
+

+
#define kv_concat(type, v1, v0) do {										\
+
	if ((v1).m < (v0).n + (v1).n) kv_resize(type, v1, (v0).n + (v1).n);		\
+
		memcpy((v1).a + (v1).n, (v0).a, sizeof(type) * ((v0).n + (v1).n));	\
+
		(v1).n = (v0).n + (v1).n;											\
+
	} while (0)
+

+
#define kv_del(type, v, i) do {												\
+
	if ((i) < (v).n) {														\
+
		memmove((v).a + (i), (v).a + ((i) + 1), sizeof(type) * ((v).n - (i) - 1)); \
+
		(v).n --;															\
+
	}																		\
+
} while (0)
+

+
#endif
modified external/libucl/src/Makefile.am
@@ -1,6 +1,7 @@
libucl_common_cflags=	-I$(top_srcdir)/src \
			-I$(top_srcdir)/include \
			-I$(top_srcdir)/uthash \
+
			-I$(top_srcdir)/klib \
			-Wall -W -Wno-unused-parameter -Wno-pointer-sign
lib_LTLIBRARIES=	libucl.la
libucl_la_SOURCES=	ucl_emitter.c \
modified external/libucl/src/ucl_emitter.c
@@ -250,6 +250,7 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
		const ucl_object_t *obj, bool print_key, bool compact)
{
	const ucl_object_t *cur;
+
	ucl_object_iter_t iter = NULL;
	const struct ucl_emitter_functions *func = ctx->func;
	bool first = true;

@@ -266,18 +267,22 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,

	if (obj->type == UCL_ARRAY) {
		/* explicit array */
-
		cur = obj->value.av;
+
		while ((cur = ucl_iterate_object (obj, &iter, true)) != NULL) {
+
			ucl_emitter_common_elt (ctx, cur, first, false, compact);
+
			first = false;
+
		}
	}
	else {
		/* implicit array */
		cur = obj;
+
		while (cur) {
+
			ucl_emitter_common_elt (ctx, cur, first, false, compact);
+
			first = false;
+
			cur = cur->next;
+
		}
	}

-
	while (cur) {
-
		ucl_emitter_common_elt (ctx, cur, first, false, compact);
-
		first = false;
-
		cur = cur->next;
-
	}
+

}

/**
modified external/libucl/src/ucl_hash.c
@@ -23,119 +23,308 @@

#include "ucl_internal.h"
#include "ucl_hash.h"
-
#include "utlist.h"
+
#include "khash.h"
+
#include "kvec.h"
+

+
struct ucl_hash_elt {
+
	const ucl_object_t *obj;
+
	size_t ar_idx;
+
};
+

+
struct ucl_hash_struct {
+
	void *hash;
+
	kvec_t(const ucl_object_t *) ar;
+
	bool caseless;
+
};
+

+
static inline uint32_t
+
ucl_hash_func (const ucl_object_t *o)
+
{
+
	return XXH32 (o->key, o->keylen, 0xdeadbeef);
+
}
+

+
static inline int
+
ucl_hash_equal (const ucl_object_t *k1, const ucl_object_t *k2)
+
{
+
	if (k1->keylen == k2->keylen) {
+
		return strncmp (k1->key, k2->key, k1->keylen) == 0;
+
	}
+

+
	return 0;
+
}
+

+
KHASH_INIT (ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt, 1,
+
		ucl_hash_func, ucl_hash_equal)
+

+
static inline uint32_t
+
ucl_hash_caseless_func (const ucl_object_t *o)
+
{
+
	void *xxh = XXH32_init (0xdeadbeef);
+
	char hash_buf[64], *c;
+
	const char *p;
+
	ssize_t remain = o->keylen;
+

+
	p = o->key;
+
	c = &hash_buf[0];
+

+
	while (remain > 0) {
+
		*c++ = tolower (*p++);
+

+
		if (c - &hash_buf[0] == sizeof (hash_buf)) {
+
			XXH32_update (xxh, hash_buf, sizeof (hash_buf));
+
			c = &hash_buf[0];
+
		}
+
		remain --;
+
	}
+

+
	if (c - &hash_buf[0] != 0) {
+
		XXH32_update (xxh, hash_buf, c - &hash_buf[0]);
+
	}
+

+
	return XXH32_digest (xxh);
+
}
+

+
static inline int
+
ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)
+
{
+
	if (k1->keylen == k2->keylen) {
+
		return strncasecmp (k1->key, k2->key, k1->keylen) == 0;
+
	}
+

+
	return 0;
+
}
+

+
KHASH_INIT (ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt, 1,
+
		ucl_hash_caseless_func, ucl_hash_caseless_equal)

ucl_hash_t*
-
ucl_hash_create (void)
+
ucl_hash_create (bool ignore_case)
{
	ucl_hash_t *new;

	new = UCL_ALLOC (sizeof (ucl_hash_t));
	if (new != NULL) {
-
		new->buckets = NULL;
+
		kv_init (new->ar);
+

+
		new->caseless = ignore_case;
+
		if (ignore_case) {
+
			khash_t(ucl_hash_caseless_node) *h = kh_init (ucl_hash_caseless_node);
+
			new->hash = (void *)h;
+
		}
+
		else {
+
			khash_t(ucl_hash_node) *h = kh_init (ucl_hash_node);
+
			new->hash = (void *)h;
+
		}
	}
	return new;
}

void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
{
-
	ucl_hash_node_t *elt, *tmp;
-
	const ucl_object_t *cur, *otmp;
-

-
	HASH_ITER (hh, hashlin->buckets, elt, tmp) {
-
		HASH_DELETE (hh, hashlin->buckets, elt);
-
		if (func) {
-
			DL_FOREACH_SAFE (elt->data, cur, otmp) {
-
				/* Need to deconst here */
-
				func (__DECONST (ucl_object_t *, cur));
+
	const ucl_object_t *cur, *tmp;
+

+
	if (func != NULL) {
+
		/* Iterate over the hash first */
+
		khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
+
				hashlin->hash;
+
		khiter_t k;
+

+
		for (k = kh_begin (h); k != kh_end (h); ++k) {
+
			if (kh_exist (h, k)) {
+
				cur = (kh_value (h, k)).obj;
+
				while (cur != NULL) {
+
					tmp = cur->next;
+
					func (__DECONST (ucl_object_t *, cur));
+
					cur = tmp;
+
				}
			}
		}
-
		UCL_FREE (sizeof (ucl_hash_node_t), elt);
	}
-
	UCL_FREE (sizeof (ucl_hash_t), hashlin);
+

+
	if (hashlin->caseless) {
+
		khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
+
			hashlin->hash;
+
		kh_destroy (ucl_hash_caseless_node, h);
+
	}
+
	else {
+
		khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
+
			hashlin->hash;
+
		kh_destroy (ucl_hash_node, h);
+
	}
+

+
	kv_destroy (hashlin->ar);
+
	UCL_FREE (sizeof (*hashlin), hashlin);
}

void
ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
		const char *key, unsigned keylen)
{
-
	ucl_hash_node_t *node;
+
	khiter_t k;
+
	int ret;
+
	struct ucl_hash_elt *elt;

-
	node = UCL_ALLOC (sizeof (ucl_hash_node_t));
-
	node->data = obj;
-
	HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node);
+
	if (hashlin->caseless) {
+
		khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
+
				hashlin->hash;
+
		k = kh_put (ucl_hash_caseless_node, h, obj, &ret);
+
		if (ret > 0) {
+
			elt = &kh_value (h, k);
+
			kv_push (const ucl_object_t *, hashlin->ar, obj);
+
			elt->obj = obj;
+
			elt->ar_idx = kv_size (hashlin->ar) - 1;
+
		}
+
	}
+
	else {
+
		khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
+
				hashlin->hash;
+
		k = kh_put (ucl_hash_node, h, obj, &ret);
+
		if (ret > 0) {
+
			elt = &kh_value (h, k);
+
			kv_push (const ucl_object_t *, hashlin->ar, obj);
+
			elt->obj = obj;
+
			elt->ar_idx = kv_size (hashlin->ar) - 1;
+
		}
+
	}
}

void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
		const ucl_object_t *new)
{
-
	ucl_hash_node_t *node;
+
	khiter_t k;
+
	int ret;
+
	struct ucl_hash_elt elt, *pelt;

-
	HASH_FIND (hh, hashlin->buckets, old->key, old->keylen, node);
-
	if (node != NULL) {
-
		/* Direct replacement */
-
		node->data = new;
-
		node->hh.key = new->key;
-
		node->hh.keylen = new->keylen;
+
	if (hashlin->caseless) {
+
		khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
+
				hashlin->hash;
+
		k = kh_put (ucl_hash_caseless_node, h, old, &ret);
+
		if (ret == 0) {
+
			elt = kh_value (h, k);
+
			kh_del (ucl_hash_caseless_node, h, k);
+
			k = kh_put (ucl_hash_caseless_node, h, new, &ret);
+
			pelt = &kh_value (h, k);
+
			pelt->obj = new;
+
			pelt->ar_idx = elt.ar_idx;
+
			kv_A (hashlin->ar, elt.ar_idx) = new;
+
		}
+
	}
+
	else {
+
		khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
+
				hashlin->hash;
+
		k = kh_put (ucl_hash_node, h, old, &ret);
+
		if (ret == 0) {
+
			elt = kh_value (h, k);
+
			kh_del (ucl_hash_node, h, k);
+
			k = kh_put (ucl_hash_node, h, new, &ret);
+
			pelt = &kh_value (h, k);
+
			pelt->obj = new;
+
			pelt->ar_idx = elt.ar_idx;
+
			kv_A (hashlin->ar, elt.ar_idx) = new;
+
		}
	}
}

+
struct ucl_hash_real_iter {
+
	const ucl_object_t **cur;
+
	const ucl_object_t **end;
+
};
+

const void*
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
{
-
	ucl_hash_node_t *elt = *iter;
+
	struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(*iter);
+
	const ucl_object_t *ret = NULL;

-
	if (elt == NULL) {
-
		if (hashlin == NULL || hashlin->buckets == NULL) {
-
			return NULL;
-
		}
-
		elt = hashlin->buckets;
-
		if (elt == NULL) {
-
			return NULL;
-
		}
-
	}
-
	else if (elt == hashlin->buckets) {
+
	if (hashlin == NULL)
		return NULL;
+

+
	if (it == NULL) {
+
		it = UCL_ALLOC (sizeof (*it));
+
		it->cur = &hashlin->ar.a[0];
+
		it->end = it->cur + hashlin->ar.n;
+
	}
+

+
	if (it->cur < it->end) {
+
		ret = *it->cur++;
+
	}
+
	else {
+
		UCL_FREE (sizeof (*it), it);
	}

-
	*iter = elt->hh.next ? elt->hh.next : hashlin->buckets;
-
	return elt->data;
+
	*iter = it;
+

+
	return ret;
}

bool
-
ucl_hash_iter_has_next (ucl_hash_iter_t iter)
+
ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter)
{
-
	ucl_hash_node_t *elt = iter;
+
	struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(iter);

-
	return (elt == NULL || elt->hh.prev != NULL);
+
	return it->cur < it->end - 1;
}


const ucl_object_t*
ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)
{
-
	ucl_hash_node_t *found;
+
	khiter_t k;
+
	const ucl_object_t *ret = NULL;
+
	ucl_object_t search;
+
	struct ucl_hash_elt *elt;

-
	if (hashlin == NULL) {
-
		return NULL;
-
	}
-
	HASH_FIND (hh, hashlin->buckets, key, keylen, found);
+
	search.key = key;
+
	search.keylen = keylen;
+

+
	if (hashlin->caseless) {
+
		khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
+
						hashlin->hash;

-
	if (found) {
-
		return found->data;
+
		k = kh_get (ucl_hash_caseless_node, h, &search);
+
		if (k != kh_end (h)) {
+
			elt = &kh_value (h, k);
+
			ret = elt->obj;
+
		}
+
	}
+
	else {
+
		khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
+
						hashlin->hash;
+
		k = kh_get (ucl_hash_node, h, &search);
+
		if (k != kh_end (h)) {
+
			elt = &kh_value (h, k);
+
			ret = elt->obj;
+
		}
	}
-
	return NULL;
+

+
	return ret;
}

void
ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
{
-
	ucl_hash_node_t *found;
+
	khiter_t k;
+
	struct ucl_hash_elt *elt;

-
	HASH_FIND (hh, hashlin->buckets, obj->key, obj->keylen, found);
+
	if (hashlin->caseless) {
+
		khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
+
			hashlin->hash;

-
	if (found) {
-
		HASH_DELETE (hh, hashlin->buckets, found);
-
		UCL_FREE (sizeof (ucl_hash_node_t), found);
+
		k = kh_get (ucl_hash_caseless_node, h, obj);
+
		if (k != kh_end (h)) {
+
			elt = &kh_value (h, k);
+
			kv_A (hashlin->ar, elt->ar_idx) = NULL;
+
			kh_del (ucl_hash_caseless_node, h, k);
+
		}
+
	}
+
	else {
+
		khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
+
			hashlin->hash;
+
		k = kh_get (ucl_hash_node, h, obj);
+
		if (k != kh_end (h)) {
+
			elt = &kh_value (h, k);
+
			kv_A (hashlin->ar, elt->ar_idx) = NULL;
+
			kh_del (ucl_hash_node, h, k);
+
		}
	}
}
modified external/libucl/src/ucl_hash.h
@@ -25,15 +25,11 @@
#define __UCL_HASH_H

#include "ucl.h"
-
#include "uthash.h"

/******************************************************************************/

-
typedef struct ucl_hash_node_s
-
{
-
	const ucl_object_t *data;
-
	UT_hash_handle hh;
-
} ucl_hash_node_t;
+
struct ucl_hash_node_s;
+
typedef struct ucl_hash_node_s ucl_hash_node_t;

typedef int ucl_hash_cmp_func (const void* void_a, const void* void_b);
typedef void ucl_hash_free_func (void *ptr);
@@ -43,16 +39,14 @@ typedef void* ucl_hash_iter_t;
/**
 * Linear chained hashtable.
 */
-
typedef struct ucl_hash_struct
-
{
-
	ucl_hash_node_t *buckets; /**< array of hash buckets. One list for each hash modulus. */
-
} ucl_hash_t;
+
struct ucl_hash_struct;
+
typedef struct ucl_hash_struct ucl_hash_t;


/**
 * Initializes the hashtable.
 */
-
ucl_hash_t* ucl_hash_create (void);
+
ucl_hash_t* ucl_hash_create (bool ignore_case);

/**
 * Deinitializes the hashtable.
@@ -94,6 +88,6 @@ const void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter);
/**
 * Check whether an iterator has next element
 */
-
bool ucl_hash_iter_has_next (ucl_hash_iter_t iter);
+
bool ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter);

#endif
modified external/libucl/src/ucl_internal.h
@@ -339,14 +339,17 @@ ucl_hash_search_obj (ucl_hash_t* hashlin, ucl_object_t *obj)
	return (const ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen);
}

-
static inline ucl_hash_t *
-
ucl_hash_insert_object (ucl_hash_t *hashlin, const ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
+
static inline ucl_hash_t * ucl_hash_insert_object (ucl_hash_t *hashlin,
+
		const ucl_object_t *obj,
+
		bool ignore_case) UCL_WARN_UNUSED_RESULT;

static inline ucl_hash_t *
-
ucl_hash_insert_object (ucl_hash_t *hashlin, const ucl_object_t *obj)
+
ucl_hash_insert_object (ucl_hash_t *hashlin,
+
		const ucl_object_t *obj,
+
		bool ignore_case)
{
	if (hashlin == NULL) {
-
		hashlin = ucl_hash_create ();
+
		hashlin = ucl_hash_create (ignore_case);
	}
	ucl_hash_insert (hashlin, obj, obj->key, obj->keylen);

modified external/libucl/src/ucl_parser.c
@@ -570,7 +570,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
		else {
			obj->type = UCL_OBJECT;
		}
-
		obj->value.ov = ucl_hash_create ();
+
		obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
		parser->state = UCL_STATE_KEY;
	}
	else {
@@ -975,7 +975,7 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
	else {
		if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
			/* Just add to the explicit array */
-
			DL_APPEND (top->value.av, elt);
+
			ucl_array_append (top, elt);
		}
		else {
			/* Convert to an array */
@@ -984,8 +984,8 @@ ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
			nobj->key = top->key;
			nobj->keylen = top->keylen;
			nobj->flags |= UCL_OBJECT_MULTIVALUE;
-
			DL_APPEND (nobj->value.av, top);
-
			DL_APPEND (nobj->value.av, elt);
+
			ucl_array_append (nobj, top);
+
			ucl_array_append (nobj, elt);
			ucl_hash_insert (cont, nobj, nobj->key, nobj->keylen);
		}
	}
@@ -1195,7 +1195,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
	nobj->keylen = keylen;
	tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
	if (tobj == NULL) {
-
		container = ucl_hash_insert_object (container, nobj);
+
		container = ucl_hash_insert_object (container, nobj,
+
				parser->flags & UCL_PARSER_KEY_LOWERCASE);
		nobj->prev = nobj;
		nobj->next = NULL;
		parser->stack->obj->len ++;
@@ -1366,11 +1367,9 @@ ucl_get_value_object (struct ucl_parser *parser)
	if (parser->stack->obj->type == UCL_ARRAY) {
		/* Object must be allocated */
		obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
-
		t = parser->stack->obj->value.av;
-
		DL_APPEND (t, obj);
+
		t = parser->stack->obj;
+
		ucl_array_append (t, obj);
		parser->cur_obj = obj;
-
		parser->stack->obj->value.av = t;
-
		parser->stack->obj->len ++;
	}
	else {
		/* Object has been already allocated */
modified external/libucl/src/ucl_util.c
@@ -24,6 +24,7 @@
#include "ucl.h"
#include "ucl_internal.h"
#include "ucl_chartable.h"
+
#include "kvec.h"

#include <glob.h>

@@ -31,6 +32,11 @@
#include <libgen.h> /* For dirname */
#endif

+
typedef kvec_t(ucl_object_t *) ucl_array_t;
+

+
#define UCL_ARRAY_GET(ar, obj) ucl_array_t *ar = \
+
	(ucl_array_t *)((obj) != NULL ? (obj)->value.av : NULL)
+

#ifdef HAVE_OPENSSL
#include <openssl/err.h>
#include <openssl/sha.h>
@@ -195,15 +201,27 @@ ucl_object_dtor_unref (ucl_object_t *obj)
static void
ucl_object_free_internal (ucl_object_t *obj, bool allow_rec, ucl_object_dtor dtor)
{
-
	ucl_object_t *sub, *tmp;
+
	ucl_object_t *tmp, *sub;

	while (obj != NULL) {
		if (obj->type == UCL_ARRAY) {
-
			sub = obj->value.av;
-
			while (sub != NULL) {
-
				tmp = sub->next;
-
				dtor (sub);
-
				sub = tmp;
+
			UCL_ARRAY_GET (vec, obj);
+
			unsigned int i;
+

+
			if (vec != NULL) {
+
				for (i = 0; i < vec->n; i ++) {
+
					sub = kv_A (*vec, i);
+
					if (sub != NULL) {
+
						tmp = sub;
+
						while (sub) {
+
							tmp = sub->next;
+
							dtor (sub);
+
							sub = tmp;
+
						}
+
					}
+
				}
+
				kv_destroy (*vec);
+
				UCL_FREE (sizeof (*vec), vec);
			}
		}
		else if (obj->type == UCL_OBJECT) {
@@ -455,6 +473,15 @@ ucl_parser_get_error(struct ucl_parser *parser)
	return utstring_body(parser->err);
}

+
UCL_EXTERN void
+
ucl_parser_clear_error(struct ucl_parser *parser)
+
{
+
	if (parser != NULL && parser->err != NULL) {
+
		utstring_free(parser->err);
+
		parser->err = NULL;
+
	}
+
}
+

UCL_EXTERN bool
ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len)
{
@@ -1394,7 +1421,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
	}

	if (top->value.ov == NULL) {
-
		top->value.ov = ucl_hash_create ();
+
		top->value.ov = ucl_hash_create (false);
	}

	if (keylen == 0) {
@@ -1427,7 +1454,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
	found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));

	if (found == NULL) {
-
		top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
+
		top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
		top->len ++;
		if (replace) {
			ret = false;
@@ -1444,7 +1471,7 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
				ucl_object_insert_key_common (elt, found, found->key,
						found->keylen, copy_key, false, false);
				ucl_hash_delete (top->value.ov, found);
-
				top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
+
				top->value.ov = ucl_hash_insert_object (top->value.ov, elt, false);
			}
			else if (found->type == UCL_OBJECT && elt->type != UCL_OBJECT) {
				/* Insert new to old */
@@ -1568,7 +1595,7 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
		found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
		if (found == NULL) {
			/* The key does not exist */
-
			top->value.ov = ucl_hash_insert_object (top->value.ov, cp);
+
			top->value.ov = ucl_hash_insert_object (top->value.ov, cp, false);
			top->len ++;
		}
		else {
@@ -1610,7 +1637,7 @@ ucl_object_find_key (const ucl_object_t *obj, const char *key)
const ucl_object_t*
ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values)
{
-
	const ucl_object_t *elt;
+
	const ucl_object_t *elt = NULL;

	if (obj == NULL || iter == NULL) {
		return NULL;
@@ -1621,19 +1648,25 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
		case UCL_OBJECT:
			return (const ucl_object_t*)ucl_hash_iterate (obj->value.ov, iter);
			break;
-
		case UCL_ARRAY:
-
			elt = *iter;
-
			if (elt == NULL) {
-
				elt = obj->value.av;
-
				if (elt == NULL) {
-
					return NULL;
+
		case UCL_ARRAY: {
+
			unsigned int idx;
+
			UCL_ARRAY_GET (vec, obj);
+
			idx = (unsigned int)(uintptr_t)(*iter);
+

+
			if (vec != NULL) {
+
				while (idx < kv_size (*vec)) {
+
					if ((elt = kv_A (*vec, idx)) != NULL) {
+
						idx ++;
+
						break;
+
					}
+
					idx ++;
				}
+
				*iter = (void *)(uintptr_t)idx;
			}
-
			else if (elt == obj->value.av) {
-
				return NULL;
-
			}
-
			*iter = elt->next ? elt->next : obj->value.av;
+

			return elt;
+
			break;
+
		}
		default:
			/* Go to linear iteration */
			break;
@@ -1654,6 +1687,95 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
	return NULL;
}

+
const char safe_iter_magic[4] = {'u', 'i', 't', 'e'};
+
struct ucl_object_safe_iter {
+
	char magic[4]; /* safety check */
+
	const ucl_object_t *impl_it; /* implicit object iteration */
+
	ucl_object_iter_t expl_it; /* explicit iteration */
+
};
+

+
#define UCL_SAFE_ITER(ptr) (struct ucl_object_safe_iter *)(ptr)
+
#define UCL_SAFE_ITER_CHECK(it) do { \
+
	assert (it != NULL); \
+
	assert (memcmp (it->magic, safe_iter_magic, sizeof (it->magic)) == 0); \
+
 } while (0)
+

+
ucl_object_iter_t
+
ucl_object_iterate_new (const ucl_object_t *obj)
+
{
+
	struct ucl_object_safe_iter *it;
+

+
	it = UCL_ALLOC (sizeof (*it));
+
	if (it != NULL) {
+
		memcpy (it->magic, safe_iter_magic, sizeof (it->magic));
+
		it->expl_it = NULL;
+
		it->impl_it = obj;
+
	}
+

+
	return (ucl_object_iter_t)it;
+
}
+

+

+
ucl_object_iter_t
+
ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
+
{
+
	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
+

+
	UCL_SAFE_ITER_CHECK (rit);
+

+
	rit->impl_it = obj;
+
	rit->expl_it = NULL;
+

+
	return it;
+
}
+

+
const ucl_object_t*
+
ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
+
{
+
	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
+
	const ucl_object_t *ret = NULL;
+

+
	UCL_SAFE_ITER_CHECK (rit);
+

+
	if (rit->impl_it == NULL) {
+
		return NULL;
+
	}
+

+
	if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) {
+
		ret = ucl_iterate_object (rit->impl_it, &rit->expl_it, true);
+

+
		if (ret == NULL) {
+
			/* Need to switch to another implicit object in chain */
+
			rit->impl_it = rit->impl_it->next;
+
			rit->expl_it = NULL;
+
			return ucl_object_iterate_safe (it, expand_values);
+
		}
+
	}
+
	else {
+
		/* Just iterate over the implicit array */
+
		ret = rit->impl_it;
+
		rit->impl_it = rit->impl_it->next;
+
		if (expand_values) {
+
			/* We flatten objects if need to expand values */
+
			if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) {
+
				return ucl_object_iterate_safe (it, expand_values);
+
			}
+
		}
+
	}
+

+
	return ret;
+
}
+

+
void
+
ucl_object_iterate_free (ucl_object_iter_t it)
+
{
+
	struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
+

+
	UCL_SAFE_ITER_CHECK (rit);
+

+
	UCL_FREE (sizeof (*rit), it);
+
}
+

const ucl_object_t *
ucl_lookup_path (const ucl_object_t *top, const char *path_in) {
	const ucl_object_t *o = NULL, *found;
@@ -1733,6 +1855,17 @@ ucl_object_new_full (ucl_type_t type, unsigned priority)
			new->next = NULL;
			new->prev = new;
			ucl_object_set_priority (new, priority);
+

+
			if (type == UCL_ARRAY) {
+
				new->value.av = UCL_ALLOC (sizeof (ucl_array_t));
+
				if (new->value.av) {
+
					memset (new->value.av, 0, sizeof (ucl_array_t));
+
					UCL_ARRAY_GET (vec, new);
+

+
					/* Preallocate some space for arrays */
+
					kv_resize (ucl_object_t *, *vec, 8);
+
				}
+
			}
		}
	}
	else {
@@ -1826,23 +1959,20 @@ ucl_object_frombool (bool bv)
bool
ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
{
-
	ucl_object_t *head;
+
	UCL_ARRAY_GET (vec, top);

	if (elt == NULL || top == NULL) {
		return false;
	}

-
	head = top->value.av;
-
	if (head == NULL) {
-
		top->value.av = elt;
-
		elt->prev = elt;
+
	if (vec == NULL) {
+
		vec = UCL_ALLOC (sizeof (*vec));
+
		kv_init (*vec);
+
		top->value.av = (void *)vec;
	}
-
	else {
-
		elt->prev = head->prev;
-
		head->prev->next = elt;
-
		head->prev = elt;
-
	}
-
	elt->next = NULL;
+

+
	kv_push (ucl_object_t *, *vec, elt);
+

	top->len ++;

	return true;
@@ -1851,24 +1981,23 @@ ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
bool
ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
{
-
	ucl_object_t *head;
+
	UCL_ARRAY_GET (vec, top);

	if (elt == NULL || top == NULL) {
		return false;
	}

-

-
	head = top->value.av;
-
	if (head == NULL) {
-
		top->value.av = elt;
-
		elt->prev = elt;
+
	if (vec == NULL) {
+
		vec = UCL_ALLOC (sizeof (*vec));
+
		kv_init (*vec);
+
		top->value.av = (void *)vec;
+
		kv_push (ucl_object_t *, *vec, elt);
	}
	else {
-
		elt->prev = head->prev;
-
		head->prev = elt;
+
		/* Slow O(n) algorithm */
+
		kv_prepend (ucl_object_t *, *vec, elt);
	}
-
	elt->next = head;
-
	top->value.av = elt;
+

	top->len ++;

	return true;
@@ -1877,21 +2006,29 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
bool
ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
{
-
	ucl_object_t *cur, *tmp, *cp;
+
	unsigned i;
+
	ucl_object_t **obj;
+
	UCL_ARRAY_GET (v1, top);
+
	UCL_ARRAY_GET (v2, elt);

	if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
		return false;
	}

-
	DL_FOREACH_SAFE (elt->value.av, cur, tmp) {
+
	kv_concat (ucl_object_t *, *v1, *v2);
+

+
	for (i = v2->n; i < v1->n; i ++) {
+
		obj = &kv_A (*v1, i);
+
		if (*obj == NULL) {
+
			continue;
+
		}
+

+
		top->len ++;
		if (copy) {
-
			cp = ucl_object_copy (cur);
+
			*obj = ucl_object_copy (*obj);
		}
		else {
-
			cp = ucl_object_ref (cur);
-
		}
-
		if (cp != NULL) {
-
			ucl_array_append (top, cp);
+
			ucl_object_ref (*obj);
		}
	}

@@ -1901,82 +2038,85 @@ ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
ucl_object_t *
ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
{
-
	ucl_object_t *head;
-

-
	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
-
		return NULL;
-
	}
-
	head = top->value.av;
+
	UCL_ARRAY_GET (vec, top);
+
	ucl_object_t *ret = NULL;
+
	unsigned i;

-
	if (elt->prev == elt) {
-
		top->value.av = NULL;
-
	}
-
	else if (elt == head) {
-
		elt->next->prev = elt->prev;
-
		top->value.av = elt->next;
-
	}
-
	else {
-
		elt->prev->next = elt->next;
-
		if (elt->next) {
-
			elt->next->prev = elt->prev;
-
		}
-
		else {
-
			head->prev = elt->prev;
+
	for (i = 0; i < vec->n; i ++) {
+
		if (kv_A (*vec, i) == elt) {
+
			kv_del (ucl_object_t *, *vec, i);
+
			ret = elt;
+
			top->len --;
+
			break;
		}
	}
-
	elt->next = NULL;
-
	elt->prev = elt;
-
	top->len --;

-
	return elt;
+
	return ret;
}

const ucl_object_t *
ucl_array_head (const ucl_object_t *top)
{
+
	UCL_ARRAY_GET (vec, top);
+

	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
		return NULL;
	}
-
	return top->value.av;
+

+
	return (vec->n > 0 ? vec->a[0] : NULL);
}

const ucl_object_t *
ucl_array_tail (const ucl_object_t *top)
{
+
	UCL_ARRAY_GET (vec, top);
+

	if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
		return NULL;
	}
-
	return top->value.av->prev;
+

+
	return (vec->n > 0 ? vec->a[vec->n - 1] : NULL);
}

ucl_object_t *
ucl_array_pop_last (ucl_object_t *top)
{
-
	return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_tail (top)));
+
	UCL_ARRAY_GET (vec, top);
+
	ucl_object_t **obj, *ret = NULL;
+

+
	if (vec != NULL && vec->n > 0) {
+
		obj = &kv_A (*vec, vec->n - 1);
+
		ret = *obj;
+
		kv_del (ucl_object_t *, *vec, vec->n - 1);
+
		top->len --;
+
	}
+

+
	return ret;
}

ucl_object_t *
ucl_array_pop_first (ucl_object_t *top)
{
-
	return ucl_array_delete (top, __DECONST(ucl_object_t *, ucl_array_head (top)));
+
	UCL_ARRAY_GET (vec, top);
+
	ucl_object_t **obj, *ret = NULL;
+

+
	if (vec != NULL && vec->n > 0) {
+
		obj = &kv_A (*vec, 0);
+
		ret = *obj;
+
		kv_del (ucl_object_t *, *vec, 0);
+
		top->len --;
+
	}
+

+
	return ret;
}

const ucl_object_t *
ucl_array_find_index (const ucl_object_t *top, unsigned int index)
{
-
	ucl_object_iter_t it = NULL;
-
	const ucl_object_t *ret;
-

-
	if (top == NULL || top->type != UCL_ARRAY || top->len == 0 ||
-
	    (index + 1) > top->len) {
-
		return NULL;
-
	}
+
	UCL_ARRAY_GET (vec, top);

-
	while ((ret = ucl_iterate_object (top, &it, true)) != NULL) {
-
		if (index == 0) {
-
			return ret;
-
		}
-
		--index;
+
	if (vec != NULL && vec->n > 0 && index < vec->n) {
+
		return kv_A (*vec, index);
	}

	return NULL;
@@ -1986,22 +2126,15 @@ ucl_object_t *
ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
	unsigned int index)
{
-
	ucl_object_t *cur, *tmp;
-

-
	if (top == NULL || top->type != UCL_ARRAY || elt == NULL ||
-
			top->len == 0 || (index + 1) > top->len) {
-
		return NULL;
-
	}
+
	UCL_ARRAY_GET (vec, top);
+
	ucl_object_t *ret = NULL;

-
	DL_FOREACH_SAFE (top->value.av, cur, tmp) {
-
		if (index == 0) {
-
			DL_REPLACE_ELEM (top->value.av, cur, elt);
-
			return cur;
-
		}
-
		--index;
+
	if (vec != NULL && vec->n > 0 && index < vec->n) {
+
		ret = kv_A (*vec, index);
+
		kv_A (*vec, index) = elt;
	}

-
	return NULL;
+
	return ret;
}

ucl_object_t *
@@ -2331,16 +2464,27 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)
		break;
	case UCL_ARRAY:
		if (o1->len == o2->len) {
-
			it1 = o1->value.av;
-
			it2 = o2->value.av;
+
			UCL_ARRAY_GET (vec1, o1);
+
			UCL_ARRAY_GET (vec2, o1);
+
			unsigned i;
+

			/* Compare all elements in both arrays */
-
			while (it1 != NULL && it2 != NULL) {
-
				ret = ucl_object_compare (it1, it2);
-
				if (ret != 0) {
-
					break;
+
			for (i = 0; i < vec1->n; i ++) {
+
				it1 = kv_A (*vec1, i);
+
				it2 = kv_A (*vec2, i);
+

+
				if (it1 == NULL && it2 != NULL) {
+
					return -1;
+
				}
+
				else if (it2 == NULL && it1 != NULL) {
+
					return 1;
+
				}
+
				else if (it1 != NULL && it2 != NULL) {
+
					ret = ucl_object_compare (it1, it2);
+
					if (ret != 0) {
+
						break;
+
					}
				}
-
				it1 = it1->next;
-
				it2 = it2->next;
			}
		}
		else {
@@ -2377,11 +2521,14 @@ void
ucl_object_array_sort (ucl_object_t *ar,
		int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2))
{
+
	UCL_ARRAY_GET (vec, ar);
+

	if (cmp == NULL || ar == NULL || ar->type != UCL_ARRAY) {
		return;
	}

-
	DL_SORT (ar->value.av, cmp);
+
	qsort (vec->a, vec->n, sizeof (ucl_object_t *),
+
			(int (*)(const void *, const void *))cmp);
}

#define PRIOBITS 4
modified external/libucl/tests/test_generate.c
@@ -30,7 +30,8 @@ int
main (int argc, char **argv)
{
	ucl_object_t *obj, *cur, *ar, *ref;
-
	const ucl_object_t *found;
+
	ucl_object_iter_t it;
+
	const ucl_object_t *found, *it_obj;
	FILE *out;
	unsigned char *emitted;
	const char *fname_out = NULL;
@@ -59,7 +60,7 @@ main (int argc, char **argv)
	cur = ucl_object_fromstring_common ("value1", 0, UCL_STRING_TRIM);
	ucl_object_insert_key (obj, cur, "key0", 0, false);
	cur = ucl_object_fromdouble (0.1);
-
	ucl_object_replace_key (obj, cur, "key0", 0, false);
+
	assert (ucl_object_replace_key (obj, cur, "key0", 0, false));

	/* Create some strings */
	cur = ucl_object_fromstring_common ("  test string    ", 0, UCL_STRING_TRIM);
@@ -139,6 +140,33 @@ main (int argc, char **argv)
	found = ucl_lookup_path (obj, "key9..key1");
	assert (found == NULL);

+
	/* Test iteration */
+
	it = ucl_object_iterate_new (obj);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	/* key0 = 0.1 */
+
	assert (ucl_object_type (it_obj) == UCL_FLOAT);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	/* key1 = "" */
+
	assert (ucl_object_type (it_obj) == UCL_STRING);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	/* key2 = "" */
+
	assert (ucl_object_type (it_obj) == UCL_STRING);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	/* key3 = "" */
+
	assert (ucl_object_type (it_obj) == UCL_STRING);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	/* key4 = ([float, int, float], boolean) */
+
	ucl_object_iterate_reset (it, it_obj);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (ucl_object_type (it_obj) == UCL_FLOAT);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (ucl_object_type (it_obj) == UCL_INT);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (ucl_object_type (it_obj) == UCL_FLOAT);
+
	it_obj = ucl_object_iterate_safe (it, true);
+
	assert (ucl_object_type (it_obj) == UCL_BOOLEAN);
+
	ucl_object_iterate_free (it);
+

	emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);

	fprintf (out, "%s\n", emitted);