sc/CppunitTest_sc_basic_types_test.mk | 35 +++++ sc/Module_sc.mk | 1 sc/inc/address.hxx | 217 ++++++++++++++++------------------ sc/qa/unit/ScAddressTest.cxx | 78 ++++++++++++ 4 files changed, 217 insertions(+), 114 deletions(-)
New commits: commit ee1a2299931c33470fc28c3e5f26f69d3c35b0d8 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Tue Aug 26 21:56:16 2025 +0200 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Wed Aug 27 16:52:10 2025 +0200 sc: use three-way comparison to reduce the number of operators Change-Id: Ie3c409b0b8b7f66e4d6e7bd548b798a6474e5250 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190256 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx index 7c19ef3925ac..61d895c443c2 100644 --- a/sc/inc/address.hxx +++ b/sc/inc/address.hxx @@ -393,33 +393,17 @@ public: return nRow == rAddress.nRow && nCol == rAddress.nCol && nTab == rAddress.nTab; } - /** Less than ordered by tab,col,row. */ - constexpr bool operator<(const ScAddress& rAddress) const + constexpr auto operator<=>(const ScAddress& rAddress) const { - if (nTab == rAddress.nTab) + if (auto bTabResult = nTab <=> rAddress.nTab; bTabResult == 0) { - if (nCol == rAddress.nCol) - return nRow < rAddress.nRow; + if (auto bColResult = nCol <=> rAddress.nCol; bColResult == 0) + return nRow <=> rAddress.nRow; else - return nCol < rAddress.nCol; + return bColResult; } else - return nTab < rAddress.nTab; - } - - constexpr bool operator<=( const ScAddress& rAddress ) const - { - return operator<(rAddress) || operator==(rAddress); - } - - constexpr bool operator>(const ScAddress& rAddress) const - { - return !(operator<=(rAddress)); - } - - constexpr bool operator>=(const ScAddress& rAddress) const - { - return !(operator<(rAddress)); + return bTabResult; } /** Less than ordered by tab,row,col as needed by row-wise import/export */ commit 4ad007de60abb686a080680380893b3aebc05daa Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Tue Aug 26 21:52:14 2025 +0200 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Wed Aug 27 16:52:01 2025 +0200 sc: make ScAddress constexpr and clean-up - remove the inlines which are implicit anyway - make compile type tests of the class - move inline methods into body Change-Id: If2656c1b750a300bc0ed589bc7ea6aec27b3237a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190255 Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> Tested-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/sc/CppunitTest_sc_basic_types_test.mk b/sc/CppunitTest_sc_basic_types_test.mk new file mode 100644 index 000000000000..072ec157c989 --- /dev/null +++ b/sc/CppunitTest_sc_basic_types_test.mk @@ -0,0 +1,35 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,sc_basic_types_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sc_basic_types_test,\ + sc/qa/unit/ScAddressTest \ +)) + +$(eval $(call gb_CppunitTest_use_external,sc_basic_types_test,boost_headers)) + +$(eval $(call gb_CppunitTest_set_include,sc_basic_types_test,\ + -I$(SRCDIR)/sc/source/ui/inc \ + -I$(SRCDIR)/sc/source/core/inc \ + -I$(SRCDIR)/sc/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,sc_basic_types_test,\ + sal \ +)) + +# Needed for include/test/cppunitasserthelper.hxx +$(eval $(call gb_CppunitTest_use_sdk_api,sc_basic_types_test)) + + +# vim: set noet sw=4 ts=4: diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk index 3e1dc0d120e0..64fdfca08289 100644 --- a/sc/Module_sc.mk +++ b/sc/Module_sc.mk @@ -61,6 +61,7 @@ $(eval $(call gb_Module_add_check_targets,sc,\ CppunitTest_sc_filters_test \ CppunitTest_sc_mark_test \ CppunitTest_sc_core \ + CppunitTest_sc_basic_types_test \ CppunitTest_sc_dataprovider \ CppunitTest_sc_cache_test \ CppunitTest_sc_parallelism \ diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx index 02bd6579450e..7c19ef3925ac 100644 --- a/sc/inc/address.hxx +++ b/sc/inc/address.hxx @@ -248,77 +248,107 @@ public: {} }; - ScAddress() : + constexpr ScAddress() : nRow(0), nCol(0), nTab(0) {} - ScAddress( SCCOL nColP, SCROW nRowP, SCTAB nTabP ) : + + constexpr ScAddress( SCCOL nColP, SCROW nRowP, SCTAB nTabP ) : nRow(nRowP), nCol(nColP), nTab(nTabP) {} + /** coverity[uninit_member] - Yes, it is what it seems to be: Uninitialized. May be used for performance reasons if it is initialized by other means. */ - ScAddress( Uninitialized ) + constexpr ScAddress( Uninitialized ) {} - ScAddress( InitializeInvalid ) : + + constexpr ScAddress( InitializeInvalid ) : nRow(-1), nCol(-1), nTab(-1) {} - ScAddress( const ScAddress& rAddress ) : + + constexpr ScAddress( const ScAddress& rAddress ) : nRow(rAddress.nRow), nCol(rAddress.nCol), nTab(rAddress.nTab) {} - inline ScAddress& operator=( const ScAddress& rAddress ); - inline void Set( SCCOL nCol, SCROW nRow, SCTAB nTab ); + constexpr ScAddress& operator=(const ScAddress& rAddress) + { + nCol = rAddress.nCol; + nRow = rAddress.nRow; + nTab = rAddress.nTab; + return *this; + } - SCROW Row() const + constexpr void Set(SCCOL nColP, SCROW nRowP, SCTAB nTabP) + { + nCol = nColP; + nRow = nRowP; + nTab = nTabP; + } + + constexpr SCROW Row() const { return nRow; } - SCCOL Col() const + constexpr SCCOL Col() const { return nCol; } - SCTAB Tab() const + + constexpr SCTAB Tab() const { return nTab; } - void SetRow( SCROW nRowP ) + + constexpr void SetRow( SCROW nRowP ) { nRow = nRowP; } - void SetCol( SCCOL nColP ) + + constexpr void SetCol( SCCOL nColP ) { nCol = nColP; } - void SetTab( SCTAB nTabP ) + + constexpr void SetTab( SCTAB nTabP ) { nTab = nTabP; } - void SetInvalid() + + constexpr void SetInvalid() { nRow = -1; nCol = -1; nTab = -1; } - bool IsValid() const + + constexpr bool IsValid() const { return (nRow >= 0) && (nCol >= 0) && (nTab >= 0); } - inline void PutInOrder( ScAddress& rAddress ); + constexpr void PutInOrder(ScAddress& rAddress) + { + ::PutInOrder(nCol, rAddress.nCol); + ::PutInOrder(nRow, rAddress.nRow); + ::PutInOrder(nTab, rAddress.nTab); + } - void IncRow( SCROW nDelta = 1 ) + constexpr void IncRow( SCROW nDelta = 1 ) { - nRow = sal::static_int_cast<SCROW>(nRow + nDelta); + nRow = static_cast<SCROW>(nRow + nDelta); } - void IncCol( SCCOL nDelta = 1 ) + + constexpr void IncCol( SCCOL nDelta = 1 ) { - nCol = sal::static_int_cast<SCCOL>(nCol + nDelta); + nCol = static_cast<SCCOL>(nCol + nDelta); } - void IncTab( SCTAB nDelta = 1 ) + + constexpr void IncTab( SCTAB nDelta = 1 ) { - nTab = sal::static_int_cast<SCTAB>(nTab + nDelta); + nTab = static_cast<SCTAB>(nTab + nDelta); } - void GetVars( SCCOL& nColP, SCROW& nRowP, SCTAB& nTabP ) const + + constexpr void GetVars( SCCOL& nColP, SCROW& nRowP, SCTAB& nTabP ) const { nColP = nCol; nRowP = nRow; @@ -358,13 +388,72 @@ public: [[nodiscard]] SC_DLLPUBLIC bool Move( SCCOL nDeltaX, SCROW nDeltaY, SCTAB nDeltaZ, ScAddress& rErrorPos, const ScDocument& rDoc ); - inline bool operator==( const ScAddress& rAddress ) const; - inline bool operator!=( const ScAddress& rAddress ) const; - inline bool operator<( const ScAddress& rAddress ) const; - inline bool operator<=( const ScAddress& rAddress ) const; - inline bool lessThanByRow( const ScAddress& rAddress ) const; + constexpr bool operator==( const ScAddress& rAddress ) const + { + return nRow == rAddress.nRow && nCol == rAddress.nCol && nTab == rAddress.nTab; + } - inline size_t hash() const; + /** Less than ordered by tab,col,row. */ + constexpr bool operator<(const ScAddress& rAddress) const + { + if (nTab == rAddress.nTab) + { + if (nCol == rAddress.nCol) + return nRow < rAddress.nRow; + else + return nCol < rAddress.nCol; + } + else + return nTab < rAddress.nTab; + } + + constexpr bool operator<=( const ScAddress& rAddress ) const + { + return operator<(rAddress) || operator==(rAddress); + } + + constexpr bool operator>(const ScAddress& rAddress) const + { + return !(operator<=(rAddress)); + } + + constexpr bool operator>=(const ScAddress& rAddress) const + { + return !(operator<(rAddress)); + } + + /** Less than ordered by tab,row,col as needed by row-wise import/export */ + bool lessThanByRow(const ScAddress& rAddress) const + { + if (nTab == rAddress.nTab) + { + if (nRow == rAddress.nRow) + return nCol < rAddress.nCol; + else + return nRow < rAddress.nRow; + } + else + return nTab < rAddress.nTab; + } + + size_t hash() const + { + #if SAL_TYPES_SIZEOFPOINTER == 8 + // 16 bits for the columns, and 20 bits for the rows + return (static_cast<size_t>(nTab) << 36) ^ + (static_cast<size_t>(nCol) << 20) ^ + static_cast<size_t>(nRow); + #else + // Assume that there are not that many addresses with row > 2^16 AND column + // > 2^8 AND sheet > 2^8 so we won't have too many collisions. + if (nRow <= 0xffff) + return (static_cast<size_t>(nTab) << 24) ^ + (static_cast<size_t>(nCol) << 16) ^ static_cast<size_t>(nRow); + else + return (static_cast<size_t>(nTab) << 28) ^ + (static_cast<size_t>(nCol) << 24) ^ static_cast<size_t>(nRow); + #endif + } /** * Create a human-readable string representation of the cell address. You @@ -390,90 +479,6 @@ inline std::basic_ostream<charT, traits> & operator <<(std::basic_ostream<charT, return stream; } -inline void ScAddress::PutInOrder( ScAddress& rAddress ) -{ - ::PutInOrder(nCol, rAddress.nCol); - ::PutInOrder(nRow, rAddress.nRow); - ::PutInOrder(nTab, rAddress.nTab); -} - -inline void ScAddress::Set( SCCOL nColP, SCROW nRowP, SCTAB nTabP ) -{ - nCol = nColP; - nRow = nRowP; - nTab = nTabP; -} - -inline ScAddress& ScAddress::operator=( const ScAddress& rAddress ) -{ - nCol = rAddress.nCol; - nRow = rAddress.nRow; - nTab = rAddress.nTab; - return *this; -} - -inline bool ScAddress::operator==( const ScAddress& rAddress ) const -{ - return nRow == rAddress.nRow && nCol == rAddress.nCol && nTab == rAddress.nTab; -} - -inline bool ScAddress::operator!=( const ScAddress& rAddress ) const -{ - return !operator==( rAddress ); -} - -/** Less than ordered by tab,col,row. */ -inline bool ScAddress::operator<( const ScAddress& rAddress ) const -{ - if (nTab == rAddress.nTab) - { - if (nCol == rAddress.nCol) - return nRow < rAddress.nRow; - else - return nCol < rAddress.nCol; - } - else - return nTab < rAddress.nTab; -} - -inline bool ScAddress::operator<=( const ScAddress& rAddress ) const -{ - return operator<( rAddress ) || operator==( rAddress ); -} - -/** Less than ordered by tab,row,col as needed by row-wise import/export */ -inline bool ScAddress::lessThanByRow( const ScAddress& rAddress ) const -{ - if (nTab == rAddress.nTab) - { - if (nRow == rAddress.nRow) - return nCol < rAddress.nCol; - else - return nRow < rAddress.nRow; - } - else - return nTab < rAddress.nTab; -} - -inline size_t ScAddress::hash() const -{ -#if SAL_TYPES_SIZEOFPOINTER == 8 - // 16 bits for the columns, and 20 bits for the rows - return (static_cast<size_t>(nTab) << 36) ^ - (static_cast<size_t>(nCol) << 20) ^ - static_cast<size_t>(nRow); -#else - // Assume that there are not that many addresses with row > 2^16 AND column - // > 2^8 AND sheet > 2^8 so we won't have too many collisions. - if (nRow <= 0xffff) - return (static_cast<size_t>(nTab) << 24) ^ - (static_cast<size_t>(nCol) << 16) ^ static_cast<size_t>(nRow); - else - return (static_cast<size_t>(nTab) << 28) ^ - (static_cast<size_t>(nCol) << 24) ^ static_cast<size_t>(nRow); -#endif -} - struct ScAddressHashFunctor { size_t operator()( const ScAddress & rAddress ) const @@ -482,7 +487,7 @@ struct ScAddressHashFunctor } }; -[[nodiscard]] inline bool ValidAddress( const ScAddress& rAddress, SCCOL nMaxCol, SCROW nMaxRow ) +[[nodiscard]] constexpr bool ValidAddress(const ScAddress& rAddress, SCCOL nMaxCol, SCROW nMaxRow) { return ValidCol(rAddress.Col(), nMaxCol) && ValidRow(rAddress.Row(), nMaxRow) && ValidTab(rAddress.Tab()); } diff --git a/sc/qa/unit/ScAddressTest.cxx b/sc/qa/unit/ScAddressTest.cxx new file mode 100644 index 000000000000..97f17b79da38 --- /dev/null +++ b/sc/qa/unit/ScAddressTest.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <address.hxx> + +#include <cppunit/plugin/TestPlugIn.h> + +// Compile time tests for ScAddress + +static_assert(ScAddress() == ScAddress(0, 0, 0)); +static_assert(ScAddress().IsValid() == true); +static_assert(ScAddress(ScAddress::INITIALIZE_INVALID).IsValid() == false); + +// Equal, not Equal + +// Format is Col, Row, Tab and Col has priority over Row +static_assert(ScAddress(0, 0, 0) != ScAddress(1, 0, 0)); // A1 != B1 +static_assert(ScAddress(0, 0, 0) != ScAddress(0, 1, 0)); // A1 != A2 +static_assert(ScAddress(0, 0, 0) != ScAddress(0, 0, 1)); // Sheet1:A1 != Sheet2:A1 +static_assert(ScAddress(0, 0, 0) == ScAddress(0, 0, 0)); // A1 == A1 + +// Less + +static_assert(!(ScAddress(1, 0, 0) < ScAddress(1, 0, 0))); // B1 < B1 +static_assert(!(ScAddress(0, 1, 0) < ScAddress(0, 1, 0))); // A2 < A2 +static_assert(!(ScAddress(0, 0, 1) < ScAddress(0, 0, 1))); // Sheet2:A1 < Sheet2:A1 + +static_assert(ScAddress(0, 0, 0) < ScAddress(1, 0, 0)); // A1 < B1 +static_assert(ScAddress(0, 1, 0) < ScAddress(1, 0, 0)); // A2 < B1 +static_assert(ScAddress(0, 10000, 0) < ScAddress(1, 0, 0)); // A10000 < B1 +static_assert(ScAddress(0, 10000, 0) < ScAddress(1, 10000, 0)); // A10000 < B10000 +static_assert(ScAddress(1, 0, 0) < ScAddress(1, 0, 1)); // Sheet1:A1 < Sheet2:A1 + +// Less or Equal + +static_assert(ScAddress(1, 0, 0) <= ScAddress(1, 0, 0)); // B1 <= B1 +static_assert(ScAddress(0, 1, 0) <= ScAddress(0, 1, 0)); // A2 <= A2 +static_assert(ScAddress(0, 0, 1) <= ScAddress(0, 0, 1)); // Sheet2:A1 <= Sheet2:A1 + +static_assert(ScAddress(0, 0, 0) <= ScAddress(1, 0, 0)); // A1 <= B1 +static_assert(ScAddress(0, 1, 0) <= ScAddress(1, 0, 0)); // A2 <= B1 +static_assert(ScAddress(0, 10000, 0) <= ScAddress(1, 0, 0)); // A10000 <= B1 +static_assert(ScAddress(0, 10000, 0) <= ScAddress(1, 10000, 0)); // A10000 <= B10000 +static_assert(ScAddress(1, 0, 0) <= ScAddress(1, 0, 1)); // Sheet1:A1 <= Sheet2:A1 + +// More + +static_assert(!(ScAddress(1, 0, 0) > ScAddress(1, 0, 0))); // B1 > B1 +static_assert(!(ScAddress(0, 1, 0) > ScAddress(0, 1, 0))); // A2 > A2 +static_assert(!(ScAddress(0, 0, 1) > ScAddress(0, 0, 1))); // Sheet1:A1 > Sheet2:A1 + +static_assert(ScAddress(1, 0, 0) > ScAddress(0, 0, 0)); // B1 > A1 +static_assert(ScAddress(1, 0, 0) > ScAddress(0, 1, 0)); // B1 > A2 +static_assert(ScAddress(1, 0, 0) > ScAddress(0, 10000, 0)); // B1 > A10000 +static_assert(ScAddress(1, 10000, 0) > ScAddress(0, 10000, 0)); // B10000 > A10000 +static_assert(ScAddress(1, 0, 1) > ScAddress(1, 0, 0)); // Sheet2:A1 > Sheet1:A1 + +// More or Equal + +static_assert(ScAddress(1, 0, 0) >= ScAddress(1, 0, 0)); // B1 >= B1 +static_assert(ScAddress(0, 1, 0) >= ScAddress(0, 1, 0)); // A2 >= A2 +static_assert(ScAddress(0, 0, 1) >= ScAddress(0, 0, 1)); // Sheet1:A1 >= Sheet2:A1 + +static_assert(ScAddress(1, 0, 0) >= ScAddress(0, 0, 0)); // B1 >= A1 +static_assert(ScAddress(1, 0, 0) >= ScAddress(0, 1, 0)); // B1 >= A2 +static_assert(ScAddress(1, 0, 0) >= ScAddress(0, 10000, 0)); // B1 >= A10000 +static_assert(ScAddress(1, 10000, 0) >= ScAddress(0, 10000, 0)); // B10000 >= A10000 +static_assert(ScAddress(1, 0, 1) >= ScAddress(1, 0, 0)); // Sheet2:A1 >= Sheet1:A1 + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */