aboutsummaryrefslogtreecommitdiffstats
path: root/lv2/lv2plug.in/ns/ext/atom/util.h
diff options
context:
space:
mode:
Diffstat (limited to 'lv2/lv2plug.in/ns/ext/atom/util.h')
-rw-r--r--lv2/lv2plug.in/ns/ext/atom/util.h372
1 files changed, 372 insertions, 0 deletions
diff --git a/lv2/lv2plug.in/ns/ext/atom/util.h b/lv2/lv2plug.in/ns/ext/atom/util.h
new file mode 100644
index 0000000..6ba792c
--- /dev/null
+++ b/lv2/lv2plug.in/ns/ext/atom/util.h
@@ -0,0 +1,372 @@
+/*
+ Copyright 2008-2012 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+ @file util.h Helper functions for the LV2 Atom extension.
+
+ Note these functions are all static inline, do not take their address.
+
+ This header is non-normative, it is provided for convenience.
+*/
+
+#ifndef LV2_ATOM_HELPERS_H
+#define LV2_ATOM_HELPERS_H
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+
+#ifdef __cplusplus
+extern "C" {
+#else
+# include <stdbool.h>
+#endif
+
+/** Pad a size to 64 bits. */
+static inline uint32_t
+lv2_atom_pad_size(uint32_t size)
+{
+ return (size + 7) & (~7);
+}
+
+/** Return the total size of @p atom, including the header. */
+static inline uint32_t
+lv2_atom_total_size(const LV2_Atom* atom)
+{
+ return sizeof(LV2_Atom) + atom->size;
+}
+
+/** Return true iff @p atom is null. */
+static inline bool
+lv2_atom_is_null(const LV2_Atom* atom)
+{
+ return !atom || (atom->type == 0 && atom->size == 0);
+}
+
+/** Return true iff @p a is equal to @p b. */
+static inline bool
+lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b)
+{
+ return (a == b) || (
+ (a->type == b->type) &&
+ (a->size == b->size) &&
+ !memcmp(LV2_ATOM_CONTENTS(LV2_Atom, a),
+ LV2_ATOM_CONTENTS(LV2_Atom, b),
+ a->size));
+}
+
+/**
+ @name Sequence Iterator
+ @{
+*/
+
+/** An iterator over the elements of an LV2_Atom_Sequence. */
+typedef LV2_Atom_Event* LV2_Atom_Sequence_Iter;
+
+/** Get an iterator pointing to the first element in @p tup. */
+static inline LV2_Atom_Sequence_Iter
+lv2_sequence_begin(const LV2_Atom_Sequence* seq)
+{
+ return (LV2_Atom_Sequence_Iter)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq));
+}
+
+/** Return true iff @p i has reached the end of @p tup. */
+static inline bool
+lv2_sequence_is_end(const LV2_Atom_Sequence* seq, LV2_Atom_Sequence_Iter i)
+{
+ return (uint8_t*)i >= ((uint8_t*)seq + sizeof(LV2_Atom) + seq->atom.size);
+}
+
+/** Return an iterator to the element following @p i. */
+static inline LV2_Atom_Sequence_Iter
+lv2_sequence_iter_next(const LV2_Atom_Sequence_Iter i)
+{
+ return (LV2_Atom_Sequence_Iter)((uint8_t*)i
+ + sizeof(LV2_Atom_Event)
+ + lv2_atom_pad_size(i->body.size));
+}
+
+/** Return the element pointed to by @p i. */
+static inline LV2_Atom_Event*
+lv2_sequence_iter_get(LV2_Atom_Sequence_Iter i)
+{
+ return (LV2_Atom_Event*)i;
+}
+
+/**
+ A macro for iterating over all events in a Sequence.
+ @param sequence The sequence to iterate over
+ @param iter The name of the iterator
+
+ This macro is used similarly to a for loop (which it expands to), e.g.:
+ @code
+ LV2_SEQUENCE_FOREACH(sequence, i) {
+ LV2_Atom_Event* ev = lv2_sequence_iter_get(i);
+ // Do something with ev here...
+ }
+ @endcode
+*/
+#define LV2_SEQUENCE_FOREACH(sequence, iter) \
+ for (LV2_Atom_Sequence_Iter (iter) = lv2_sequence_begin(sequence); \
+ !lv2_sequence_is_end(sequence, (iter)); \
+ (iter) = lv2_sequence_iter_next(iter))
+
+/**
+ @}
+ @name Tuple Iterator
+ @{
+*/
+
+/** An iterator over the elements of an LV2_Atom_Tuple. */
+typedef LV2_Atom* LV2_Atom_Tuple_Iter;
+
+/** Get an iterator pointing to the first element in @p tup. */
+static inline LV2_Atom_Tuple_Iter
+lv2_tuple_begin(const LV2_Atom_Tuple* tup)
+{
+ return (LV2_Atom_Tuple_Iter)(LV2_ATOM_BODY(tup));
+}
+
+/** Return true iff @p i has reached the end of @p tup. */
+static inline bool
+lv2_tuple_is_end(const LV2_Atom_Tuple* tup, LV2_Atom_Tuple_Iter i)
+{
+ return (uint8_t*)i >= ((uint8_t*)tup + sizeof(LV2_Atom) + tup->atom.size);
+}
+
+/** Return an iterator to the element following @p i. */
+static inline LV2_Atom_Tuple_Iter
+lv2_tuple_iter_next(const LV2_Atom_Tuple_Iter i)
+{
+ return (LV2_Atom_Tuple_Iter)(
+ (uint8_t*)i + sizeof(LV2_Atom) + lv2_atom_pad_size(i->size));
+}
+
+/** Return the element pointed to by @p i. */
+static inline LV2_Atom*
+lv2_tuple_iter_get(LV2_Atom_Tuple_Iter i)
+{
+ return (LV2_Atom*)i;
+}
+
+/**
+ A macro for iterating over all properties of a Tuple.
+ @param tuple The tuple to iterate over
+ @param iter The name of the iterator
+
+ This macro is used similarly to a for loop (which it expands to), e.g.:
+ @code
+ LV2_TUPLE_FOREACH(tuple, i) {
+ LV2_Atom* elem = lv2_tuple_iter_get(i);
+ // Do something with elem here...
+ }
+ @endcode
+*/
+#define LV2_TUPLE_FOREACH(tuple, iter) \
+ for (LV2_Atom_Tuple_Iter (iter) = lv2_tuple_begin(tuple); \
+ !lv2_tuple_is_end(tuple, (iter)); \
+ (iter) = lv2_tuple_iter_next(iter))
+
+/**
+ @}
+ @name Object Iterator
+ @{
+*/
+
+/** An iterator over the properties of an LV2_Atom_Object. */
+typedef LV2_Atom_Property_Body* LV2_Atom_Object_Iter;
+
+/** Get an iterator pointing to the first property in @p obj. */
+static inline LV2_Atom_Object_Iter
+lv2_object_begin(const LV2_Atom_Object* obj)
+{
+ return (LV2_Atom_Object_Iter)(LV2_ATOM_CONTENTS(LV2_Atom_Object, obj));
+}
+
+/** Return true iff @p i has reached the end of @p obj. */
+static inline bool
+lv2_object_is_end(const LV2_Atom_Object* obj, LV2_Atom_Object_Iter i)
+{
+ return (uint8_t*)i >= ((uint8_t*)obj + sizeof(LV2_Atom) + obj->atom.size);
+}
+
+/** Return true iff @p l points to the same property as @p r. */
+static inline bool
+lv2_object_iter_equals(const LV2_Atom_Object_Iter l,
+ const LV2_Atom_Object_Iter r)
+{
+ return l == r;
+}
+
+/** Return an iterator to the property following @p i. */
+static inline LV2_Atom_Object_Iter
+lv2_object_iter_next(const LV2_Atom_Object_Iter i)
+{
+ const LV2_Atom* const value = (LV2_Atom*)((uint8_t*)i + sizeof(i));
+ return (LV2_Atom_Object_Iter)((uint8_t*)i
+ + sizeof(LV2_Atom_Property_Body)
+ + lv2_atom_pad_size(value->size));
+}
+
+/** Return the property pointed to by @p i. */
+static inline LV2_Atom_Property_Body*
+lv2_object_iter_get(LV2_Atom_Object_Iter i)
+{
+ return (LV2_Atom_Property_Body*)i;
+}
+
+/**
+ A macro for iterating over all properties of an Object.
+ @param object The object to iterate over
+ @param iter The name of the iterator
+
+ This macro is used similarly to a for loop (which it expands to), e.g.:
+ @code
+ LV2_OBJECT_FOREACH(object, i) {
+ LV2_Atom_Property_Body* prop = lv2_object_iter_get(i);
+ // Do something with prop here...
+ }
+ @endcode
+*/
+#define LV2_OBJECT_FOREACH(object, iter) \
+ for (LV2_Atom_Object_Iter (iter) = lv2_object_begin(object); \
+ !lv2_object_is_end(object, (iter)); \
+ (iter) = lv2_object_iter_next(iter))
+
+/**
+ @}
+ @name Object Query
+ @{
+*/
+
+/** A single entry in an Object query. */
+typedef struct {
+ uint32_t key; /**< Key to query (input set by user) */
+ const LV2_Atom** value; /**< Found value (output set by query function) */
+} LV2_Atom_Object_Query;
+
+static const LV2_Atom_Object_Query LV2_OBJECT_QUERY_END = { 0, NULL };
+
+/**
+ Get an object's values for various keys.
+
+ The value pointer of each item in @p query will be set to the location of
+ the corresponding value in @p object. Every value pointer in @p query MUST
+ be initialised to NULL. This function reads @p object in a single linear
+ sweep. By allocating @p query on the stack, objects can be "queried"
+ quickly without allocating any memory. This function is realtime safe.
+
+ For example:
+ @code
+ const LV2_Atom* name = NULL;
+ const LV2_Atom* age = NULL;
+ LV2_Atom_Object_Query q[] = {
+ { urids.eg_name, &name },
+ { urids.eg_age, &age },
+ LV2_OBJECT_QUERY_END
+ };
+ lv2_object_get(obj, q);
+ // name and age are now set to the appropriate values in obj, or NULL.
+ @endcode
+*/
+static inline int
+lv2_object_get(const LV2_Atom_Object* object, LV2_Atom_Object_Query* query)
+{
+ int matches = 0;
+ int n_queries = 0;
+
+ /* Count number of query keys so we can short-circuit when done */
+ for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
+ ++n_queries;
+ }
+
+ LV2_OBJECT_FOREACH(object, o) {
+ const LV2_Atom_Property_Body* prop = lv2_object_iter_get(o);
+ for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
+ if (q->key == prop->key && !*q->value) {
+ *q->value = &prop->value;
+ if (++matches == n_queries) {
+ return matches;
+ }
+ break;
+ }
+ }
+ }
+ return matches;
+}
+
+/**
+ Variable argument version of lv2_object_get().
+
+ This is nicer-looking in code, but a bit more error-prone since it is not
+ type safe and the argument list must be terminated.
+
+ The arguments should be a series of uint32_t key and const LV2_Atom** value
+ pairs, terminated by a zero key. The value pointers MUST be initialized to
+ NULL. For example:
+
+ @code
+ const LV2_Atom* name = NULL;
+ const LV2_Atom* age = NULL;
+ lv2_object_getv(obj,
+ uris.name_key, &name,
+ uris.age_key, &age,
+ 0);
+ @endcode
+*/
+static inline int
+lv2_object_getv(const LV2_Atom_Object* object, ...)
+{
+ int matches = 0;
+ int n_queries = 0;
+
+ /* Count number of query keys so we can short-circuit when done */
+ va_list args;
+ va_start(args, object);
+ for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
+ if (!va_arg(args, const LV2_Atom**)) {
+ return -1;
+ }
+ }
+ va_end(args);
+
+ LV2_OBJECT_FOREACH(object, o) {
+ const LV2_Atom_Property_Body* prop = lv2_object_iter_get(o);
+ va_start(args, object);
+ for (int i = 0; i < n_queries; ++i) {
+ uint32_t qkey = va_arg(args, uint32_t);
+ const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
+ if (qkey == prop->key && !*qval) {
+ *qval = &prop->value;
+ if (++matches == n_queries) {
+ return matches;
+ }
+ break;
+ }
+ }
+ va_end(args);
+ }
+ return matches;
+}
+
+/**
+ @}
+*/
+
+#endif /* LV2_ATOM_HELPERS_H */