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