xref: /aosp_15_r20/external/stg/order.h (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2021-2024 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License.  You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker //     https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida
19*9e3b08aeSAndroid Build Coastguard Worker 
20*9e3b08aeSAndroid Build Coastguard Worker #ifndef STG_ORDER_H_
21*9e3b08aeSAndroid Build Coastguard Worker #define STG_ORDER_H_
22*9e3b08aeSAndroid Build Coastguard Worker 
23*9e3b08aeSAndroid Build Coastguard Worker #include <algorithm>
24*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
25*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
26*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
27*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
28*9e3b08aeSAndroid Build Coastguard Worker 
29*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
30*9e3b08aeSAndroid Build Coastguard Worker 
31*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
32*9e3b08aeSAndroid Build Coastguard Worker // Combines two orderings of unique items, eliminating duplicates between the
33*9e3b08aeSAndroid Build Coastguard Worker // sequences, preserving the relative positions of the items in the second
34*9e3b08aeSAndroid Build Coastguard Worker // ordering and incorporating as much of the first's order as is compatible.
35*9e3b08aeSAndroid Build Coastguard Worker //
36*9e3b08aeSAndroid Build Coastguard Worker // The two orderings are reconciled by examining each item from the first
37*9e3b08aeSAndroid Build Coastguard Worker // sequence in turn. If it is not present in the second sequence, it is greedily
38*9e3b08aeSAndroid Build Coastguard Worker // appended to the combined sequence. If it is present but hasn't yet been
39*9e3b08aeSAndroid Build Coastguard Worker // appended, then all items from the current position in the second sequence up
40*9e3b08aeSAndroid Build Coastguard Worker // to and including it are appended in bulk. Otherwise it is skipped. Finally,
41*9e3b08aeSAndroid Build Coastguard Worker // all items from the current position in the second sequence are appended.
42*9e3b08aeSAndroid Build Coastguard Worker //
43*9e3b08aeSAndroid Build Coastguard Worker // This guarantees that the second sequence is a subsequence of the combined
44*9e3b08aeSAndroid Build Coastguard Worker // sequence and that items unique to the first subsequence are output as early
45*9e3b08aeSAndroid Build Coastguard Worker // as possible and only out of order if they are one of the extra items appended
46*9e3b08aeSAndroid Build Coastguard Worker // in bulk.
47*9e3b08aeSAndroid Build Coastguard Worker //
48*9e3b08aeSAndroid Build Coastguard Worker // Example, before and after:
49*9e3b08aeSAndroid Build Coastguard Worker //
50*9e3b08aeSAndroid Build Coastguard Worker // indexes1: rose, george, emily
51*9e3b08aeSAndroid Build Coastguard Worker // indexes2: george, ted, emily
52*9e3b08aeSAndroid Build Coastguard Worker //
53*9e3b08aeSAndroid Build Coastguard Worker // combined: rose, george, ted, emily
54*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
CombineOrders(const std::vector<T> & indexes1,const std::vector<T> & indexes2,size_t combined_size)55*9e3b08aeSAndroid Build Coastguard Worker std::vector<T> CombineOrders(const std::vector<T>& indexes1,
56*9e3b08aeSAndroid Build Coastguard Worker                              const std::vector<T>& indexes2,
57*9e3b08aeSAndroid Build Coastguard Worker                              size_t combined_size) {
58*9e3b08aeSAndroid Build Coastguard Worker   std::vector<T> combined;
59*9e3b08aeSAndroid Build Coastguard Worker   combined.reserve(combined_size);
60*9e3b08aeSAndroid Build Coastguard Worker   // keep track of where we are up to in indexes2
61*9e3b08aeSAndroid Build Coastguard Worker   auto position = indexes2.begin();
62*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& value : indexes1) {
63*9e3b08aeSAndroid Build Coastguard Worker     auto found = std::find(indexes2.begin(), indexes2.end(), value);
64*9e3b08aeSAndroid Build Coastguard Worker     if (found == indexes2.end()) {
65*9e3b08aeSAndroid Build Coastguard Worker       // value not found in the second ordering, append immediately
66*9e3b08aeSAndroid Build Coastguard Worker       combined.push_back(value);
67*9e3b08aeSAndroid Build Coastguard Worker     } else {
68*9e3b08aeSAndroid Build Coastguard Worker       // copy up to and including found value, if not yet copied
69*9e3b08aeSAndroid Build Coastguard Worker       for (; position <= found; ++position) {
70*9e3b08aeSAndroid Build Coastguard Worker         combined.push_back(*position);
71*9e3b08aeSAndroid Build Coastguard Worker       }
72*9e3b08aeSAndroid Build Coastguard Worker     }
73*9e3b08aeSAndroid Build Coastguard Worker   }
74*9e3b08aeSAndroid Build Coastguard Worker   // copy any remaining values unique to indexes2
75*9e3b08aeSAndroid Build Coastguard Worker   for (; position < indexes2.end(); ++position) {
76*9e3b08aeSAndroid Build Coastguard Worker     combined.push_back(*position);
77*9e3b08aeSAndroid Build Coastguard Worker   }
78*9e3b08aeSAndroid Build Coastguard Worker   return combined;
79*9e3b08aeSAndroid Build Coastguard Worker }
80*9e3b08aeSAndroid Build Coastguard Worker 
81*9e3b08aeSAndroid Build Coastguard Worker // Permutes the data array according to the permutation.
82*9e3b08aeSAndroid Build Coastguard Worker //
83*9e3b08aeSAndroid Build Coastguard Worker // The vectors must be the same size and permutation must contain [0, size()).
84*9e3b08aeSAndroid Build Coastguard Worker //
85*9e3b08aeSAndroid Build Coastguard Worker // Each data[i] <- data[permutation[i]].
86*9e3b08aeSAndroid Build Coastguard Worker //
87*9e3b08aeSAndroid Build Coastguard Worker // Each permutation[i] <- i.
88*9e3b08aeSAndroid Build Coastguard Worker //
89*9e3b08aeSAndroid Build Coastguard Worker // Example (where the permutation consists of a single cycle), step by step:
90*9e3b08aeSAndroid Build Coastguard Worker //
91*9e3b08aeSAndroid Build Coastguard Worker // data: emily, george, rose, ted
92*9e3b08aeSAndroid Build Coastguard Worker // permutation: 2, 1, 3, 0
93*9e3b08aeSAndroid Build Coastguard Worker //
94*9e3b08aeSAndroid Build Coastguard Worker // from = 0
95*9e3b08aeSAndroid Build Coastguard Worker // initialise to = 0
96*9e3b08aeSAndroid Build Coastguard Worker // resolve cycle by swapping elements
97*9e3b08aeSAndroid Build Coastguard Worker //
98*9e3b08aeSAndroid Build Coastguard Worker // permutation[to = 0] = 2 != from = 2
99*9e3b08aeSAndroid Build Coastguard Worker //   want data[2] = rose at data[0] = emily, swap them
100*9e3b08aeSAndroid Build Coastguard Worker //   also swap to = 0 with permutation[to] = 2
101*9e3b08aeSAndroid Build Coastguard Worker //   data: rose, george, emily, ted
102*9e3b08aeSAndroid Build Coastguard Worker //   permutation 0, 1, 3, 0
103*9e3b08aeSAndroid Build Coastguard Worker //   to = 2
104*9e3b08aeSAndroid Build Coastguard Worker //
105*9e3b08aeSAndroid Build Coastguard Worker // permutation[to = 2] = 3 != from = 0
106*9e3b08aeSAndroid Build Coastguard Worker //   want data[3] = ted at data[2] = emily, swap them
107*9e3b08aeSAndroid Build Coastguard Worker //   also swap to = 2 with permutation[2] = 3
108*9e3b08aeSAndroid Build Coastguard Worker //   data: rose, george, ted, emily
109*9e3b08aeSAndroid Build Coastguard Worker //   permutation 0, 1, 2, 0
110*9e3b08aeSAndroid Build Coastguard Worker //   to = 3
111*9e3b08aeSAndroid Build Coastguard Worker //
112*9e3b08aeSAndroid Build Coastguard Worker // permutation[to = 3] = 0 == from = 0
113*9e3b08aeSAndroid Build Coastguard Worker //   emily is now in right position
114*9e3b08aeSAndroid Build Coastguard Worker //   finish the cycle and set permutation[to = 3] = to = 3
115*9e3b08aeSAndroid Build Coastguard Worker //   permutation 0, 1, 2, 3
116*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
Permute(std::vector<T> & data,std::vector<size_t> & permutation)117*9e3b08aeSAndroid Build Coastguard Worker void Permute(std::vector<T>& data, std::vector<size_t>& permutation) {
118*9e3b08aeSAndroid Build Coastguard Worker   const size_t size = permutation.size();
119*9e3b08aeSAndroid Build Coastguard Worker   Check(data.size() == size) << "internal error: bad Permute vectors";
120*9e3b08aeSAndroid Build Coastguard Worker   for (size_t from = 0; from < size; ++from) {
121*9e3b08aeSAndroid Build Coastguard Worker     size_t to = from;
122*9e3b08aeSAndroid Build Coastguard Worker     while (permutation[to] != from) {
123*9e3b08aeSAndroid Build Coastguard Worker       Check(permutation[to] < size) << "internal error: bad Permute index";
124*9e3b08aeSAndroid Build Coastguard Worker       using std::swap;
125*9e3b08aeSAndroid Build Coastguard Worker       swap(data[to], data[permutation[to]]);
126*9e3b08aeSAndroid Build Coastguard Worker       swap(to, permutation[to]);
127*9e3b08aeSAndroid Build Coastguard Worker     }
128*9e3b08aeSAndroid Build Coastguard Worker     permutation[to] = to;
129*9e3b08aeSAndroid Build Coastguard Worker   }
130*9e3b08aeSAndroid Build Coastguard Worker }
131*9e3b08aeSAndroid Build Coastguard Worker 
132*9e3b08aeSAndroid Build Coastguard Worker // Reorders the data array according to its implicit ordering constraints.
133*9e3b08aeSAndroid Build Coastguard Worker //
134*9e3b08aeSAndroid Build Coastguard Worker // At least one of each pair of positions must be present.
135*9e3b08aeSAndroid Build Coastguard Worker //
136*9e3b08aeSAndroid Build Coastguard Worker // Each pair gives 1 or 2 abstract positions for the corresponding data item.
137*9e3b08aeSAndroid Build Coastguard Worker //
138*9e3b08aeSAndroid Build Coastguard Worker // The first and second positions are interpreted separately, with the second
139*9e3b08aeSAndroid Build Coastguard Worker // implied ordering having precedence over the first in the event of a conflict.
140*9e3b08aeSAndroid Build Coastguard Worker //
141*9e3b08aeSAndroid Build Coastguard Worker // The real work is done by CombineOrders and Permute.
142*9e3b08aeSAndroid Build Coastguard Worker //
143*9e3b08aeSAndroid Build Coastguard Worker // In practice the input data are the output of a matching process, consider:
144*9e3b08aeSAndroid Build Coastguard Worker //
145*9e3b08aeSAndroid Build Coastguard Worker // sequence1: rose, george, emily
146*9e3b08aeSAndroid Build Coastguard Worker // sequence2: george, ted, emily
147*9e3b08aeSAndroid Build Coastguard Worker //
148*9e3b08aeSAndroid Build Coastguard Worker // These have the corresponding matches (here just ordered by the matching key;
149*9e3b08aeSAndroid Build Coastguard Worker // this algorithm gives the same result independent of this ordering):
150*9e3b08aeSAndroid Build Coastguard Worker //
151*9e3b08aeSAndroid Build Coastguard Worker // emily:  {{2}, {2}}
152*9e3b08aeSAndroid Build Coastguard Worker // george: {{1}, {0}}
153*9e3b08aeSAndroid Build Coastguard Worker // rose:   {{0}, {} }
154*9e3b08aeSAndroid Build Coastguard Worker // ted:    {{},  {1}}
155*9e3b08aeSAndroid Build Coastguard Worker //
156*9e3b08aeSAndroid Build Coastguard Worker // Now ignore the matching keys.
157*9e3b08aeSAndroid Build Coastguard Worker //
158*9e3b08aeSAndroid Build Coastguard Worker // This function processes the matches into intermediate data structures:
159*9e3b08aeSAndroid Build Coastguard Worker //
160*9e3b08aeSAndroid Build Coastguard Worker // positions1: {{2, 0}, {1, 1}, {0, 2},        }
161*9e3b08aeSAndroid Build Coastguard Worker // positions2: {{2, 0}, {0, 1},         {1, 3},}
162*9e3b08aeSAndroid Build Coastguard Worker //
163*9e3b08aeSAndroid Build Coastguard Worker // The indexes (.second) are sorted by the positions (.first):
164*9e3b08aeSAndroid Build Coastguard Worker //
165*9e3b08aeSAndroid Build Coastguard Worker // positions1: {{0, 2}, {1, 1}, {2, 0}}
166*9e3b08aeSAndroid Build Coastguard Worker // positions2: {{0, 1}, {1, 3}, {2, 0}}
167*9e3b08aeSAndroid Build Coastguard Worker //
168*9e3b08aeSAndroid Build Coastguard Worker // And the positions are discarded:
169*9e3b08aeSAndroid Build Coastguard Worker //
170*9e3b08aeSAndroid Build Coastguard Worker // indexes1: 2, 1, 0
171*9e3b08aeSAndroid Build Coastguard Worker // indexes2: 1, 3, 0
172*9e3b08aeSAndroid Build Coastguard Worker //
173*9e3b08aeSAndroid Build Coastguard Worker // Finally a consistent ordering is made:
174*9e3b08aeSAndroid Build Coastguard Worker //
175*9e3b08aeSAndroid Build Coastguard Worker // indexes1: 2, 1, 3, 0
176*9e3b08aeSAndroid Build Coastguard Worker //
177*9e3b08aeSAndroid Build Coastguard Worker // And this is used to permute the original matching sequence, for clarity
178*9e3b08aeSAndroid Build Coastguard Worker // including the implicit keys here:
179*9e3b08aeSAndroid Build Coastguard Worker //
180*9e3b08aeSAndroid Build Coastguard Worker // rose:   {{0}, {} }
181*9e3b08aeSAndroid Build Coastguard Worker // george: {{1}, {0}}
182*9e3b08aeSAndroid Build Coastguard Worker // ted:    {{},  {1}}
183*9e3b08aeSAndroid Build Coastguard Worker // emily:  {{2}, {2}}
184*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
Reorder(std::vector<std::pair<std::optional<T>,std::optional<T>>> & data)185*9e3b08aeSAndroid Build Coastguard Worker void Reorder(std::vector<std::pair<std::optional<T>, std::optional<T>>>& data) {
186*9e3b08aeSAndroid Build Coastguard Worker   const auto size = data.size();
187*9e3b08aeSAndroid Build Coastguard Worker   // Split out the ordering constraints as position-index pairs.
188*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<T, size_t>> positions1;
189*9e3b08aeSAndroid Build Coastguard Worker   positions1.reserve(size);
190*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<T, size_t>> positions2;
191*9e3b08aeSAndroid Build Coastguard Worker   positions2.reserve(size);
192*9e3b08aeSAndroid Build Coastguard Worker   for (size_t index = 0; index < size; ++index) {
193*9e3b08aeSAndroid Build Coastguard Worker     const auto& [position1, position2] = data[index];
194*9e3b08aeSAndroid Build Coastguard Worker     Check(position1 || position2)
195*9e3b08aeSAndroid Build Coastguard Worker         << "internal error: Reorder constraint with no positions";
196*9e3b08aeSAndroid Build Coastguard Worker     if (position1) {
197*9e3b08aeSAndroid Build Coastguard Worker       positions1.push_back({*position1, index});
198*9e3b08aeSAndroid Build Coastguard Worker     }
199*9e3b08aeSAndroid Build Coastguard Worker     if (position2) {
200*9e3b08aeSAndroid Build Coastguard Worker       positions2.push_back({*position2, index});
201*9e3b08aeSAndroid Build Coastguard Worker     }
202*9e3b08aeSAndroid Build Coastguard Worker   }
203*9e3b08aeSAndroid Build Coastguard Worker   // Order the indexes by the desired positions.
204*9e3b08aeSAndroid Build Coastguard Worker   std::stable_sort(positions1.begin(), positions1.end());
205*9e3b08aeSAndroid Build Coastguard Worker   std::stable_sort(positions2.begin(), positions2.end());
206*9e3b08aeSAndroid Build Coastguard Worker   std::vector<size_t> indexes1;
207*9e3b08aeSAndroid Build Coastguard Worker   indexes1.reserve(positions1.size());
208*9e3b08aeSAndroid Build Coastguard Worker   std::vector<size_t> indexes2;
209*9e3b08aeSAndroid Build Coastguard Worker   indexes2.reserve(positions2.size());
210*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& ordered_index : positions1) {
211*9e3b08aeSAndroid Build Coastguard Worker     indexes1.push_back(ordered_index.second);
212*9e3b08aeSAndroid Build Coastguard Worker   }
213*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& ordered_index : positions2) {
214*9e3b08aeSAndroid Build Coastguard Worker     indexes2.push_back(ordered_index.second);
215*9e3b08aeSAndroid Build Coastguard Worker   }
216*9e3b08aeSAndroid Build Coastguard Worker   // Merge the two orderings of indexes, giving preference to the second.
217*9e3b08aeSAndroid Build Coastguard Worker   auto combined = CombineOrders(indexes1, indexes2, size);
218*9e3b08aeSAndroid Build Coastguard Worker   // Use this to permute the original data array.
219*9e3b08aeSAndroid Build Coastguard Worker   Permute(data, combined);
220*9e3b08aeSAndroid Build Coastguard Worker }
221*9e3b08aeSAndroid Build Coastguard Worker 
222*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
223*9e3b08aeSAndroid Build Coastguard Worker 
224*9e3b08aeSAndroid Build Coastguard Worker #endif  // STG_ORDER_H_
225