• 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 #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()