1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "compress.h"
30 
31 #include <QtCore/qdebug.h>
32 #include <QtCore/qlist.h>
33 
34 #include <algorithm>
35 #include <iterator>
36 #include <iostream>
37 
38 #define QLALR_NO_CHECK_SORTED_TABLE
39 
40 struct _Fit
41 {
operator ()_Fit42   inline bool operator () (int a, int b) const
43   {
44     return a == 0 || b == 0 || a == b;
45   }
46 };
47 
48 struct _PerfectMatch
49 {
operator ()_PerfectMatch50   inline bool operator () (int a, int b) const
51   { return a == b; }
52 };
53 
54 struct _GenerateCheck
55 {
56   QVector<int>::const_iterator iterator;
57   int initial;
58 
_GenerateCheck_GenerateCheck59   _GenerateCheck (QVector<int>::const_iterator it, int i):
60     iterator (it),
61     initial (i) {}
62 
operator ()_GenerateCheck63   inline int operator () ()
64   {
65     int check = initial++;
66     return *iterator++ ? check : -1;
67   }
68 };
69 
70 class UncompressedRow
71 {
72 public:
73   typedef const int *const_iterator;
74   typedef const int *iterator;
75 
76 public:
UncompressedRow()77   inline UncompressedRow ():
78     _M_index (0),
79     _M_begin (0),
80     _M_end (0),
81     _M_beginNonZeros (0),
82     _M_endNonZeros (0) {}
83 
UncompressedRow(int index,const_iterator begin,const_iterator end)84   inline UncompressedRow (int index, const_iterator begin, const_iterator end)
85   { assign (index, begin, end); }
86 
index() const87   inline int index () const { return _M_index; }
begin() const88   inline const_iterator begin () const { return _M_begin; }
end() const89   inline const_iterator end () const { return _M_end; }
90 
assign(int index,const_iterator begin,const_iterator end)91   inline void assign (int index, const_iterator begin, const_iterator end)
92   {
93     _M_index = index;
94     _M_begin = begin;
95     _M_end = end;
96 
97     _M_beginNonZeros = _M_begin;
98     _M_endNonZeros = _M_end;
99 
100     for (_M_beginNonZeros = _M_begin; _M_beginNonZeros != _M_end && ! _M_beginNonZeros [0]; ++_M_beginNonZeros)
101       /*continue*/ ;
102 
103 #if 0
104     for (_M_endNonZeros = _M_end; _M_endNonZeros != _M_beginNonZeros && ! _M_endNonZeros [-1]; --_M_endNonZeros)
105       /*continue*/ ;
106 #endif
107   }
108 
at(int index) const109   inline int at (int index) const
110   { return _M_begin [index]; }
111 
isEmpty() const112   inline bool isEmpty () const
113   { return _M_begin == _M_end; }
114 
size() const115   inline int size () const
116   { return _M_end - _M_begin; }
117 
nonZeroElements() const118   inline int nonZeroElements () const
119   { return _M_endNonZeros - _M_beginNonZeros; }
120 
count(int value) const121   inline int count (int value) const
122   { return std::count (begin (), end (), value); }
123 
beginNonZeros() const124   inline const_iterator beginNonZeros () const
125   { return _M_beginNonZeros; }
126 
endNonZeros() const127   inline const_iterator endNonZeros () const
128   { return _M_endNonZeros; }
129 
130 private:
131   int _M_index;
132   const_iterator _M_begin;
133   const_iterator _M_end;
134   const_iterator _M_beginNonZeros;
135   const_iterator _M_endNonZeros;
136 };
137 
138 struct _SortUncompressedRow
139 {
operator ()_SortUncompressedRow140   inline bool operator () (const UncompressedRow &a, const UncompressedRow &b) const
141   { return a.count (0) > b.count (0); }
142 };
143 
Compress()144 Compress::Compress ()
145 {
146 }
147 
operator ()(int * table,int row_count,int column_count)148 void Compress::operator () (int *table, int row_count, int column_count)
149 {
150   index.clear ();
151   info.clear ();
152   check.clear ();
153 
154   QVector<UncompressedRow> sortedTable (row_count);
155 
156   for (int i = 0; i < row_count; ++i)
157     {
158       int *begin = &table [i * column_count];
159       int *end = begin + column_count;
160 
161       sortedTable [i].assign (i, begin, end);
162     }
163 
164   std::sort (sortedTable.begin (), sortedTable.end (), _SortUncompressedRow ());
165 
166 #ifndef QLALR_NO_CHECK_SORTED_TABLE
167   int previous_zeros = INT_MAX;
168 
169   for (const UncompressedRow &row : qAsConst(sortedTable))
170     {
171       int zeros = row.count (0);
172 
173       Q_ASSERT (zeros <= previous_zeros);
174       zeros = previous_zeros;
175       qDebug () << "OK!";
176     }
177 #endif
178 
179   index.fill (-999999, row_count);
180 
181   for (const UncompressedRow &row : qAsConst(sortedTable))
182     {
183       int first_token = std::distance (row.begin (), row.beginNonZeros ());
184       QVector<int>::iterator pos = info.begin ();
185 
186       while (pos != info.end ())
187         {
188           if (pos == info.begin ())
189             {
190               // try to find a perfect match
191               QVector<int>::iterator pm = std::search (pos, info.end (), row.beginNonZeros (), row.endNonZeros (), _PerfectMatch ());
192 
193               if (pm != info.end ())
194                 {
195                   pos = pm;
196                   break;
197                 }
198             }
199 
200           pos = std::search (pos, info.end (), row.beginNonZeros (), row.endNonZeros (), _Fit ());
201 
202           if (pos == info.end ())
203             break;
204 
205           int idx = std::distance (info.begin (), pos) - first_token;
206           bool conflict = false;
207 
208           for (int j = 0; ! conflict && j < row.size (); ++j)
209             {
210               if (row.at (j) == 0)
211                 conflict |= idx + j >= 0 && check [idx + j] == j;
212 
213               else
214                 conflict |= check [idx + j] == j;
215             }
216 
217           if (! conflict)
218             break;
219 
220           ++pos;
221         }
222 
223       if (pos == info.end ())
224         {
225           int size = info.size ();
226 
227           info.resize (info.size () + row.nonZeroElements ());
228           check.resize (info.size ());
229 
230           std::fill (check.begin () + size, check.end (), -1);
231           pos = info.begin () + size;
232         }
233 
234       int offset = std::distance (info.begin (), pos);
235       index [row.index ()] = offset - first_token;
236 
237       for (const int *it = row.beginNonZeros (); it != row.endNonZeros (); ++it, ++pos)
238         {
239           if (*it)
240             *pos = *it;
241         }
242 
243       int i = row.index ();
244 
245       for (int j = 0; j < row.size (); ++j)
246         {
247           if (row.at (j) == 0)
248             continue;
249 
250           check [index [i] + j] = j;
251         }
252     }
253 
254 #if 0
255   for (const UncompressedRow &row : qAsConst(sortedTable))
256     {
257       int i = row.index ();
258       Q_ASSERT (i < sortedTable.size ());
259 
260       for (int j = 0; j < row.size (); ++j)
261         {
262           if (row.at (j) == 0)
263             {
264               Q_ASSERT (index [i] + j < 0 || check [index [i] + j] != j);
265               continue;
266             }
267 
268           Q_ASSERT ( info [index [i] + j] == row.at (j));
269           Q_ASSERT (check [index [i] + j] == j);
270         }
271     }
272 #endif
273 }
274