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 #ifndef INCLUDED_COMPHELPER_SEQUENCE_HXX
21 #define INCLUDED_COMPHELPER_SEQUENCE_HXX
22 
23 #include <com/sun/star/uno/Sequence.hxx>
24 #include <osl/diagnose.h>
25 
26 #include <algorithm>
27 #include <vector>
28 
29 namespace comphelper
30 {
31     /** Search the given value within the given sequence, return the position of the first occurrence.
32         Returns -1 if nothing found.
33     */
34     template <class T1, class T2>
findValue(const css::uno::Sequence<T1> & _rList,const T2 & _rValue)35     inline sal_Int32 findValue(const css::uno::Sequence<T1>& _rList, const T2& _rValue)
36     {
37         // at which position do I find the value?
38         for (sal_Int32 i = 0; i < _rList.getLength(); ++i)
39         {
40             if (_rList[i] == _rValue)
41                 return i;
42         }
43 
44         return -1;
45     }
46 
47     /// concat several sequences
48     template <class T, class... Ss>
concatSequences(const css::uno::Sequence<T> & rS1,const Ss &...rSn)49     inline css::uno::Sequence<T> concatSequences(const css::uno::Sequence<T>& rS1, const Ss&... rSn)
50     {
51         // unary fold to disallow empty parameter pack: at least have one sequence in rSn
52         css::uno::Sequence<T> aReturn(std::size(rS1) + (... + std::size(rSn)));
53         T* pReturn = std::copy(std::begin(rS1), std::end(rS1), aReturn.begin());
54         (..., (pReturn = std::copy(std::begin(rSn), std::end(rSn), pReturn)));
55         return aReturn;
56     }
57 
58     /// concat additional elements from right sequence to left sequence
59     ///
60     /// be aware that this takes time O(|left| * |right|)
combineSequences(css::uno::Sequence<T> const & left,css::uno::Sequence<T> const & right)61     template<typename T> inline css::uno::Sequence<T> combineSequences(
62         css::uno::Sequence<T> const & left, css::uno::Sequence<T> const & right)
63     {
64         sal_Int32 n1 = left.getLength();
65         css::uno::Sequence<T> ret(n1 + right.getLength());
66             //TODO: check for overflow
67         std::copy_n(left.getConstArray(), n1, ret.getArray());
68         sal_Int32 n2 = n1;
69         for (sal_Int32 i = 0; i != right.getLength(); ++i) {
70             bool found = false;
71             for (sal_Int32 j = 0; j != n1; ++j) {
72                 if (right[i] == left[j]) {
73                     found = true;
74                     break;
75                 }
76             }
77             if (!found) {
78                 ret[n2++] = right[i];
79             }
80         }
81         ret.realloc(n2);
82         return ret;
83     }
84 
85     /// remove a specified element from a sequences
86     template<class T>
removeElementAt(css::uno::Sequence<T> & _rSeq,sal_Int32 _nPos)87     inline void removeElementAt(css::uno::Sequence<T>& _rSeq, sal_Int32 _nPos)
88     {
89         sal_Int32 nLength = _rSeq.getLength();
90 
91         OSL_ENSURE(0 <= _nPos && _nPos < nLength, "invalid index");
92 
93         T* pPos = _rSeq.getArray() + _nPos;
94         std::move(pPos + 1, pPos + nLength - _nPos, pPos);
95 
96         _rSeq.realloc(nLength-1);
97     }
98 
99     /** Copy from a plain C/C++ array into a Sequence.
100 
101         @tpl SrcType
102         Array element type. Must be assignable to DstType
103 
104         @tpl DstType
105         Sequence element type. Must be assignable from SrcType
106 
107         @param i_pArray
108         Valid pointer to at least num elements of type SrcType
109 
110         @param nNum
111         Number of array elements to copy
112 
113         @return the resulting Sequence
114 
115         @attention when copying from e.g. a double array to a
116         Sequence<int>, no proper rounding will be performed, but the
117         values will be truncated. There's currently no measure to
118         prevent or detect precision loss, overflow or truncation.
119      */
120     template < typename DstType, typename SrcType >
arrayToSequence(const SrcType * i_pArray,sal_Int32 nNum)121     inline css::uno::Sequence< DstType > arrayToSequence( const SrcType* i_pArray, sal_Int32 nNum )
122     {
123         css::uno::Sequence< DstType > result( nNum );
124         ::std::copy( i_pArray, i_pArray+nNum, result.getArray() );
125         return result;
126     }
127 
128 
129     /** Copy from a Sequence into a plain C/C++ array
130 
131         @tpl SrcType
132         Sequence element type. Must be assignable to DstType
133 
134         @tpl DstType
135         Array element type. Must be assignable from SrcType
136 
137         @param io_pArray
138         Valid pointer to at least i_Sequence.getLength() elements of
139         type DstType
140 
141         @param i_Sequence
142         Reference to a Sequence of SrcType elements
143 
144         @return a pointer to the array
145 
146         @attention when copying from e.g. a Sequence<double> to an int
147         array, no proper rounding will be performed, but the values
148         will be truncated. There's currently no measure to prevent or
149         detect precision loss, overflow or truncation.
150      */
151     template < typename DstType, typename SrcType >
sequenceToArray(DstType * io_pArray,const css::uno::Sequence<SrcType> & i_Sequence)152     inline DstType* sequenceToArray( DstType* io_pArray, const css::uno::Sequence< SrcType >& i_Sequence )
153     {
154         ::std::copy( i_Sequence.begin(), i_Sequence.end(), io_pArray );
155         return io_pArray;
156     }
157 
158 
159     /** Copy from a container into a Sequence
160 
161         @tpl SrcType
162         Container type. This type must fulfill the STL container
163         concept, in particular, the size(), begin() and end() methods
164         must be available and have the usual semantics.
165 
166         @tpl DstType
167         Sequence element type. Must be assignable from SrcType's
168         elements
169 
170         @param i_Container
171         Reference to the input contain with elements of type SrcType
172 
173         @return the generated Sequence
174 
175         @attention this function always performs a copy. Furthermore,
176         when copying from e.g. a vector<double> to a Sequence<int>, no
177         proper rounding will be performed, but the values will be
178         truncated. There's currently no measure to prevent or detect
179         precision loss, overflow or truncation.
180      */
181     template < typename DstElementType, typename SrcType >
containerToSequence(const SrcType & i_Container)182     inline css::uno::Sequence< DstElementType > containerToSequence( const SrcType& i_Container )
183     {
184         css::uno::Sequence< DstElementType > result( i_Container.size() );
185         ::std::copy( i_Container.begin(), i_Container.end(), result.getArray() );
186         return result;
187     }
188 
189     // this one does better type deduction, but does not allow us to copy into a different element type
190     template < typename SrcType >
containerToSequence(const SrcType & i_Container)191     inline css::uno::Sequence< typename SrcType::value_type > containerToSequence( const SrcType& i_Container )
192     {
193         css::uno::Sequence< typename SrcType::value_type > result( i_Container.size() );
194         ::std::copy( i_Container.begin(), i_Container.end(), result.getArray() );
195         return result;
196     }
197 
198     // handle arrays
199     template<typename ElementType, std::size_t SrcSize>
containerToSequence(ElementType const (& i_Array)[SrcSize])200     inline css::uno::Sequence< ElementType > containerToSequence( ElementType const (&i_Array)[ SrcSize ] )
201     {
202         return css::uno::Sequence< ElementType >( i_Array, SrcSize );
203     }
204 
205     template <typename T>
containerToSequence(::std::vector<T> const & v)206     inline css::uno::Sequence<T> containerToSequence(
207         ::std::vector<T> const& v )
208     {
209         return css::uno::Sequence<T>(
210             v.data(), static_cast<sal_Int32>(v.size()) );
211     }
212 
213 
214     /** Copy from a Sequence into a container
215 
216         @tpl SrcType
217         Sequence element type. Must be assignable to SrcType's
218         elements
219 
220         @tpl DstType
221         Container type. This type must have a constructor taking a pair
222         of iterators defining a range to copy from
223 
224         @param i_Sequence
225         Reference to a Sequence of SrcType elements
226 
227         @return the generated container. C++17 copy elision rules apply
228 
229         @attention this function always performs a copy. Furthermore,
230         when copying from e.g. a Sequence<double> to a vector<int>, no
231         proper rounding will be performed, but the values will be
232         truncated. There's currently no measure to prevent or detect
233         precision loss, overflow or truncation.
234      */
235     template < typename DstType, typename SrcType >
sequenceToContainer(const css::uno::Sequence<SrcType> & i_Sequence)236     inline DstType sequenceToContainer( const css::uno::Sequence< SrcType >& i_Sequence )
237     {
238         return DstType(i_Sequence.begin(), i_Sequence.end());
239     }
240 
241     // this one does better type deduction, but does not allow us to copy into a different element type
242     template < typename DstType >
sequenceToContainer(const css::uno::Sequence<typename DstType::value_type> & i_Sequence)243     inline DstType sequenceToContainer( const css::uno::Sequence< typename DstType::value_type >& i_Sequence )
244     {
245         return DstType(i_Sequence.begin(), i_Sequence.end());
246     }
247 
248     /** Copy from a Sequence into an existing container
249 
250         This potentially saves a needless extra copy operation over
251         the whole container, as it passes the target object by
252         reference.
253 
254         @tpl SrcType
255         Sequence element type. Must be assignable to SrcType's
256         elements
257 
258         @tpl DstType
259         Container type. This type must fulfill the STL container and
260         sequence concepts, in particular, the begin(), end() and
261         resize(int) methods must be available and have the usual
262         semantics.
263 
264         @param o_Output
265         Reference to the target container
266 
267         @param i_Sequence
268         Reference to a Sequence of SrcType elements
269 
270         @return a non-const reference to the given container
271 
272         @attention this function always performs a copy. Furthermore,
273         when copying from e.g. a Sequence<double> to a vector<int>, no
274         proper rounding will be performed, but the values will be
275         truncated. There's currently no measure to prevent or detect
276         precision loss, overflow or truncation.
277      */
278     template < typename DstType, typename SrcType >
sequenceToContainer(DstType & o_Output,const css::uno::Sequence<SrcType> & i_Sequence)279     inline DstType& sequenceToContainer( DstType& o_Output, const css::uno::Sequence< SrcType >& i_Sequence )
280     {
281         o_Output.resize( i_Sequence.getLength() );
282         ::std::copy( i_Sequence.begin(), i_Sequence.end(), o_Output.begin() );
283         return o_Output;
284     }
285 
286     /** Copy (keys or values) from an associate container into a Sequence
287 
288         @tpl M map container type eg. std::map/std::unordered_map
289 
290         @return the generated Sequence
291      */
292     template < typename M >
mapKeysToSequence(M const & map)293     inline css::uno::Sequence< typename M::key_type > mapKeysToSequence( M const& map )
294     {
295         css::uno::Sequence< typename M::key_type > ret( static_cast<sal_Int32>(map.size()) );
296         typename M::key_type* pArray = ret.getArray();
297         for (const auto& i : map)
298             *pArray++ = i.first;
299         return ret;
300     }
301 
302     template < typename M >
mapValuesToSequence(M const & map)303     inline css::uno::Sequence< typename M::mapped_type > mapValuesToSequence( M const& map )
304     {
305         css::uno::Sequence< typename M::mapped_type > ret( static_cast<sal_Int32>(map.size()) );
306         typename M::mapped_type* pArray = ret.getArray();
307         for (const auto& i : map)
308             *pArray++ = i.second;
309         return ret;
310     }
311 
312 }   // namespace comphelper
313 
314 
315 #endif // INCLUDED_COMPHELPER_SEQUENCE_HXX
316 
317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
318