1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (c) 2019, Nefelus Inc
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice, this
11 // list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright notice,
14 // this list of conditions and the following disclaimer in the documentation
15 // and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32
33 #pragma once
34
35 #include <algorithm>
36
37 #include "dbSet.h"
38
39 namespace odb {
40 //
41 // diff_object - Diff the object if this is a deep-diff, otherwise diff the
42 // field.
43 //
44 // diff_object - Diff the object if this is a deep-diff, otherwise diff the
45 template <class T>
diff_object(dbDiff & diff,const char * field,dbId<T> lhs,dbId<T> rhs,dbTable<T> * lhs_tbl,dbTable<T> * rhs_tbl)46 inline void diff_object(dbDiff& diff,
47 const char* field,
48 dbId<T> lhs,
49 dbId<T> rhs,
50 dbTable<T>* lhs_tbl,
51 dbTable<T>* rhs_tbl)
52 {
53 if (diff.deepDiff() == false) {
54 diff.diff(field, (unsigned int) lhs, (unsigned int) rhs);
55 } else {
56 if (lhs != 0 && rhs != 0) {
57 T* o1 = lhs_tbl->getPtr(lhs);
58 T* o2 = rhs_tbl->getPtr(rhs);
59 o1->differences(diff, field, *o2);
60 } else if (lhs != 0) {
61 T* o1 = lhs_tbl->getPtr(lhs);
62 o1->out(diff, dbDiff::LEFT, field);
63 } else if (rhs != 0) {
64 T* o2 = rhs_tbl->getPtr(rhs);
65 o2->out(diff, dbDiff::RIGHT, field);
66 }
67 }
68 }
69
70 template <class T>
diff_object(dbDiff & diff,const char * field,dbId<T> lhs,dbId<T> rhs,dbArrayTable<T> * lhs_tbl,dbArrayTable<T> * rhs_tbl)71 inline void diff_object(dbDiff& diff,
72 const char* field,
73 dbId<T> lhs,
74 dbId<T> rhs,
75 dbArrayTable<T>* lhs_tbl,
76 dbArrayTable<T>* rhs_tbl)
77 {
78 if (diff.deepDiff() == false) {
79 diff.diff(field, (unsigned int) lhs, (unsigned int) rhs);
80 } else {
81 if (lhs != 0 && rhs != 0) {
82 T* o1 = lhs_tbl->getPtr(lhs);
83 T* o2 = rhs_tbl->getPtr(rhs);
84 o1->differences(diff, field, *o2);
85 } else if (lhs != 0) {
86 T* o1 = lhs_tbl->getPtr(lhs);
87 o1->out(diff, dbDiff::LEFT, field);
88 } else if (rhs != 0) {
89 T* o2 = rhs_tbl->getPtr(rhs);
90 o2->out(diff, dbDiff::RIGHT, field);
91 }
92 }
93 }
94
95 template <class T>
diff_out_object(dbDiff & diff,char side,const char * field,dbId<T> id,dbTable<T> * tbl)96 inline void diff_out_object(dbDiff& diff,
97 char side,
98 const char* field,
99 dbId<T> id,
100 dbTable<T>* tbl)
101 {
102 if (diff.deepDiff() == false)
103 diff.out(side, field, (unsigned int) id);
104
105 else if (id != 0) {
106 T* o = tbl->getPtr(id);
107 o->out(diff, side, field);
108 }
109 }
110
111 template <class T>
diff_out_object(dbDiff & diff,char side,const char * field,dbId<T> id,dbArrayTable<T> * tbl)112 inline void diff_out_object(dbDiff& diff,
113 char side,
114 const char* field,
115 dbId<T> id,
116 dbArrayTable<T>* tbl)
117 {
118 if (diff.deepDiff() == false)
119 diff.out(side, field, (unsigned int) id);
120
121 else if (id != 0) {
122 T* o = tbl->getPtr(id);
123 o->out(diff, side, field);
124 }
125 }
126
127 //
128 // diff_set - This function will diff the "set" this field represents if
129 // this is a "deep" differences. Otherwise, only the field is
130 // diff'ed.
131 //
132 template <class T>
diff_set(dbDiff & diff,const char * field,dbId<T> lhs,dbId<T> rhs,dbObject * lhs_owner,dbObject * rhs_owner,dbIterator * lhs_itr,dbIterator * rhs_itr)133 inline void diff_set(dbDiff& diff,
134 const char* field,
135 dbId<T> lhs,
136 dbId<T> rhs,
137 dbObject* lhs_owner,
138 dbObject* rhs_owner,
139 dbIterator* lhs_itr,
140 dbIterator* rhs_itr)
141 {
142 if (diff.deepDiff() == false) {
143 diff.diff(field, (unsigned int) lhs, (unsigned int) rhs);
144 } else {
145 typename dbSet<T>::iterator itr;
146
147 dbSet<T> lhs_set(lhs_owner, lhs_itr);
148 std::vector<T*> lhs_vec;
149
150 for (itr = lhs_set.begin(); itr != lhs_set.end(); ++itr)
151 lhs_vec.push_back(*itr);
152
153 dbSet<T> rhs_set(rhs_owner, rhs_itr);
154 std::vector<T*> rhs_vec;
155
156 for (itr = rhs_set.begin(); itr != rhs_set.end(); ++itr)
157 rhs_vec.push_back(*itr);
158 #ifndef WIN32
159 set_symmetric_diff(diff, field, lhs_vec, rhs_vec);
160 #endif
161 }
162 }
163
164 template <class T>
diff_out_set(dbDiff & diff,char side,const char * field,dbId<T> id,dbObject * owner,dbIterator * set_itr)165 inline void diff_out_set(dbDiff& diff,
166 char side,
167 const char* field,
168 dbId<T> id,
169 dbObject* owner,
170 dbIterator* set_itr)
171 {
172 if (diff.deepDiff() == false) {
173 diff.out(side, field, (unsigned int) id);
174 } else {
175 typename dbSet<T>::iterator itr;
176
177 diff.begin_object("<> %s\n", field);
178 dbSet<T> oset(owner, set_itr);
179
180 for (itr = oset.begin(); itr != oset.end(); ++itr)
181 (*itr)->out(diff, side, NULL);
182
183 diff.end_object();
184 }
185 }
186
187 //
188 // set_symmetric_diff - Diff the two tables
189 //
190 template <class T>
set_symmetric_diff(dbDiff & diff,const char * field,dbTable<T> & lhs,dbTable<T> & rhs)191 inline void set_symmetric_diff(dbDiff& diff,
192 const char* field,
193 dbTable<T>& lhs,
194 dbTable<T>& rhs)
195 {
196 std::vector<T*> lhs_vec;
197 std::vector<T*> rhs_vec;
198 lhs.getObjects(lhs_vec);
199 rhs.getObjects(rhs_vec);
200 #ifndef WIN32
201 set_symmetric_diff(diff, field, lhs_vec, rhs_vec);
202 #endif
203 }
204
205 //
206 // set_symmetric_diff - Diff the two tables
207 //
208 template <class T>
set_symmetric_diff(dbDiff & diff,const char * field,dbArrayTable<T> & lhs,dbArrayTable<T> & rhs)209 inline void set_symmetric_diff(dbDiff& diff,
210 const char* field,
211 dbArrayTable<T>& lhs,
212 dbArrayTable<T>& rhs)
213 {
214 std::vector<T*> lhs_vec;
215 std::vector<T*> rhs_vec;
216 lhs.getObjects(lhs_vec);
217 rhs.getObjects(rhs_vec);
218 #ifndef WIN32
219 set_symmetric_diff(diff, field, lhs_vec, rhs_vec);
220 #endif
221 }
222
223 //
224 // set_symmetric_diff - Diff the two vectors of objects. The objects must have
225 // the "operator<" defined and a the equal method defined.
226 //
227 template <class T>
set_symmetric_diff(dbDiff & diff,const char * field,std::vector<T * > & lhs,std::vector<T * > & rhs)228 inline void set_symmetric_diff(dbDiff& diff,
229 const char* field,
230 std::vector<T*>& lhs,
231 std::vector<T*>& rhs)
232 {
233 diff.begin_object("<> %s\n", field);
234 std::sort(lhs.begin(), lhs.end(), dbDiffCmp<T>());
235 std::sort(rhs.begin(), rhs.end(), dbDiffCmp<T>());
236
237 typename std::vector<T*>::iterator end;
238 std::vector<T*> symmetric_diff;
239
240 symmetric_diff.resize(lhs.size() + rhs.size());
241
242 end = std::set_symmetric_difference(lhs.begin(),
243 lhs.end(),
244 rhs.begin(),
245 rhs.end(),
246 symmetric_diff.begin(),
247 dbDiffCmp<T>());
248
249 typename std::vector<T*>::iterator i1 = lhs.begin();
250 typename std::vector<T*>::iterator i2 = rhs.begin();
251 typename std::vector<T*>::iterator sd = symmetric_diff.begin();
252
253 while ((i1 != lhs.end()) && (i2 != rhs.end())) {
254 T* o1 = *i1;
255 T* o2 = *i2;
256
257 if (o1 == *sd) {
258 o1->out(diff, dbDiff::LEFT, NULL);
259 ++i1;
260 ++sd;
261 } else if (o2 == *sd) {
262 o2->out(diff, dbDiff::RIGHT, NULL);
263 ++i2;
264 ++sd;
265 } else // equal keys
266 {
267 // compare internals
268 o1->differences(diff, NULL, *o2);
269 ++i1;
270 ++i2;
271 }
272 }
273
274 for (; i1 != lhs.end(); ++i1) {
275 T* o1 = *i1;
276 o1->out(diff, dbDiff::LEFT, NULL);
277 }
278
279 for (; i2 != rhs.end(); ++i2) {
280 T* o2 = *i2;
281 o2->out(diff, dbDiff::RIGHT, NULL);
282 }
283
284 diff.end_object();
285 }
286
287 //
288 // set_symmetric_diff - Diff the two vectors of objects. The objects must have
289 // the "operator<" defined.
290 //
291 template <class T>
set_symmetric_diff(dbDiff & diff,const char * field,const std::vector<T> & lhs_v,const std::vector<T> & rhs_v)292 inline void set_symmetric_diff(dbDiff& diff,
293 const char* field,
294 const std::vector<T>& lhs_v,
295 const std::vector<T>& rhs_v)
296 {
297 std::vector<T> lhs = lhs_v;
298 std::vector<T> rhs = rhs_v;
299 diff.begin_object("<> %s\n", field);
300 std::sort(lhs.begin(), lhs.end());
301 std::sort(rhs.begin(), rhs.end());
302
303 typename std::vector<T>::iterator end;
304 std::vector<T> symmetric_diff;
305
306 symmetric_diff.resize(lhs.size() + rhs.size());
307
308 end = std::set_symmetric_difference(
309 lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), symmetric_diff.begin());
310
311 typename std::vector<T>::iterator i1 = lhs.begin();
312 typename std::vector<T>::iterator i2 = rhs.begin();
313 typename std::vector<T>::iterator sd = symmetric_diff.begin();
314
315 while ((i1 != lhs.end()) && (i2 != rhs.end())) {
316 T& o1 = *i1;
317 T& o2 = *i2;
318
319 if (o1 == *sd) {
320 diff.out(dbDiff::LEFT, "", o1);
321 ++i1;
322 ++sd;
323 } else if (o2 == *sd) {
324 diff.out(dbDiff::RIGHT, "", o2);
325 ++i2;
326 ++sd;
327 } else // equal keys
328 {
329 ++i1;
330 ++i2;
331 }
332 }
333
334 for (; i1 != lhs.end(); ++i1) {
335 T& o1 = *i1;
336 diff.out(dbDiff::LEFT, "", o1);
337 }
338
339 for (; i2 != rhs.end(); ++i2) {
340 T& o2 = *i2;
341 diff.out(dbDiff::RIGHT, "", o2);
342 }
343
344 diff.end_object();
345 }
346
347 } // namespace odb
348