From 046c0a8bbffb572df1c6376d3bf525aac9b3a9fa Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 8 Feb 2012 01:38:38 +0000 Subject: Heavily revise atom extension into a release candidate. --- lv2/ns/ext/atom/atom-helpers.h | 306 +++++++++++++++++++++++++++++------------ 1 file changed, 221 insertions(+), 85 deletions(-) (limited to 'lv2/ns/ext/atom/atom-helpers.h') diff --git a/lv2/ns/ext/atom/atom-helpers.h b/lv2/ns/ext/atom/atom-helpers.h index 4e51c89..6fff74b 100644 --- a/lv2/ns/ext/atom/atom-helpers.h +++ b/lv2/ns/ext/atom/atom-helpers.h @@ -1,5 +1,5 @@ /* - Copyright 2008-2011 David Robillard + Copyright 2008-2012 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -17,153 +17,285 @@ /** @file atom-helpers.h Helper functions for the LV2 Atom extension. - These functions are provided for convenience only, use of them is not - required for supporting atoms. + Note these functions are all static inline, do not take their address. - Note that these functions are all static inline which basically means: - do not take the address of these functions. + This header is non-normative, it is provided for convenience. */ #ifndef LV2_ATOM_HELPERS_H #define LV2_ATOM_HELPERS_H -#include #include #include #include #include "lv2/lv2plug.in/ns/ext/atom/atom.h" -typedef LV2_Atom_Property* LV2_Thing_Iter; +#ifdef __cplusplus +extern "C" { +#else +# include +#endif -/** Get an iterator pointing to @c prop in some LV2_Thing */ -static inline LV2_Thing_Iter -lv2_thing_begin(const LV2_Thing* obj) +/** Pad a size to 64 bits. */ +static inline uint32_t +lv2_atom_pad_size(uint32_t size) { - return (LV2_Thing_Iter)(obj->properties); + return (size + 7) & (~7); } -/** Return true iff @c iter has reached the end of @c thing */ +/** Return true iff @p atom is null. */ static inline bool -lv2_thing_iter_is_end(const LV2_Thing* obj, LV2_Thing_Iter iter) +lv2_atom_is_null(const LV2_Atom* atom) { - return (uint8_t*)iter >= ((uint8_t*)obj + sizeof(LV2_Atom) + obj->size); + return !atom || (atom->type == 0 && atom->size == 0); } -/** Return true iff @c l points to the same property as @c r */ +/** Return true iff @p a is equal to @p b. */ static inline bool -lv2_thing_iter_equals(const LV2_Thing_Iter l, const LV2_Thing_Iter r) +lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) { - return l == r; + 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 an iterator to the property following @c iter */ -static inline LV2_Thing_Iter -lv2_thing_iter_next(const LV2_Thing_Iter iter) +/** 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 (LV2_Thing_Iter)((uint8_t*)iter - + sizeof(LV2_Atom_Property) - + lv2_atom_pad_size(iter->value.size)); + return (uint8_t*)i >= ((uint8_t*)seq + sizeof(LV2_Atom) + seq->atom.size); } -/** Return the property pointed to by @c iter */ -static inline LV2_Atom_Property* -lv2_thing_iter_get(LV2_Thing_Iter iter) +/** 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_Property*)iter; + 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 properties of an Thing. - @param thing The thing to iterate over + 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.: -
-   LV2_THING_FOREACH(thing, i) {
-   LV2_Atom_Property* prop = lv2_thing_iter_get(i);
-   // Do things with prop here...
+   @code
+   LV2_SEQUENCE_FOREACH(sequence, i) {
+       LV2_Atom_Event* ev = lv2_sequence_iter_get(i);
+       // Do something with ev here...
    }
-   
+ @endcode */ -#define LV2_THING_FOREACH(thing, iter) \ - for (LV2_Thing_Iter (iter) = lv2_thing_begin(thing); \ - !lv2_thing_iter_is_end(thing, (iter)); \ - (iter) = lv2_thing_iter_next(iter)) +#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)) /** - Append a Property body to an Atom that contains properties (e.g. atom:Thing). - @param thing Pointer to the atom that contains the property to add. thing.size - must be valid, but thing.type is ignored. - @param key The key of the new property - @param value_type The type of the new value - @param value_size The size of the new value - @param value_body Pointer to the new value's data - @return a pointer to the new LV2_Atom_Property in @c body. - - This function will write the property body (not including an LV2_Thing - header) at lv2_atom_pad_size(body + size). Thus, it can be used with any - Atom type that contains headerless 32-bit aligned properties. + @} + @name Tuple Iterator + @{ */ -static inline LV2_Atom_Property* -lv2_thing_append(LV2_Thing* thing, - uint32_t key, - uint32_t value_type, - uint32_t value_size, - const void* value_body) -{ - thing->size = lv2_atom_pad_size(thing->size); - LV2_Atom_Property* prop = (LV2_Atom_Property*)( - (uint8_t*)thing + sizeof(LV2_Atom) + thing->size); - prop->key = key; - prop->value.type = value_type; - prop->value.size = value_size; - memcpy(prop->value.body, value_body, value_size); - thing->size += sizeof(LV2_Atom_Property) + value_size; - return prop; -} - -/** Return true iff @c atom is NULL */ + +/** 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_atom_is_null(LV2_Atom* atom) +lv2_tuple_is_end(const LV2_Atom_Tuple* tup, LV2_Atom_Tuple_Iter i) { - return !atom || (atom->type == 0 && atom->size == 0); + return (uint8_t*)i >= ((uint8_t*)tup + sizeof(LV2_Atom) + tup->atom.size); } -/** A single entry in an Thing query. */ +/** 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_Property* prop = lv2_tuple_iter_get(i); + // Do something with prop 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* 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_Thing_Query; +} LV2_Atom_Object_Query; -static const LV2_Thing_Query LV2_THING_QUERY_END = { 0, NULL }; +static const LV2_Atom_Object_Query LV2_OBJECT_QUERY_END = { 0, NULL }; /** - "Query" an thing, getting a pointer to the values for various keys. + Get an object's values for various keys. - The value pointer of each item in @c query will be set to the location of - the corresponding value in @c thing. Every value pointer in @c query MUST - be initialised to NULL. This function reads @c thing in a single linear - sweep. By allocating @c query on the stack, things can be "queried" + 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_thing_query(const LV2_Thing* thing, LV2_Thing_Query* query) +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_Thing_Query* q = query; q->key; ++q) + for (LV2_Atom_Object_Query* q = query; q->key; ++q) { ++n_queries; + } - LV2_THING_FOREACH(thing, o) { - const LV2_Atom_Property* prop = lv2_thing_iter_get(o); - for (LV2_Thing_Query* q = query; q->key; ++q) { + 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) + if (++matches == n_queries) { return matches; + } break; } } @@ -171,4 +303,8 @@ lv2_thing_query(const LV2_Thing* thing, LV2_Thing_Query* query) return matches; } +/** + @} +*/ + #endif /* LV2_ATOM_HELPERS_H */ -- cgit v1.2.1