1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include <comphelper/anycompare.hxx>
23 #include <typelib/typedescription.hxx>
25 #include <com/sun/star/util/Date.hpp>
26 #include <com/sun/star/util/Time.hpp>
27 #include <com/sun/star/util/DateTime.hpp>
29 #include "typedescriptionref.hxx"
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
;
60 class DatePredicateLess
: public IKeyPredicateLess
63 virtual bool isLess( css::uno::Any
const & _lhs
, css::uno::Any
const & _rhs
) const override
66 if ( !( _lhs
>>= lhs
)
69 throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference
<css::uno::XInterface
>(), -1);
72 if ( lhs
.Year
< rhs
.Year
)
74 if ( lhs
.Year
> rhs
.Year
)
77 if ( lhs
.Month
< rhs
.Month
)
79 if ( lhs
.Month
> rhs
.Month
)
82 if ( lhs
.Day
< rhs
.Day
)
88 class TimePredicateLess
: public IKeyPredicateLess
91 virtual bool isLess( css::uno::Any
const & _lhs
, css::uno::Any
const & _rhs
) const override
94 if ( !( _lhs
>>= lhs
)
97 throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference
<css::uno::XInterface
>(), -1);
100 if ( lhs
.Hours
< rhs
.Hours
)
102 if ( lhs
.Hours
> rhs
.Hours
)
105 if ( lhs
.Minutes
< rhs
.Minutes
)
107 if ( lhs
.Minutes
> rhs
.Minutes
)
110 if ( lhs
.Seconds
< rhs
.Seconds
)
112 if ( lhs
.Seconds
> rhs
.Seconds
)
115 if ( lhs
.NanoSeconds
< rhs
.NanoSeconds
)
121 class DateTimePredicateLess
: public IKeyPredicateLess
124 virtual bool isLess( css::uno::Any
const & _lhs
, css::uno::Any
const & _rhs
) const override
127 if ( !( _lhs
>>= lhs
)
130 throw css::lang::IllegalArgumentException("bad ordering", css::uno::Reference
<css::uno::XInterface
>(), -1);
133 if ( lhs
.Year
< rhs
.Year
)
135 if ( lhs
.Year
> rhs
.Year
)
138 if ( lhs
.Month
< rhs
.Month
)
140 if ( lhs
.Month
> rhs
.Month
)
143 if ( lhs
.Day
< rhs
.Day
)
145 if ( lhs
.Day
> rhs
.Day
)
148 if ( lhs
.Hours
< rhs
.Hours
)
150 if ( lhs
.Hours
> rhs
.Hours
)
153 if ( lhs
.Minutes
< rhs
.Minutes
)
155 if ( lhs
.Minutes
> rhs
.Minutes
)
158 if ( lhs
.Seconds
< rhs
.Seconds
)
160 if ( lhs
.Seconds
> rhs
.Seconds
)
163 if ( lhs
.NanoSeconds
< rhs
.NanoSeconds
)
169 bool anyLess( void const * lhs
, typelib_TypeDescriptionReference
* lhsType
,
170 void const * rhs
, typelib_TypeDescriptionReference
* rhsType
);
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
)
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
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
)
189 if( lhsType
== rhsType
)
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
);
198 bool anyLess( void const * lhs
, typelib_TypeDescriptionReference
* lhsType
,
199 void const * rhs
, typelib_TypeDescriptionReference
* rhsType
)
201 if (lhsType
->eTypeClass
!= rhsType
->eTypeClass
)
202 return lhsType
->eTypeClass
< rhsType
->eTypeClass
;
204 if (lhsType
->eTypeClass
== typelib_TypeClass_VOID
) {
207 assert(lhs
!= nullptr);
208 assert(rhs
!= nullptr);
210 switch (lhsType
->eTypeClass
) {
211 case typelib_TypeClass_INTERFACE
:
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());
229 typelib_CompoundTypeDescription
* compType
=
230 reinterpret_cast< typelib_CompoundTypeDescription
* >(
231 lhsTypeDescr
.get() );
232 sal_Int32 nDescr
= compType
->nMembers
;
234 if (compType
->pBaseTypeDescription
) {
235 std::optional
<bool> subLess
= anyCompare(
236 lhs
, reinterpret_cast<
237 typelib_TypeDescription
* >(
238 compType
->pBaseTypeDescription
)->pWeakRef
,
239 rhs
, reinterpret_cast<
240 typelib_TypeDescription
* >(
241 compType
->pBaseTypeDescription
)->pWeakRef
);
242 if(subLess
.has_value())
246 typelib_TypeDescriptionReference
** ppTypeRefs
=
247 compType
->ppTypeRefs
;
248 sal_Int32
* memberOffsets
= compType
->pMemberOffsets
;
250 for ( sal_Int32 nPos
= 0; nPos
< nDescr
; ++nPos
)
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())
265 return false; // equal
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
;
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());
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
)));
292 sal_Int32 nElementSize
= elementTypeDescr
->nSize
;
295 char const * lhsElements
= lhsSeq
->elements
;
296 char const * rhsElements
= rhsSeq
->elements
;
297 for ( sal_Int32 nPos
= 0; nPos
< nElements
; ++nPos
)
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())
308 return false; // equal
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
);
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
;
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
;
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());
344 return *static_cast< int const * >(lhs
) < *static_cast< int const * >(rhs
);
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:
378 std::unique_ptr
< IKeyPredicateLess
> getStandardLessPredicate( Type
const & i_type
, Reference
< XCollator
> const & i_collator
)
380 std::unique_ptr
< IKeyPredicateLess
> pComparator
;
381 switch ( i_type
.getTypeClass() )
384 pComparator
.reset( new ScalarPredicateLess
< sal_Unicode
> );
386 case TypeClass_BOOLEAN
:
387 pComparator
.reset( new ScalarPredicateLess
< bool > );
390 pComparator
.reset( new ScalarPredicateLess
< sal_Int8
> );
392 case TypeClass_SHORT
:
393 pComparator
.reset( new ScalarPredicateLess
< sal_Int16
> );
395 case TypeClass_UNSIGNED_SHORT
:
396 pComparator
.reset( new ScalarPredicateLess
< sal_uInt16
> );
399 pComparator
.reset( new ScalarPredicateLess
< sal_Int32
> );
401 case TypeClass_UNSIGNED_LONG
:
402 pComparator
.reset( new ScalarPredicateLess
< sal_uInt32
> );
404 case TypeClass_HYPER
:
405 pComparator
.reset( new ScalarPredicateLess
< sal_Int64
> );
407 case TypeClass_UNSIGNED_HYPER
:
408 pComparator
.reset( new ScalarPredicateLess
< sal_uInt64
> );
410 case TypeClass_FLOAT
:
411 pComparator
.reset( new ScalarPredicateLess
< float > );
413 case TypeClass_DOUBLE
:
414 pComparator
.reset( new ScalarPredicateLess
< double > );
416 case TypeClass_STRING
:
417 if ( i_collator
.is() )
418 pComparator
.reset( new StringCollationPredicateLess( i_collator
) );
420 pComparator
.reset( new StringPredicateLess
);
423 pComparator
.reset( new TypePredicateLess
);
426 pComparator
.reset( new EnumPredicateLess( i_type
) );
428 case TypeClass_INTERFACE
:
429 pComparator
.reset( new InterfacePredicateLess
);
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
);
445 bool anyLess( css::uno::Any
const & lhs
, css::uno::Any
const & rhs
)
447 return anyLess( lhs
.getValue(), lhs
.getValueTypeRef(), rhs
.getValue(), rhs
.getValueTypeRef());
450 } // namespace comphelper
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */