1 /*
2     Copyright (c) 2019, Michael Fisher <mfisher@kushview.net>
3 
4     Permission to use, copy, modify, and/or distribute this software for any
5     purpose with or without fee is hereby granted, provided that the above
6     copyright notice and this permission notice appear in all copies.
7 
8     THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9     WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10     MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11     ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12     WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13     ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 
17 /** @defgroup atom Atom
18     Dealing with LV2 Atoms
19 */
20 
21 #pragma once
22 
23 #include <iostream>
24 #include <string>
25 
26 #include <lv2/lv2plug.in/ns/ext/atom/atom.h>
27 #include <lv2/lv2plug.in/ns/ext/atom/forge.h>
28 #include <lv2/lv2plug.in/ns/ext/atom/util.h>
29 
30 namespace lvtk {
31 /* @{ */
32 /** Alias to `LV2_Atom_Event` */
33 using AtomEvent             = LV2_Atom_Event;
34 
35 /** Alias to `LV2_Atom_Property_Body` */
36 using PropertyBody          = LV2_Atom_Property_Body ;
37 
38 /** Alias to `LV2_Atom_Forge_Frame` */
39 using ForgeFrame            = LV2_Atom_Forge_Frame;
40 
41 /** Alias to `LV2_Atom_Forge_Ref` */
42 using ForgeRef              = LV2_Atom_Forge_Ref;
43 
44 /** Alias to `LV2_Atom_Object_Query` */
45 using ObjectQuery           = LV2_Atom_Object_Query;
46 
47 /** An LV2_Atom_Object wrapper
48     @headerfile lvtk/ext/atom.hpp
49  */
50 struct Object final
51 {
52     /** Create an Object from raw data. The data passed in will be casted
53         to a LV2_Atom_Object pointer
54 
55         @param data Pointer to an LV2_Atom_Object
56      */
Objectlvtk::Object57     Object (const void* data)
58         : obj ((LV2_Atom_Object*) data) { }
59 
60     /** Create an Object from a ForgeRef
61 
62         @param ref  A ForgeRef which will be casted to LV2_Atom_Object internally
63     */
Objectlvtk::Object64     Object (ForgeRef ref)
65         : obj ((LV2_Atom_Object*) ref) { }
66 
67     /** Copy constructor only references the internal pointer */
Objectlvtk::Object68     Object (const Object& other) {
69         operator= (other);
70     }
71 
72     /** @returns the object type */
otypelvtk::Object73     inline uint32_t otype() const {
74         return object_type();
75     }
76 
77     /** @returns the object type */
object_typelvtk::Object78     inline uint32_t object_type() const {
79         return obj->body.otype;
80     }
81 
82     /** Return the object's id */
idlvtk::Object83     inline uint32_t id() const {
84         return obj->body.id;
85     }
86 
87     /** Return the object's total size */
total_sizelvtk::Object88     inline uint32_t total_size() const {
89         return lv2_atom_total_size ((LV2_Atom*) obj);
90     }
91 
92     /** Get an object's values for various keys.
93 
94         The value pointer of each item in @p query will be set to the location of
95         the corresponding value in @p object.  Every value pointer in @p query MUST
96         be initialised to NULL.  This function reads @p object in a single linear
97         sweep.  By allocating @p query on the stack, objects can be "queried"
98         quickly without allocating any memory.  This method is realtime safe.
99 
100         This function can only do "flat" queries, it is not smart enough to match
101         variables in nested objects.
102     */
querylvtk::Object103     inline void query (ObjectQuery& query) const {
104         lv2_atom_object_query (obj, &query);
105     }
106 
107     /** Get the underlying LV2_Atom_Object pointer */
c_objlvtk::Object108     inline LV2_Atom_Object* c_obj()          const { return obj; }
109 
110     /** Pass this as a LV2_Atom Object* parameter */
operator LV2_Atom_Object*lvtk::Object111     inline operator LV2_Atom_Object*()       const { return obj; }
112 
113     /** Pass this as a const LV2_Atom Object* parameter */
operator const LV2_Atom_Object*lvtk::Object114     inline operator const LV2_Atom_Object*() const { return obj; }
115 
116     /** Assignment operator takes reference of the internal pointer */
operator =lvtk::Object117     inline Object& operator= (const Object& other) {
118         obj = other.obj;
119         return *this;
120     }
121 
122     /** @private */
123     struct iterator {
operator *lvtk::Object::iterator124         const PropertyBody& operator*()  const { assert (index); return *index; }
operator ->lvtk::Object::iterator125         const PropertyBody* operator->() const { assert (index); return index; }
126 
operator ++lvtk::Object::iterator127         iterator& operator++() {
128             index = lv2_atom_object_next (index);
129             if (lv2_atom_object_is_end (&obj->body, obj->atom.size, index))
130                 index = nullptr;
131             return *this;
132         }
133 
operator ++lvtk::Object::iterator134         iterator operator++ (int)  {
135             iterator ret (obj, index);
136             ++(*this);
137             return ret;
138         }
139 
operator ==lvtk::Object::iterator140         bool operator== (const iterator& other) const { return index == other.index; }
operator !=lvtk::Object::iterator141         bool operator!= (const iterator& other) const { return index != other.index; }
142 
143     private:
144         friend struct Object;
iteratorlvtk::Object::iterator145         iterator (LV2_Atom_Object* o, LV2_Atom_Property_Body* i)
146             : index (i), obj (o) { }
147         LV2_Atom_Property_Body* index;
148         LV2_Atom_Object*        obj;
149     };
150 
151     /** Start of properties */
beginlvtk::Object152     iterator begin() const { return iterator (obj, lv2_atom_object_begin (&obj->body)); }
153 
154     /** End of properties */
endlvtk::Object155     iterator end()   const { return iterator (obj, nullptr); }
156 
157 private:
158     LV2_Atom_Object* obj = nullptr;
159 };
160 
161 /** An LV2_Atom wrapper
162     These are intended to be used on the stack
163 
164     @headerfile lvtk/ext/atom.hpp
165  */
166 struct Atom final
167 {
168     /** Create a null Atom */
Atomlvtk::Atom169     Atom()
170         : atom (nullptr) {}
171 
172     /** Create an Atom from raw data */
Atomlvtk::Atom173     Atom (const void* data)
174         : atom (reinterpret_cast<const LV2_Atom*> (data))  { }
175 
176     /** Create an Atom from a Forge Ref */
Atomlvtk::Atom177     Atom (ForgeRef ref)
178         : atom (reinterpret_cast<LV2_Atom*> (ref)) { }
179 
180     /** Create an Atom from an AtomEvent */
Atomlvtk::Atom181     Atom (const AtomEvent* ev)
182         : atom (&ev->body) {}
183 
184     /** Create an Atom from a CType reference */
Atomlvtk::Atom185     Atom (const LV2_Atom& ref)
186         : atom (&ref) {}
187 
188     /** Create an Atom from an Object */
Atomlvtk::Atom189     Atom (const Object& obj)
190         : atom ((const LV2_Atom*) obj.c_obj()) { }
191 
192     /** Pad a size to 64 bits
193         @param size The size to pad
194         @returns The padded size
195      */
pad_sizelvtk::Atom196     inline static uint32_t pad_size (uint32_t size) {
197         return lv2_atom_pad_size (size);
198     }
199 
200     /** Determine if the Atom is null */
is_nulllvtk::Atom201     inline bool is_null() const {
202         return lv2_atom_is_null (atom);
203     }
204 
205     /** Returns true if this atom has type and equals a given value
206         @param type     The atom POD type
207         @param value    The value to test
208     */
209     template<typename POD>
has_type_and_equalslvtk::Atom210     inline bool has_type_and_equals (uint32_t type, const POD& value) const {
211         return atom->type == type && operator== (value);
212     }
213 
214     /** Get the Atom's body */
bodylvtk::Atom215     inline void* body()           const { return LV2_ATOM_BODY (atom); }
216 
217     /** Get the body as a boolean */
as_boollvtk::Atom218     inline bool as_bool()         const { return ((LV2_Atom_Bool*)atom)->body > 0; }
219 
220     /** Get the body as a float */
as_floatlvtk::Atom221     inline float as_float()       const { return ((LV2_Atom_Float*)atom)->body; }
222 
223     /** Get the body as a double */
as_doublelvtk::Atom224     inline double as_double()     const { return ((LV2_Atom_Double*)atom)->body; }
225 
226     /** Returns the atom casted to LV2_Atom_Object */
as_objectlvtk::Atom227     const Object as_object()      const { return Object ((LV2_Atom_Object* ) atom); }
228 
229     /** Get the body as a string */
as_stringlvtk::Atom230     inline const char* as_string() const { return (const char*) LV2_ATOM_BODY (atom); }
231 
232     /** Get the body as a 32bit integer */
as_intlvtk::Atom233     inline int32_t as_int()       const { return ((LV2_Atom_Int*)atom)->body; }
234 
235     /** Get the body as a long */
as_longlvtk::Atom236     inline int64_t as_long()      const { return ((LV2_Atom_Long*)atom)->body; }
237 
238     /** Get the body as a URID */
as_uridlvtk::Atom239     inline uint32_t as_urid()     const { return ((LV2_Atom_URID*)atom)->body; }
240 
241     /** Get this Atom's type */
typelvtk::Atom242     inline uint32_t type()        const { return atom->type; }
243 
244     /** Get the Atom's total size */
total_sizelvtk::Atom245     inline uint32_t total_size()  const { return lv2_atom_total_size (atom); }
246 
247     /** Get the Atom's body size */
sizelvtk::Atom248     inline uint32_t size()        const { return atom->size; }
249 
250     /** Get the underlying LV2_Atom pointer */
c_objlvtk::Atom251     inline const LV2_Atom* c_obj() const { return atom; }
252 
253     /** Castable to bool */
operator boollvtk::Atom254     inline operator bool() const { return ! lv2_atom_is_null (atom); }
255 
256     /** Castable to const LV2_Atom* */
operator const LV2_Atom*lvtk::Atom257     inline operator const LV2_Atom*() const { return atom; }
258 
259     /** Reference another atom
260         Does NOT make a copy, instead references the other
261         Atom's internal pointer
262      */
operator =lvtk::Atom263     inline Atom& operator= (const Atom& other) {
264         atom = other.atom;
265         return *this;
266     }
267 
268     /** Equality operator */
operator ==lvtk::Atom269     inline bool operator== (const Atom& other) const {
270         return lv2_atom_equals (atom, other.atom);
271     }
272 
273     /** Inequality operator */
operator !=lvtk::Atom274     inline bool operator!= (const Atom& other) const {
275         return ! lv2_atom_equals (atom, other.atom);
276     }
277 
278 private:
279     friend struct Object;
280     const LV2_Atom* atom = nullptr;
281 
282     /** @private Used by has_type_and_equals */
operator ==lvtk::Atom283     inline bool operator== (const LV2_URID& u) const { return (((LV2_Atom_URID*)atom)->body == u); }
operator ==lvtk::Atom284     inline bool operator== (const int32_t& i)  const { return (((LV2_Atom_Int*)atom)->body == i); }
operator ==lvtk::Atom285     inline bool operator== (const int64_t& l)  const { return (((LV2_Atom_Long*)atom)->body == l); }
operator ==lvtk::Atom286     inline bool operator== (const float& f)    const { return (((LV2_Atom_Float*)atom)->body == f); }
operator ==lvtk::Atom287     inline bool operator== (const double& f)   const { return (((LV2_Atom_Double*)atom)->body == f); }
288 };
289 
290 /** An LV2_Atom_Sequence wrapper.
291 
292     Since this implements an STL style container, you can use it as follows:
293     @code
294 
295         Sequence seq (my_lv2_sequence_ptr());
296         for (const auto& ev : seq) {
297             // handle event
298         }
299 
300     @endcode
301     @headerfile lvtk/ext/atom.hpp
302 */
303 struct Sequence final
304 {
305     typedef AtomEvent* pointer;
306     typedef AtomEvent& reference;
307     typedef const AtomEvent* const_pointer;
308     typedef const AtomEvent& const_reference;
309 
310     /** Create an Sequence from raw data
311         @param seq  Pointer to an LV2_Atom_Sequence
312      */
Sequencelvtk::Sequence313     Sequence (const void* data)
314         : sequence ((LV2_Atom_Sequence*) data) { }
315 
316     /** Create an AtomSequnce from an LV2_Atom_Sequence
317         @param seq The sequence to wrap
318      */
Sequencelvtk::Sequence319     Sequence (LV2_Atom_Sequence* seq)
320         : sequence (seq) { }
321 
322     /** Create an Sequence from a ForgeRef */
Sequencelvtk::Sequence323     Sequence (ForgeRef ref)
324         : sequence ((LV2_Atom_Sequence*) ref) { }
325 
326     /** Reset for writing */
resetlvtk::Sequence327     inline void reset() {
328         sequence->atom.size = sizeof (LV2_Atom_Sequence_Body);
329     }
330 
331     /** Return the sequence body's pad. Currently unused per LV2 spec. */
padlvtk::Sequence332     inline uint32_t pad() const { return sequence->body.pad; }
333 
334     /** Return the sequence's body size
335         @note This method does NOT return the number of events contained in
336               the Sequence.  It is the size in terms of bytes.
337     */
sizelvtk::Sequence338     inline uint32_t size() const        { return sequence->atom.size; }
339 
340     /** Return the sequence's unit */
unitlvtk::Sequence341     inline uint32_t unit() const        { return sequence->body.unit; }
342 
343     /** Return the sequence's c-type */
c_objlvtk::Sequence344     inline LV2_Atom_Sequence* c_obj()   { return sequence; }
345 
346     /** Castable to bool. True if the sequence isn't nullptr */
operator boollvtk::Sequence347     inline operator bool() const        { return sequence != 0; }
348 
349     /** Castable to LV2_Atom_Sequence */
operator LV2_Atom_Sequence*lvtk::Sequence350     inline operator LV2_Atom_Sequence*() const { return sequence; }
351 
352     /** @private */
operator uint8_t*lvtk::Sequence353     inline operator uint8_t*() const    { return (uint8_t*) sequence; }
354 
355     /** Append an AtomEvent to the end of the sequence.
356 
357         Effectively this is the same as lv2_atom_sequence_append, but
358         re-implemented to avoid an extra function call.
359 
360         @param ev The event to add
361      */
appendlvtk::Sequence362     inline void append (const AtomEvent& ev) {
363         if (AtomEvent* pos = lv2_atom_sequence_end (&sequence->body, sequence->atom.size)) {
364             auto total_size = (uint32_t)sizeof(ev) + ev.body.size;
365             memcpy (pos, &ev, total_size);
366             sequence->atom.size += lv2_atom_pad_size (total_size);
367         }
368     }
369 
370     /** Insert an AtomEvent into the middle of the sequence
371 
372         @param ev The event to insert
373      */
insertlvtk::Sequence374     inline void insert (const AtomEvent& ev) {
375         AtomEvent* e = lv2_atom_sequence_end (&sequence->body, sequence->atom.size);
376         LV2_ATOM_SEQUENCE_FOREACH (sequence, iter) {
377             if (iter->time.frames > ev.time.frames) {
378                 memmove (((uint8_t*) iter) + lv2_atom_pad_size ((uint32_t) sizeof(*iter) + iter->body.size),
379                          (uint8_t*) iter,
380                          (uint8_t*) e - (uint8_t*) iter);
381                 e = iter;
382                 break;
383             }
384         }
385 
386         if (e) {
387             auto total_size = (uint32_t)sizeof(ev) + ev.body.size;
388             memcpy (e, &ev, total_size);
389             sequence->atom.size += lv2_atom_pad_size (total_size);
390         }
391     }
392 
393     /** @private */
394     struct iterator {
operator *lvtk::Sequence::iterator395         AtomEvent&  operator*()  { return *event; }
operator ->lvtk::Sequence::iterator396         const AtomEvent* operator->() const { return event; }
397 
operator ++lvtk::Sequence::iterator398         iterator& operator++()
399         {
400             event = lv2_atom_sequence_next (event);
401             return *this;
402         }
403 
operator ++lvtk::Sequence::iterator404         iterator operator++(int)
405         {
406             iterator res (sequence, event);
407             ++(*this);
408             return res;
409         }
410 
operator ==lvtk::Sequence::iterator411         inline bool operator== (const iterator& other) const { return event == other.event; }
operator !=lvtk::Sequence::iterator412         inline bool operator!= (const iterator& other) const { return event != other.event; }
413 
414     private:
415         friend struct Sequence;
iteratorlvtk::Sequence::iterator416         iterator (LV2_Atom_Sequence *seq, AtomEvent* ev)
417             : event (ev), sequence (seq) { }
418         LV2_Atom_Event* event = nullptr;
419         LV2_Atom_Sequence* sequence = nullptr;
420     };
421 
422     /** @returns an iterator starting at the first event */
beginlvtk::Sequence423     inline iterator begin() const {
424         return iterator (sequence, lv2_atom_sequence_begin (&sequence->body));
425     }
426 
427     /** @returns the end iterator of this sequence */
endlvtk::Sequence428     inline iterator end() const {
429         return iterator (sequence, lv2_atom_sequence_end (&sequence->body, sequence->atom.size));
430     }
431 
432 private:
433     LV2_Atom_Sequence* sequence = nullptr;
434     uint32_t capacity = 0;
435 };
436 
437 /** Class wrapper around LV2_Atom_Forge
438     @headerfile lvtk/ext/atom.hpp
439 */
440 struct Forge final : LV2_Atom_Forge
441 {
442     /** Uninitialized Forge.
443         Client code must call Forge::init() before using otherwise
444         written output will be unpredictable and likely cause a nasty crash
445     */
446     Forge() = default;
447 
448     /** Initialized Forge.
449         @param map The LV2_URID_Map to use for initialization
450      */
Forgelvtk::Forge451     Forge (LV2_URID_Map* map)   { init (map); }
452 
453     /** Initialize the underlying atom forge
454          @param map The mapping function needed for init
455     */
initlvtk::Forge456     inline void init (LV2_URID_Map* map) {
457         lv2_atom_forge_init (this, map);
458     }
459 
460     /** Set the Forge's buffer
461 
462         You must call this before writing Atoms with the forge. Failing
463         to do so could result in a nasty crash.
464 
465         @param buf The buffer to use
466         @param size The size of the buffer
467     */
set_bufferlvtk::Forge468     inline void set_buffer (uint8_t* buf, uint32_t size) {
469         lv2_atom_forge_set_buffer (this, buf, size);
470     }
471 
472     /** Forge the header of a sequence */
write_sequence_headlvtk::Forge473     inline ForgeRef write_sequence_head (ForgeFrame& frame, uint32_t unit) {
474         return lv2_atom_forge_sequence_head (this, &frame, unit);
475     }
476 
477     /** Forge frame time (in a sequence) */
write_beat_timelvtk::Forge478     inline ForgeRef write_beat_time (double beats) {
479         return lv2_atom_forge_beat_time (this, beats);
480     }
481 
482     /** Forge frame time (in a sequence). The returned ForgeRef is to an
483         LV2_Atom_Event
484     */
write_frame_timelvtk::Forge485     inline ForgeRef write_frame_time (int64_t frames) {
486         return lv2_atom_forge_frame_time (this, frames);
487     }
488 
489     /** Write a property header
490         @param key The URID for the key
491         @param context The context
492     */
write_property_headlvtk::Forge493     inline ForgeRef write_property_head (uint32_t key, uint32_t context) {
494         return lv2_atom_forge_property_head (this, key, context);
495     }
496 
497     /** Pop a forge frame
498         @param frame The frame to pop
499     */
poplvtk::Forge500     inline void pop (ForgeFrame& frame) {
501         lv2_atom_forge_pop (this, &frame);
502     }
503 
504     /** Write an atom header
505 
506         @param size The atom's body size
507         @param type The atom's body type
508         @return A reference to the written atom
509     */
write_atomlvtk::Forge510     inline ForgeRef write_atom (uint32_t size, uint32_t type) {
511         return lv2_atom_forge_atom (this, size, type);
512     }
513 
write_keylvtk::Forge514     inline ForgeRef write_key (uint32_t urid) {
515         return lv2_atom_forge_key (this, urid);
516     }
517 
518     /** Write an atom object */
write_objectlvtk::Forge519     inline ForgeRef write_object (ForgeFrame& frame, uint32_t id, uint32_t otype) {
520         return lv2_atom_forge_object (this, &frame, id, otype);
521     }
522 
523     /** Write an atom path from string
524 
525         @param path The path to forge
526         @return An Atom
527     */
write_pathlvtk::Forge528     inline ForgeRef write_path (const std::string& path) {
529         return lv2_atom_forge_path (this, path.c_str(), path.size());
530     }
531 
write_primitivelvtk::Forge532     inline ForgeRef write_primitive (const Atom& atom) {
533         return lv2_atom_forge_primitive (this, atom.c_obj());
534     }
535 
536     /** Write a boolean value
537         @param val  The value to write
538         @returns    A reference to the Atom
539     */
write_boollvtk::Forge540     inline ForgeRef write_bool (const bool val) {
541         return lv2_atom_forge_bool (this, val);
542     }
543 
544     /** Write an integeger value
545         @param val The value to write
546         @returns    A reference to the Atom
547      */
write_intlvtk::Forge548     inline ForgeRef write_int (const int val) {
549         return lv2_atom_forge_int (this, val);
550     }
551 
552     /** Write a double value @param val the value to write
553         @param val The value to write
554         @returns    A reference to the Atom
555      */
write_doublelvtk::Forge556     inline ForgeRef write_double (const double val) {
557         return lv2_atom_forge_double (this, val);
558     }
559 
560     /** Write a float value */
write_floatlvtk::Forge561     inline ForgeRef write_float (const float val) {
562         return lv2_atom_forge_float (this, val);
563     }
564 
565     /** Write a long integer value  */
write_longlvtk::Forge566     inline ForgeRef write_long (const int64_t val) {
567         return lv2_atom_forge_long (this, val);
568     }
569 
570     /** Write a string value */
write_stringlvtk::Forge571     inline ForgeRef write_string (const char* str) {
572         return lv2_atom_forge_string (this, str, strlen (str));
573     }
574 
575     /** Write a URI string */
write_urilvtk::Forge576     inline ForgeRef write_uri (const char* uri) {
577         return lv2_atom_forge_uri (this, uri, strlen (uri));
578     }
579 
580     /** Write raw data
581         @param data The data to write
582         @param size The size in bytes of data
583      */
write_rawlvtk::Forge584     inline ForgeRef write_raw (const void* data, uint32_t size) {
585         return lv2_atom_forge_raw (this, data, size);
586     }
587 
588     /** Write a URID value
589         @param id The URID to write
590      */
write_uridlvtk::Forge591     inline ForgeRef write_urid (LV2_URID id) {
592         return lv2_atom_forge_urid (this, id);
593     }
594 };
595 
596 /** An LV2_Atom_Vector Wrapper
597     @headerfile lvtk/ext/atom.hpp
598  */
599 struct Vector final
600 {
Vectorlvtk::Vector601     inline Vector (ForgeRef ref) : vec ((LV2_Atom_Vector*) ref) { }
602     ~Vector() = default;
603 
sizelvtk::Vector604     inline size_t size() const { return vec->atom.size / vec->body.child_size; }
child_sizelvtk::Vector605     inline uint32_t child_size() const { return vec->body.child_size; }
child_typelvtk::Vector606     inline uint32_t child_type() const { return vec->body.child_type; }
c_objlvtk::Vector607     inline LV2_Atom_Vector* c_obj() const { return vec; }
operator LV2_Atom_Vector*lvtk::Vector608     inline operator LV2_Atom_Vector* () const { return vec; }
609 
610     /** @private */
611     struct iterator {
operator ++lvtk::Vector::iterator612         iterator& operator++()
613         {
614             offset += vec->body.child_size;
615 
616             if (vec && offset >= vec->atom.size)
617                 offset = vec->atom.size;
618 
619             return *this;
620         }
621 
operator ++lvtk::Vector::iterator622         iterator operator++(int)
623         {
624             iterator it (vec, offset);
625             ++(*this);
626             return it;
627         }
628 
operator ==lvtk::Vector::iterator629         inline bool operator== (const iterator& other) const { return vec == other.vec && offset == other.offset; }
operator !=lvtk::Vector::iterator630         inline bool operator!= (const iterator& other) const { return vec != other.vec && offset != other.offset; }
631 
632         /** Reference another iterator */
operator =lvtk::Vector::iterator633         inline iterator& operator= (const iterator& other) {
634             this->vec = other.vec;
635             this->offset = other.offset;
636             return *this;
637         }
638 
639     private:
640         friend class Vector;
iteratorlvtk::Vector::iterator641         iterator (LV2_Atom_Vector *v, uint32_t os = 0) : vec (v), offset (os) { }
642         LV2_Atom_Vector* vec = nullptr;
643         uint32_t offset = 0;
644     };
645 
646     /** Returns an iterator to the begining of the vector */
beginlvtk::Vector647     iterator begin() const { return iterator (vec); }
648 
649     /** Returns the end iterator */
endlvtk::Vector650     iterator end()   const { return iterator (vec, vec->atom.size); }
651 
652 private:
653     LV2_Atom_Vector* vec = nullptr;
654 };
655 /* @} */
656 }  /* namespace lvtk */
657