LibreOffice Module comphelper (master)  1
anycompare.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <memory>
21 #include <optional>
23 #include <typelib/typedescription.hxx>
24 
25 #include <com/sun/star/util/Date.hpp>
26 #include <com/sun/star/util/Time.hpp>
27 #include <com/sun/star/util/DateTime.hpp>
28 
29 #include "typedescriptionref.hxx"
30 
31 namespace comphelper
32 {
33  using ::com::sun::star::uno::Reference;
34  using ::com::sun::star::uno::Type;
35  using ::com::sun::star::uno::TypeDescription;
36  using ::com::sun::star::uno::TypeClass_CHAR;
37  using ::com::sun::star::uno::TypeClass_BOOLEAN;
38  using ::com::sun::star::uno::TypeClass_BYTE;
39  using ::com::sun::star::uno::TypeClass_SHORT;
40  using ::com::sun::star::uno::TypeClass_UNSIGNED_SHORT;
41  using ::com::sun::star::uno::TypeClass_LONG;
42  using ::com::sun::star::uno::TypeClass_UNSIGNED_LONG;
43  using ::com::sun::star::uno::TypeClass_HYPER;
44  using ::com::sun::star::uno::TypeClass_UNSIGNED_HYPER;
45  using ::com::sun::star::uno::TypeClass_FLOAT;
46  using ::com::sun::star::uno::TypeClass_DOUBLE;
47  using ::com::sun::star::uno::TypeClass_STRING;
48  using ::com::sun::star::uno::TypeClass_TYPE;
49  using ::com::sun::star::uno::TypeClass_ENUM;
50  using ::com::sun::star::uno::TypeClass_INTERFACE;
51  using ::com::sun::star::uno::TypeClass_STRUCT;
52  using ::com::sun::star::i18n::XCollator;
53  using ::com::sun::star::util::Date;
54  using ::com::sun::star::util::Time;
55  using ::com::sun::star::util::DateTime;
56  using ::comphelper::detail::TypeDescriptionRef;
57 
58  namespace {
59 
60  class DatePredicateLess : public IKeyPredicateLess
61  {
62  public:
63  virtual bool isLess( css::uno::Any const & _lhs, css::uno::Any const & _rhs ) const override
64  {
65  Date lhs, rhs;
66  if ( !( _lhs >>= lhs )
67  || !( _rhs >>= rhs )
68  )
69  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
70  // FIXME Timezone?
71 
72  if ( lhs.Year < rhs.Year )
73  return true;
74  if ( lhs.Year > rhs.Year )
75  return false;
76 
77  if ( lhs.Month < rhs.Month )
78  return true;
79  if ( lhs.Month > rhs.Month )
80  return false;
81 
82  if ( lhs.Day < rhs.Day )
83  return true;
84  return false;
85  }
86  };
87 
88  class TimePredicateLess : public IKeyPredicateLess
89  {
90  public:
91  virtual bool isLess( css::uno::Any const & _lhs, css::uno::Any const & _rhs ) const override
92  {
93  Time lhs, rhs;
94  if ( !( _lhs >>= lhs )
95  || !( _rhs >>= rhs )
96  )
97  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
98  // FIXME Timezone?
99 
100  if ( lhs.Hours < rhs.Hours )
101  return true;
102  if ( lhs.Hours > rhs.Hours )
103  return false;
104 
105  if ( lhs.Minutes < rhs.Minutes )
106  return true;
107  if ( lhs.Minutes > rhs.Minutes )
108  return false;
109 
110  if ( lhs.Seconds < rhs.Seconds )
111  return true;
112  if ( lhs.Seconds > rhs.Seconds )
113  return false;
114 
115  if ( lhs.NanoSeconds < rhs.NanoSeconds )
116  return true;
117  return false;
118  }
119  };
120 
121  class DateTimePredicateLess : public IKeyPredicateLess
122  {
123  public:
124  virtual bool isLess( css::uno::Any const & _lhs, css::uno::Any const & _rhs ) const override
125  {
126  DateTime lhs, rhs;
127  if ( !( _lhs >>= lhs )
128  || !( _rhs >>= rhs )
129  )
130  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
131  // FIXME Timezone?
132 
133  if ( lhs.Year < rhs.Year )
134  return true;
135  if ( lhs.Year > rhs.Year )
136  return false;
137 
138  if ( lhs.Month < rhs.Month )
139  return true;
140  if ( lhs.Month > rhs.Month )
141  return false;
142 
143  if ( lhs.Day < rhs.Day )
144  return true;
145  if ( lhs.Day > rhs.Day )
146  return false;
147 
148  if ( lhs.Hours < rhs.Hours )
149  return true;
150  if ( lhs.Hours > rhs.Hours )
151  return false;
152 
153  if ( lhs.Minutes < rhs.Minutes )
154  return true;
155  if ( lhs.Minutes > rhs.Minutes )
156  return false;
157 
158  if ( lhs.Seconds < rhs.Seconds )
159  return true;
160  if ( lhs.Seconds > rhs.Seconds )
161  return false;
162 
163  if ( lhs.NanoSeconds < rhs.NanoSeconds )
164  return true;
165  return false;
166  }
167  };
168 
169  bool anyLess( void const * lhs, typelib_TypeDescriptionReference * lhsType,
170  void const * rhs, typelib_TypeDescriptionReference * rhsType );
171 
172  // For compound types we need to compare them member by member until we've
173  // checked them all or found a member that differs. For inequality checks
174  // we need to call anyLess() twice in both directions, this function does that.
175  std::optional<bool> anyCompare( void const * lhs, typelib_TypeDescriptionReference * lhsType,
176  void const * rhs, typelib_TypeDescriptionReference * rhsType )
177  {
178  if( anyLess( lhs, lhsType, rhs, rhsType ))
179  return std::optional( true );
180  if( anyLess( rhs, rhsType, lhs, lhsType ))
181  return std::optional( false );
182  return std::nullopt; // equal, so can't yet tell if anyLess() should return
183  }
184 
185  // This is typelib_typedescription_equals(), but returns -1/0/1 values like strcmp().
186  int compareTypes( const typelib_TypeDescription * lhsType,
187  const typelib_TypeDescription * rhsType )
188  {
189  if( lhsType == rhsType )
190  return 0;
191  if( lhsType->eTypeClass != rhsType->eTypeClass )
192  return lhsType->eTypeClass - rhsType->eTypeClass;
193  if( lhsType->pTypeName->length != rhsType->pTypeName->length )
194  return lhsType->pTypeName->length - rhsType->pTypeName->length;
195  return rtl_ustr_compare( lhsType->pTypeName->buffer, rhsType->pTypeName->buffer );
196  }
197 
198  bool anyLess( void const * lhs, typelib_TypeDescriptionReference * lhsType,
199  void const * rhs, typelib_TypeDescriptionReference * rhsType )
200  {
201  if (lhsType->eTypeClass != rhsType->eTypeClass)
202  return lhsType->eTypeClass < rhsType->eTypeClass;
203 
204  if (lhsType->eTypeClass == typelib_TypeClass_VOID) {
205  return false;
206  }
207  assert(lhs != nullptr);
208  assert(rhs != nullptr);
209 
210  switch (lhsType->eTypeClass) {
211  case typelib_TypeClass_INTERFACE:
212  return lhs < rhs;
213  case typelib_TypeClass_STRUCT:
214  case typelib_TypeClass_EXCEPTION: {
215  TypeDescription lhsTypeDescr( lhsType );
216  if (!lhsTypeDescr.is())
217  lhsTypeDescr.makeComplete();
218  if (!lhsTypeDescr.is())
219  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
220  TypeDescription rhsTypeDescr( rhsType );
221  if (!rhsTypeDescr.is())
222  rhsTypeDescr.makeComplete();
223  if (!rhsTypeDescr.is())
224  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
225  int compare = compareTypes( lhsTypeDescr.get(), rhsTypeDescr.get());
226  if( compare != 0 )
227  return compare < 0;
228 
229  typelib_CompoundTypeDescription * compType =
230  reinterpret_cast< typelib_CompoundTypeDescription * >(
231  lhsTypeDescr.get() );
232  sal_Int32 nDescr = compType->nMembers;
233 
234  if (compType->pBaseTypeDescription) {
235  std::optional<bool> subLess = anyCompare(
236  lhs, reinterpret_cast<
238  compType->pBaseTypeDescription)->pWeakRef,
239  rhs, reinterpret_cast<
241  compType->pBaseTypeDescription)->pWeakRef);
242  if(subLess.has_value())
243  return *subLess;
244  }
245 
246  typelib_TypeDescriptionReference ** ppTypeRefs =
247  compType->ppTypeRefs;
248  sal_Int32 * memberOffsets = compType->pMemberOffsets;
249 
250  for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos )
251  {
252  TypeDescriptionRef memberType( ppTypeRefs[ nPos ] );
253  if (!memberType.is())
254  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
255  std::optional<bool> subLess = anyCompare(
256  static_cast< char const * >(
257  lhs ) + memberOffsets[ nPos ],
258  memberType->pWeakRef,
259  static_cast< char const * >(
260  rhs ) + memberOffsets[ nPos ],
261  memberType->pWeakRef);
262  if(subLess.has_value())
263  return *subLess;
264  }
265  return false; // equal
266  }
267  case typelib_TypeClass_SEQUENCE: {
268  uno_Sequence * lhsSeq = *static_cast< uno_Sequence * const * >(lhs);
269  uno_Sequence * rhsSeq = *static_cast< uno_Sequence * const * >(rhs);
270  if( lhsSeq->nElements != rhsSeq->nElements)
271  return lhsSeq->nElements < rhsSeq->nElements;
272  sal_Int32 nElements = lhsSeq->nElements;
273 
274  TypeDescriptionRef lhsTypeDescr( lhsType );
275  if (!lhsTypeDescr.is())
276  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
277  TypeDescriptionRef rhsTypeDescr( rhsType );
278  if (!rhsTypeDescr.is())
279  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
280  int compare = compareTypes( lhsTypeDescr.get(), rhsTypeDescr.get());
281  if( compare != 0 )
282  return compare < 0;
283 
284  typelib_TypeDescriptionReference * elementTypeRef =
285  reinterpret_cast< typelib_IndirectTypeDescription * >(lhsTypeDescr.get())->pType;
286  TypeDescriptionRef elementTypeDescr( elementTypeRef );
287  if (!elementTypeDescr.is())
288  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
289  assert( elementTypeDescr.equals( TypeDescriptionRef(
290  reinterpret_cast< typelib_IndirectTypeDescription * >(lhsTypeDescr.get())->pType )));
291 
292  sal_Int32 nElementSize = elementTypeDescr->nSize;
293  if (nElements > 0)
294  {
295  char const * lhsElements = lhsSeq->elements;
296  char const * rhsElements = rhsSeq->elements;
297  for ( sal_Int32 nPos = 0; nPos < nElements; ++nPos )
298  {
299  std::optional<bool> subLess = anyCompare(
300  lhsElements + (nElementSize * nPos),
301  elementTypeDescr->pWeakRef,
302  rhsElements + (nElementSize * nPos),
303  elementTypeDescr->pWeakRef );
304  if(subLess.has_value())
305  return *subLess;
306  }
307  }
308  return false; // equal
309  }
310  case typelib_TypeClass_ANY: {
311  uno_Any const * lhsAny = static_cast< uno_Any const * >(lhs);
312  uno_Any const * rhsAny = static_cast< uno_Any const * >(rhs);
313  return anyLess( lhsAny->pData, lhsAny->pType, rhsAny->pData, rhsAny->pType );
314  }
315  case typelib_TypeClass_TYPE: {
316  OUString const & lhsTypeName = OUString::unacquired(
317  &(*static_cast< typelib_TypeDescriptionReference * const * >(lhs))->pTypeName);
318  OUString const & rhsTypeName = OUString::unacquired(
319  &(*static_cast< typelib_TypeDescriptionReference * const * >(rhs))->pTypeName);
320  return lhsTypeName < rhsTypeName;
321  }
322  case typelib_TypeClass_STRING: {
323  OUString const & lhsStr = OUString::unacquired(
324  static_cast< rtl_uString * const * >(lhs) );
325  OUString const & rhsStr = OUString::unacquired(
326  static_cast< rtl_uString * const * >(rhs) );
327  return lhsStr < rhsStr;
328  }
329  case typelib_TypeClass_ENUM: {
330  TypeDescription lhsTypeDescr( lhsType );
331  if (!lhsTypeDescr.is())
332  lhsTypeDescr.makeComplete();
333  if (!lhsTypeDescr.is())
334  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
335  TypeDescription rhsTypeDescr( rhsType );
336  if (!rhsTypeDescr.is())
337  rhsTypeDescr.makeComplete();
338  if (!rhsTypeDescr.is())
339  throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference<css::uno::XInterface>(), -1);
340  int compare = compareTypes( lhsTypeDescr.get(), rhsTypeDescr.get());
341  if( compare != 0 )
342  return compare < 0;
343 
344  return *static_cast< int const * >(lhs) < *static_cast< int const * >(rhs);
345  }
346  case typelib_TypeClass_BOOLEAN:
347  return *static_cast< sal_Bool const * >(lhs) < *static_cast< sal_Bool const * >(rhs);
348  case typelib_TypeClass_CHAR:
349  return *static_cast< sal_Unicode const * >(lhs) < *static_cast< sal_Unicode const * >(rhs);
350  case typelib_TypeClass_FLOAT:
351  return *static_cast< float const * >(lhs) < *static_cast< float const * >(rhs);
352  case typelib_TypeClass_DOUBLE:
353  return *static_cast< double const * >(lhs) < *static_cast< double const * >(rhs);
354  case typelib_TypeClass_BYTE:
355  return *static_cast< sal_Int8 const * >(lhs) < *static_cast< sal_Int8 const * >(rhs);
356  case typelib_TypeClass_SHORT:
357  return *static_cast< sal_Int16 const * >(lhs) < *static_cast< sal_Int16 const * >(rhs);
358  case typelib_TypeClass_UNSIGNED_SHORT:
359  return *static_cast< sal_uInt16 const * >(lhs) < *static_cast< sal_uInt16 const * >(rhs);
360  case typelib_TypeClass_LONG:
361  return *static_cast< sal_Int32 const * >(lhs) < *static_cast< sal_Int32 const * >(rhs);
362  case typelib_TypeClass_UNSIGNED_LONG:
363  return *static_cast< sal_uInt32 const * >(lhs) < *static_cast< sal_uInt32 const * >(rhs);
364  case typelib_TypeClass_HYPER:
365  return *static_cast< sal_Int64 const * >(lhs) < *static_cast< sal_Int64 const * >(rhs);
366  case typelib_TypeClass_UNSIGNED_HYPER:
367  return *static_cast< sal_uInt64 const * >(lhs) < *static_cast< sal_uInt64 const * >(rhs);
368  // case typelib_TypeClass_UNKNOWN:
369  // case typelib_TypeClass_SERVICE:
370  // case typelib_TypeClass_MODULE:
371  default:
372  return false;
373  }
374  }
375 
376  } // namespace
377 
378  std::unique_ptr< IKeyPredicateLess > getStandardLessPredicate( Type const & i_type, Reference< XCollator > const & i_collator )
379  {
380  std::unique_ptr< IKeyPredicateLess > pComparator;
381  switch ( i_type.getTypeClass() )
382  {
383  case TypeClass_CHAR:
384  pComparator.reset( new ScalarPredicateLess< sal_Unicode > );
385  break;
386  case TypeClass_BOOLEAN:
387  pComparator.reset( new ScalarPredicateLess< bool > );
388  break;
389  case TypeClass_BYTE:
390  pComparator.reset( new ScalarPredicateLess< sal_Int8 > );
391  break;
392  case TypeClass_SHORT:
393  pComparator.reset( new ScalarPredicateLess< sal_Int16 > );
394  break;
395  case TypeClass_UNSIGNED_SHORT:
396  pComparator.reset( new ScalarPredicateLess< sal_uInt16 > );
397  break;
398  case TypeClass_LONG:
399  pComparator.reset( new ScalarPredicateLess< sal_Int32 > );
400  break;
401  case TypeClass_UNSIGNED_LONG:
402  pComparator.reset( new ScalarPredicateLess< sal_uInt32 > );
403  break;
404  case TypeClass_HYPER:
405  pComparator.reset( new ScalarPredicateLess< sal_Int64 > );
406  break;
407  case TypeClass_UNSIGNED_HYPER:
408  pComparator.reset( new ScalarPredicateLess< sal_uInt64 > );
409  break;
410  case TypeClass_FLOAT:
411  pComparator.reset( new ScalarPredicateLess< float > );
412  break;
413  case TypeClass_DOUBLE:
414  pComparator.reset( new ScalarPredicateLess< double > );
415  break;
416  case TypeClass_STRING:
417  if ( i_collator.is() )
418  pComparator.reset( new StringCollationPredicateLess( i_collator ) );
419  else
420  pComparator.reset( new StringPredicateLess );
421  break;
422  case TypeClass_TYPE:
423  pComparator.reset( new TypePredicateLess );
424  break;
425  case TypeClass_ENUM:
426  pComparator.reset( new EnumPredicateLess( i_type ) );
427  break;
428  case TypeClass_INTERFACE:
429  pComparator.reset( new InterfacePredicateLess );
430  break;
431  case TypeClass_STRUCT:
432  if ( i_type.equals( ::cppu::UnoType< Date >::get() ) )
433  pComparator.reset( new DatePredicateLess );
434  else if ( i_type.equals( ::cppu::UnoType< Time >::get() ) )
435  pComparator.reset( new TimePredicateLess );
436  else if ( i_type.equals( ::cppu::UnoType< DateTime >::get() ) )
437  pComparator.reset( new DateTimePredicateLess );
438  break;
439  default:
440  break;
441  }
442  return pComparator;
443  }
444 
445  bool anyLess( css::uno::Any const & lhs, css::uno::Any const & rhs)
446  {
447  return anyLess( lhs.getValue(), lhs.getValueTypeRef(), rhs.getValue(), rhs.getValueTypeRef());
448  }
449 
450 } // namespace comphelper
451 
452 
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Type
signed char sal_Int8
sal_uInt16 sal_Unicode
bool anyLess(css::uno::Any const &lhs, css::uno::Any const &rhs)
Compare two Anys.
Definition: anycompare.cxx:445
sal_Int32 nElements
struct _uno_Any uno_Any
unsigned char sal_Bool
struct _typelib_TypeDescription typelib_TypeDescription
std::unique_ptr< IKeyPredicateLess > getStandardLessPredicate(Type const &i_type, Reference< XCollator > const &i_collator)
Definition: anycompare.cxx:378
SbxDecimal::CmpResult compare(SAL_UNUSED_PARAMETER const SbxDecimal &, SAL_UNUSED_PARAMETER const SbxDecimal &)
sal_uInt16 nPos