1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef META_INTERFACE_ICONTAINER_H
17 #define META_INTERFACE_ICONTAINER_H
18
19 #include <meta/api/iteration.h>
20 #include <meta/base/ids.h>
21 #include <meta/base/interface_utils.h>
22 #include <meta/base/object_traits.h>
23 #include <meta/interface/interface_macros.h>
24 #include <meta/interface/intf_iterable.h>
25 #include <meta/interface/intf_object.h>
26 #include <meta/interface/property/intf_property.h>
27 #include <meta/interface/simple_event.h>
28
29 META_BEGIN_NAMESPACE()
30
31 META_REGISTER_INTERFACE(IContainer, "55ce4604-91f4-4378-9c7d-9ab0fe97b3ce")
32 META_REGISTER_INTERFACE(IContainerProxyParent, "d57c03fc-23ac-4cba-8f9f-0363ca781bfa")
33
34 META_REGISTER_INTERFACE(IOnChildChanged, "686e62cc-66b1-409d-821f-e5ac69e33863")
35 META_REGISTER_INTERFACE(IOnChildMoved, "5890fe47-4829-42bb-bdb1-03f8a399ba0e")
36
37 struct IOnChildChangedInfo {
38 constexpr static BASE_NS::Uid UID { META_NS::InterfaceId::IOnChildChanged };
39 constexpr static char const* NAME { "OnChildChanged" };
40 };
41
42 class IContainer;
43
44 enum class ContainerChangeType : uint8_t {
45 ADDING = 1,
46 ADDED = 2,
47 REMOVING = 3,
48 REMOVED = 4,
49 MOVED = 5,
50 };
51
52 /**
53 * @brief The ChildChangedInfo struct defines the parameters for an event which is invoked when
54 * an object is added to or removed from an IContainer.
55 */
56 struct ChildChangedInfo {
57 ContainerChangeType type; ///< change type
58 IObject::Ptr object; ///< The object
59 BASE_NS::weak_ptr<const IContainer> parent; ///< The parent IContainer for the change
60 size_t from = size_t(-1); ///< From index (removed, moved)
61 size_t to = size_t(-1); ///< To index (added, moved)
62 };
63
64 using IOnChildChanged = META_NS::SimpleEvent<IOnChildChangedInfo, void(const ChildChangedInfo&)>;
65 /**
66 * @brief An interface implemented by objects that may contain other objects.
67 * @note The implementer shall use IObjectFlags::SERIALIZE_HIERARCHY flag to determine
68 * if the children should be serialized when exporting the object. By default
69 * IContainer implementations should serialize their child objects.
70 */
71 class IContainer : public CORE_NS::IInterface {
72 META_INTERFACE(CORE_NS::IInterface, IContainer)
73 public:
74 using SizeType = size_t;
75
76 /**
77 * @brief The FindOptions struct defines a set of options that can be used to find objects from a container.
78 */
79 struct FindOptions {
80 /** Name of the object to find. If name is empty, only the uids are taken into account. */
81 BASE_NS::string name;
82 /** Search mode */
83 TraversalType behavior { TraversalType::BREADTH_FIRST_ORDER };
84 /** List of interface ids that the object must implement. If empty, no check is made */
85 BASE_NS::vector<TypeId> uids;
86 /** If true, the found object must implement all of the uids.
87 * If false, any uid is enough to consider the object as a match */
88 bool strict { false };
89 };
90 /**
91 * @brief Returns the contained children.
92 */
93 virtual BASE_NS::vector<IObject::Ptr> GetAll() const = 0;
94 /**
95 * @brief Returns the child at given index.
96 * @param index Index of the child to return.
97 * @return The child at given index or nullptr in case of invalid index.
98 */
99 virtual IObject::Ptr GetAt(SizeType index) const = 0;
100 /**
101 * @brief Returns the number of children in the container. Equal to GetAll().size().
102 */
103 virtual SizeType GetSize() const = 0;
104 /**
105 * @brief Find all objects matching a search criteria from the container.
106 * @param options The options to use for finding.
107 * @return The child objects that match the search criteria.
108 */
109 virtual BASE_NS::vector<IObject::Ptr> FindAll(const FindOptions& options) const = 0;
110 /**
111 * @brief Returns the first found object matching a search criteria from the container.
112 * @note If the user is interested in finding some object that matches the criteria, it
113 * is more efficient to call FindAny rather than FindAll as the implementation
114 * can do an early exit when the first suitable object is found.
115 * @param options The options to use for finding.
116 * @return The first object which matches the search criteria.
117 */
118 virtual IObject::Ptr FindAny(const FindOptions& options) const = 0;
119 /**
120 * @brief Get child by name from the immediate children of the container.
121 * @param name Name of the child object to find.
122 * @note Use FindAny to find from the hierarchy.
123 * @return The first child object with given name or null if non found.
124 */
125 virtual IObject::Ptr FindByName(BASE_NS::string_view name) const = 0;
126 /**
127 * @brief Add child object.
128 * @param object The object to add.
129 * @note An object can be added to the container only once. Subsequent add operations
130 * for the same object will succeed but do not add anything to the container
131 * (since the object was already there).
132 * @note Adding may fail due to e.g. the object not fulfilling the constraints set to
133 * the interfaces each object in the container should implement (defined by calling
134 * SetRequiredInterfaces).
135 * @return True if the object is in the container after the operation, false otherwise.
136 */
137 virtual bool Add(const IObject::Ptr& object) = 0;
138 /**
139 * @brief Inserts a child object at given index.
140 * @param index The index where the object should be added. If index >= container size, the
141 * object is added at the end of the container.
142 * @param object The object to add.
143 * @note If the object is already in the container, the function will move the object
144 * to the given index.
145 * @return True if the object is in the container after the operation, false otherwise.
146 */
147 virtual bool Insert(SizeType index, const IObject::Ptr& object) = 0;
148 /**
149 * @brief Remove child object.
150 * @param index The index of child object to remove.
151 * @return True if the object was removed from the container, false otherwise.
152 */
153 virtual bool Remove(SizeType index) = 0;
154 /**
155 * @brief Remove child object.
156 * @param child The child object to remove.
157 * @return True if the object was removed from the container, false otherwise.
158 */
159 virtual bool Remove(const IObject::Ptr& child) = 0;
160 /**
161 * @brief Move a child object from one index to another.
162 * @note OnMoved event will be invoked only for the moved item, but not for other items in the
163 * container whose index may change as a side effect of the move operation.
164 * @param fromIndex The index to move from.
165 * @param toIndex The index to move the object to. The target position is the position in the
166 * container before the the object has been removed from its original position.
167 * @return True if the object was successfully moved, false otherwise.
168 */
169 virtual bool Move(SizeType fromIndex, SizeType toIndex) = 0;
170 /**
171 * @brief Move a child object to a new index.
172 * @note OnMoved event will be invoked only for the moved item, but not for other items in the
173 * container whose index may change as a side effect of the move operation.
174 * @param child The child to move.
175 * @param toIndex The index to move the object to. The target position is the position in the
176 * container before the the object has been removed from its original position.
177 * @return True if the object was successfully moved, false otherwise.
178 */
179 virtual bool Move(const IObject::Ptr& child, SizeType toIndex) = 0;
180 /**
181 * @brief Replace a child item with another one. The function will fail if child is not found.
182 * @note Does nothing if the parameters point to the same object.
183 * @param child The child to replace. If the child is not found from the container, does nothing or
184 * adds replaceWith to the container, depending on addAlways.
185 * @param replaceWith The item to replace the child with. If null, the child is removed.
186 * @return True if any changes were made in the container as a result of this call, or if child == replaceWith
187 * and child is found from the container. In other cases returns false.
188 */
Replace(const IObject::Ptr & child,const IObject::Ptr & replaceWith)189 bool Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith)
190 {
191 return Replace(child, replaceWith, false);
192 }
193 /**
194 * @brief Replace a child item with another one.
195 * @note Does nothing if the parameters point to the same object.
196 * @note If both child and replaceWith are already in the container, child is removed and replaceWith
197 * is moved to its location.
198 * @param child The child to replace. If the child is not found from the container, does nothing or
199 * adds replaceWith to the container, depending on addAlways.
200 * @param replaceWith The item to replace the child with. If null, the child is removed.
201 * @param addAlways If true, and if child is not found from the container, adds replaceWith to
202 * the end of the container. If false, the function will fail if child is not found.
203 * @return True if any changes were made in the container as a result of this call, or if child == replaceWith
204 * and child is found from the container. In other cases returns false.
205 */
206 virtual bool Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith, bool addAlways) = 0;
207 /**
208 * @brief Removes all children from container.
209 */
210 virtual void RemoveAll() = 0;
211 /**
212 * @brief Invoked after container changed
213 */
META_EVENT(IOnChildChanged,OnContainerChanged)214 META_EVENT(IOnChildChanged, OnContainerChanged)
215
216 template<class T>
217 typename T::Ptr FindAny(BASE_NS::string_view name, TraversalType order) const
218 {
219 return interface_pointer_cast<T>(FindAny({ BASE_NS::string(name), order, { T::UID }, false }));
220 }
221 /**
222 * @brief A helper template for finding a child item in this container that matches the name.
223 */
224 template<class T>
FindByName(BASE_NS::string_view name)225 typename T::Ptr FindByName(BASE_NS::string_view name) const
226 {
227 return interface_pointer_cast<T>(FindByName(name));
228 }
229 /**
230 * @brief A helper template for finding a child item in this container that matches the name and implements
231 * the interface given as a template parameter.
232 */
233 template<class T>
FindAnyFromHierarchy(BASE_NS::string_view name)234 typename T::Ptr FindAnyFromHierarchy(BASE_NS::string_view name) const
235 {
236 return FindAny<T>(name, TraversalType::BREADTH_FIRST_ORDER);
237 }
238 /**
239 * @brief Typed helper for IContainer::GetAll, returns all children which implement T.
240 */
241 template<class T>
GetAll()242 BASE_NS::vector<typename T::Ptr> GetAll() const
243 {
244 return PtrArrayCast<T>(GetAll());
245 }
246 /**
247 * @brief Checks if object is part of this container's hierarchy.
248 * @param object The object to check.
249 * @return True if object can be found from this container's hierarchy.
250 */
251 virtual bool IsAncestorOf(const IObject::ConstPtr& object) const = 0;
252
253 public:
254 /**
255 * @brief Typed helper for IContainer::GetAt, returns object at index converted to T::Ptr.
256 */
257 template<class T>
GetAt(SizeType index)258 typename T::Ptr GetAt(SizeType index) const
259 {
260 return interface_pointer_cast<T>(GetAt(index));
261 }
262 /**
263 * @brief Typed helper for IContainer::Add
264 */
265 template<class T>
Add(const T & object)266 bool Add(const T& object)
267 {
268 return Add(interface_pointer_cast<IObject>(object));
269 }
270 /**
271 * @brief Typed helper for IContainer::Insert
272 */
273 template<class T>
Insert(SizeType index,const T & object)274 bool Insert(SizeType index, const T& object)
275 {
276 return Insert(index, interface_pointer_cast<IObject>(object));
277 }
278 /**
279 * @brief Typed helper for IContainer::Remove
280 */
281 template<class T, class = BASE_NS::enable_if_t<IsInterfacePtr_v<T>>>
Remove(const T & child)282 bool Remove(const T& child)
283 {
284 return Remove(interface_pointer_cast<IObject>(child));
285 }
286 /**
287 * @brief Typed helper for IContainer::Replace
288 */
289 template<class T1, class T2>
290 bool Replace(const T1& child, const T2& replaceWith, bool addAlways = false)
291 {
292 return Replace(interface_pointer_cast<IObject>(child), interface_pointer_cast<IObject>(replaceWith), addAlways);
293 }
294 };
295
296 /**
297 * @brief Typed helper for IContainer::GetAll. Returns all children which implement T from container.
298 */
299 template<class T>
GetAll(const META_NS::IContainer::ConstPtr & container)300 BASE_NS::vector<typename T::Ptr> GetAll(const META_NS::IContainer::ConstPtr& container)
301 {
302 if (!container) {
303 return {};
304 }
305 if constexpr (IsIObjectPtr_v<typename T::Ptr>) {
306 return container->GetAll();
307 } else {
308 return container->GetAll<T>();
309 }
310 }
311
312 /**
313 * @brief Returns true if a container contains a given child object.
314 * @param container The container to check against.
315 * @param child The child to find.
316 * @return True if the child can be found in the container, false otherwise.
317 */
318 template<class T, class = BASE_NS::enable_if_t<IsInterfacePtr_v<T>>>
ContainsObject(const META_NS::IContainer::ConstPtr & container,const T & child)319 bool ContainsObject(const META_NS::IContainer::ConstPtr& container, const T& child)
320 {
321 bool found = false;
322 if (const auto object = interface_pointer_cast<IObject>(child); container && object) {
323 IterateShared(container, [&](const IObject::Ptr& o) {
324 if (o == object) {
325 found = true;
326 }
327 return !found;
328 });
329 }
330 return found;
331 }
332
333 /**
334 * @brief The IContainerProxyParent interface can be used to defined a proxied parent
335 * that an IContainer implementation sets to its child objects.
336 * @note Child objects must implement IMutableContainable for the proxy to have effect.
337 */
338 class IContainerProxyParent : public CORE_NS::IInterface {
339 META_INTERFACE(CORE_NS::IInterface, IContainerProxyParent)
340 public:
341 /**
342 * @brief Sets the object that should be used as the parent object when an IContainer
343 * implementation calls IMutableContainable::SetParent on objects that are
344 * added to the container.
345 * @note This call only affects the parent for objects added to the container
346 * after SetProxyParent is called. Existing objects are not updated.
347 * @param parent The parent container to set.
348 * @return True if setting the parent was successful, false otherwise.
349 */
350 virtual bool SetProxyParent(const IContainer::Ptr& parent) = 0;
351 };
352
353 META_REGISTER_INTERFACE(IContainerPreTransaction, "1a1d3ba0-302c-442f-8a13-0701938a5f4c")
354 META_REGISTER_INTERFACE(IOnChildChanging, "385aec1c-0d4b-4ca1-85b5-6235e13ded3e")
355 META_REGISTER_INTERFACE(IOnChildChangingCallable, "7977c014-8181-465d-8d86-48d30c754e6c")
356
357 /**
358 * @brief IOnChildChanging defines the interface for IContainerPreTransaction events.
359 * @param info Information about the change that is about to happen
360 * @param success The callee can request cancelling the operation by setting the parameter to false.
361 * @note Cancelling the operation may not always be possible.
362 * @note Cancelling the operation does not work for deferred event callbacks.
363 */
364 using IOnChildChanging = META_NS::SimpleEvent<IOnChildChangedInfo, void(const ChildChangedInfo& info, bool& success)>;
365
366 /**
367 * @brief The IContainerPreTransaction interface can be implemented by containers which support invoking events
368 * about transactions within the container that are about to happen.
369 */
370 class IContainerPreTransaction : public CORE_NS::IInterface {
371 META_INTERFACE(CORE_NS::IInterface, IContainerPreTransaction)
372 public:
373 /**
374 * @brief Invoked when the container is about to change
375 */
376 META_EVENT(IOnChildChanging, ContainerAboutToChange)
377 };
378
379 META_END_NAMESPACE()
380
381 META_TYPE(META_NS::IContainer::Ptr)
382 META_TYPE(META_NS::IContainer::WeakPtr)
383 META_TYPE(META_NS::TraversalType)
384
385 #endif
386