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
17 #include "composite_object_provider.h"
18
19 #include <meta/api/iteration.h>
20 #include <meta/api/make_callback.h>
21
22 META_BEGIN_NAMESPACE()
23
24 CompositeObjectProvider::CompositeObjectProvider() = default;
25
~CompositeObjectProvider()26 CompositeObjectProvider::~CompositeObjectProvider()
27 {
28 ForEachShared(GetSelf(), [&](const IObject::Ptr& obj) {
29 if (auto provider = interface_cast<IObjectProvider>(obj)) {
30 provider->OnDataAdded()->RemoveHandler(uintptr_t(this));
31 provider->OnDataRemoved()->RemoveHandler(uintptr_t(this));
32 provider->OnDataMoved()->RemoveHandler(uintptr_t(this));
33 }
34 });
35 }
36
Build(const IMetadata::Ptr &)37 bool CompositeObjectProvider::Build(const IMetadata::Ptr&)
38 {
39 SetRequiredInterfaces({ IObjectProvider::UID });
40 OnContainerChanged()->AddHandler(MakeCallback<IOnChildChanged>(this, &CompositeObjectProvider::OnProviderChanged));
41
42 META_ACCESS_PROPERTY(CacheHint)->OnChanged()->AddHandler(MakeCallback<IOnChanged>([&] {
43 ForEachShared(GetSelf(), [&](const IObject::Ptr& obj) {
44 if (auto provider = interface_cast<IObjectProvider>(obj)) {
45 provider->CacheHint()->SetValue(CacheHint()->GetValue());
46 }
47 });
48 }));
49 return true;
50 }
51
CreateObject(const DataModelIndex & index)52 IObject::Ptr CompositeObjectProvider::CreateObject(const DataModelIndex& index)
53 {
54 size_t ni = index.Index();
55 if (auto p = FindProvider(ni)) {
56 if (auto o = p->CreateObject(DataModelIndex { ni, index.GetDimensionPointer() })) {
57 objects_[o.get()] = p;
58 return o;
59 }
60 }
61 return nullptr;
62 }
63
DisposeObject(const META_NS::IObject::Ptr & item)64 bool CompositeObjectProvider::DisposeObject(const META_NS::IObject::Ptr& item)
65 {
66 auto it = objects_.find(item.get());
67 if (it == objects_.end()) {
68 return false;
69 }
70
71 auto p = it->second;
72 objects_.erase(it);
73 return p->DisposeObject(item);
74 }
75
FindProvider(size_t & index) const76 IObjectProvider* CompositeObjectProvider::FindProvider(size_t& index) const
77 {
78 size_t curSize = 0;
79 IObjectProvider* res {};
80
81 IterateShared(GetSelf(), [&](const IObject::Ptr& obj) {
82 if (auto provider = interface_cast<IObjectProvider>(obj)) {
83 auto prevSize = curSize;
84 curSize += provider->GetObjectCount();
85 if (index < curSize) {
86 index = index - prevSize;
87 res = provider;
88 return false;
89 }
90 }
91 return true;
92 });
93
94 return res;
95 }
96
GetObjectCount(const DataModelIndex & index) const97 size_t CompositeObjectProvider::GetObjectCount(const DataModelIndex& index) const
98 {
99 // is the size asked for other than first dimension?
100 if (index.IsValid()) {
101 size_t ni = index.Index();
102 if (auto p = FindProvider(ni)) {
103 return p->GetObjectCount(DataModelIndex { ni, index.GetDimensionPointer() });
104 }
105 }
106
107 // calculate size for first dimension
108 size_t res = 0;
109 IterateShared(GetSelf(), [&](const IObject::Ptr& obj) {
110 if (auto provider = interface_cast<IObjectProvider>(obj)) {
111 res += provider->GetObjectCount();
112 }
113 return true;
114 });
115 return res;
116 }
117
CalculateIndex(const IObjectProvider::Ptr & provider,size_t localIndex) const118 size_t CompositeObjectProvider::CalculateIndex(const IObjectProvider::Ptr& provider, size_t localIndex) const
119 {
120 size_t base = 0;
121 bool ret = IterateShared(GetSelf(), [&](const IObject::Ptr& obj) {
122 if (auto prov = interface_cast<IObjectProvider>(obj)) {
123 if (prov == provider.get()) {
124 return false;
125 }
126 base += prov->GetObjectCount();
127 }
128 return true;
129 });
130 return ret ? base + localIndex : -1;
131 }
132
OnAddedProviderData(const IObjectProvider::Ptr & provider,DataModelIndex base,size_t count)133 void CompositeObjectProvider::OnAddedProviderData(
134 const IObjectProvider::Ptr& provider, DataModelIndex base, size_t count)
135 {
136 if (provider && base.IsValid()) {
137 size_t index = CalculateIndex(provider, base.Index());
138 if (index != -1) {
139 Invoke<IOnDataAdded>(
140 META_ACCESS_EVENT(OnDataAdded), DataModelIndex { index, base.GetDimensionPointer() }, count);
141 }
142 }
143 }
144
OnRemovedProviderData(const IObjectProvider::Ptr & provider,DataModelIndex base,size_t count)145 void CompositeObjectProvider::OnRemovedProviderData(
146 const IObjectProvider::Ptr& provider, DataModelIndex base, size_t count)
147 {
148 if (provider && base.IsValid()) {
149 size_t index = CalculateIndex(provider, base.Index());
150 if (index != -1) {
151 Invoke<IOnDataRemoved>(
152 META_ACCESS_EVENT(OnDataRemoved), DataModelIndex { index, base.GetDimensionPointer() }, count);
153 }
154 }
155 }
156
OnMovedProviderData(const IObjectProvider::Ptr & provider,DataModelIndex from,size_t count,DataModelIndex to)157 void CompositeObjectProvider::OnMovedProviderData(
158 const IObjectProvider::Ptr& provider, DataModelIndex from, size_t count, DataModelIndex to)
159 {
160 if (provider && from.IsValid() && to.IsValid()) {
161 size_t fromIndex = CalculateIndex(provider, from.Index());
162 size_t toIndex = CalculateIndex(provider, to.Index());
163 if (fromIndex != -1 && toIndex != -1) {
164 Invoke<IOnDataMoved>(META_ACCESS_EVENT(OnDataMoved),
165 DataModelIndex { fromIndex, from.GetDimensionPointer() }, count,
166 DataModelIndex { toIndex, to.GetDimensionPointer() });
167 }
168 }
169 }
170
OnProviderChanged(const ChildChangedInfo & info)171 void CompositeObjectProvider::OnProviderChanged(const ChildChangedInfo& info)
172 {
173 if (info.type == ContainerChangeType::ADDED) {
174 OnProviderAdded(info);
175 } else if (info.type == ContainerChangeType::REMOVED) {
176 OnProviderRemoved(info);
177 } else if (info.type == ContainerChangeType::MOVED) {
178 OnProviderMoved(info);
179 }
180 }
181
OnProviderAdded(const ChildChangedInfo & info)182 void CompositeObjectProvider::OnProviderAdded(const ChildChangedInfo& info)
183 {
184 auto provider = interface_pointer_cast<IObjectProvider>(info.object);
185 if (!provider) {
186 return;
187 }
188 assert(!interface_cast<IContainer>(info.object));
189
190 auto added = provider->OnDataAdded()->AddHandler(
191 MakeCallback<IOnDataAdded>(
192 [this](auto provider, DataModelIndex base, size_t count) { OnAddedProviderData(provider, base, count); },
193 provider),
194 uintptr_t(this));
195 auto removed = provider->OnDataRemoved()->AddHandler(
196 MakeCallback<IOnDataRemoved>(
197 [this](auto provider, DataModelIndex base, size_t count) { OnRemovedProviderData(provider, base, count); },
198 provider),
199 uintptr_t(this));
200 auto moved = provider->OnDataMoved()->AddHandler(
201 MakeCallback<IOnDataMoved>([this](auto provider, DataModelIndex from, size_t count,
202 DataModelIndex to) { OnMovedProviderData(provider, from, count, to); },
203 provider),
204 uintptr_t(this));
205
206 provider->CacheHint()->SetValue(CacheHint()->GetValue());
207
208 if (provider->GetObjectCount() > 0) {
209 size_t index = CalculateIndex(provider, 0);
210 if (index != -1) {
211 Invoke<IOnDataAdded>(META_ACCESS_EVENT(OnDataAdded), DataModelIndex { index }, provider->GetObjectCount());
212 }
213 }
214 }
215
CalculateIndexBase(size_t provider) const216 size_t CompositeObjectProvider::CalculateIndexBase(size_t provider) const
217 {
218 size_t index = 0;
219 size_t base = 0;
220 IterateShared(GetSelf(), [&](const IObject::Ptr& obj) {
221 if (auto prov = interface_cast<IObjectProvider>(obj)) {
222 if (++index > provider) {
223 return false;
224 }
225 base += prov->GetObjectCount();
226 }
227 return true;
228 });
229 return base;
230 }
231
OnProviderRemoved(const ChildChangedInfo & info)232 void CompositeObjectProvider::OnProviderRemoved(const ChildChangedInfo& info)
233 {
234 auto provider = interface_pointer_cast<IObjectProvider>(info.object);
235 if (!provider) {
236 return;
237 }
238
239 provider->OnDataAdded()->RemoveHandler(uintptr_t(this));
240 provider->OnDataRemoved()->RemoveHandler(uintptr_t(this));
241 provider->OnDataMoved()->RemoveHandler(uintptr_t(this));
242
243 if (provider->GetObjectCount() > 0) {
244 size_t index = CalculateIndexBase(info.from);
245 Invoke<IOnDataRemoved>(META_ACCESS_EVENT(OnDataRemoved), DataModelIndex { index }, provider->GetObjectCount());
246 }
247 }
248
OnProviderMoved(const ChildChangedInfo & info)249 void CompositeObjectProvider::OnProviderMoved(const ChildChangedInfo& info)
250 {
251 auto provider = interface_pointer_cast<IObjectProvider>(info.object);
252 if (!provider || provider->GetObjectCount() == 0) {
253 return;
254 }
255
256 size_t index = 0;
257 size_t fromAdjust = info.to < info.from;
258 size_t from = CalculateIndexBase(info.from + fromAdjust);
259 if (fromAdjust) {
260 // in case we moved it already before to the from-location, we need to remove it to get the previous state
261 from -= provider->GetObjectCount();
262 }
263
264 auto to = CalculateIndex(provider, 0);
265 if (to != -1) {
266 // if the provider was before where it is currently, we need to add its content to get the previous state
267 if (info.from < info.to) {
268 to += provider->GetObjectCount();
269 }
270 Invoke<IOnDataMoved>(
271 META_ACCESS_EVENT(OnDataMoved), DataModelIndex { from }, provider->GetObjectCount(), DataModelIndex { to });
272 }
273 }
274
275 META_END_NAMESPACE()