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