view nvl.c @ 831:1475c8609196

synch: stash the condition variable name in the condition variable This was supposed to be done during the great refactor in 2019. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Mon, 22 Feb 2021 08:21:03 -0500
parents ccb955138113
children 2198701308ed
line wrap: on
line source

/*
 * Copyright (c) 2017-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
 *
 * 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.
 */

#include <jeffpc/error.h>
#include <jeffpc/mem.h>
#include <jeffpc/nvl.h>

#include "val_impl.h"

int nvl_merge(struct nvlist *dest, struct nvlist *src)
{
	const struct nvpair *spair;

	nvl_for_each(spair, src) {
		int ret;

		ret = nvl_set(dest, str_cstr(spair->name),
			      val_getref(spair->value));
		if (ret)
			return ret;
	}

	return 0;
}

static struct nvpair *find(struct nvlist *nvl, const char *name)
{
	struct str name_str = STR_STATIC_INITIALIZER(name);
	struct nvpair key = {
		.name = &name_str,
	};

	return rb_find(&nvl->val._set_nvl.values, &key, NULL);
}

/*
 * nvlist iteration
 */

size_t nvl_numitems(struct nvlist *nvl)
{
	return rb_numnodes(&nvl->val._set_nvl.values);
}

const struct nvpair *nvl_iter_start(struct nvlist *nvl)
{
	return rb_first(&nvl->val._set_nvl.values);
}

const struct nvpair *nvl_iter_next(struct nvlist *nvl,
				   const struct nvpair *prev)
{
	return rb_next(&nvl->val._set_nvl.values, (void *) prev);
}

/*
 * nvlist lookup
 */

#define LOOKUP_INT(fxn, ctype, pairfxn)					\
int fxn(struct nvlist *nvl, const char *name, ctype *out)		\
{									\
	return pairfxn(find(nvl, name), out);				\
}

#define LOOKUP_PTR(fxn, ctype, pairfxn)					\
ctype fxn(struct nvlist *nvl, const char *name)				\
{									\
	return pairfxn(find(nvl, name));				\
}

const struct nvpair *nvl_lookup(struct nvlist *nvl, const char *name)
{
	struct nvpair *pair;

	pair = find(nvl, name);

	return pair ? pair : ERR_PTR(-ENOENT);
}

int nvl_lookup_array(struct nvlist *nvl, const char *name,
		     struct val ***vals, size_t *nelem)
{
	return nvpair_value_array(find(nvl, name), vals, nelem);
}

int nvl_lookup_blob(struct nvlist *nvl, const char *name,
		    const void **ptr, size_t *size)
{
	return nvpair_value_blob(find(nvl, name), ptr, size);
}

LOOKUP_INT(nvl_lookup_bool, bool, nvpair_value_bool);
LOOKUP_INT(nvl_lookup_int, uint64_t, nvpair_value_int);

int nvl_lookup_null(struct nvlist *nvl, const char *name)
{
	return nvpair_value_null(find(nvl, name));
}

LOOKUP_PTR(nvl_lookup_nvl, struct nvlist *, nvpair_value_nvl);
LOOKUP_PTR(nvl_lookup_str, struct str *, nvpair_value_str);
LOOKUP_PTR(nvl_lookup_val, struct val *, nvpair_value);

/*
 * nvlist set
 */

static inline int do_nvl_set(struct nvlist *nvl, const char *cname,
			     struct str *name, struct val *val)
{
	struct nvpair *pair;

	pair = find(nvl, cname);
	if (!pair) {
		/* not found - allocate a new pair */
		pair = __nvpair_alloc(name ? name : str_dup(cname));
		if (!pair) {
			val_putref(val);
			return -ENOMEM;
		}

		rb_add(&nvl->val._set_nvl.values, pair);
	} else {
		str_putref(name);
	}

	val_putref(pair->value);
	pair->value = val ? val : val_alloc_null();

	return 0;
}

int nvl_set_pair(struct nvlist *nvl, const struct nvpair *value)
{
	return do_nvl_set(nvl, nvpair_name(value), nvpair_name_str(value),
			  nvpair_value(value));
}

int nvl_set(struct nvlist *nvl, const char *name, struct val *val)
{
	return do_nvl_set(nvl, name, NULL, val);
}

#define SET(nvl, name, valalloc)					\
	do {								\
		struct val *val;					\
									\
		val = valalloc;						\
		if (IS_ERR(val))					\
			return PTR_ERR(val);				\
									\
		return nvl_set(nvl, name, val);				\
	} while (0)

#define SET_ARG0(fxn, valalloc)						\
int fxn(struct nvlist *nvl, const char *name)				\
{									\
	SET(nvl, name, valalloc());					\
}

#define SET_ARG1(fxn, ctype, valalloc)					\
int fxn(struct nvlist *nvl, const char *name, ctype v)			\
{									\
	SET(nvl, name, valalloc(v));					\
}

#define SET_ARG2(fxn, ctype1, ctype2, valalloc)				\
int fxn(struct nvlist *nvl, const char *name, ctype1 a, ctype2 b)	\
{									\
	SET(nvl, name, valalloc(a, b));					\
}

SET_ARG2(nvl_set_array, struct val **, size_t, val_alloc_array);
SET_ARG2(nvl_set_array_copy, struct val **, size_t, val_alloc_array_dup);
SET_ARG2(nvl_set_blob, void *, size_t, val_alloc_blob);
SET_ARG2(nvl_set_blob_copy, const void *, size_t, val_alloc_blob_dup);
SET_ARG1(nvl_set_bool, bool, val_alloc_bool);
SET_ARG1(nvl_set_cstr_dup, const char *, val_dup_str);
SET_ARG1(nvl_set_int, uint64_t, val_alloc_int);
SET_ARG0(nvl_set_null, val_alloc_null);
SET_ARG1(nvl_set_nvl, struct nvlist *, nvl_cast_to_val);
SET_ARG1(nvl_set_str, struct str *, str_cast_to_val);

/*
 * nvlist unset
 */

static int unset(struct nvlist *nvl, const char *name, enum val_type type,
		 bool matchtype)
{
	struct nvpair *pair;

	pair = find(nvl, name);
	if (!pair)
		return -ENOENT;

	if (matchtype && (pair->value->type != type))
		return -ERANGE;

	rb_remove(&nvl->val._set_nvl.values, pair);

	__nvpair_free(pair);

	return 0;
}

int nvl_unset(struct nvlist *nvl, const char *name)
{
	return unset(nvl, name, VT_NULL, false);
}

int nvl_unset_type(struct nvlist *nvl, const char *name, enum val_type type)
{
	return unset(nvl, name, type, true);
}

/*
 * nvlist exists
 */
bool nvl_exists(struct nvlist *nvl, const char *name)
{
	return find(nvl, name) != NULL;
}

int nvl_exists_type(struct nvlist *nvl, const char *name, enum val_type type)
{
	struct nvpair *pair;

	pair = find(nvl, name);
	if (!pair)
		return -ENOENT;

	if (pair->value->type != type)
		return -ERANGE;

	return 0;
}

/*
 * nvpair value
 */

#define VALUE_INT(fxn, ctype, nvtype, valmember)			\
int fxn(const struct nvpair *pair, ctype *out)				\
{									\
	if (!pair)							\
		return -ENOENT;						\
									\
	if (pair->value->type != nvtype)				\
		return -ERANGE;						\
									\
	*out = pair->value->valmember;					\
									\
	return 0;							\
}

#define VALUE_PTR(fxn, ctype, valtype, getref)				\
ctype fxn(const struct nvpair *pair)					\
{									\
	if (!pair)							\
		return ERR_PTR(-ENOENT);				\
									\
	if (pair->value->type != valtype)				\
		return ERR_PTR(-ERANGE);				\
									\
	return getref(pair->value);					\
}

int nvpair_value_array(const struct nvpair *pair, struct val ***vals,
		       size_t *nelem)
{
	if (!pair)
		return -ENOENT;

	if (pair->value->type != VT_ARRAY)
		return -ERANGE;

	*vals = pair->value->_set_array.vals;
	*nelem = pair->value->array.nelem;

	return 0;
}

int nvpair_value_blob(const struct nvpair *pair, const void **ptr, size_t *size)
{
	if (!pair)
		return -ENOENT;

	if (pair->value->type != VT_BLOB)
		return -ERANGE;

	*ptr = pair->value->blob.ptr;
	*size = pair->value->blob.size;

	return 0;
}

VALUE_INT(nvpair_value_bool, bool, VT_BOOL, b);
VALUE_INT(nvpair_value_int, uint64_t, VT_INT, i);

int nvpair_value_null(const struct nvpair *pair)
{
	if (!pair)
		return -ENOENT;

	if (pair->value->type != VT_NULL)
		return -ERANGE;

	return 0;
}

VALUE_PTR(nvpair_value_nvl, struct nvlist *, VT_NVL, val_getref_nvl);
VALUE_PTR(nvpair_value_str, struct str *, VT_STR, val_getref_str);

/*
 * Packing & unpacking
 */

struct nvlist *nvl_unpack(const void *ptr, size_t len, enum val_format format)
{
	struct val *val;

	val = val_unpack(ptr, len, format);
	if (IS_ERR(val))
		return ERR_CAST(val);

	if (val->type != VT_NVL) {
		val_putref(val);
		return ERR_PTR(-EINVAL);
	}

	return val_cast_to_nvl(val);
}