2 * Copyright (c) 2023 Philippe Proulx <pproulx@efficios.com>
4 * SPDX-License-Identifier: MIT
7 #ifndef BABELTRACE_CPP_COMMON_BT2_MESSAGE_ARRAY_HPP
8 #define BABELTRACE_CPP_COMMON_BT2_MESSAGE_ARRAY_HPP
12 #include <babeltrace2/babeltrace.h>
14 #include "common/assert.h"
16 #include "message.hpp"
20 class ConstMessageArray;
22 class ConstMessageArrayIterator final
24 friend class ConstMessageArray;
27 using difference_type = std::ptrdiff_t;
28 using value_type = ConstMessage;
29 using pointer = value_type *;
30 using reference = value_type&;
31 using iterator_category = std::input_iterator_tag;
34 explicit ConstMessageArrayIterator(const ConstMessageArray& msgArray,
35 const uint64_t idx) noexcept :
36 _mMsgArray {&msgArray},
42 ConstMessageArrayIterator& operator++() noexcept
48 ConstMessageArrayIterator operator++(int) noexcept
50 const auto tmp = *this;
56 bool operator==(const ConstMessageArrayIterator& other) const noexcept
58 BT_ASSERT_DBG(_mMsgArray == other._mMsgArray);
59 return _mIdx == other._mIdx;
62 bool operator!=(const ConstMessageArrayIterator& other) const noexcept
64 return !(*this == other);
67 ConstMessage operator*() noexcept;
70 const ConstMessageArray *_mMsgArray;
75 * A wrapper of `bt_message_array_const`, either:
77 * Containing existing messages:
78 * Use ConstMessageArray::wrapExisting().
82 * bt_message_array_const libMsgs;
85 * if (bt_message_iterator_next(myIter, &libMsgs, &count) !=
86 * BT_MESSAGE_ITERATOR_NEXT_STATUS_OK) {
87 * // Handle special status
90 * const auto msgs = bt2::ConstMessageArray::wrapExisting(libMsgs,
93 * // At this point `msgs` manages `libMsgs`
95 * An empty one which you need to fill:
96 * Use ConstMessageArray::wrapEmpty().
98 * Use the release() method to move the ownership of the wrapped
99 * library array to you.
103 * bt_message_iterator_class_next_method_status myNext(
104 * bt_self_message_iterator * const libSelfMsgIter,
105 * const bt_message_array_const libMsgs,
106 * const uint64_t capacity, uint64_t * const count)
108 * auto msgs = bt2::ConstMessageArray::wrapEmpty(libMsgs,
111 * // Create messages and append with `msgs.append(...)`
113 * *count = msgs.release();
114 * return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
117 * In both cases, the returned message array wrapper is always the sole
118 * owner of the wrapped library array: it's not a simple passive view.
119 * The destructor puts the references of the contained messages.
121 class ConstMessageArray final
124 explicit ConstMessageArray(const bt_message_array_const libArrayPtr, const std::uint64_t length,
125 const std::uint64_t capacity) noexcept :
126 _mLibArrayPtr {libArrayPtr},
127 _mLen {length}, _mCap {capacity}
129 BT_ASSERT_DBG(length <= capacity);
130 BT_ASSERT_DBG(capacity > 0);
134 using Iterator = ConstMessageArrayIterator;
142 * Not available because there's no underlying message array to
145 ConstMessageArray(const ConstMessageArray&) = delete;
148 * Not available because we don't need it yet.
150 ConstMessageArray& operator=(const ConstMessageArray&) = delete;
152 ConstMessageArray(ConstMessageArray&& other) noexcept :
153 ConstMessageArray {other._mLibArrayPtr, other._mLen, other._mCap}
158 ConstMessageArray& operator=(ConstMessageArray&& other) noexcept
160 /* Put existing message references */
163 /* Move other members to this message array */
164 _mLibArrayPtr = other._mLibArrayPtr;
168 /* Reset other message array */
175 * Wraps an existing library array `libArrayPtr`, known to contain
178 * CAUTION: The ownership of the existing messages contained in
179 * `libArrayPtr` is _moved_ to the returned `ConstMessageArray`
182 * This is similar to what the constructor of `std::shared_ptr`
183 * does. Do NOT wrap the same library array twice.
185 static ConstMessageArray wrapExisting(const bt_message_array_const libArrayPtr,
186 const std::uint64_t length) noexcept
188 return ConstMessageArray {libArrayPtr, length, length};
192 * Wraps an existing library array `libArrayPtr`, known to be empty,
193 * with a capacity of `capacity` messages.
195 static ConstMessageArray wrapEmpty(const bt_message_array_const libArrayPtr,
196 const std::uint64_t capacity) noexcept
198 return ConstMessageArray {libArrayPtr, 0, capacity};
201 std::uint64_t length() const noexcept
206 std::uint64_t capacity() const noexcept
211 bool isEmpty() const noexcept
216 bool isFull() const noexcept
218 return _mLen == _mCap;
221 ConstMessageArray& append(ConstMessage::Shared message) noexcept
223 BT_ASSERT_DBG(!this->isFull());
225 /* Move reference to underlying array */
226 _mLibArrayPtr[_mLen] = message.release().libObjPtr();
232 * Transfers the ownership of the wrapped library array to the
233 * caller, returning the number of contained messages (array
236 std::uint64_t release() noexcept
238 const auto len = _mLen;
244 ConstMessage operator[](const std::uint64_t index) const noexcept
246 BT_ASSERT_DBG(index < _mLen);
247 return ConstMessage {_mLibArrayPtr[index]};
250 Iterator begin() const noexcept
252 return Iterator {*this, 0};
255 Iterator end() const noexcept
257 return Iterator {*this, this->length()};
261 void _reset() noexcept
264 * This means this array is pretty much dead, and any call to
265 * append() or operator[]() will make assertions fail.
267 * That being said, you may still move another array to this
275 * Decrements the reference count of all the contained messages.
277 void _putMsgRefs() noexcept
279 std::for_each(&_mLibArrayPtr[0], &_mLibArrayPtr[_mLen], [](const bt_message * const msg) {
280 bt_message_put_ref(msg);
284 /* Underlying array which is generally owned by the library */
285 bt_message_array_const _mLibArrayPtr;
287 /* Length (count of contained messages) */
290 /* Capacity (maximum length) */
294 inline ConstMessage ConstMessageArrayIterator::operator*() noexcept
296 return (*_mMsgArray)[_mIdx];
299 } /* namespace bt2 */
301 #endif /* BABELTRACE_CPP_COMMON_BT2_MESSAGE_ARRAY_HPP */