ProteoWizard
diff_std.hpp
Go to the documentation of this file.
1 //
2 // $Id: diff_std.hpp 3725 2012-06-20 05:31:18Z pcbrefugee $
3 //
4 //
5 // Original author: Robert Burke <robert.burke@proteowizard.org>
6 //
7 // Copyright 2009 Spielberg Family Center for Applied Proteomics
8 // University of Southern California, Los Angeles, California 90033
9 //
10 // Licensed under the Apache License, Version 2.0 (the "License");
11 // you may not use this file except in compliance with the License.
12 // You may obtain a copy of the License at
13 //
14 // http://www.apache.org/licenses/LICENSE-2.0
15 //
16 // Unless required by applicable law or agreed to in writing, software
17 // distributed under the License is distributed on an "AS IS" BASIS,
18 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 // See the License for the specific language governing permissions and
20 // limitations under the License.
21 //
22 
23 
24 #ifndef _DIFF_STD_HPP_
25 #define _DIFF_STD_HPP_
26 
28 #include <string>
29 #include <vector>
30 #include <cmath>
31 #include <limits>
32 #include <stdexcept>
33 #include "ParamTypes.hpp"
34 #include <boost/logic/tribool.hpp>
35 
36 
37 namespace pwiz {
38 namespace data {
39 
40 
42 {
43  BaseDiffConfig(double _precision = 1e-6) : precision(_precision), partialDiffOK(false), ignoreVersions(false) {}
44  double precision;
45  bool partialDiffOK; // if true, can stop checking at first difference found
46  bool ignoreVersions; // if true, don't sweat version number mismatches
47 };
48 
49 
50 namespace diff_impl {
51 
52 
54 void diff(const std::string& a,
55  const std::string& b,
56  std::string& a_b,
57  std::string& b_a,
58  const BaseDiffConfig& config);
59 
60 // special handling for strings which are likely
61 // to differ only by a trailing version number
63 void diff_ids(const std::string& a,
64  const std::string& b,
65  std::string& a_b,
66  std::string& b_a,
67  const BaseDiffConfig& config);
68 
70 void diff(const boost::logic::tribool& a,
71  const boost::logic::tribool& b,
72  boost::logic::tribool& a_b,
73  boost::logic::tribool& b_a,
74  const BaseDiffConfig& config);
75 
77 void diff(const CV& a,
78  const CV& b,
79  CV& a_b,
80  CV& b_a,
81  const BaseDiffConfig& config);
82 
84 void diff(CVID a,
85  CVID b,
86  CVID& a_b,
87  CVID& b_a,
88  const BaseDiffConfig& config);
89 
91 void diff(const CVParam& a,
92  const CVParam& b,
93  CVParam& a_b,
94  CVParam& b_a,
95  const BaseDiffConfig& config);
96 
98 void diff(const UserParam& a,
99  const UserParam& b,
100  UserParam& a_b,
101  UserParam& b_a,
102  const BaseDiffConfig& config);
103 
105 void diff(const ParamContainer& a,
106  const ParamContainer& b,
107  ParamContainer& a_b,
108  ParamContainer& b_a,
109  const BaseDiffConfig& config);
110 
112 void diff(const ParamGroup& a,
113  const ParamGroup& b,
114  ParamGroup& a_b,
115  ParamGroup& b_a,
116  const BaseDiffConfig& config);
117 
118 
119 } // namespace diff_impl
120 
121 
122 ///
123 /// Calculate diffs of objects in a ProteoWizard data model hierarchy.
124 ///
125 /// A diff between two objects a and b calculates the set differences
126 /// a\b and b\a.
127 ///
128 /// The Diff struct acts as a functor, but also stores the
129 /// results of the diff calculation.
130 ///
131 /// The bool conversion operator is provided to indicate whether
132 /// the two objects are different (either a\b or b\a is non-empty).
133 ///
134 /// object_type requirements:
135 /// object_type a;
136 /// a.empty();
137 /// pwiz::data::diff::diff(const object_type& a, const object_type& b, object_result_type& a_b, object_result_type& b_a);
138 ///
139 /// config_type must be pwiz::data::diff::BaseDiffConfig or derived from it
140 ///
141 template <typename object_type, typename config_type = BaseDiffConfig, typename object_result_type = object_type>
142 struct Diff
143 {
144  Diff(const config_type& config = config_type())
145  : config_(config)
146  {}
147 
148  Diff(const object_type& a,
149  const object_type& b,
150  const config_type& config = config_type())
151  : config_(config)
152  {
153  diff_impl::diff(a, b, a_b, b_a, config_);
154  }
155 
156  object_result_type a_b;
157  object_result_type b_a;
158 
159  /// conversion to bool, with same semantics as *nix diff command:
160  /// true == different
161  /// false == not different
162  operator bool() {return !(a_b.empty() && b_a.empty());}
163 
164  Diff& operator()(const object_type& a,
165  const object_type& b)
166  {
167  diff_impl::diff(a, b, a_b, b_a, config_);
168  return *this;
169  }
170 
171  private:
172  config_type config_;
173 };
174 
175 
176 template <typename textwriter_type, typename diff_type>
177 std::string diff_string(const diff_type& diff)
178 {
179  std::ostringstream os;
180  textwriter_type write(os, 1);
181 
182  if (!diff.a_b.empty())
183  {
184  os << "+\n";
185  write(diff.a_b);
186  }
187 
188  if (!diff.b_a.empty())
189  {
190  os << "-\n";
191  write(diff.b_a);
192  }
193 
194  return os.str();
195 }
196 
197 
198 /// stream insertion of Diff results
199 template <typename textwriter_type, typename object_type, typename config_type>
200 std::ostream& operator<<(std::ostream& os, const Diff<object_type, config_type>& diff)
201 {
202  textwriter_type write(os, 1);
203 
204  if (!diff.a_b.empty())
205  {
206  os << "+\n";
207  write(diff.a_b);
208  }
209 
210  if (!diff.b_a.empty())
211  {
212  os << "-\n";
213  write(diff.b_a);
214  }
215 
216  return os;
217 }
218 
219 
220 namespace diff_impl {
221 
222 
223 template <typename string_type>
224 void diff_string(const string_type& a,
225  const string_type& b,
226  string_type& a_b,
227  string_type& b_a)
228 {
229  a_b.clear();
230  b_a.clear();
231 
232  if (a != b)
233  {
234  a_b = a;
235  b_a = b;
236  }
237 }
238 
239 
240 template <typename char_type>
241 void diff_char(const char_type& a,
242  const char_type& b,
243  char_type& a_b,
244  char_type& b_a)
245 {
246  a_b = 0;
247  b_a = 0;
248 
249  if (a != b)
250  {
251  a_b = a;
252  b_a = b;
253  }
254 }
255 
256 
257 template <typename integral_type>
258 void diff_integral(const integral_type& a,
259  const integral_type& b,
260  integral_type& a_b,
261  integral_type& b_a,
262  const BaseDiffConfig& config)
263 {
264  a_b = integral_type();
265  b_a = integral_type();
266 
267  if (a != b)
268  {
269  a_b = static_cast<integral_type>(a);
270  b_a = static_cast<integral_type>(b);
271  }
272 }
273 
274 
275 template <typename floating_type>
276 void diff_floating(const floating_type& a,
277  const floating_type& b,
278  floating_type& a_b,
279  floating_type& b_a,
280  const BaseDiffConfig& config)
281 {
282  a_b = 0;
283  b_a = 0;
284 
285  if (fabs(a - b) > config.precision + std::numeric_limits<floating_type>::epsilon())
286  {
287  a_b = fabs(a - b);
288  b_a = fabs(a - b);
289  }
290 }
291 
292 
293 /// measure maximum relative difference between elements in the vectors
294 template <typename floating_type>
295 floating_type maxdiff(const std::vector<floating_type>& a, const std::vector<floating_type>& b)
296 {
297  if (a.size() != b.size())
298  throw std::runtime_error("[Diff::maxdiff()] Sizes differ.");
299 
300  typename std::vector<floating_type>::const_iterator i = a.begin();
301  typename std::vector<floating_type>::const_iterator j = b.begin();
302 
303  floating_type max = 0;
304 
305  for (; i!=a.end(); ++i, ++j)
306  {
307  floating_type denominator = std::min(*i, *j);
308  if (denominator == 0) denominator = 1;
309  floating_type current = fabs(*i - *j)/denominator;
310  if (max < current) max = current;
311 
312  }
313 
314  return max;
315 }
316 
317 
318 template <typename object_type>
319 void vector_diff(const std::vector<object_type>& a,
320  const std::vector<object_type>& b,
321  std::vector<object_type>& a_b,
322  std::vector<object_type>& b_a)
323 {
324  // calculate set differences of two vectors
325 
326  a_b.clear();
327  b_a.clear();
328 
329  for (typename std::vector<object_type>::const_iterator it=a.begin(); it!=a.end(); ++it)
330  if (std::find(b.begin(), b.end(), *it) == b.end())
331  a_b.push_back(*it);
332 
333  for (typename std::vector<object_type>::const_iterator it=b.begin(); it!=b.end(); ++it)
334  if (std::find(a.begin(), a.end(), *it) == a.end())
335  b_a.push_back(*it);
336 }
337 
338 
339 template <typename object_type>
340 struct HasID
341 {
342  const std::string& id_;
343  HasID(const std::string& id) : id_(id) {}
344  bool operator()(const boost::shared_ptr<object_type>& objectPtr) {return objectPtr->id == id_;}
345 };
346 
347 
348 template <typename object_type, typename config_type>
349 class Same
350 {
351  public:
352 
353  Same(const object_type& object,
354  const config_type& config)
355  : mine_(object), config_(config)
356  {}
357 
358  bool operator()(const object_type& yours)
359  {
360  // true iff yours is the same as mine
362  }
363 
364  private:
365  const object_type& mine_;
366  const config_type& config_;
367 };
368 
369 
370 template <typename object_type, typename config_type>
371 void vector_diff_diff(const std::vector<object_type>& a,
372  const std::vector<object_type>& b,
373  std::vector<object_type>& a_b,
374  std::vector<object_type>& b_a,
375  const config_type& config)
376 {
377  // calculate set differences of two vectors, using diff on each object
378 
379  a_b.clear();
380  b_a.clear();
381 
382  for (typename std::vector<object_type>::const_iterator it=a.begin(); it!=a.end(); ++it)
383  if (std::find_if(b.begin(), b.end(), Same<object_type, config_type>(*it, config)) == b.end())
384  a_b.push_back(*it);
385 
386  for (typename std::vector<object_type>::const_iterator it=b.begin(); it!=b.end(); ++it)
387  if (std::find_if(a.begin(), a.end(), Same<object_type, config_type>(*it, config)) == a.end())
388  b_a.push_back(*it);
389 }
390 
391 
392 template <typename object_type, typename config_type>
393 class SameDeep
394 {
395  public:
396 
397  SameDeep(const object_type& object,
398  const config_type& config)
399  : mine_(object), config_(config)
400  {}
401 
402  bool operator()(const boost::shared_ptr<object_type>& yours)
403  {
404  // true iff yours is the same as mine
405  return !Diff<object_type, config_type>(mine_, *yours, config_);
406  }
407 
408  private:
409  const object_type& mine_;
410  const config_type& config_;
411 };
412 
413 
414 template <typename object_type, typename config_type>
415 void vector_diff_deep(const std::vector< boost::shared_ptr<object_type> >& a,
416  const std::vector< boost::shared_ptr<object_type> >& b,
417  std::vector< boost::shared_ptr<object_type> >& a_b,
418  std::vector< boost::shared_ptr<object_type> >& b_a,
419  const config_type& config)
420 {
421  // calculate set differences of two vectors of ObjectPtrs (deep compare using diff)
422 
423  a_b.clear();
424  b_a.clear();
425 
426  config_type quick_config(config);
427  quick_config.partialDiffOK = true; // for fastest check in SameDeep
428 
429  for (typename std::vector< boost::shared_ptr<object_type> >::const_iterator it=a.begin(); it!=a.end(); ++it)
430  if (std::find_if(b.begin(), b.end(), SameDeep<object_type, config_type>(**it, quick_config)) == b.end())
431  a_b.push_back(*it);
432 
433  for (typename std::vector< boost::shared_ptr<object_type> >::const_iterator it=b.begin(); it!=b.end(); ++it)
434  if (std::find_if(a.begin(), a.end(), SameDeep<object_type, config_type>(**it, quick_config)) == a.end())
435  b_a.push_back(*it);
436 }
437 
438 
439 template <typename object_type, typename config_type>
440 void ptr_diff(const boost::shared_ptr<object_type>& a,
441  const boost::shared_ptr<object_type>& b,
442  boost::shared_ptr<object_type>& a_b,
443  boost::shared_ptr<object_type>& b_a,
444  const config_type& config)
445 {
446  if (!a.get() && !b.get()) return;
447 
448  boost::shared_ptr<object_type> a_temp = a.get() ? a : boost::shared_ptr<object_type>(new object_type);
449  boost::shared_ptr<object_type> b_temp = b.get() ? b : boost::shared_ptr<object_type>(new object_type);
450 
451  if (!a_b.get()) a_b = boost::shared_ptr<object_type>(new object_type);
452  if (!b_a.get()) b_a = boost::shared_ptr<object_type>(new object_type);
453  diff(*a_temp, *b_temp, *a_b, *b_a, config);
454 
455  if (a_b->empty()) a_b = boost::shared_ptr<object_type>();
456  if (b_a->empty()) b_a = boost::shared_ptr<object_type>();
457 }
458 
459 
460 } // namespace diff_impl
461 } // namespace data
462 } // namespace pwiz
463 
464 
465 #endif // _DIFF_STD_HPP_