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
30
31namespace 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: */
sal_Int32 nElements
sal_uInt16 nPos
struct _typelib_TypeDescription typelib_TypeDescription
struct _uno_Any uno_Any
std::unique_ptr< IKeyPredicateLess > getStandardLessPredicate(Type const &i_type, Reference< XCollator > const &i_collator)
Definition: anycompare.cxx:378
bool anyLess(css::uno::Any const &lhs, css::uno::Any const &rhs)
Compare two Anys.
Definition: anycompare.cxx:445
Type
SbxDecimal::CmpResult compare(SAL_UNUSED_PARAMETER const SbxDecimal &, SAL_UNUSED_PARAMETER const SbxDecimal &)
unsigned char sal_Bool
sal_uInt16 sal_Unicode
signed char sal_Int8