• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()