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