Version 7.5.1.1, tag libreoffice-7.5.1.1
[LibreOffice.git] / sc / inc / address.hxx
blob85a581f5c765097c189136e492c03dbbc11c49bc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */
2 /*
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 .
20 #pragma once
22 #include <rtl/ustrbuf.hxx>
23 #include <rtl/strbuf.hxx>
25 #include <array>
26 #include <limits>
27 #include <ostream>
29 #include "scdllapi.h"
30 #include "types.hxx"
31 #include <formula/grammar.hxx>
33 #include <o3tl/typed_flags_set.hxx>
34 #include <o3tl/underlyingenumvalue.hxx>
36 namespace com::sun::star {
37 namespace sheet {
38 struct ExternalLinkInfo;
42 namespace com::sun::star::uno { template <typename > class Sequence; }
44 class ScDocument;
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.
53 #undef min
54 #undef max
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();
61 // Count values
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;
67 // Maximum values
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");
89 // Special values
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)
152 if (nEnd < nStart)
153 std::swap(nStart, nEnd);
156 // The result of ConvertRef() is a bit group of the following:
157 enum class ScRefFlags : sal_uInt16
159 ZERO = 0x0000,
160 COL_ABS = 0x0001,
161 ROW_ABS = 0x0002,
162 TAB_ABS = 0x0004,
163 TAB_3D = 0x0008,
164 COL2_ABS = 0x0010,
165 ROW2_ABS = 0x0020,
166 TAB2_ABS = 0x0040,
167 TAB2_3D = 0x0080,
168 ROW_VALID = 0x0100,
169 COL_VALID = 0x0200,
170 TAB_VALID = 0x0400,
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
176 FORCE_DOC = 0x0800,
177 ROW2_VALID = 0x1000,
178 COL2_VALID = 0x2000,
179 TAB2_VALID = 0x4000,
180 VALID = 0x8000,
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
192 namespace o3tl
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);
205 // ScAddress
206 class SAL_WARN_UNUSED ScAddress
208 private:
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.
214 SCROW nRow;
215 SCCOL nCol;
216 SCTAB nTab;
218 public:
220 enum Uninitialized { UNINITIALIZED };
221 enum InitializeInvalid { INITIALIZE_INVALID };
223 struct Details
225 formula::FormulaGrammar::AddressConvention eConv;
226 SCROW nRow;
227 SCCOL nCol;
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;
243 struct ExternalInfo
245 OUString maTabName;
246 sal_uInt16 mnFileId;
247 bool mbExternal;
249 ExternalInfo() :
250 mnFileId(0), mbExternal(false)
254 ScAddress() :
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 );
274 SCROW Row() const
276 return nRow;
279 SCCOL Col() const
281 return nCol;
283 SCTAB Tab() const
285 return nTab;
287 void SetRow( SCROW nRowP )
289 nRow = nRowP;
291 void SetCol( SCCOL nColP )
293 nCol = nColP;
295 void SetTab( SCTAB nTabP )
297 nTab = nTabP;
299 void SetInvalid()
301 nRow = -1;
302 nCol = -1;
303 nTab = -1;
305 bool IsValid() const
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
326 nColP = nCol;
327 nRowP = nRow;
328 nTabP = nTab;
332 @param pSheetEndPos
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;
355 @param rErrorPos
356 If FALSE is returned, the positions contain <0 or >MAX...
357 values if shifted out of bounds.
358 @param pDocument
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)
388 stream <<
389 rAddress.Tab()+1 << "!"
390 "R" << rAddress.Row()+1 <<
391 "C" << rAddress.Col()+1;
393 return stream;
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 )
405 nCol = nColP;
406 nRow = nRowP;
407 nTab = nTabP;
410 inline ScAddress& ScAddress::operator=( const ScAddress& rAddress )
412 nCol = rAddress.nCol;
413 nRow = rAddress.nRow;
414 nTab = rAddress.nTab;
415 return *this;
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;
435 else
436 return nCol < rAddress.nCol;
438 else
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;
454 else
455 return nRow < rAddress.nRow;
457 else
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);
468 #else
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.
471 if (nRow <= 0xffff)
472 return (static_cast<size_t>(nTab) << 24) ^
473 (static_cast<size_t>(nCol) << 16) ^ static_cast<size_t>(nRow);
474 else
475 return (static_cast<size_t>(nTab) << 28) ^
476 (static_cast<size_t>(nCol) << 24) ^ static_cast<size_t>(nRow);
477 #endif
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());
493 // ScRange
494 class SAL_WARN_UNUSED SC_DLLPUBLIC ScRange final
496 public:
497 ScAddress aStart;
498 ScAddress aEnd;
500 ScRange() :
501 aStart(), aEnd()
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 )
513 PutInOrder();
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;
531 aEnd = rRange.aEnd;
532 return *this;
534 ScRange& operator=( const ScAddress& rPos )
536 aStart = aEnd = rPos;
537 return *this;
539 void SetInvalid()
541 aStart.SetInvalid();
542 aEnd.SetInvalid();
544 bool IsValid() const
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,
561 const OUString&,
562 const ScAddress::Details& rDetails = ScAddress::detailsOOOa1 );
563 void ParseRows( const ScDocument& rDoc,
564 const OUString&,
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
577 not resolved.
578 @param pErrRef pointer to "#REF!" string if to be accepted.
579 @returns
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.
597 @param nFlags
598 Cell reference flags
599 @param rDocument
600 Reference to document which is used for example to get tab names.
601 @param rDetails
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.
612 @returns
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); }
625 @param rErrorRange
626 If FALSE is returned, the positions contain <0 or >MAX...
627 values if shifted out of bounds.
628 @param pDocument
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)
678 stream << ":";
679 if (rRange.aEnd.Tab() != rRange.aStart.Tab())
680 stream << rRange.aEnd;
681 else
682 stream <<
683 "R" << rRange.aEnd.Row()+1 <<
684 "C" << rRange.aEnd.Col()+1;
687 return stream;
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
720 return
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
728 return
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
736 return
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
746 return
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());
751 #else
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.
759 return
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
764 #endif
767 inline size_t ScRange::hashStartColumn() const
769 #if SAL_TYPES_SIZEOFPOINTER == 8
770 // 20 bits for the rows
771 return
772 (static_cast<size_t>(aStart.Col()) << 40) ^
773 (static_cast<size_t>(aStart.Row()) << 20) ^
774 static_cast<size_t>(aEnd.Row());
775 #else
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
778 // values.
779 return
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());
783 #endif
786 [[nodiscard]] inline bool ValidRange( const ScRange& rRange, SCCOL nMaxCol, SCROW nMaxRow )
788 return ValidAddress(rRange.aStart, nMaxCol, nMaxRow) && ValidAddress(rRange.aEnd, nMaxCol, nMaxRow);
791 // ScRangePair
792 class SAL_WARN_UNUSED ScRangePair final
794 private:
795 std::array<ScRange,2> aRange;
797 public:
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 )
805 aRange[0] = rRange1;
806 aRange[1] = rRange2;
809 inline ScRangePair& operator= ( const ScRangePair& rRange );
810 const ScRange& GetRange( sal_uInt16 n ) const
812 return aRange[n];
814 ScRange& GetRange( sal_uInt16 n )
816 return aRange[n];
820 inline ScRangePair& ScRangePair::operator= ( const ScRangePair& rRange )
822 aRange[0] = rRange.aRange[0];
823 aRange[1] = rRange.aRange[1];
824 return *this;
827 // ScRefAddress
828 class SAL_WARN_UNUSED ScRefAddress
830 private:
831 ScAddress aAdr;
832 bool bRelCol;
833 bool bRelRow;
834 bool bRelTab;
835 public:
836 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
852 return bRelCol;
854 bool IsRelRow() const
856 return bRelRow;
858 bool IsRelTab() const
860 return bRelTab;
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
883 return aAdr;
886 SCCOL Col() const
888 return aAdr.Col();
890 SCROW Row() const
892 return aAdr.Row();
894 SCTAB Tab() const
896 return aAdr.Tab();
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 )
907 aAdr = rRef.aAdr;
908 bRelCol = rRef.bRelCol;
909 bRelRow = rRef.bRelRow;
910 bRelTab = rRef.bRelTab;
911 return *this;
914 inline void ScRefAddress::Set( const ScAddress& rAdr,
915 bool bNewRelCol, bool bNewRelRow, bool bNewRelTab )
917 aAdr = rAdr;
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;
940 // Global functions
942 // Special values for cells always broadcasting or listening (ScRecalcMode::ALWAYS
943 // and the like).
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);
965 rStr += aBuf;
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: */