xref: /aosp_15_r20/external/brotli/research/find_opt_references.cc (revision f4ee7fba7774faf2a30f13154332c0a06550dbc4)
1*f4ee7fbaSAndroid Build Coastguard Worker /* Copyright 2016 Google Inc. All Rights Reserved.
2*f4ee7fbaSAndroid Build Coastguard Worker    Author: [email protected] (Ivan Nikulin)
3*f4ee7fbaSAndroid Build Coastguard Worker 
4*f4ee7fbaSAndroid Build Coastguard Worker    Distributed under MIT license.
5*f4ee7fbaSAndroid Build Coastguard Worker    See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
6*f4ee7fbaSAndroid Build Coastguard Worker */
7*f4ee7fbaSAndroid Build Coastguard Worker 
8*f4ee7fbaSAndroid Build Coastguard Worker /* Tool for generating optimal backward references for the input file. Uses
9*f4ee7fbaSAndroid Build Coastguard Worker    sais-lite library for building suffix array. */
10*f4ee7fbaSAndroid Build Coastguard Worker 
11*f4ee7fbaSAndroid Build Coastguard Worker #include <algorithm>
12*f4ee7fbaSAndroid Build Coastguard Worker #include <cassert>
13*f4ee7fbaSAndroid Build Coastguard Worker #include <cstdio>
14*f4ee7fbaSAndroid Build Coastguard Worker #include <cstring>
15*f4ee7fbaSAndroid Build Coastguard Worker #include <functional>
16*f4ee7fbaSAndroid Build Coastguard Worker #include <utility>
17*f4ee7fbaSAndroid Build Coastguard Worker #include <vector>
18*f4ee7fbaSAndroid Build Coastguard Worker 
19*f4ee7fbaSAndroid Build Coastguard Worker #include <gflags/gflags.h>
20*f4ee7fbaSAndroid Build Coastguard Worker using gflags::ParseCommandLineFlags;
21*f4ee7fbaSAndroid Build Coastguard Worker 
22*f4ee7fbaSAndroid Build Coastguard Worker #include "./esaxx/sais.hxx"
23*f4ee7fbaSAndroid Build Coastguard Worker 
24*f4ee7fbaSAndroid Build Coastguard Worker DEFINE_bool(advanced, false, "Advanced searching mode: finds all longest "
25*f4ee7fbaSAndroid Build Coastguard Worker     "matches at positions that are not covered by matches of length at least "
26*f4ee7fbaSAndroid Build Coastguard Worker     "max_length. WARNING: uses much more memory than simple mode, especially "
27*f4ee7fbaSAndroid Build Coastguard Worker     "for small values of min_length.");
28*f4ee7fbaSAndroid Build Coastguard Worker DEFINE_int32(min_length, 1, "Minimal length of found backward references.");
29*f4ee7fbaSAndroid Build Coastguard Worker /* For advanced mode. */
30*f4ee7fbaSAndroid Build Coastguard Worker DEFINE_int32(long_length, 32,
31*f4ee7fbaSAndroid Build Coastguard Worker              "Maximal length of found backward references for advanced mode.");
32*f4ee7fbaSAndroid Build Coastguard Worker DEFINE_int32(skip, 1, "Number of bytes to skip.");
33*f4ee7fbaSAndroid Build Coastguard Worker 
34*f4ee7fbaSAndroid Build Coastguard Worker const size_t kFileBufferSize = (1 << 16);  // 64KB
35*f4ee7fbaSAndroid Build Coastguard Worker 
36*f4ee7fbaSAndroid Build Coastguard Worker typedef int sarray_type;  // Can't make it unsigned because of templates :(
37*f4ee7fbaSAndroid Build Coastguard Worker typedef uint8_t input_type;
38*f4ee7fbaSAndroid Build Coastguard Worker typedef uint32_t lcp_type;
39*f4ee7fbaSAndroid Build Coastguard Worker typedef std::pair<int, std::vector<int> > entry_type;
40*f4ee7fbaSAndroid Build Coastguard Worker typedef std::function<void(sarray_type*, lcp_type*, size_t, int, int, int, int,
41*f4ee7fbaSAndroid Build Coastguard Worker                            int)> Fn;
42*f4ee7fbaSAndroid Build Coastguard Worker 
ReadInput(FILE * fin,input_type * storage,size_t input_size)43*f4ee7fbaSAndroid Build Coastguard Worker void ReadInput(FILE* fin, input_type* storage, size_t input_size) {
44*f4ee7fbaSAndroid Build Coastguard Worker   size_t last_pos = 0;
45*f4ee7fbaSAndroid Build Coastguard Worker   size_t available_in;
46*f4ee7fbaSAndroid Build Coastguard Worker   fseek(fin, 0, SEEK_SET);
47*f4ee7fbaSAndroid Build Coastguard Worker   do {
48*f4ee7fbaSAndroid Build Coastguard Worker     available_in = fread(storage + last_pos, 1, kFileBufferSize, fin);
49*f4ee7fbaSAndroid Build Coastguard Worker     last_pos += available_in;
50*f4ee7fbaSAndroid Build Coastguard Worker   } while (available_in != 0);
51*f4ee7fbaSAndroid Build Coastguard Worker   assert(last_pos == input_size);
52*f4ee7fbaSAndroid Build Coastguard Worker }
53*f4ee7fbaSAndroid Build Coastguard Worker 
BuildLCP(input_type * storage,sarray_type * sarray,lcp_type * lcp,size_t size,uint32_t * pos)54*f4ee7fbaSAndroid Build Coastguard Worker void BuildLCP(input_type* storage, sarray_type* sarray, lcp_type* lcp,
55*f4ee7fbaSAndroid Build Coastguard Worker               size_t size, uint32_t* pos) {
56*f4ee7fbaSAndroid Build Coastguard Worker   for (int i = 0; i < size; ++i) {
57*f4ee7fbaSAndroid Build Coastguard Worker     pos[sarray[i]] = i;
58*f4ee7fbaSAndroid Build Coastguard Worker   }
59*f4ee7fbaSAndroid Build Coastguard Worker   uint32_t k = 0;
60*f4ee7fbaSAndroid Build Coastguard Worker   lcp[size - 1] = 0;
61*f4ee7fbaSAndroid Build Coastguard Worker   for (int i = 0; i < size; ++i) {
62*f4ee7fbaSAndroid Build Coastguard Worker     if (pos[i] == size - 1) {
63*f4ee7fbaSAndroid Build Coastguard Worker       k = 0;
64*f4ee7fbaSAndroid Build Coastguard Worker       continue;
65*f4ee7fbaSAndroid Build Coastguard Worker     }
66*f4ee7fbaSAndroid Build Coastguard Worker     uint32_t j = sarray[pos[i] + 1];  // Suffix which follow i-th suffix in SA.
67*f4ee7fbaSAndroid Build Coastguard Worker     while (i + k < size && j + k < size && storage[i + k] == storage[j + k]) {
68*f4ee7fbaSAndroid Build Coastguard Worker       ++k;
69*f4ee7fbaSAndroid Build Coastguard Worker     }
70*f4ee7fbaSAndroid Build Coastguard Worker     lcp[pos[i]] = k;
71*f4ee7fbaSAndroid Build Coastguard Worker     if (k > 0) --k;
72*f4ee7fbaSAndroid Build Coastguard Worker   }
73*f4ee7fbaSAndroid Build Coastguard Worker }
74*f4ee7fbaSAndroid Build Coastguard Worker 
PrintReference(sarray_type * sarray,lcp_type * lcp,size_t size,int idx,int left_ix,int right_ix,int left_lcp,int right_lcp,FILE * fout)75*f4ee7fbaSAndroid Build Coastguard Worker inline void PrintReference(sarray_type* sarray, lcp_type* lcp, size_t size,
76*f4ee7fbaSAndroid Build Coastguard Worker                            int idx, int left_ix, int right_ix, int left_lcp,
77*f4ee7fbaSAndroid Build Coastguard Worker                            int right_lcp, FILE* fout) {
78*f4ee7fbaSAndroid Build Coastguard Worker   int max_lcp_ix;
79*f4ee7fbaSAndroid Build Coastguard Worker   if (right_ix == size - 1 || (left_ix >= 0 && left_lcp >= right_lcp)) {
80*f4ee7fbaSAndroid Build Coastguard Worker     max_lcp_ix = left_ix;
81*f4ee7fbaSAndroid Build Coastguard Worker   } else {
82*f4ee7fbaSAndroid Build Coastguard Worker     max_lcp_ix = right_ix;
83*f4ee7fbaSAndroid Build Coastguard Worker   }
84*f4ee7fbaSAndroid Build Coastguard Worker   int dist = idx - sarray[max_lcp_ix];
85*f4ee7fbaSAndroid Build Coastguard Worker   assert(dist > 0);
86*f4ee7fbaSAndroid Build Coastguard Worker   fputc(1, fout);
87*f4ee7fbaSAndroid Build Coastguard Worker   fwrite(&idx, sizeof(int), 1, fout);   // Position in input.
88*f4ee7fbaSAndroid Build Coastguard Worker   fwrite(&dist, sizeof(int), 1, fout);  // Backward distance.
89*f4ee7fbaSAndroid Build Coastguard Worker }
90*f4ee7fbaSAndroid Build Coastguard Worker 
GoLeft(sarray_type * sarray,lcp_type * lcp,int idx,int left_ix,int left_lcp,entry_type * entry)91*f4ee7fbaSAndroid Build Coastguard Worker inline void GoLeft(sarray_type* sarray, lcp_type* lcp, int idx, int left_ix,
92*f4ee7fbaSAndroid Build Coastguard Worker                    int left_lcp, entry_type* entry) {
93*f4ee7fbaSAndroid Build Coastguard Worker   entry->first = left_lcp;
94*f4ee7fbaSAndroid Build Coastguard Worker   if (left_lcp > FLAGS_long_length) return;
95*f4ee7fbaSAndroid Build Coastguard Worker   for (; left_ix >= 0; --left_ix) {
96*f4ee7fbaSAndroid Build Coastguard Worker     if (lcp[left_ix] < left_lcp) break;
97*f4ee7fbaSAndroid Build Coastguard Worker     if (sarray[left_ix] < idx) {
98*f4ee7fbaSAndroid Build Coastguard Worker       entry->second.push_back(idx - sarray[left_ix]);
99*f4ee7fbaSAndroid Build Coastguard Worker     }
100*f4ee7fbaSAndroid Build Coastguard Worker   }
101*f4ee7fbaSAndroid Build Coastguard Worker }
102*f4ee7fbaSAndroid Build Coastguard Worker 
GoRight(sarray_type * sarray,lcp_type * lcp,int idx,size_t size,int right_ix,int right_lcp,entry_type * entry)103*f4ee7fbaSAndroid Build Coastguard Worker inline void GoRight(sarray_type* sarray, lcp_type* lcp, int idx, size_t size,
104*f4ee7fbaSAndroid Build Coastguard Worker                     int right_ix, int right_lcp, entry_type* entry) {
105*f4ee7fbaSAndroid Build Coastguard Worker   entry->first = right_lcp;
106*f4ee7fbaSAndroid Build Coastguard Worker   if (right_lcp > FLAGS_long_length) return;
107*f4ee7fbaSAndroid Build Coastguard Worker   for (; right_ix < size - 1; ++right_ix) {
108*f4ee7fbaSAndroid Build Coastguard Worker     if (lcp[right_ix] < right_lcp) break;
109*f4ee7fbaSAndroid Build Coastguard Worker     if (sarray[right_ix] < idx) {
110*f4ee7fbaSAndroid Build Coastguard Worker       entry->second.push_back(idx - sarray[right_ix]);
111*f4ee7fbaSAndroid Build Coastguard Worker     }
112*f4ee7fbaSAndroid Build Coastguard Worker   }
113*f4ee7fbaSAndroid Build Coastguard Worker }
114*f4ee7fbaSAndroid Build Coastguard Worker 
StoreReference(sarray_type * sarray,lcp_type * lcp,size_t size,int idx,int left_ix,int right_ix,int left_lcp,int right_lcp,entry_type * entries)115*f4ee7fbaSAndroid Build Coastguard Worker inline void StoreReference(sarray_type* sarray, lcp_type* lcp, size_t size,
116*f4ee7fbaSAndroid Build Coastguard Worker                            int idx, int left_ix, int right_ix, int left_lcp,
117*f4ee7fbaSAndroid Build Coastguard Worker                            int right_lcp, entry_type* entries) {
118*f4ee7fbaSAndroid Build Coastguard Worker   if (right_ix == size - 1 || (left_ix >= 0 && left_lcp > right_lcp)) {
119*f4ee7fbaSAndroid Build Coastguard Worker     // right is invalid or left is better
120*f4ee7fbaSAndroid Build Coastguard Worker     GoLeft(sarray, lcp, idx, left_ix, left_lcp, &entries[idx]);
121*f4ee7fbaSAndroid Build Coastguard Worker   } else if (left_ix < 0 || (right_ix < size - 1 && right_lcp > left_lcp)) {
122*f4ee7fbaSAndroid Build Coastguard Worker     // left is invalid or right is better
123*f4ee7fbaSAndroid Build Coastguard Worker     GoRight(sarray, lcp, idx, size, right_ix, right_lcp, &entries[idx]);
124*f4ee7fbaSAndroid Build Coastguard Worker   } else {  // both are valid and of equal length
125*f4ee7fbaSAndroid Build Coastguard Worker     GoLeft(sarray, lcp, idx, left_ix, left_lcp, &entries[idx]);
126*f4ee7fbaSAndroid Build Coastguard Worker     GoRight(sarray, lcp, idx, size, right_ix, right_lcp, &entries[idx]);
127*f4ee7fbaSAndroid Build Coastguard Worker   }
128*f4ee7fbaSAndroid Build Coastguard Worker }
129*f4ee7fbaSAndroid Build Coastguard Worker 
ProcessReferences(sarray_type * sarray,lcp_type * lcp,size_t size,uint32_t * pos,const Fn & process_output)130*f4ee7fbaSAndroid Build Coastguard Worker void ProcessReferences(sarray_type* sarray, lcp_type* lcp, size_t size,
131*f4ee7fbaSAndroid Build Coastguard Worker                        uint32_t* pos, const Fn& process_output) {
132*f4ee7fbaSAndroid Build Coastguard Worker   int min_length = FLAGS_min_length;
133*f4ee7fbaSAndroid Build Coastguard Worker   for (int idx = FLAGS_skip; idx < size; ++idx) {
134*f4ee7fbaSAndroid Build Coastguard Worker     int left_lcp = -1;
135*f4ee7fbaSAndroid Build Coastguard Worker     int left_ix;
136*f4ee7fbaSAndroid Build Coastguard Worker     for (left_ix = pos[idx] - 1; left_ix >= 0; --left_ix) {
137*f4ee7fbaSAndroid Build Coastguard Worker       if (left_lcp == -1 || left_lcp > lcp[left_ix]) {
138*f4ee7fbaSAndroid Build Coastguard Worker         left_lcp = lcp[left_ix];
139*f4ee7fbaSAndroid Build Coastguard Worker       }
140*f4ee7fbaSAndroid Build Coastguard Worker       if (left_lcp == 0) break;
141*f4ee7fbaSAndroid Build Coastguard Worker       if (sarray[left_ix] < idx) break;
142*f4ee7fbaSAndroid Build Coastguard Worker     }
143*f4ee7fbaSAndroid Build Coastguard Worker 
144*f4ee7fbaSAndroid Build Coastguard Worker     int right_lcp = -1;
145*f4ee7fbaSAndroid Build Coastguard Worker     int right_ix;
146*f4ee7fbaSAndroid Build Coastguard Worker     for (right_ix = pos[idx]; right_ix < size - 1; ++right_ix) {
147*f4ee7fbaSAndroid Build Coastguard Worker       if (right_lcp == -1 || right_lcp > lcp[right_ix]) {
148*f4ee7fbaSAndroid Build Coastguard Worker         right_lcp = lcp[right_ix];
149*f4ee7fbaSAndroid Build Coastguard Worker       }
150*f4ee7fbaSAndroid Build Coastguard Worker       // Stop if we have better result from the left side already.
151*f4ee7fbaSAndroid Build Coastguard Worker       if (right_lcp < left_lcp && left_ix >= 0) break;
152*f4ee7fbaSAndroid Build Coastguard Worker       if (right_lcp == 0) break;
153*f4ee7fbaSAndroid Build Coastguard Worker       if (sarray[right_ix] < idx) break;
154*f4ee7fbaSAndroid Build Coastguard Worker     }
155*f4ee7fbaSAndroid Build Coastguard Worker 
156*f4ee7fbaSAndroid Build Coastguard Worker     if ((left_ix >= 0 && left_lcp >= min_length) ||
157*f4ee7fbaSAndroid Build Coastguard Worker         (right_ix < size - 1 && right_lcp >= min_length)) {
158*f4ee7fbaSAndroid Build Coastguard Worker       process_output(sarray, lcp, size, idx, left_ix, right_ix, left_lcp,
159*f4ee7fbaSAndroid Build Coastguard Worker                      right_lcp);
160*f4ee7fbaSAndroid Build Coastguard Worker     }
161*f4ee7fbaSAndroid Build Coastguard Worker   }
162*f4ee7fbaSAndroid Build Coastguard Worker }
163*f4ee7fbaSAndroid Build Coastguard Worker 
ProcessEntries(entry_type * entries,size_t size,FILE * fout)164*f4ee7fbaSAndroid Build Coastguard Worker void ProcessEntries(entry_type* entries, size_t size, FILE* fout) {
165*f4ee7fbaSAndroid Build Coastguard Worker   int long_length = FLAGS_long_length;
166*f4ee7fbaSAndroid Build Coastguard Worker   std::vector<std::pair<int, int> > segments;
167*f4ee7fbaSAndroid Build Coastguard Worker   size_t idx;
168*f4ee7fbaSAndroid Build Coastguard Worker   for (idx = 0; idx < size;) {
169*f4ee7fbaSAndroid Build Coastguard Worker     entry_type& entry = entries[idx];
170*f4ee7fbaSAndroid Build Coastguard Worker     if (entry.first > long_length) {
171*f4ee7fbaSAndroid Build Coastguard Worker       // Add segment.
172*f4ee7fbaSAndroid Build Coastguard Worker       if (segments.empty() || segments.back().second < idx) {
173*f4ee7fbaSAndroid Build Coastguard Worker         segments.push_back({idx, idx + entry.first});
174*f4ee7fbaSAndroid Build Coastguard Worker       } else {
175*f4ee7fbaSAndroid Build Coastguard Worker         segments.back().second = idx + entry.first;
176*f4ee7fbaSAndroid Build Coastguard Worker       }
177*f4ee7fbaSAndroid Build Coastguard Worker     }
178*f4ee7fbaSAndroid Build Coastguard Worker     ++idx;
179*f4ee7fbaSAndroid Build Coastguard Worker   }
180*f4ee7fbaSAndroid Build Coastguard Worker   printf("Segments generated.\n");
181*f4ee7fbaSAndroid Build Coastguard Worker   size_t segments_ix = 0;
182*f4ee7fbaSAndroid Build Coastguard Worker   for (idx = 0; idx < size;) {
183*f4ee7fbaSAndroid Build Coastguard Worker     if (idx == segments[segments_ix].first) {
184*f4ee7fbaSAndroid Build Coastguard Worker       // Skip segment.
185*f4ee7fbaSAndroid Build Coastguard Worker       idx = segments[segments_ix].second;
186*f4ee7fbaSAndroid Build Coastguard Worker     } else {
187*f4ee7fbaSAndroid Build Coastguard Worker       for (auto& dist : entries[idx].second) {
188*f4ee7fbaSAndroid Build Coastguard Worker         fputc(1, fout);
189*f4ee7fbaSAndroid Build Coastguard Worker         fwrite(&idx, sizeof(int), 1, fout);   // Position in input.
190*f4ee7fbaSAndroid Build Coastguard Worker         fwrite(&dist, sizeof(int), 1, fout);  // Backward distance.
191*f4ee7fbaSAndroid Build Coastguard Worker       }
192*f4ee7fbaSAndroid Build Coastguard Worker       ++idx;
193*f4ee7fbaSAndroid Build Coastguard Worker     }
194*f4ee7fbaSAndroid Build Coastguard Worker   }
195*f4ee7fbaSAndroid Build Coastguard Worker }
196*f4ee7fbaSAndroid Build Coastguard Worker 
main(int argc,char * argv[])197*f4ee7fbaSAndroid Build Coastguard Worker int main(int argc, char* argv[]) {
198*f4ee7fbaSAndroid Build Coastguard Worker   ParseCommandLineFlags(&argc, &argv, true);
199*f4ee7fbaSAndroid Build Coastguard Worker   if (argc != 3) {
200*f4ee7fbaSAndroid Build Coastguard Worker     printf("usage: %s input_file output_file\n", argv[0]);
201*f4ee7fbaSAndroid Build Coastguard Worker     return 1;
202*f4ee7fbaSAndroid Build Coastguard Worker   }
203*f4ee7fbaSAndroid Build Coastguard Worker 
204*f4ee7fbaSAndroid Build Coastguard Worker   FILE* fin = fopen(argv[1], "rb");
205*f4ee7fbaSAndroid Build Coastguard Worker   FILE* fout = fopen(argv[2], "w");
206*f4ee7fbaSAndroid Build Coastguard Worker 
207*f4ee7fbaSAndroid Build Coastguard Worker   fseek(fin, 0, SEEK_END);
208*f4ee7fbaSAndroid Build Coastguard Worker   int input_size = ftell(fin);
209*f4ee7fbaSAndroid Build Coastguard Worker   fseek(fin, 0, SEEK_SET);
210*f4ee7fbaSAndroid Build Coastguard Worker   printf("The file size is %u bytes\n", input_size);
211*f4ee7fbaSAndroid Build Coastguard Worker 
212*f4ee7fbaSAndroid Build Coastguard Worker   input_type* storage = new input_type[input_size];
213*f4ee7fbaSAndroid Build Coastguard Worker 
214*f4ee7fbaSAndroid Build Coastguard Worker   ReadInput(fin, storage, input_size);
215*f4ee7fbaSAndroid Build Coastguard Worker   fclose(fin);
216*f4ee7fbaSAndroid Build Coastguard Worker 
217*f4ee7fbaSAndroid Build Coastguard Worker   sarray_type* sarray = new sarray_type[input_size];
218*f4ee7fbaSAndroid Build Coastguard Worker   saisxx(storage, sarray, input_size);
219*f4ee7fbaSAndroid Build Coastguard Worker   printf("Suffix array calculated.\n");
220*f4ee7fbaSAndroid Build Coastguard Worker 
221*f4ee7fbaSAndroid Build Coastguard Worker   // Inverse suffix array.
222*f4ee7fbaSAndroid Build Coastguard Worker   uint32_t* pos = new uint32_t[input_size];
223*f4ee7fbaSAndroid Build Coastguard Worker 
224*f4ee7fbaSAndroid Build Coastguard Worker   lcp_type* lcp = new lcp_type[input_size];
225*f4ee7fbaSAndroid Build Coastguard Worker   BuildLCP(storage, sarray, lcp, input_size, pos);
226*f4ee7fbaSAndroid Build Coastguard Worker   printf("LCP array constructed.\n");
227*f4ee7fbaSAndroid Build Coastguard Worker   delete[] storage;
228*f4ee7fbaSAndroid Build Coastguard Worker 
229*f4ee7fbaSAndroid Build Coastguard Worker   using std::placeholders::_1;
230*f4ee7fbaSAndroid Build Coastguard Worker   using std::placeholders::_2;
231*f4ee7fbaSAndroid Build Coastguard Worker   using std::placeholders::_3;
232*f4ee7fbaSAndroid Build Coastguard Worker   using std::placeholders::_4;
233*f4ee7fbaSAndroid Build Coastguard Worker   using std::placeholders::_5;
234*f4ee7fbaSAndroid Build Coastguard Worker   using std::placeholders::_6;
235*f4ee7fbaSAndroid Build Coastguard Worker   using std::placeholders::_7;
236*f4ee7fbaSAndroid Build Coastguard Worker   using std::placeholders::_8;
237*f4ee7fbaSAndroid Build Coastguard Worker   entry_type* entries;
238*f4ee7fbaSAndroid Build Coastguard Worker   if (FLAGS_advanced) {
239*f4ee7fbaSAndroid Build Coastguard Worker     entries = new entry_type[input_size];
240*f4ee7fbaSAndroid Build Coastguard Worker     for (size_t i = 0; i < input_size; ++i) entries[i].first = -1;
241*f4ee7fbaSAndroid Build Coastguard Worker   }
242*f4ee7fbaSAndroid Build Coastguard Worker   Fn print = std::bind(PrintReference, _1, _2, _3, _4, _5, _6, _7, _8, fout);
243*f4ee7fbaSAndroid Build Coastguard Worker   Fn store = std::bind(StoreReference, _1, _2, _3, _4, _5, _6, _7, _8, entries);
244*f4ee7fbaSAndroid Build Coastguard Worker 
245*f4ee7fbaSAndroid Build Coastguard Worker   ProcessReferences(sarray, lcp, input_size, pos,
246*f4ee7fbaSAndroid Build Coastguard Worker                     FLAGS_advanced ? store : print);
247*f4ee7fbaSAndroid Build Coastguard Worker   printf("References processed.\n");
248*f4ee7fbaSAndroid Build Coastguard Worker 
249*f4ee7fbaSAndroid Build Coastguard Worker   if (FLAGS_advanced) {
250*f4ee7fbaSAndroid Build Coastguard Worker     int good_cnt = 0;
251*f4ee7fbaSAndroid Build Coastguard Worker     uint64_t avg_cnt = 0;
252*f4ee7fbaSAndroid Build Coastguard Worker     for (size_t i = 0; i < input_size; ++i) {
253*f4ee7fbaSAndroid Build Coastguard Worker       if (entries[i].first != -1) {
254*f4ee7fbaSAndroid Build Coastguard Worker         ++good_cnt;
255*f4ee7fbaSAndroid Build Coastguard Worker         avg_cnt += entries[i].second.size();
256*f4ee7fbaSAndroid Build Coastguard Worker       }
257*f4ee7fbaSAndroid Build Coastguard Worker     }
258*f4ee7fbaSAndroid Build Coastguard Worker     printf("Number of covered positions = %d\n", good_cnt);
259*f4ee7fbaSAndroid Build Coastguard Worker     printf("Average number of references per covered position = %.4lf\n",
260*f4ee7fbaSAndroid Build Coastguard Worker             static_cast<double>(avg_cnt) / good_cnt);
261*f4ee7fbaSAndroid Build Coastguard Worker     ProcessEntries(entries, input_size, fout);
262*f4ee7fbaSAndroid Build Coastguard Worker     printf("Entries processed.\n");
263*f4ee7fbaSAndroid Build Coastguard Worker   }
264*f4ee7fbaSAndroid Build Coastguard Worker 
265*f4ee7fbaSAndroid Build Coastguard Worker   fclose(fout);
266*f4ee7fbaSAndroid Build Coastguard Worker   return 0;
267*f4ee7fbaSAndroid Build Coastguard Worker }
268