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