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 #ifndef META_API_PROPERTY_ARRAY_PROPERTY_CHANGES_RECOGNIZER_H
17 #define META_API_PROPERTY_ARRAY_PROPERTY_CHANGES_RECOGNIZER_H
18 
19 #include <base/containers/unordered_map.h>
20 
21 #include <meta/base/algorithms.h>
22 #include <meta/interface/property/array_property.h>
23 
24 META_BEGIN_NAMESPACE()
25 
26 template<typename ValueType>
27 struct AddedValue {
28     ValueType value;
29     int index = 0;
30 
31     bool operator==(const AddedValue& v) const
32     {
33         return value == v.value && index == v.index;
34     }
35 };
36 
37 struct IndexChange {
38     int previousIndex = 0;
39     int newIndex = 0;
40 
41     bool operator==(const IndexChange& v) const
42     {
43         return previousIndex == v.previousIndex && newIndex == v.newIndex;
44     }
45 };
46 
47 template<typename ValueType>
48 struct ArrayChanges {
49     BASE_NS::vector<size_t> indexesRemoved;
50     BASE_NS::vector<AddedValue<ValueType>> valuesAdded;
51     BASE_NS::vector<IndexChange> positionChanged;
52 };
53 
54 template<typename ValueType>
55 class ArrayPropertyChangesRecognizer {
56 public:
57     ArrayPropertyChangesRecognizer() = default;
58 
SetValue(const META_NS::ArrayProperty<ValueType> & arrayProperty)59     void SetValue(const META_NS::ArrayProperty<ValueType>& arrayProperty)
60     {
61         previousValues_ = arrayProperty->GetValue();
62     }
63 
Clear()64     void Clear()
65     {
66         previousValues_.clear();
67     }
68 
OnArrayPropertyChanged(const META_NS::ArrayProperty<ValueType> & arrayProperty)69     ArrayChanges<ValueType> OnArrayPropertyChanged(const META_NS::ArrayProperty<ValueType>& arrayProperty)
70     {
71         auto newValuesVector = arrayProperty->GetValue();
72         auto changes = ArrayChanges<ValueType>();
73 
74         { // check for removes
75             BASE_NS::unordered_map<ValueType, size_t> prev;
76             for (size_t oldIndex = 0; oldIndex != previousValues_.size(); ++oldIndex) {
77                 auto& v = previousValues_[oldIndex];
78                 if (auto p = FindFirstOf(newValuesVector, v, prev[v]); p != NPOS) {
79                     prev[v] = p + 1;
80                 } else {
81                     changes.indexesRemoved.push_back(static_cast<int>(oldIndex));
82                 }
83             }
84         }
85 
86         { // check for modifications and additions
87             BASE_NS::unordered_map<ValueType, size_t> prev;
88             for (size_t newIndex = 0; newIndex < newValuesVector.size(); ++newIndex) {
89                 auto& v = newValuesVector[newIndex];
90                 if (auto p = FindFirstOf(previousValues_, v, prev[v]); p != NPOS) {
91                     prev[v] = p + 1;
92                     if (p != newIndex) {
93                         changes.positionChanged.push_back({ static_cast<int>(p), static_cast<int>(newIndex) });
94                     }
95                 } else {
96                     changes.valuesAdded.push_back({ v, static_cast<int>(newIndex) });
97                 }
98             }
99         }
100 
101         previousValues_ = BASE_NS::move(newValuesVector);
102 
103         return changes;
104     }
105 
106 private:
107     BASE_NS::vector<ValueType> previousValues_;
108 };
109 
110 META_END_NAMESPACE()
111 
112 #endif
113