1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */
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 <rtl/ustrbuf.hxx>
23 #include <rtl/strbuf.hxx>
31 #include <formula/grammar.hxx>
33 #include <o3tl/typed_flags_set.hxx>
34 #include <o3tl/underlyingenumvalue.hxx>
36 namespace com::sun::star
{
38 struct ExternalLinkInfo
;
42 namespace com::sun::star::uno
{ template <typename
> class Sequence
; }
46 /** size_t typedef to be able to find places where code was changed from USHORT
47 to size_t and is used to read/write from/to streams. */
48 typedef size_t SCSIZE
;
50 // Maximum possible value of data type, NOT maximum row value.
51 // MSC confuses numeric_limit max() with macro max() if vcl/wintypes.hxx is
52 // included, we should not be using those stupid macros anyway.
55 const SCROW SCROW_MAX
= ::std::numeric_limits
<SCROW
>::max();
56 const SCCOL SCCOL_MAX
= ::std::numeric_limits
<SCCOL
>::max();
57 const SCTAB SCTAB_MAX
= ::std::numeric_limits
<SCTAB
>::max();
58 const SCCOLROW SCCOLROW_MAX
= ::std::numeric_limits
<SCCOLROW
>::max();
59 const SCSIZE SCSIZE_MAX
= ::std::numeric_limits
<SCSIZE
>::max();
62 const SCROW MAXROWCOUNT
= 1048576;
63 const SCCOL MAXCOLCOUNT
= 16384;
64 const SCCOL INITIALCOLCOUNT
= 1; // initial number of columns we allocate memory for
65 /// limiting to 10000 for now, problem with 32 bit builds for now
66 const SCTAB MAXTABCOUNT
= 10000;
68 const SCROW MAXROW
= MAXROWCOUNT
- 1;
69 const SCCOL MAXCOL
= MAXCOLCOUNT
- 1;
70 const SCTAB MAXTAB
= MAXTABCOUNT
- 1;
71 const SCCOLROW MAXCOLROW
= MAXROW
;
72 const SCROW MAXROWCOUNT_JUMBO
= 16 * 1024 * 1024;
73 const SCCOL MAXCOLCOUNT_JUMBO
= 16384;
74 const SCROW MAXROW_JUMBO
= MAXROWCOUNT_JUMBO
- 1;
75 const SCCOL MAXCOL_JUMBO
= MAXCOLCOUNT_JUMBO
- 1;
76 // Maximum tiled rendering values
77 const SCROW MAXTILEDROW
= MAXROW
;
78 // Limit the initial tab count to prevent users to set the count too high,
79 // which could cause the memory usage of blank documents to exceed the
80 // available system memory.
81 const SCTAB MAXINITTAB
= 1024;
82 const SCTAB MININITTAB
= 1;
84 inline constexpr OUStringLiteral
MAXROW_STRING(u
"1048575");
85 inline constexpr OUStringLiteral
MAXCOL_STRING(u
"XFD");
86 inline constexpr OUStringLiteral
MAXROW_JUMBO_STRING(u
"16777215");
87 inline constexpr OUStringLiteral
MAXCOL_JUMBO_STRING(u
"XFD");
90 const SCTAB SC_TAB_APPEND
= SCTAB_MAX
;
91 const SCTAB TABLEID_DOC
= SCTAB_MAX
; // entire document, e.g. protect
92 const SCROW SCROWS32K
= 32000; // for fuzzing
93 const SCCOL SCCOL_REPEAT_NONE
= SCCOL_MAX
;
94 const SCROW SCROW_REPEAT_NONE
= SCROW_MAX
;
95 const SCCOL SC_TABSTART_NONE
= SCCOL_MAX
;
97 const SCROW MAXROW_30
= 8191;
99 [[nodiscard
]] inline bool ValidCol( SCCOL nCol
, SCCOL nMaxCol
)
101 assert(nMaxCol
== MAXCOL
|| nMaxCol
== MAXCOL_JUMBO
); // temporary to debug jumbo sheets work
102 return nCol
>= 0 && nCol
<= nMaxCol
;
105 [[nodiscard
]] inline bool ValidRow( SCROW nRow
, SCROW nMaxRow
)
107 assert(nMaxRow
== MAXROW
|| nMaxRow
== MAXROW_JUMBO
); // temporary to debug jumbo sheets work
108 return nRow
>= 0 && nRow
<= nMaxRow
;
111 [[nodiscard
]] inline bool ValidTab( SCTAB nTab
)
113 return nTab
>= 0 && nTab
<= MAXTAB
;
116 [[nodiscard
]] inline bool ValidTab( SCTAB nTab
, SCTAB nMaxTab
)
118 return nTab
>= 0 && nTab
<= nMaxTab
;
121 [[nodiscard
]] inline bool ValidColRow( SCCOL nCol
, SCROW nRow
, SCCOL nMaxCol
, SCROW nMaxRow
)
123 assert(nMaxRow
== MAXROW
|| nMaxRow
== MAXROW_JUMBO
); // temporary to debug jumbo sheets work
124 return ValidCol(nCol
,nMaxCol
) && ValidRow(nRow
,nMaxRow
);
127 [[nodiscard
]] inline bool ValidColRowTab( SCCOL nCol
, SCROW nRow
, SCTAB nTab
, SCCOL nMaxCol
, SCROW nMaxRow
)
129 assert(nMaxRow
== MAXROW
|| nMaxRow
== MAXROW_JUMBO
); // temporary to debug jumbo sheets work
130 return ValidCol(nCol
,nMaxCol
) && ValidRow(nRow
,nMaxRow
) && ValidTab( nTab
);
133 [[nodiscard
]] inline SCCOL
SanitizeCol( SCCOL nCol
, SCCOL nMaxCol
)
135 assert(nMaxCol
== MAXCOL
|| nMaxCol
== MAXCOL_JUMBO
); // temporary to debug jumbo sheets work
136 return nCol
< 0 ? 0 : (nCol
> nMaxCol
? nMaxCol
: nCol
);
139 [[nodiscard
]] inline SCROW
SanitizeRow( SCROW nRow
, SCROW nMaxRow
)
141 assert(nMaxRow
== MAXROW
|| nMaxRow
== MAXROW_JUMBO
); // temporary to debug jumbo sheets work
142 return nRow
< 0 ? 0 : (nRow
> nMaxRow
? nMaxRow
: nRow
);
145 [[nodiscard
]] inline SCTAB
SanitizeTab( SCTAB nTab
)
147 return nTab
< 0 ? 0 : (nTab
> MAXTAB
? MAXTAB
: nTab
);
150 template <typename T
> inline void PutInOrder(T
& nStart
, T
& nEnd
)
153 std::swap(nStart
, nEnd
);
156 // The result of ConvertRef() is a bit group of the following:
157 enum class ScRefFlags
: sal_uInt16
171 // BITS for convenience
172 BITS
= COL_ABS
| ROW_ABS
| TAB_ABS
| TAB_3D
173 | ROW_VALID
| COL_VALID
| TAB_VALID
,
174 // somewhat cheesy kludge to force the display of the document name even for
175 // local references. Requires TAB_3D to be valid
182 TAB_ABS_3D
= TAB_ABS
| TAB_3D
,
184 ADDR_ABS
= VALID
| COL_ABS
| ROW_ABS
| TAB_ABS
,
186 RANGE_ABS
= ADDR_ABS
| COL2_ABS
| ROW2_ABS
| TAB2_ABS
,
188 ADDR_ABS_3D
= ADDR_ABS
| TAB_3D
,
189 RANGE_ABS_3D
= RANGE_ABS
| TAB_3D
194 template<> struct typed_flags
<ScRefFlags
> : is_typed_flags
<ScRefFlags
, 0xffff> {};
196 inline void applyStartToEndFlags(ScRefFlags
&target
,const ScRefFlags source
)
198 target
|= ScRefFlags(o3tl::to_underlying(source
) << 4);
200 inline void applyStartToEndFlags(ScRefFlags
&target
)
202 target
|= ScRefFlags(o3tl::to_underlying(target
) << 4);
206 class SAL_WARN_UNUSED ScAddress
209 // Even if the fields are in the order "row, column, tab", in all (?) the ScAddress and
210 // ScDocument APIs that take separate row, column, and tab parameters, the parameters are in the
211 // order "column, row, tab", which matches the most common (A1) address syntax, if you ignore
212 // the sheet (tab). Don't let this confuse you, like it confused me for a while.
220 enum Uninitialized
{ UNINITIALIZED
};
221 enum InitializeInvalid
{ INITIALIZE_INVALID
};
225 formula::FormulaGrammar::AddressConvention eConv
;
229 Details( formula::FormulaGrammar::AddressConvention eConvP
, SCROW nRowP
, SCCOL nColP
) :
230 eConv(eConvP
), nRow(nRowP
), nCol(nColP
)
232 Details( formula::FormulaGrammar::AddressConvention eConvP
, ScAddress
const & rAddr
) :
233 eConv(eConvP
), nRow(rAddr
.Row()), nCol(rAddr
.Col())
235 Details( formula::FormulaGrammar::AddressConvention eConvP
) :
236 eConv(eConvP
), nRow(0), nCol(0)
238 /* Use the formula::FormulaGrammar::AddressConvention associated with rAddr::Tab() */
239 Details( const ScDocument
& rDoc
, const ScAddress
& rAddr
);
241 SC_DLLPUBLIC
static const Details detailsOOOa1
;
250 mnFileId(0), mbExternal(false)
255 nRow(0), nCol(0), nTab(0)
257 ScAddress( SCCOL nColP
, SCROW nRowP
, SCTAB nTabP
) :
258 nRow(nRowP
), nCol(nColP
), nTab(nTabP
)
260 /** coverity[uninit_member] - Yes, it is what it seems to be: Uninitialized.
261 May be used for performance reasons if it is initialized by other means. */
262 ScAddress( Uninitialized
)
264 ScAddress( InitializeInvalid
) :
265 nRow(-1), nCol(-1), nTab(-1)
267 ScAddress( const ScAddress
& rAddress
) :
268 nRow(rAddress
.nRow
), nCol(rAddress
.nCol
), nTab(rAddress
.nTab
)
270 inline ScAddress
& operator=( const ScAddress
& rAddress
);
272 inline void Set( SCCOL nCol
, SCROW nRow
, SCTAB nTab
);
287 void SetRow( SCROW nRowP
)
291 void SetCol( SCCOL nColP
)
295 void SetTab( SCTAB nTabP
)
307 return (nRow
>= 0) && (nCol
>= 0) && (nTab
>= 0);
310 inline void PutInOrder( ScAddress
& rAddress
);
312 void IncRow( SCROW nDelta
= 1 )
314 nRow
= sal::static_int_cast
<SCROW
>(nRow
+ nDelta
);
316 void IncCol( SCCOL nDelta
= 1 )
318 nCol
= sal::static_int_cast
<SCCOL
>(nCol
+ nDelta
);
320 void IncTab( SCTAB nDelta
= 1 )
322 nTab
= sal::static_int_cast
<SCTAB
>(nTab
+ nDelta
);
324 void GetVars( SCCOL
& nColP
, SCROW
& nRowP
, SCTAB
& nTabP
) const
333 If given and Parse() successfully parsed a sheet name it returns
334 the end position (exclusive) behind the sheet name AND a
335 following sheet name separator. This independent of whether the
336 resulting reference is fully valid or not.
338 SC_DLLPUBLIC ScRefFlags
Parse(
339 const OUString
&, const ScDocument
&,
340 const Details
& rDetails
= detailsOOOa1
,
341 ExternalInfo
* pExtInfo
= nullptr,
342 const css::uno::Sequence
<css::sheet::ExternalLinkInfo
>* pExternalLinks
= nullptr,
343 sal_Int32
* pSheetEndPos
= nullptr,
344 const OUString
* pErrRef
= nullptr );
346 SC_DLLPUBLIC
void Format( OStringBuffer
& r
, ScRefFlags nFlags
,
347 const ScDocument
* pDocument
= nullptr,
348 const Details
& rDetails
= detailsOOOa1
) const;
350 SC_DLLPUBLIC OUString
Format( ScRefFlags nFlags
,
351 const ScDocument
* pDocument
= nullptr,
352 const Details
& rDetails
= detailsOOOa1
) const;
356 If FALSE is returned, the positions contain <0 or >MAX...
357 values if shifted out of bounds.
359 The document for the maximum defined sheet number.
361 [[nodiscard
]] SC_DLLPUBLIC
bool Move( SCCOL nDeltaX
, SCROW nDeltaY
, SCTAB nDeltaZ
,
362 ScAddress
& rErrorPos
, const ScDocument
& rDoc
);
364 inline bool operator==( const ScAddress
& rAddress
) const;
365 inline bool operator!=( const ScAddress
& rAddress
) const;
366 inline bool operator<( const ScAddress
& rAddress
) const;
367 inline bool operator<=( const ScAddress
& rAddress
) const;
368 inline bool lessThanByRow( const ScAddress
& rAddress
) const;
370 inline size_t hash() const;
373 * Create a human-readable string representation of the cell address. You
374 * cannot specify precise formatting with this method; use Format() if you
375 * need to specify how the address needs to be formatted.
377 * The address string does not display sheet name.
379 * @return human-readable string representation of the cell address.
381 OUString
GetColRowString() const;
384 // For use in SAL_DEBUG etc. Output format not guaranteed to be stable.
385 template<typename charT
, typename traits
>
386 inline std::basic_ostream
<charT
, traits
> & operator <<(std::basic_ostream
<charT
, traits
> & stream
, const ScAddress
& rAddress
)
389 rAddress
.Tab()+1 << "!"
390 "R" << rAddress
.Row()+1 <<
391 "C" << rAddress
.Col()+1;
396 inline void ScAddress::PutInOrder( ScAddress
& rAddress
)
398 ::PutInOrder(nCol
, rAddress
.nCol
);
399 ::PutInOrder(nRow
, rAddress
.nRow
);
400 ::PutInOrder(nTab
, rAddress
.nTab
);
403 inline void ScAddress::Set( SCCOL nColP
, SCROW nRowP
, SCTAB nTabP
)
410 inline ScAddress
& ScAddress::operator=( const ScAddress
& rAddress
)
412 nCol
= rAddress
.nCol
;
413 nRow
= rAddress
.nRow
;
414 nTab
= rAddress
.nTab
;
418 inline bool ScAddress::operator==( const ScAddress
& rAddress
) const
420 return nRow
== rAddress
.nRow
&& nCol
== rAddress
.nCol
&& nTab
== rAddress
.nTab
;
423 inline bool ScAddress::operator!=( const ScAddress
& rAddress
) const
425 return !operator==( rAddress
);
428 /** Less than ordered by tab,col,row. */
429 inline bool ScAddress::operator<( const ScAddress
& rAddress
) const
431 if (nTab
== rAddress
.nTab
)
433 if (nCol
== rAddress
.nCol
)
434 return nRow
< rAddress
.nRow
;
436 return nCol
< rAddress
.nCol
;
439 return nTab
< rAddress
.nTab
;
442 inline bool ScAddress::operator<=( const ScAddress
& rAddress
) const
444 return operator<( rAddress
) || operator==( rAddress
);
447 /** Less than ordered by tab,row,col as needed by row-wise import/export */
448 inline bool ScAddress::lessThanByRow( const ScAddress
& rAddress
) const
450 if (nTab
== rAddress
.nTab
)
452 if (nRow
== rAddress
.nRow
)
453 return nCol
< rAddress
.nCol
;
455 return nRow
< rAddress
.nRow
;
458 return nTab
< rAddress
.nTab
;
461 inline size_t ScAddress::hash() const
463 #if SAL_TYPES_SIZEOFPOINTER == 8
464 // 16 bits for the columns, and 20 bits for the rows
465 return (static_cast<size_t>(nTab
) << 36) ^
466 (static_cast<size_t>(nCol
) << 20) ^
467 static_cast<size_t>(nRow
);
469 // Assume that there are not that many addresses with row > 2^16 AND column
470 // > 2^8 AND sheet > 2^8 so we won't have too many collisions.
472 return (static_cast<size_t>(nTab
) << 24) ^
473 (static_cast<size_t>(nCol
) << 16) ^ static_cast<size_t>(nRow
);
475 return (static_cast<size_t>(nTab
) << 28) ^
476 (static_cast<size_t>(nCol
) << 24) ^ static_cast<size_t>(nRow
);
480 struct ScAddressHashFunctor
482 size_t operator()( const ScAddress
& rAddress
) const
484 return rAddress
.hash();
488 [[nodiscard
]] inline bool ValidAddress( const ScAddress
& rAddress
, SCCOL nMaxCol
, SCROW nMaxRow
)
490 return ValidCol(rAddress
.Col(), nMaxCol
) && ValidRow(rAddress
.Row(), nMaxRow
) && ValidTab(rAddress
.Tab());
494 class SAL_WARN_UNUSED SC_DLLPUBLIC ScRange final
504 ScRange( ScAddress::Uninitialized eUninitialized
) :
505 aStart( eUninitialized
), aEnd( eUninitialized
)
507 ScRange( ScAddress::InitializeInvalid eInvalid
) :
508 aStart( eInvalid
), aEnd( eInvalid
)
510 ScRange( const ScAddress
& aInputStart
, const ScAddress
& aInputEnd
) :
511 aStart( aInputStart
), aEnd( aInputEnd
)
515 ScRange( const ScRange
& rRange
) :
516 aStart( rRange
.aStart
), aEnd( rRange
.aEnd
)
518 ScRange( const ScAddress
& rRange
) :
519 aStart( rRange
), aEnd( rRange
)
521 ScRange( SCCOL nCol
, SCROW nRow
, SCTAB nTab
) :
522 aStart( nCol
, nRow
, nTab
), aEnd( aStart
)
524 ScRange( SCCOL nCol1
, SCROW nRow1
, SCTAB nTab1
, SCCOL nCol2
, SCROW nRow2
, SCTAB nTab2
) :
525 aStart( nCol1
, nRow1
, nTab1
), aEnd( nCol2
, nRow2
, nTab2
)
528 ScRange
& operator=( const ScRange
& rRange
)
530 aStart
= rRange
.aStart
;
534 ScRange
& operator=( const ScAddress
& rPos
)
536 aStart
= aEnd
= rPos
;
546 return aStart
.IsValid() && aEnd
.IsValid();
548 inline bool Contains( const ScAddress
& ) const; ///< is Address& fully in Range?
549 inline bool Contains( const ScRange
& ) const; ///< is Range& fully in Range?
550 inline bool Intersects( const ScRange
& rRange
) const; // do two ranges intersect?
552 ScRefFlags
Parse( const OUString
&, const ScDocument
&,
553 const ScAddress::Details
& rDetails
= ScAddress::detailsOOOa1
,
554 ScAddress::ExternalInfo
* pExtInfo
= nullptr,
555 const css::uno::Sequence
<css::sheet::ExternalLinkInfo
>* pExternalLinks
= nullptr,
556 const OUString
* pErrRef
= nullptr );
558 ScRefFlags
ParseAny( const OUString
&, const ScDocument
&,
559 const ScAddress::Details
& rDetails
= ScAddress::detailsOOOa1
);
560 ScRefFlags
ParseCols( const ScDocument
& rDoc
,
562 const ScAddress::Details
& rDetails
= ScAddress::detailsOOOa1
);
563 void ParseRows( const ScDocument
& rDoc
,
565 const ScAddress::Details
& rDetails
= ScAddress::detailsOOOa1
);
567 /** Parse an Excel style reference up to and including the sheet name
568 separator '!', including detection of external documents and sheet
569 names, and in case of MOOXML import the bracketed index is used to
570 determine the actual document name passed in pExternalLinks. For
571 internal references (resulting rExternDocName empty), aStart.nTab and
572 aEnd.nTab are set, or -1 if sheet name not found.
573 @param bOnlyAcceptSingle If <TRUE/>, a 3D reference (Sheet1:Sheet2)
574 encountered results in an error (NULL returned).
575 @param pExternalLinks pointer to ExternalLinkInfo sequence, may be
576 NULL for non-filter usage, in which case indices such as [1] are
578 @param pErrRef pointer to "#REF!" string if to be accepted.
580 Pointer to the position after '!' if successfully parsed, and
581 rExternDocName, rStartTabName and/or rEndTabName filled if
582 applicable. ScRefFlags::... flags set in nFlags.
583 Or if no valid document and/or sheet header could be parsed the start
584 position passed with pString.
585 Or NULL if a 3D sheet header could be parsed but
586 bOnlyAcceptSingle==true was given.
588 const sal_Unicode
* Parse_XL_Header( const sal_Unicode
* pString
, const ScDocument
& rDocument
,
589 OUString
& rExternDocName
, OUString
& rStartTabName
,
590 OUString
& rEndTabName
, ScRefFlags
& nFlags
,
591 bool bOnlyAcceptSingle
,
592 const css::uno::Sequence
<css::sheet::ExternalLinkInfo
>* pExternalLinks
= nullptr,
593 const OUString
* pErrRef
= nullptr );
595 /** Returns string with formatted cell range from aStart to aEnd,
596 according to provided address convention.
600 Reference to document which is used for example to get tab names.
602 Provide information about required address convention.
603 Supported address conventions are:
604 CONV_OOO 'doc'#sheet.A1:sheet2.B2
605 CONV_XL_A1, [doc]sheet:sheet2!A1:B2
606 CONV_XL_OOX, [#]sheet:sheet2!A1:B2
607 CONV_XL_R1C1, [doc]sheet:sheet2!R1C1:R2C2
608 @param bFullAddressNotation
609 If TRUE, the full address notation will be used.
610 For example in case all columns are used, "A1:AMJ177" is full address notation
611 and "1:177" is shortened address notation.
613 String contains formatted cell range in address convention
615 OUString
Format( const ScDocument
& rDocument
,
616 ScRefFlags nFlags
= ScRefFlags::ZERO
,
617 const ScAddress::Details
& rDetails
= ScAddress::detailsOOOa1
,
618 bool bFullAddressNotation
= false ) const;
620 inline void GetVars( SCCOL
& nCol1
, SCROW
& nRow1
, SCTAB
& nTab1
,
621 SCCOL
& nCol2
, SCROW
& nRow2
, SCTAB
& nTab2
) const;
622 void PutInOrder() { aStart
.PutInOrder(aEnd
); }
626 If FALSE is returned, the positions contain <0 or >MAX...
627 values if shifted out of bounds.
629 The document for the maximum defined sheet number.
631 [[nodiscard
]] bool Move( SCCOL aDeltaX
, SCROW aDeltaY
, SCTAB aDeltaZ
,
632 ScRange
& rErrorRange
, const ScDocument
& rDoc
);
634 /** Same as Move() but with sticky end col/row anchors. */
635 [[nodiscard
]] bool MoveSticky( const ScDocument
& rDoc
, SCCOL aDeltaX
, SCROW aDeltaY
, SCTAB aDeltaZ
,
636 ScRange
& rErrorRange
);
638 void IncColIfNotLessThan(const ScDocument
& rDoc
, SCCOL nStartCol
, SCCOL nOffset
);
639 void IncRowIfNotLessThan(const ScDocument
& rDoc
, SCROW nStartRow
, SCROW nOffset
);
641 void ExtendTo( const ScRange
& rRange
);
643 ScRange
Intersection( const ScRange
& rOther
) const;
645 /// If maximum end column should not be adapted during reference update.
646 bool IsEndColSticky( const ScDocument
& rDoc
) const;
647 /// If maximum end row should not be adapted during reference update.
648 bool IsEndRowSticky( const ScDocument
& rDoc
) const;
650 /** Increment or decrement end column unless sticky or until it becomes
651 sticky. Checks if the range encompasses at least two columns so should
652 be called before adjusting the start column. */
653 void IncEndColSticky( const ScDocument
& rDoc
, SCCOL nDelta
);
655 /** Increment or decrement end row unless sticky or until it becomes
656 sticky. Checks if the range encompasses at least two rows so should
657 be called before adjusting the start row. */
658 void IncEndRowSticky( const ScDocument
& rDoc
, SCROW nDelta
);
660 inline bool operator==( const ScRange
& rRange
) const;
661 inline bool operator!=( const ScRange
& rRange
) const;
662 inline bool operator<( const ScRange
& rRange
) const;
663 inline bool operator<=( const ScRange
& rRange
) const;
665 /// Hash 2D area ignoring table number.
666 inline size_t hashArea() const;
667 /// Hash start column and start and end rows.
668 inline size_t hashStartColumn() const;
671 // For use in SAL_DEBUG etc. Output format not guaranteed to be stable.
672 template<typename charT
, typename traits
>
673 inline std::basic_ostream
<charT
, traits
> & operator <<(std::basic_ostream
<charT
, traits
> & stream
, const ScRange
& rRange
)
675 stream
<< rRange
.aStart
;
676 if (rRange
.aEnd
!= rRange
.aStart
)
679 if (rRange
.aEnd
.Tab() != rRange
.aStart
.Tab())
680 stream
<< rRange
.aEnd
;
683 "R" << rRange
.aEnd
.Row()+1 <<
684 "C" << rRange
.aEnd
.Col()+1;
690 inline void ScRange::GetVars( SCCOL
& nCol1
, SCROW
& nRow1
, SCTAB
& nTab1
,
691 SCCOL
& nCol2
, SCROW
& nRow2
, SCTAB
& nTab2
) const
693 aStart
.GetVars( nCol1
, nRow1
, nTab1
);
694 aEnd
.GetVars( nCol2
, nRow2
, nTab2
);
697 inline bool ScRange::operator==( const ScRange
& rRange
) const
699 return ( (aStart
== rRange
.aStart
) && (aEnd
== rRange
.aEnd
) );
702 inline bool ScRange::operator!=( const ScRange
& rRange
) const
704 return !operator==( rRange
);
707 /// Sort on upper left corner tab,col,row, if equal then use lower right too.
708 inline bool ScRange::operator<( const ScRange
& r
) const
710 return aStart
< r
.aStart
|| (aStart
== r
.aStart
&& aEnd
< r
.aEnd
) ;
713 inline bool ScRange::operator<=( const ScRange
& rRange
) const
715 return operator<( rRange
) || operator==( rRange
);
718 inline bool ScRange::Contains( const ScAddress
& rAddress
) const
721 aStart
.Col() <= rAddress
.Col() && rAddress
.Col() <= aEnd
.Col() &&
722 aStart
.Row() <= rAddress
.Row() && rAddress
.Row() <= aEnd
.Row() &&
723 aStart
.Tab() <= rAddress
.Tab() && rAddress
.Tab() <= aEnd
.Tab();
726 inline bool ScRange::Contains( const ScRange
& rRange
) const
729 aStart
.Col() <= rRange
.aStart
.Col() && rRange
.aEnd
.Col() <= aEnd
.Col() &&
730 aStart
.Row() <= rRange
.aStart
.Row() && rRange
.aEnd
.Row() <= aEnd
.Row() &&
731 aStart
.Tab() <= rRange
.aStart
.Tab() && rRange
.aEnd
.Tab() <= aEnd
.Tab();
734 inline bool ScRange::Intersects( const ScRange
& rRange
) const
737 aStart
.Col() <= rRange
.aEnd
.Col() && rRange
.aStart
.Col() <= aEnd
.Col() &&
738 aStart
.Row() <= rRange
.aEnd
.Row() && rRange
.aStart
.Row() <= aEnd
.Row() &&
739 aStart
.Tab() <= rRange
.aEnd
.Tab() && rRange
.aStart
.Tab() <= aEnd
.Tab();
742 inline size_t ScRange::hashArea() const
744 #if SAL_TYPES_SIZEOFPOINTER == 8
745 // 12 bits for the columns and 20 bits for the rows
747 (static_cast<size_t>(aStart
.Row()) << 44) ^
748 (static_cast<size_t>(aStart
.Col()) << 32) ^
749 (static_cast<size_t>(aEnd
.Col()) << 20) ^
750 static_cast<size_t>(aEnd
.Row());
752 // Assume that there are not that many ranges with identical corners so we
753 // won't have too many collisions. Also assume that more lower row and
754 // column numbers are used so that there are not too many conflicts with
755 // the columns hashed into the values, and that start row and column
756 // usually don't exceed certain values. High bits are not masked off and
757 // may overlap with lower bits of other values, e.g. if start column is
758 // greater than assumed.
760 (static_cast<size_t>(aStart
.Row()) << 26) ^ // start row <= 2^6
761 (static_cast<size_t>(aStart
.Col()) << 21) ^ // start column <= 2^5
762 (static_cast<size_t>(aEnd
.Col()) << 15) ^ // end column <= 2^6
763 static_cast<size_t>(aEnd
.Row()); // end row <= 2^15
767 inline size_t ScRange::hashStartColumn() const
769 #if SAL_TYPES_SIZEOFPOINTER == 8
770 // 20 bits for the rows
772 (static_cast<size_t>(aStart
.Col()) << 40) ^
773 (static_cast<size_t>(aStart
.Row()) << 20) ^
774 static_cast<size_t>(aEnd
.Row());
776 // Assume that for the start row more lower row numbers are used so that
777 // there are not too many conflicts with the column hashed into the higher
780 (static_cast<size_t>(aStart
.Col()) << 24) ^ // start column <= 2^8
781 (static_cast<size_t>(aStart
.Row()) << 16) ^ // start row <= 2^8
782 static_cast<size_t>(aEnd
.Row());
786 [[nodiscard
]] inline bool ValidRange( const ScRange
& rRange
, SCCOL nMaxCol
, SCROW nMaxRow
)
788 return ValidAddress(rRange
.aStart
, nMaxCol
, nMaxRow
) && ValidAddress(rRange
.aEnd
, nMaxCol
, nMaxRow
);
792 class SAL_WARN_UNUSED ScRangePair final
795 std::array
<ScRange
,2> aRange
;
798 ScRangePair( const ScRangePair
& r
)
800 aRange
[0] = r
.aRange
[0];
801 aRange
[1] = r
.aRange
[1];
803 ScRangePair( const ScRange
& rRange1
, const ScRange
& rRange2
)
809 inline ScRangePair
& operator= ( const ScRangePair
& rRange
);
810 const ScRange
& GetRange( sal_uInt16 n
) const
814 ScRange
& GetRange( sal_uInt16 n
)
820 inline ScRangePair
& ScRangePair::operator= ( const ScRangePair
& rRange
)
822 aRange
[0] = rRange
.aRange
[0];
823 aRange
[1] = rRange
.aRange
[1];
828 class SAL_WARN_UNUSED ScRefAddress
837 bRelCol(false), bRelRow(false), bRelTab(false)
839 ScRefAddress( SCCOL nCol
, SCROW nRow
, SCTAB nTab
) :
840 aAdr(nCol
, nRow
, nTab
),
841 bRelCol(false), bRelRow(false), bRelTab(false)
843 ScRefAddress( const ScRefAddress
& rRef
) :
844 aAdr(rRef
.aAdr
), bRelCol(rRef
.bRelCol
), bRelRow(rRef
.bRelRow
),
845 bRelTab(rRef
.bRelTab
)
848 inline ScRefAddress
& operator=( const ScRefAddress
& );
850 bool IsRelCol() const
854 bool IsRelRow() const
858 bool IsRelTab() const
863 void SetRelCol(bool bNewRelCol
)
865 bRelCol
= bNewRelCol
;
867 void SetRelRow(bool bNewRelRow
)
869 bRelRow
= bNewRelRow
;
871 void SetRelTab(bool bNewRelTab
)
873 bRelTab
= bNewRelTab
;
876 inline void Set( const ScAddress
& rAdr
,
877 bool bNewRelCol
, bool bNewRelRow
, bool bNewRelTab
);
878 inline void Set( SCCOL nNewCol
, SCROW nNewRow
, SCTAB nNewTab
,
879 bool bNewRelCol
, bool bNewRelRow
, bool bNewRelTab
);
881 const ScAddress
& GetAddress() const
899 inline bool operator == ( const ScRefAddress
& r
) const;
901 OUString
GetRefString( const ScDocument
& rDocument
, SCTAB nActTab
,
902 const ScAddress::Details
& rDetails
= ScAddress::detailsOOOa1
) const;
905 inline ScRefAddress
& ScRefAddress::operator=( const ScRefAddress
& rRef
)
908 bRelCol
= rRef
.bRelCol
;
909 bRelRow
= rRef
.bRelRow
;
910 bRelTab
= rRef
.bRelTab
;
914 inline void ScRefAddress::Set( const ScAddress
& rAdr
,
915 bool bNewRelCol
, bool bNewRelRow
, bool bNewRelTab
)
918 bRelCol
= bNewRelCol
;
919 bRelRow
= bNewRelRow
;
920 bRelTab
= bNewRelTab
;
923 inline void ScRefAddress::Set( SCCOL nNewCol
, SCROW nNewRow
, SCTAB nNewTab
,
924 bool bNewRelCol
, bool bNewRelRow
, bool bNewRelTab
)
926 aAdr
.Set( nNewCol
, nNewRow
, nNewTab
);
927 bRelCol
= bNewRelCol
;
928 bRelRow
= bNewRelRow
;
929 bRelTab
= bNewRelTab
;
932 inline bool ScRefAddress::operator==( const ScRefAddress
& rRefAddress
) const
934 return aAdr
== rRefAddress
.aAdr
&&
935 bRelCol
== rRefAddress
.bRelCol
&&
936 bRelRow
== rRefAddress
.bRelRow
&&
937 bRelTab
== rRefAddress
.bRelTab
;
942 // Special values for cells always broadcasting or listening (ScRecalcMode::ALWAYS
944 #define BCA_BRDCST_ALWAYS ScAddress( 0, SCROW_MAX, 0 )
945 #define BCA_LISTEN_ALWAYS ScRange( BCA_BRDCST_ALWAYS, BCA_BRDCST_ALWAYS )
947 bool ConvertSingleRef( const ScDocument
& pDocument
, const OUString
& rRefString
,
948 SCTAB nDefTab
, ScRefAddress
& rRefAddress
,
949 const ScAddress::Details
& rDetails
,
950 ScAddress::ExternalInfo
* pExtInfo
= nullptr );
952 bool ConvertDoubleRef( const ScDocument
& rDocument
, const OUString
& rRefString
,
953 SCTAB nDefTab
, ScRefAddress
& rStartRefAddress
,
954 ScRefAddress
& rEndRefAddress
,
955 const ScAddress::Details
& rDetails
,
956 ScAddress::ExternalInfo
* pExtInfo
= nullptr );
958 /// append alpha representation of column to buffer
959 SC_DLLPUBLIC
void ScColToAlpha( OUStringBuffer
& rBuffer
, SCCOL nCol
);
961 inline void ScColToAlpha( OUString
& rStr
, SCCOL nCol
)
963 OUStringBuffer
aBuf(4);
964 ScColToAlpha( aBuf
, nCol
);
968 inline OUString
ScColToAlpha( SCCOL nCol
)
970 OUStringBuffer
aBuf(4);
971 ScColToAlpha( aBuf
, nCol
);
972 return aBuf
.makeStringAndClear();
975 /// get column number of A..IV... string
976 bool AlphaToCol(const ScDocument
& rDoc
, SCCOL
& rCol
, std::u16string_view rStr
);
978 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */