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 "bridge/cj_frontend/interfaces/cj_ffi/cj_foreach_ffi.h"
17 
18 #include <cstdlib>
19 #include <string>
20 #include <unordered_set>
21 
22 #include "cj_lambda.h"
23 
24 #include "bridge/cj_frontend/runtime/cj_runtime_delegate.h"
25 #include "core/components_ng/syntax/for_each_model.h"
26 
27 using namespace OHOS::Ace;
28 using namespace OHOS::FFI;
29 using namespace OHOS::Ace::Framework;
30 
31 extern "C" {
FfiOHOSAceFrameworkForEachCreateFU(char * viewId,int64_t parentViewID,int64_t dataSize,ViewCallBack callbackView,IdCallBack callbackKey)32 void FfiOHOSAceFrameworkForEachCreateFU(
33     char* viewId, int64_t parentViewID, int64_t dataSize, ViewCallBack callbackView, IdCallBack callbackKey)
34 {
35     std::function<void(int64_t)> ffiViewCallback = CJLambda::Create(callbackView);
36     std::function<std::string(int64_t)> ffiKeyCallback = [callback = CJLambda::Create(callbackKey)](
37                                                              int64_t info) -> std::string {
38         auto ffiStr = callback(info);
39         std::string res = ffiStr.value;
40         ffiStr.free(ffiStr.value);
41         return res;
42     };
43     auto* model = ForEachModel::GetInstance();
44     model->Create();
45     for (int64_t i = 0; i < dataSize; i++) {
46         auto key = ffiKeyCallback(i);
47         model->CreateNewChildStart(key);
48         ffiViewCallback(i);
49         model->CreateNewChildFinish(key);
50     }
51 }
52 
FfiOHOSAceFrameworkForEachCreate()53 void FfiOHOSAceFrameworkForEachCreate()
54 {
55     auto* model = ForEachModel::GetInstance();
56     model->Create();
57 }
58 
FfiOHOSAceFrameworkForEachPop()59 void FfiOHOSAceFrameworkForEachPop()
60 {
61     ForEachModel::GetInstance()->Pop();
62 }
63 
FfiOHOSAceFrameworkDeleteIdArray(VectorToCFFIArrayString * src)64 static void FfiOHOSAceFrameworkDeleteIdArray(VectorToCFFIArrayString* src)
65 {
66     for (size_t i = 0; i < src->size; ++i) {
67         free(src->buffer[i]);
68     }
69     free(src->buffer);
70 }
71 
FfiOHOSAceFrameworkViewGetIdArray(int64_t elmtId)72 VectorToCFFIArrayString FfiOHOSAceFrameworkViewGetIdArray(int64_t elmtId)
73 {
74     std::list<std::string> result = ForEachModel::GetInstance()->GetCurrentIdList(elmtId);
75 
76     auto buffer = (char**)malloc(sizeof(const char*) * result.size());
77     if (!buffer) {
78         return { .size = 0, .buffer = nullptr, .free = FfiOHOSAceFrameworkDeleteIdArray };
79     }
80 
81     size_t i = 0;
82     for (const auto& element : result) {
83         auto data = (char*)malloc(element.size() * sizeof(char));
84         if (data == nullptr) {
85             for (size_t j = 0; j < result.size(); j++) {
86                 free(buffer[j]);
87             }
88             free(buffer);
89             return { .size = 0, .buffer = nullptr, .free = FfiOHOSAceFrameworkDeleteIdArray };
90         }
91         std::char_traits<char>::copy(data, element.c_str(), element.size());
92         buffer[i++] = data;
93     }
94 
95     return { .size = result.size(), .buffer = buffer, .free = FfiOHOSAceFrameworkDeleteIdArray };
96 }
97 
FfiOHOSAceFrameworkViewSetIdArray(int64_t elmtId,VectorCJStringHandle vecHandle)98 VectorToCFFIArray FfiOHOSAceFrameworkViewSetIdArray(int64_t elmtId, VectorCJStringHandle vecHandle)
99 {
100     std::list<std::string> newIdArr;
101     auto cjRectangleVec = reinterpret_cast<std::vector<std::string>*>(vecHandle);
102 
103     for (const auto& value : *cjRectangleVec) {
104         newIdArr.emplace_back(value);
105     }
106     // Get old IDs. New ID are set in the end of this function.
107     const std::list<std::string>& previousIDList = ForEachModel::GetInstance()->GetCurrentIdList(elmtId);
108     std::unordered_set<std::string> oldIdsSet(previousIDList.begin(), previousIDList.end());
109     // Get reference to output diff index array.
110     std::vector<size_t> diffIndexArray;
111     size_t index = 0;
112     for (const auto& newId : newIdArr) {
113         if (oldIdsSet.find(newId) == oldIdsSet.end()) {
114             // Populate output diff array with this index that was not in old array.
115             diffIndexArray.push_back(index);
116         }
117         index++;
118     }
119 
120     ForEachModel::GetInstance()->SetNewIds(std::move(newIdArr));
121 
122     int64_t* temp = nullptr;
123     temp = (int64_t*)malloc(sizeof(int64_t) * diffIndexArray.size());
124     if (!temp) {
125         VectorToCFFIArray faultData {
126             .size = 0, .buffer = nullptr, .free = reinterpret_cast<void (*)(int64_t*)>(free)
127         };
128         return faultData;
129     }
130 
131     VectorToCFFIArray res {
132         .size = diffIndexArray.size(), .buffer = temp, .free = reinterpret_cast<void (*)(int64_t*)>(free)
133     };
134 
135     for (size_t i = 0; i < diffIndexArray.size(); i++) {
136         res.buffer[i] = static_cast<int64_t>(diffIndexArray[i]);
137     }
138 
139     return res;
140 }
141 
HandleFFIArray(const std::vector<size_t> & vec)142 VectorToCFFIArray HandleFFIArray(const std::vector<size_t>& vec)
143 {
144     VectorToCFFIArray ffiArray;
145     ffiArray.size = vec.size();
146     ffiArray.buffer = new int64_t[ffiArray.size];
147     for (size_t i = 0; i < vec.size(); ++i) {
148         ffiArray.buffer[i] = static_cast<int64_t>(vec[i]);
149     }
150     ffiArray.free = reinterpret_cast<void (*)(int64_t*)>(free);
151     return ffiArray;
152 }
153 
AssambleSetIdResult(const std::vector<size_t> & diffIds,const std::vector<size_t> & dupIds,const std::vector<size_t> & remIds)154 SetIdResultFFI AssambleSetIdResult(
155     const std::vector<size_t>& diffIds, const std::vector<size_t>& dupIds, const std::vector<size_t>& remIds)
156 {
157     VectorToCFFIArray diffArray = HandleFFIArray(diffIds);
158     VectorToCFFIArray dupArray = HandleFFIArray(dupIds);
159     VectorToCFFIArray remArray = HandleFFIArray(remIds);
160     SetIdResultFFI result {
161         .diffIndexArrayPtr = diffArray, .duplicateIdsPtr = dupArray, .removedChildElmtIdsPtr = remArray
162     };
163     return result;
164 }
165 
FfiOHOSAceFrameworkViewSetIdArrayReturnStruct(int64_t elmtId,VectorCJStringHandle newIdArray)166 SetIdResultFFI FfiOHOSAceFrameworkViewSetIdArrayReturnStruct(int64_t elmtId, VectorCJStringHandle newIdArray)
167 {
168     std::list<std::string> cjArr;
169     std::vector<size_t> diffIds;
170     std::vector<size_t> dupIds;
171     std::vector<size_t> remIds;
172     std::list<std::string> newIdArr;
173 
174     auto cjRectangleVec = reinterpret_cast<std::vector<std::string>*>(newIdArray);
175     for (const auto& value : *cjRectangleVec) {
176         cjArr.emplace_back(value);
177     }
178     // Get old IDs. New ID are set in the end of this function.
179     const std::list<std::string>& previousIDList = ForEachModel::GetInstance()->GetCurrentIdList(elmtId);
180     std::unordered_set<std::string> oldIdsSet(previousIDList.begin(), previousIDList.end());
181     std::unordered_set<std::string> newIds;
182 
183     size_t index = 0;
184     for (const auto& strId : cjArr) {
185         // Save return value of insert to know was it duplicate...
186         std::pair<std::unordered_set<std::string>::iterator, bool> ret = newIds.insert(strId);
187         // Duplicate Id detected. Will return index of those to caller.
188         if (!ret.second) {
189             dupIds.push_back(index);
190         } else {
191             // ID was not duplicate. Accept it.
192             newIdArr.emplace_back(*ret.first);
193             // Check was ID previously available or totally new one.
194             if (oldIdsSet.find(*ret.first) == oldIdsSet.end()) {
195                 // Populate output diff array with this index that was not in old array.
196                 diffIds.push_back(index);
197             }
198         }
199         index++;
200     }
201 
202     ForEachModel::GetInstance()->SetNewIds(std::move(newIdArr));
203     std::list<int32_t> removedElmtIds;
204     ForEachModel::GetInstance()->SetRemovedElmtIds(removedElmtIds);
205     if (removedElmtIds.size()) {
206         for (const auto& rmElmtId : removedElmtIds) {
207             remIds.emplace_back(rmElmtId);
208         }
209     }
210     return AssambleSetIdResult(diffIds, dupIds, remIds);
211 }
212 
FfiOHOSAceFrameworkViewCreateNewChildStart(char * elmtId)213 void FfiOHOSAceFrameworkViewCreateNewChildStart(char* elmtId)
214 {
215     LOGD("Start create child with array id %{public}s.", elmtId);
216 
217     auto* model = ForEachModel::GetInstance();
218     model->CreateNewChildStart(elmtId);
219 }
220 
FfiOHOSAceFrameworkViewCreateNewChildFinish(char * elmtId)221 void FfiOHOSAceFrameworkViewCreateNewChildFinish(char* elmtId)
222 {
223     LOGD("Finish create child with array id %{public}s.", elmtId);
224 
225     auto* model = ForEachModel::GetInstance();
226     model->CreateNewChildFinish(elmtId);
227 }
228 }
229