diff options
Diffstat (limited to '')
-rw-r--r-- | o3tl/CompilerTest_o3tl_temporary.mk | 16 | ||||
-rw-r--r-- | o3tl/CompilerTest_o3tl_unsafe_downcast.mk | 16 | ||||
-rw-r--r-- | o3tl/CppunitTest_o3tl_tests.mk | 40 | ||||
-rw-r--r-- | o3tl/Makefile | 7 | ||||
-rw-r--r-- | o3tl/Module_o3tl.mk | 31 | ||||
-rw-r--r-- | o3tl/README | 30 | ||||
-rw-r--r-- | o3tl/qa/compile-temporary.cxx | 25 | ||||
-rw-r--r-- | o3tl/qa/compile-unsafe_downcast.cxx | 32 | ||||
-rw-r--r-- | o3tl/qa/cow_wrapper_clients.cxx | 296 | ||||
-rw-r--r-- | o3tl/qa/cow_wrapper_clients.hxx | 210 | ||||
-rw-r--r-- | o3tl/qa/test-cow_wrapper.cxx | 263 | ||||
-rw-r--r-- | o3tl/qa/test-enumarray.cxx | 48 | ||||
-rw-r--r-- | o3tl/qa/test-lru_map.cxx | 318 | ||||
-rw-r--r-- | o3tl/qa/test-safeint.cxx | 119 | ||||
-rw-r--r-- | o3tl/qa/test-sorted_vector.cxx | 321 | ||||
-rw-r--r-- | o3tl/qa/test-span.cxx | 60 | ||||
-rw-r--r-- | o3tl/qa/test-typed_flags.cxx | 71 | ||||
-rw-r--r-- | o3tl/qa/test-vector_pool.cxx | 89 |
18 files changed, 1992 insertions, 0 deletions
diff --git a/o3tl/CompilerTest_o3tl_temporary.mk b/o3tl/CompilerTest_o3tl_temporary.mk new file mode 100644 index 000000000..fe8a830e0 --- /dev/null +++ b/o3tl/CompilerTest_o3tl_temporary.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*- +# +# 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_CompilerTest_CompilerTest,o3tl_temporary)) + +$(eval $(call gb_CompilerTest_add_exception_objects,o3tl_temporary, \ + o3tl/qa/compile-temporary \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/o3tl/CompilerTest_o3tl_unsafe_downcast.mk b/o3tl/CompilerTest_o3tl_unsafe_downcast.mk new file mode 100644 index 000000000..0fbc8a247 --- /dev/null +++ b/o3tl/CompilerTest_o3tl_unsafe_downcast.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*- +# +# 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_CompilerTest_CompilerTest,o3tl_unsafe_downcast)) + +$(eval $(call gb_CompilerTest_add_exception_objects,o3tl_unsafe_downcast, \ + o3tl/qa/compile-unsafe_downcast \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/o3tl/CppunitTest_o3tl_tests.mk b/o3tl/CppunitTest_o3tl_tests.mk new file mode 100644 index 000000000..152fa48c7 --- /dev/null +++ b/o3tl/CppunitTest_o3tl_tests.mk @@ -0,0 +1,40 @@ +# -*- 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/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_CppunitTest_CppunitTest,o3tl_tests)) + +$(eval $(call gb_CppunitTest_use_external,o3tl_tests,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,o3tl_tests,\ + sal \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,o3tl_tests,\ + o3tl/qa/cow_wrapper_clients \ + o3tl/qa/test-cow_wrapper \ + o3tl/qa/test-enumarray \ + o3tl/qa/test-lru_map \ + o3tl/qa/test-safeint \ + o3tl/qa/test-sorted_vector \ + o3tl/qa/test-span \ + o3tl/qa/test-typed_flags \ + o3tl/qa/test-vector_pool \ +)) + +# vim: set noet sw=4: diff --git a/o3tl/Makefile b/o3tl/Makefile new file mode 100644 index 000000000..ccb1c85a0 --- /dev/null +++ b/o3tl/Makefile @@ -0,0 +1,7 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/o3tl/Module_o3tl.mk b/o3tl/Module_o3tl.mk new file mode 100644 index 000000000..66f7d7a1c --- /dev/null +++ b/o3tl/Module_o3tl.mk @@ -0,0 +1,31 @@ +# +# 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/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Module_Module,o3tl)) + +$(eval $(call gb_Module_add_targets,o3tl,\ +)) + +$(eval $(call gb_Module_add_check_targets,o3tl,\ + CppunitTest_o3tl_tests \ + $(if $(COM_IS_CLANG),$(if $(COMPILER_EXTERNAL_TOOL)$(COMPILER_PLUGIN_TOOL),, \ + CompilerTest_o3tl_temporary \ + CompilerTest_o3tl_unsafe_downcast)) \ +)) + +# vim: set noet sw=4: diff --git a/o3tl/README b/o3tl/README new file mode 100644 index 000000000..7900e7017 --- /dev/null +++ b/o3tl/README @@ -0,0 +1,30 @@ +Very basic template functionality, a bit like boost or stl, but specific to LibO + +o3tl stands for "OOo [o3, get it?] template library" + +From [http://blog.thebehrens.net/2006/01/15/update-cow_wrapper-is-available-now/] +The scope for o3tl is admittedly kind of ambitious, as it should contain "...very basic (template) +functionality, comparable to what's provided by boost or stl, but specific to OOo (what comes to mind +are e.g. stl adapters for our own data types and UNO, and stuff that could in principle be upstreamed +to boost, but isn't as of now)." + +== Class overview == + +[git:o3tl/inc/o3tl/cow_wrapper.hxx] +A copy-on-write wrapper. + +[git:o3tl/inc/o3tl/lazy_update.hxx] +This template collects data in input type, and updates the output type with the given update functor, +but only if the output is requested. Useful if updating is expensive, or input changes frequently, but +output is only comparatively seldom used. + +[git:o3tl/inc/o3tl/range.hxx] +Represents a range of integer or iterator values. + +[git:o3tl/inc/o3tl/vector_pool.hxx] +Simple vector-based memory pool allocator. + +[git:o3tl/inc/o3tl/functional.hxx] +Some more templates, leftovers in spirit of STLport's old functional +header that are not part of the C++ standard (STLport has been +replaced by direct use of the C++ STL in LibreOffice). diff --git a/o3tl/qa/compile-temporary.cxx b/o3tl/qa/compile-temporary.cxx new file mode 100644 index 000000000..1d8d84bd5 --- /dev/null +++ b/o3tl/qa/compile-temporary.cxx @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <sal/config.h> + +#include <o3tl/temporary.hxx> + +void f(int*); + +int g(); + +void h(int n) +{ + f(&o3tl::temporary(int())); + f(&o3tl::temporary(g())); + f(&o3tl::temporary(n)); // expected-error {{}} expected-note@o3tl/temporary.hxx:* 0+ {{}} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/o3tl/qa/compile-unsafe_downcast.cxx b/o3tl/qa/compile-unsafe_downcast.cxx new file mode 100644 index 000000000..8471fc250 --- /dev/null +++ b/o3tl/qa/compile-unsafe_downcast.cxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <sal/config.h> + +#include <o3tl/unsafe_downcast.hxx> // expected-note@o3tl/unsafe_downcast.hxx:* 0+ {{}} + +struct Base +{ + virtual ~Base(); +}; + +struct Derived : Base +{ +}; + +void f(Base* b, Derived* d) +{ + o3tl::unsafe_downcast<Derived*>(b); + o3tl::unsafe_downcast<Derived const*>(b); + o3tl::unsafe_downcast<Derived&>(*b); // expected-error {{}} + o3tl::unsafe_downcast<Derived*>(d); + o3tl::unsafe_downcast<Base*>(d); // expected-error {{}} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/o3tl/qa/cow_wrapper_clients.cxx b/o3tl/qa/cow_wrapper_clients.cxx new file mode 100644 index 000000000..913165c83 --- /dev/null +++ b/o3tl/qa/cow_wrapper_clients.cxx @@ -0,0 +1,296 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "cow_wrapper_clients.hxx" +#include <rtl/instance.hxx> + +namespace o3tltests { + +class cow_wrapper_client2_impl +{ +public: + cow_wrapper_client2_impl() : mnValue(0) {} + explicit cow_wrapper_client2_impl( int nVal ) : mnValue(nVal) {} + void setValue( int nVal ) { mnValue = nVal; } + int getValue() const { return mnValue; } + + bool operator==( const cow_wrapper_client2_impl& rRHS ) const { return mnValue == rRHS.mnValue; } + bool operator!=( const cow_wrapper_client2_impl& rRHS ) const { return mnValue != rRHS.mnValue; } + bool operator<( const cow_wrapper_client2_impl& rRHS ) const { return mnValue < rRHS.mnValue; } + +private: + int mnValue; +}; + +cow_wrapper_client2::cow_wrapper_client2() : maImpl() +{ +} + +cow_wrapper_client2::cow_wrapper_client2( int nVal ) : + maImpl( cow_wrapper_client2_impl(nVal) ) +{ +} + +cow_wrapper_client2::~cow_wrapper_client2() +{ +} + +cow_wrapper_client2::cow_wrapper_client2( const cow_wrapper_client2& rSrc ) : + maImpl(rSrc.maImpl) +{ +} + +cow_wrapper_client2::cow_wrapper_client2( cow_wrapper_client2&& rSrc ) noexcept : + maImpl( std::move( rSrc.maImpl ) ) +{ +} + +cow_wrapper_client2& cow_wrapper_client2::operator=( const cow_wrapper_client2& rSrc ) +{ + maImpl = rSrc.maImpl; + + return *this; +} + +cow_wrapper_client2& cow_wrapper_client2::operator=(cow_wrapper_client2&& rSrc) noexcept +{ + maImpl = std::move(rSrc.maImpl); + + return *this; +} + +void cow_wrapper_client2::modify( int nVal ) +{ + maImpl->setValue( nVal ); +} + +int cow_wrapper_client2::queryUnmodified() const +{ + return maImpl->getValue(); +} + +void cow_wrapper_client2::makeUnique() +{ + maImpl.make_unique(); +} +bool cow_wrapper_client2::is_unique() const +{ + return maImpl.is_unique(); +} +oslInterlockedCount cow_wrapper_client2::use_count() const +{ + return maImpl.use_count(); +} +void cow_wrapper_client2::swap( cow_wrapper_client2& r ) +{ + o3tl::swap(maImpl, r.maImpl); +} + +bool cow_wrapper_client2::operator==( const cow_wrapper_client2& rRHS ) const +{ + return maImpl == rRHS.maImpl; +} +bool cow_wrapper_client2::operator!=( const cow_wrapper_client2& rRHS ) const +{ + return maImpl != rRHS.maImpl; +} +bool cow_wrapper_client2::operator<( const cow_wrapper_client2& rRHS ) const +{ + return maImpl < rRHS.maImpl; +} + + +cow_wrapper_client3::cow_wrapper_client3() : maImpl() +{ +} + +cow_wrapper_client3::cow_wrapper_client3( int nVal ) : + maImpl( cow_wrapper_client2_impl(nVal) ) +{ +} + +cow_wrapper_client3::~cow_wrapper_client3() +{ +} + +cow_wrapper_client3::cow_wrapper_client3( const cow_wrapper_client3& rSrc ) : + maImpl(rSrc.maImpl) +{ +} + +cow_wrapper_client3::cow_wrapper_client3( cow_wrapper_client3&& rSrc ) noexcept : + maImpl( std::move( rSrc.maImpl ) ) +{ +} + +cow_wrapper_client3& cow_wrapper_client3::operator=( const cow_wrapper_client3& rSrc ) +{ + maImpl = rSrc.maImpl; + + return *this; +} + +cow_wrapper_client3& cow_wrapper_client3::operator=(cow_wrapper_client3&& rSrc) noexcept +{ + maImpl = std::move(rSrc.maImpl); + + return *this; +} + +void cow_wrapper_client3::modify( int nVal ) +{ + maImpl->setValue( nVal ); +} + +int cow_wrapper_client3::queryUnmodified() const +{ + return maImpl->getValue(); +} + +void cow_wrapper_client3::makeUnique() +{ + maImpl.make_unique(); +} +bool cow_wrapper_client3::is_unique() const +{ + return maImpl.is_unique(); +} +oslInterlockedCount cow_wrapper_client3::use_count() const +{ + return maImpl.use_count(); +} +void cow_wrapper_client3::swap( cow_wrapper_client3& r ) +{ + o3tl::swap(maImpl, r.maImpl); +} + +bool cow_wrapper_client3::operator==( const cow_wrapper_client3& rRHS ) const +{ + return maImpl == rRHS.maImpl; +} +bool cow_wrapper_client3::operator!=( const cow_wrapper_client3& rRHS ) const +{ + return maImpl != rRHS.maImpl; +} +bool cow_wrapper_client3::operator<( const cow_wrapper_client3& rRHS ) const +{ + return maImpl < rRHS.maImpl; +} + + +namespace { struct theDefaultClient4 : public rtl::Static< o3tl::cow_wrapper< int >, + theDefaultClient4 > {}; } + +cow_wrapper_client4::cow_wrapper_client4() : + maImpl(theDefaultClient4::get()) +{ +} + +cow_wrapper_client4::cow_wrapper_client4( int nVal ) : + maImpl( nVal ) +{ +} + +cow_wrapper_client4::~cow_wrapper_client4() +{ +} + +cow_wrapper_client4::cow_wrapper_client4( const cow_wrapper_client4& rSrc ) : + maImpl(rSrc.maImpl) +{ +} + +cow_wrapper_client4& cow_wrapper_client4::operator=( const cow_wrapper_client4& rSrc ) +{ + maImpl = rSrc.maImpl; + + return *this; +} + +bool cow_wrapper_client4::is_default() const +{ + return maImpl.same_object(theDefaultClient4::get()); +} + +bool cow_wrapper_client4::operator==( const cow_wrapper_client4& rRHS ) const +{ + return maImpl == rRHS.maImpl; +} +bool cow_wrapper_client4::operator!=( const cow_wrapper_client4& rRHS ) const +{ + return maImpl != rRHS.maImpl; +} +bool cow_wrapper_client4::operator<( const cow_wrapper_client4& rRHS ) const +{ + return maImpl < rRHS.maImpl; +} + +bool BogusRefCountPolicy::s_bShouldIncrement = false; +bool BogusRefCountPolicy::s_bShouldDecrement = false; +sal_uInt32 BogusRefCountPolicy::s_nEndOfScope = 0; + +cow_wrapper_client5::cow_wrapper_client5() : + maImpl() +{ +} + +cow_wrapper_client5::cow_wrapper_client5(int nX) : + maImpl(nX) +{ +} + +cow_wrapper_client5::cow_wrapper_client5( const cow_wrapper_client5& rSrc ) : + maImpl( rSrc.maImpl ) +{ +} + +cow_wrapper_client5::cow_wrapper_client5( cow_wrapper_client5&& rSrc ) noexcept : + maImpl( std::move( rSrc.maImpl ) ) +{ +} + +cow_wrapper_client5::~cow_wrapper_client5() +{ +} + +cow_wrapper_client5& cow_wrapper_client5::operator=( const cow_wrapper_client5& rSrc ) +{ + maImpl = rSrc.maImpl; + + return *this; +} + +cow_wrapper_client5& cow_wrapper_client5::operator=(cow_wrapper_client5&& rSrc) noexcept +{ + maImpl = std::move( rSrc.maImpl ); + + return *this; +} + +bool cow_wrapper_client5::operator==( const cow_wrapper_client5& rSrc ) const { + return maImpl == rSrc.maImpl; +} + +bool cow_wrapper_client5::operator!=( const cow_wrapper_client5& rSrc ) const { + return maImpl != rSrc.maImpl; +} + +} // namespace o3tltests + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/o3tl/qa/cow_wrapper_clients.hxx b/o3tl/qa/cow_wrapper_clients.hxx new file mode 100644 index 000000000..36d77553b --- /dev/null +++ b/o3tl/qa/cow_wrapper_clients.hxx @@ -0,0 +1,210 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_O3TL_QA_COW_WRAPPER_CLIENTS_HXX +#define INCLUDED_O3TL_QA_COW_WRAPPER_CLIENTS_HXX + +#include <o3tl/cow_wrapper.hxx> +#include <cppunit/extensions/HelperMacros.h> +#include <assert.h> + +/* Definition of Cow_Wrapper_Clients classes */ + +namespace o3tltests { + +/** This is a header and a separate compilation unit on purpose - + cow_wrapper needs destructor, copy constructor and assignment + operator to be outline, when pimpl idiom is used + */ + +/// test non-opaque impl type +class cow_wrapper_client1 +{ +public: + cow_wrapper_client1() : maImpl() {} + explicit cow_wrapper_client1( int nVal ) : maImpl(nVal) {} + + void modify( int nVal ) { *maImpl = nVal; } + int queryUnmodified() const { return *maImpl; } + + void makeUnique() { maImpl.make_unique(); } + bool is_unique() const { return maImpl.is_unique(); } + oslInterlockedCount use_count() const { return maImpl.use_count(); } + void swap( cow_wrapper_client1& r ) { o3tl::swap(maImpl, r.maImpl); } + + bool operator==( const cow_wrapper_client1& rRHS ) const { return maImpl == rRHS.maImpl; } + bool operator!=( const cow_wrapper_client1& rRHS ) const { return maImpl != rRHS.maImpl; } + bool operator<( const cow_wrapper_client1& rRHS ) const { return maImpl < rRHS.maImpl; } + +private: + o3tl::cow_wrapper< int > maImpl; +}; + + +class cow_wrapper_client2_impl; + +/** test opaque impl type - need to explicitly declare lifetime + methods + */ +class cow_wrapper_client2 +{ +public: + cow_wrapper_client2(); + explicit cow_wrapper_client2( int nVal ); + ~cow_wrapper_client2(); + + cow_wrapper_client2( const cow_wrapper_client2& ); + cow_wrapper_client2(cow_wrapper_client2&&) noexcept; + cow_wrapper_client2& operator=( const cow_wrapper_client2& ); + cow_wrapper_client2& operator=(cow_wrapper_client2&&) noexcept; + + void modify( int nVal ); + int queryUnmodified() const; + + void makeUnique(); + bool is_unique() const; + oslInterlockedCount use_count() const; + void swap( cow_wrapper_client2& r ); + + bool operator==( const cow_wrapper_client2& rRHS ) const; + bool operator!=( const cow_wrapper_client2& rRHS ) const; + bool operator<( const cow_wrapper_client2& rRHS ) const; + +private: + o3tl::cow_wrapper< cow_wrapper_client2_impl > maImpl; +}; + +/** test MT-safe cow_wrapper - basically the same as + cow_wrapper_client2, only with different refcounting policy + */ +class cow_wrapper_client3 +{ +public: + cow_wrapper_client3(); + explicit cow_wrapper_client3( int nVal ); + ~cow_wrapper_client3(); + + cow_wrapper_client3( const cow_wrapper_client3& ); + cow_wrapper_client3(cow_wrapper_client3&&) noexcept; + cow_wrapper_client3& operator=( const cow_wrapper_client3& ); + cow_wrapper_client3& operator=(cow_wrapper_client3&&) noexcept; + + void modify( int nVal ); + int queryUnmodified() const; + + void makeUnique(); + bool is_unique() const; + oslInterlockedCount use_count() const; + void swap( cow_wrapper_client3& r ); + + bool operator==( const cow_wrapper_client3& rRHS ) const; + bool operator!=( const cow_wrapper_client3& rRHS ) const; + bool operator<( const cow_wrapper_client3& rRHS ) const; + +private: + o3tl::cow_wrapper< cow_wrapper_client2_impl, o3tl::ThreadSafeRefCountingPolicy > maImpl; +}; + +/** test default-object comparison - have default-stored-client4 share + the same static impl instance, check if isDefault does the right + thing + */ +class cow_wrapper_client4 +{ +public: + cow_wrapper_client4(); + explicit cow_wrapper_client4(int); + ~cow_wrapper_client4(); + + cow_wrapper_client4( const cow_wrapper_client4& ); + cow_wrapper_client4& operator=( const cow_wrapper_client4& ); + + bool is_default() const; + + bool operator==( const cow_wrapper_client4& rRHS ) const; + bool operator!=( const cow_wrapper_client4& rRHS ) const; + bool operator<( const cow_wrapper_client4& rRHS ) const; + +private: + o3tl::cow_wrapper< int > maImpl; +}; + +// singleton ref-counting policy used to keep track of when +// incrementing and decrementing occurs +struct BogusRefCountPolicy +{ + static bool s_bShouldIncrement; + static bool s_bShouldDecrement; + static sal_uInt32 s_nEndOfScope; + typedef sal_uInt32 ref_count_t; + static void incrementCount( ref_count_t& rCount ) { + assert(s_bShouldIncrement && "Ref-counting policy incremented when it should not have."); + ++rCount; + s_bShouldIncrement = false; + } + static bool decrementCount( ref_count_t& rCount ) { + assert((s_nEndOfScope || s_bShouldDecrement) && "Ref-counting policy decremented when it should not have."); + if(s_nEndOfScope) + { + --rCount; + --s_nEndOfScope; + } + else if(s_bShouldDecrement) + { + --rCount; + s_bShouldDecrement = false; + } + return rCount != 0; + } +}; + +class cow_wrapper_client5 +{ +public: + cow_wrapper_client5(); + explicit cow_wrapper_client5(int); + ~cow_wrapper_client5(); + + cow_wrapper_client5( const cow_wrapper_client5& ); + cow_wrapper_client5(cow_wrapper_client5&&) noexcept; + cow_wrapper_client5& operator=( const cow_wrapper_client5& ); + cow_wrapper_client5& operator=(cow_wrapper_client5&&) noexcept; + + int queryUnmodified() const { return *maImpl; } + sal_uInt32 use_count() const { return maImpl.use_count(); } + + bool operator==( const cow_wrapper_client5& rRHS ) const; + bool operator!=( const cow_wrapper_client5& rRHS ) const; + +private: + o3tl::cow_wrapper< int, BogusRefCountPolicy > maImpl; +}; + +template< typename charT, typename traits > +inline std::basic_ostream<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & stream, const cow_wrapper_client5& client ) +{ + return stream << client.queryUnmodified(); +} + +} // namespace o3tltests + +#endif // INCLUDED_O3TL_QA_COW_WRAPPER_CLIENTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/o3tl/qa/test-cow_wrapper.cxx b/o3tl/qa/test-cow_wrapper.cxx new file mode 100644 index 000000000..b5d4936d5 --- /dev/null +++ b/o3tl/qa/test-cow_wrapper.cxx @@ -0,0 +1,263 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include "cow_wrapper_clients.hxx" + +using namespace ::o3tl; +using namespace ::o3tltests; + + +class cow_wrapper_test : public CppUnit::TestFixture +{ +public: + template< class T > void test( T& rTestObj1, T& rTestObj2, T& rTestObj3 ) + { + CPPUNIT_ASSERT_MESSAGE("rTestObj1 is unique", + rTestObj1.is_unique() ); + CPPUNIT_ASSERT_MESSAGE("rTestObj2 is unique", + rTestObj2.is_unique() ); + CPPUNIT_ASSERT_MESSAGE("rTestObj3 is unique", + rTestObj3.is_unique() ); + + CPPUNIT_ASSERT_MESSAGE("rTestObj1 != rTestObj2", + rTestObj1 != rTestObj2 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj2 != rTestObj3", + rTestObj2 != rTestObj3 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1 != rTestObj3", + rTestObj1 != rTestObj3 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1 < rTestObj2", + rTestObj1 < rTestObj2 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj2 < rTestObj3", + rTestObj2 < rTestObj3 ); + + rTestObj2 = rTestObj1; + rTestObj3 = rTestObj1; + CPPUNIT_ASSERT_MESSAGE("rTestObj1 == rTestObj2", + rTestObj1 == rTestObj2 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1 == rTestObj3", + rTestObj1 == rTestObj3 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1.use_count() == 3", + rTestObj1.use_count() == 3 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj2.use_count() == 3", + rTestObj2.use_count() == 3 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj3.use_count() == 3", + rTestObj3.use_count() == 3 ); + + rTestObj2.makeUnique(); + CPPUNIT_ASSERT_MESSAGE("rTestObj1 == rTestObj2", + rTestObj1 == rTestObj2 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1 == rTestObj3", + rTestObj1 == rTestObj3 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1.use_count() == 2", + rTestObj1.use_count() == 2 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj2.use_count() == 1", + rTestObj2.use_count() == 1 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj2.is_unique()", + rTestObj2.is_unique() ); + CPPUNIT_ASSERT_MESSAGE("rTestObj3.use_count() == 2", + rTestObj3.use_count() == 2 ); + + rTestObj2.swap( rTestObj3 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1 == rTestObj2", + rTestObj1 == rTestObj2 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1 == rTestObj3", + rTestObj1 == rTestObj3 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj1.use_count() == 2", + rTestObj1.use_count() == 2 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj2.use_count() == 2", + rTestObj2.use_count() == 2 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj3.use_count() == 1", + rTestObj3.use_count() == 1 ); + CPPUNIT_ASSERT_MESSAGE("rTestObj3.is_unique()", + rTestObj3.is_unique() ); + } + + void testCowWrapper() + { + // setup + cow_wrapper_client1 aTestObj1; + cow_wrapper_client1 aTestObj2; + cow_wrapper_client1 aTestObj3; + + cow_wrapper_client2 aTestObj4; + cow_wrapper_client2 aTestObj5; + cow_wrapper_client2 aTestObj6; + + cow_wrapper_client3 aTestObj7; + cow_wrapper_client3 aTestObj8; + cow_wrapper_client3 aTestObj9; + + { + aTestObj1 = cow_wrapper_client1( 1 ); + CPPUNIT_ASSERT_EQUAL(1, aTestObj1.queryUnmodified()); + aTestObj2.modify( 2 ); + CPPUNIT_ASSERT_EQUAL(2, aTestObj2.queryUnmodified()); + aTestObj3.modify( 3 ); + CPPUNIT_ASSERT_EQUAL(3, aTestObj3.queryUnmodified()); + + aTestObj4 = cow_wrapper_client2( 4 ); + CPPUNIT_ASSERT_EQUAL(4, aTestObj4.queryUnmodified()); + aTestObj5.modify( 5 ); + CPPUNIT_ASSERT_EQUAL(5, aTestObj5.queryUnmodified()); + aTestObj6.modify( 6 ); + CPPUNIT_ASSERT_EQUAL(6, aTestObj6.queryUnmodified()); + + aTestObj7 = cow_wrapper_client3( 7 ); + CPPUNIT_ASSERT_EQUAL(7, aTestObj7.queryUnmodified()); + aTestObj8.modify( 8 ); + CPPUNIT_ASSERT_EQUAL(8, aTestObj8.queryUnmodified()); + aTestObj9.modify( 9 ); + CPPUNIT_ASSERT_EQUAL(9, aTestObj9.queryUnmodified()); + } + // all three temporaries are dead now + + // test + test( aTestObj1, aTestObj2, aTestObj3 ); + test( aTestObj4, aTestObj5, aTestObj6 ); + test( aTestObj7, aTestObj8, aTestObj9 ); + } + + void testStaticDefault() + { + cow_wrapper_client4 aTestObj1; + cow_wrapper_client4 aTestObj2; + cow_wrapper_client4 aTestObj3(4); + + CPPUNIT_ASSERT_MESSAGE("aTestObj1.is_default()", + aTestObj1.is_default() ); + CPPUNIT_ASSERT_MESSAGE("aTestObj2.is_default()", + aTestObj2.is_default() ); + CPPUNIT_ASSERT_MESSAGE("!aTestObj3.is_default()", + !aTestObj3.is_default() ); + aTestObj1 = aTestObj2; + CPPUNIT_ASSERT_MESSAGE("aTestObj1.is_default() #2", + aTestObj1.is_default() ); + CPPUNIT_ASSERT_MESSAGE("aTestObj2.is_default() #2", + aTestObj2.is_default() ); + aTestObj1 = aTestObj3; + CPPUNIT_ASSERT_MESSAGE("!aTestObj1.is_default()", + !aTestObj1.is_default() ); + } + + void testRefCounting() + { + // add scope to ensure appropriate number of calls to + // the reference counting policy have been made + { + // if any incrementing/decrementing occurs a failure + // will occur + cow_wrapper_client5 aTestObj1(1); + cow_wrapper_client5 aTestObj2( std::move( aTestObj1 ) ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj2.use_count()", + static_cast<sal_uInt32>(1), aTestObj2.use_count() ); + + // the following should increment + BogusRefCountPolicy::s_bShouldIncrement = true; + cow_wrapper_client5 aTestObj3( aTestObj2 ); + CPPUNIT_ASSERT_MESSAGE("s_bShouldIncrement == 0", + !BogusRefCountPolicy::s_bShouldIncrement ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj3.use_count()", + static_cast<sal_uInt32>(2), aTestObj3.use_count() ); + { + cow_wrapper_client5 aTestObj4; + // the following should decrement the lvalue and then increment the rvalue + BogusRefCountPolicy::s_bShouldIncrement = true; + BogusRefCountPolicy::s_bShouldDecrement = true; + aTestObj4 = aTestObj2; + CPPUNIT_ASSERT_MESSAGE("s_bShouldIncrement == 0", + !BogusRefCountPolicy::s_bShouldIncrement ); + CPPUNIT_ASSERT_MESSAGE("s_bShouldDecrement == 0", + !BogusRefCountPolicy::s_bShouldDecrement ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj2.use_count()", + static_cast<sal_uInt32>(3), aTestObj2.use_count() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj3.use_count()", + static_cast<sal_uInt32>(3), aTestObj3.use_count() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj4.use_count()", + static_cast<sal_uInt32>(3), aTestObj4.use_count() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj2 == aTestObj3", + aTestObj3, aTestObj2 ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj3 == aTestObj4", + aTestObj4, aTestObj3 ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj2 == aTestObj4", + aTestObj4, aTestObj2 ); + + // only decrement the lvalue before assignment + BogusRefCountPolicy::s_bShouldDecrement = true; + aTestObj4 = cow_wrapper_client5( 4 ); + CPPUNIT_ASSERT_MESSAGE("s_bShouldIncrement == 0", + !BogusRefCountPolicy::s_bShouldIncrement ); + + // only one call should be made to the ref counting policy's + // decrementing function at the end of the scope + BogusRefCountPolicy::s_bShouldDecrement = true; + } + CPPUNIT_ASSERT_MESSAGE("s_bShouldDecrement == 0", + !BogusRefCountPolicy::s_bShouldDecrement ); + + // self assignment + // aTestObj2 is defunct afterwards, one decrement happens + BogusRefCountPolicy::s_bShouldDecrement = true; + aTestObj3 = std::move( aTestObj2 ); + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj2.use_count()", + static_cast<sal_uInt32>(0), aTestObj2.use_count() ); // NOLINT(bugprone-use-after-move) + CPPUNIT_ASSERT_EQUAL_MESSAGE("aTestObj3.use_count()", + static_cast<sal_uInt32>(1), aTestObj3.use_count() ); + + cow_wrapper_client5 aTestObj5; + + // only decrement the lvalue before assignment + BogusRefCountPolicy::s_bShouldDecrement = true; + aTestObj3 = std::move( aTestObj5 ); + CPPUNIT_ASSERT_MESSAGE("s_bShouldDecrement == 0", + !BogusRefCountPolicy::s_bShouldDecrement); + + // one call should be made to the ref-counting policy's + // decrementing function at the end of the scope. Only + // aTestObj3 still holds a valid instance + BogusRefCountPolicy::s_nEndOfScope = 1; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("s_EndOfScope", + static_cast<sal_uInt32>(0), BogusRefCountPolicy::s_nEndOfScope ); + } + + // Change the following lines only, if you add, remove or rename + // member functions of the current class, + // because these macros are need by auto register mechanism. + + CPPUNIT_TEST_SUITE(cow_wrapper_test); + CPPUNIT_TEST(testCowWrapper); + CPPUNIT_TEST(testStaticDefault); + CPPUNIT_TEST(testRefCounting); + CPPUNIT_TEST_SUITE_END(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(cow_wrapper_test); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/o3tl/qa/test-enumarray.cxx b/o3tl/qa/test-enumarray.cxx new file mode 100644 index 000000000..9da8dae18 --- /dev/null +++ b/o3tl/qa/test-enumarray.cxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <sal/config.h> + +#include <stdexcept> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <o3tl/enumarray.hxx> + +namespace { + +class Test: public CppUnit::TestFixture { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testOperations); + CPPUNIT_TEST_SUITE_END(); + + + void testOperations() { + enum class MyEnum { ONE, TWO, THREE, LAST = THREE }; + o3tl::enumarray<MyEnum, int> aModules; + + aModules[MyEnum::ONE] = 1; + aModules[MyEnum::TWO] = 1; + aModules[MyEnum::THREE] = 1; + + o3tl::enumarray<MyEnum, int> const & rModules = aModules; + + for (auto const & i : rModules) + CPPUNIT_ASSERT_EQUAL( 1, i ); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/o3tl/qa/test-lru_map.cxx b/o3tl/qa/test-lru_map.cxx new file mode 100644 index 000000000..a03a6bf37 --- /dev/null +++ b/o3tl/qa/test-lru_map.cxx @@ -0,0 +1,318 @@ +/* -*- 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 <sal/types.h> +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <o3tl/lru_map.hxx> + +#include <boost/functional/hash.hpp> + +using namespace ::o3tl; + +class lru_map_test : public CppUnit::TestFixture +{ +public: + void testBaseUsage(); + void testReplaceKey(); + void testReplaceValue(); + void testLruRemoval(); + void testCustomHash(); + void testRemoveIf(); + void testNoAutoCleanup(); + + CPPUNIT_TEST_SUITE(lru_map_test); + CPPUNIT_TEST(testBaseUsage); + CPPUNIT_TEST(testReplaceKey); + CPPUNIT_TEST(testReplaceValue); + CPPUNIT_TEST(testLruRemoval); + CPPUNIT_TEST(testCustomHash); + CPPUNIT_TEST(testRemoveIf); + CPPUNIT_TEST(testNoAutoCleanup); + CPPUNIT_TEST_SUITE_END(); +}; + +void lru_map_test::testBaseUsage() +{ + o3tl::lru_map<int, int> lru(10); + lru.insert(std::make_pair<int, int>(1, 1)); + + std::pair<int, int> pair; + for (int i = 2; i < 7; i++) + { + pair.first = pair.second = i; + lru.insert(pair); + } + + CPPUNIT_ASSERT_EQUAL(size_t(6), lru.size()); + + o3tl::lru_map<int, int>::const_iterator it; + + it = lru.find(2); + CPPUNIT_ASSERT(it != lru.end()); + CPPUNIT_ASSERT_EQUAL(2, it->second); + + it = lru.find(5); + CPPUNIT_ASSERT(it != lru.end()); + CPPUNIT_ASSERT_EQUAL(5, it->second); + + it = lru.find(0); + CPPUNIT_ASSERT(bool(it == lru.end())); +} + +void lru_map_test::testReplaceValue() +{ + o3tl::lru_map<int, int> lru(2); + // check if map is empty + CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size()); + + // check if inserting entry with same key replaces the value + + // inserting new entry + lru.insert(std::make_pair<int, int>(1, 2)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + CPPUNIT_ASSERT_EQUAL(2, lru.find(1)->second); + + // inserting new entry with key that already exists + lru.insert(std::make_pair<int, int>(1, 4)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + CPPUNIT_ASSERT_EQUAL(4, lru.find(1)->second); + + // inserting new entry + lru.insert(std::make_pair<int, int>(2, 200)); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT_EQUAL(4, lru.find(1)->second); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + + // check if insert with same key, moves the entry back of the lru queue + + // inserting new entry with key that already exists + lru.insert(std::make_pair<int, int>(1, 6)); + // inserting new entry, lru removed + lru.insert(std::make_pair<int, int>(3, 300)); + + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT_EQUAL(6, lru.find(1)->second); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + +} + +void lru_map_test::testReplaceKey() +{ + o3tl::lru_map<int, int> lru(2); + + // inserting new entry + lru.insert(std::make_pair<int, int>(1, 100)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + CPPUNIT_ASSERT_EQUAL(100, lru.find(1)->second); + CPPUNIT_ASSERT(bool(lru.find(2) == lru.end())); + CPPUNIT_ASSERT(bool(lru.find(3) == lru.end())); + + // inserting new entry + lru.insert(std::make_pair<int, int>(2, 200)); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT_EQUAL(100, lru.find(1)->second); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT(bool(lru.find(3) == lru.end())); + + // inserting new entry, lru entry is removed + lru.insert(std::make_pair<int, int>(3, 300)); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT(bool(lru.find(1) == lru.end())); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + + // inserting new entry, lru entry is removed + std::pair<int, int> pair(4, 400); + lru.insert(pair); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + CPPUNIT_ASSERT(bool(lru.find(1) == lru.end())); + CPPUNIT_ASSERT(bool(lru.find(2) == lru.end())); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + CPPUNIT_ASSERT_EQUAL(400, lru.find(4)->second); +} + +void lru_map_test::testLruRemoval() +{ + o3tl::lru_map<int, int> lru(5); + CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size()); + + // fill up... + lru.insert(std::make_pair<int, int>(1, 100)); + lru.insert(std::make_pair<int, int>(2, 200)); + lru.insert(std::make_pair<int, int>(3, 300)); + lru.insert(std::make_pair<int, int>(4, 400)); + lru.insert(std::make_pair<int, int>(5, 500)); + CPPUNIT_ASSERT_EQUAL(size_t(5), lru.size()); + CPPUNIT_ASSERT_EQUAL(100, lru.find(1)->second); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + CPPUNIT_ASSERT_EQUAL(400, lru.find(4)->second); + CPPUNIT_ASSERT_EQUAL(500, lru.find(5)->second); + + // add one more entry - lru entry should be removed + lru.insert(std::make_pair<int, int>(6, 600)); + + CPPUNIT_ASSERT_EQUAL(size_t(5), lru.size()); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT_EQUAL(300, lru.find(3)->second); + CPPUNIT_ASSERT_EQUAL(400, lru.find(4)->second); + CPPUNIT_ASSERT_EQUAL(500, lru.find(5)->second); + CPPUNIT_ASSERT_EQUAL(600, lru.find(6)->second); + + // access the lru entry to put it at the back of the lru queue + lru.find(2); + // add new entry - lru entry should be removed + lru.insert(std::make_pair<int, int>(7, 700)); + + CPPUNIT_ASSERT_EQUAL(size_t(5), lru.size()); + CPPUNIT_ASSERT_EQUAL(200, lru.find(2)->second); + CPPUNIT_ASSERT_EQUAL(400, lru.find(4)->second); + CPPUNIT_ASSERT_EQUAL(500, lru.find(5)->second); + CPPUNIT_ASSERT_EQUAL(600, lru.find(6)->second); + CPPUNIT_ASSERT_EQUAL(700, lru.find(7)->second); +} + +namespace { + +struct TestClassKey +{ + int mA; + int mB; + + TestClassKey(int a, int b) + : mA(a) + , mB(b) + {} + + bool operator==(TestClassKey const& aOther) const + { + return mA == aOther.mA + && mB == aOther.mB; + } +}; + +struct TestClassKeyHashFunction +{ + std::size_t operator()(TestClassKey const& aKey) const + { + std::size_t seed = 0; + boost::hash_combine(seed, aKey.mA); + boost::hash_combine(seed, aKey.mB); + return seed; + } +}; + +} + +void lru_map_test::testCustomHash() +{ + // check lru_map with custom hash function + o3tl::lru_map<TestClassKey, int, TestClassKeyHashFunction> lru(2); + CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size()); + + lru.insert(std::make_pair<TestClassKey, int>(TestClassKey(1,1), 2)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + + lru.insert(std::make_pair<TestClassKey, int>(TestClassKey(1,1), 7)); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + + lru.insert(std::make_pair<TestClassKey, int>(TestClassKey(1,2), 9)); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + + CPPUNIT_ASSERT(bool(lru.end() == lru.find(TestClassKey(0,0)))); // non existent + CPPUNIT_ASSERT_EQUAL(7, lru.find(TestClassKey(1,1))->second); + CPPUNIT_ASSERT_EQUAL(9, lru.find(TestClassKey(1,2))->second); + + lru.insert(std::make_pair<TestClassKey, int>(TestClassKey(2,1), 13)); + + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + + CPPUNIT_ASSERT(bool(lru.end() == lru.find(TestClassKey(1,1)))); + CPPUNIT_ASSERT_EQUAL(9, lru.find(TestClassKey(1,2))->second); + CPPUNIT_ASSERT_EQUAL(13, lru.find(TestClassKey(2,1))->second); +} + +void lru_map_test::testRemoveIf() +{ + typedef o3tl::lru_map<int, int> IntMap; + typedef IntMap::key_value_pair_t IntMapPair; + struct limit_except : public std::exception {}; + + IntMap lru(6); + int i = 0; + for (; i < 8; i++) + lru.insert({i, i}); + CPPUNIT_ASSERT_EQUAL(size_t(6), lru.size()); + // now contains 7..2 + + // remove everything < 4 from the back + try + { + lru.remove_if([] (IntMapPair const& rPair) { + if (rPair.first >= 4) + throw limit_except(); + return true; + }); + CPPUNIT_ASSERT(false); // not reached + } + catch (limit_except&) + { + // contains 7..4 + CPPUNIT_ASSERT_EQUAL(size_t(4), lru.size()); + } + + // remove all even numbers + lru.remove_if([] (IntMapPair const& rPair) { return (0 == rPair.first % 2); }); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + // contains 7, 5 + + lru.insert({5, 5}); + // contains 5, 7 + + i = 5; + for (auto &rPair : lru) + { + CPPUNIT_ASSERT_EQUAL(i, rPair.first); + i += 2; + } + + // remove the first item + lru.remove_if([] (IntMapPair const& rPair) { return (rPair.first == 5); }); + CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size()); + + // remove the only item + lru.remove_if([] (IntMapPair const& rPair) { return (rPair.first == 7); }); + CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size()); +} + +void lru_map_test::testNoAutoCleanup() +{ + o3tl::lru_map<int, int> lru(0); + CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size()); + lru.insert({0,0}); + lru.insert({1,1}); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + lru.insert({0,0}); + CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size()); + + int i = 0; + for (auto &rPair : lru) + { + CPPUNIT_ASSERT_EQUAL(i, rPair.first); + ++i; + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(lru_map_test); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/o3tl/qa/test-safeint.cxx b/o3tl/qa/test-safeint.cxx new file mode 100644 index 000000000..19269d4b0 --- /dev/null +++ b/o3tl/qa/test-safeint.cxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <sal/config.h> + +#include <limits> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <o3tl/safeint.hxx> + +namespace { + +class Test: public CppUnit::TestFixture { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testSignedSaturatingAdd); + CPPUNIT_TEST(testUnsignedSaturatingAdd); + CPPUNIT_TEST_SUITE_END(); + + void testSignedSaturatingAdd() { + auto const min = std::numeric_limits<int>::min(); + auto const max = std::numeric_limits<int>::max(); + + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(min, min)); + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(min, min + 1)); + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(min, -1)); + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(min, 0)); + CPPUNIT_ASSERT_EQUAL(min + 1, o3tl::saturating_add(min, 1)); + CPPUNIT_ASSERT_EQUAL(min + max - 1, o3tl::saturating_add(min, max - 1)); + CPPUNIT_ASSERT_EQUAL(min + max, o3tl::saturating_add(min, max)); + + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(min + 1, min)); + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(min + 1, min + 1)); + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(min + 1, -1)); + CPPUNIT_ASSERT_EQUAL(min + 1, o3tl::saturating_add(min + 1, 0)); + CPPUNIT_ASSERT_EQUAL(min + 2, o3tl::saturating_add(min + 1, 1)); + CPPUNIT_ASSERT_EQUAL(min + max, o3tl::saturating_add(min + 1, max - 1)); + CPPUNIT_ASSERT_EQUAL(min + max + 1, o3tl::saturating_add(min + 1, max)); + + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(-1, min)); + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(-1, min + 1)); + CPPUNIT_ASSERT_EQUAL(-2, o3tl::saturating_add(-1, -1)); + CPPUNIT_ASSERT_EQUAL(-1, o3tl::saturating_add(-1, 0)); + CPPUNIT_ASSERT_EQUAL(0, o3tl::saturating_add(-1, 1)); + CPPUNIT_ASSERT_EQUAL(max - 2, o3tl::saturating_add(-1, max - 1)); + CPPUNIT_ASSERT_EQUAL(max - 1, o3tl::saturating_add(-1, max)); + + CPPUNIT_ASSERT_EQUAL(min, o3tl::saturating_add(0, min)); + CPPUNIT_ASSERT_EQUAL(min + 1, o3tl::saturating_add(0, min + 1)); + CPPUNIT_ASSERT_EQUAL(-1, o3tl::saturating_add(0, -1)); + CPPUNIT_ASSERT_EQUAL(0, o3tl::saturating_add(0, 0)); + CPPUNIT_ASSERT_EQUAL(1, o3tl::saturating_add(0, 1)); + CPPUNIT_ASSERT_EQUAL(max - 1, o3tl::saturating_add(0, max - 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(0, max)); + + CPPUNIT_ASSERT_EQUAL(min + 1, o3tl::saturating_add(1, min)); + CPPUNIT_ASSERT_EQUAL(min + 2, o3tl::saturating_add(1, min + 1)); + CPPUNIT_ASSERT_EQUAL(0, o3tl::saturating_add(1, -1)); + CPPUNIT_ASSERT_EQUAL(1, o3tl::saturating_add(1, 0)); + CPPUNIT_ASSERT_EQUAL(2, o3tl::saturating_add(1, 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(1, max - 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(1, max)); + + CPPUNIT_ASSERT_EQUAL(min + max - 1, o3tl::saturating_add(max - 1, min)); + CPPUNIT_ASSERT_EQUAL(min + max, o3tl::saturating_add(max - 1, min + 1)); + CPPUNIT_ASSERT_EQUAL(max - 2, o3tl::saturating_add(max - 1, -1)); + CPPUNIT_ASSERT_EQUAL(max - 1, o3tl::saturating_add(max - 1, 0)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max - 1, 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max - 1, max - 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max - 1, max)); + + CPPUNIT_ASSERT_EQUAL(min + max, o3tl::saturating_add(max, min)); + CPPUNIT_ASSERT_EQUAL(min + max + 1, o3tl::saturating_add(max, min + 1)); + CPPUNIT_ASSERT_EQUAL(max - 1, o3tl::saturating_add(max, -1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max, 0)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max, 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max, max - 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max, max)); + } + + void testUnsignedSaturatingAdd() { + auto const max = std::numeric_limits<unsigned int>::max(); + + CPPUNIT_ASSERT_EQUAL(0U, o3tl::saturating_add(0U, 0U)); + CPPUNIT_ASSERT_EQUAL(1U, o3tl::saturating_add(0U, 1U)); + CPPUNIT_ASSERT_EQUAL(max - 1, o3tl::saturating_add(0U, max - 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(0U, max)); + + CPPUNIT_ASSERT_EQUAL(1U, o3tl::saturating_add(1U, 0U)); + CPPUNIT_ASSERT_EQUAL(2U, o3tl::saturating_add(1U, 1U)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(1U, max - 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(1U, max)); + + CPPUNIT_ASSERT_EQUAL(max - 1, o3tl::saturating_add(max - 1, 0U)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max - 1, 1U)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max - 1, max - 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max - 1, max)); + + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max, 0U)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max, 1U)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max, max - 1)); + CPPUNIT_ASSERT_EQUAL(max, o3tl::saturating_add(max, max)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/o3tl/qa/test-sorted_vector.cxx b/o3tl/qa/test-sorted_vector.cxx new file mode 100644 index 000000000..8b335040e --- /dev/null +++ b/o3tl/qa/test-sorted_vector.cxx @@ -0,0 +1,321 @@ +/* -*- 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 <memory> +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <o3tl/sorted_vector.hxx> +#include <rtl/ustring.hxx> + +using namespace ::o3tl; + +namespace { + +// helper class +class SwContent +{ +public: + int x; + + explicit SwContent(int x_) : x(x_) {} + + bool operator<( const SwContent &rCmp) const + { + return x < rCmp.x; + } +}; + +} + +class sorted_vector_test : public CppUnit::TestFixture +{ +public: + void testBasics() + { + o3tl::sorted_vector<SwContent*, o3tl::less_ptr_to<SwContent> > aVec; + + // create 4 test elements + std::unique_ptr<SwContent> p1( new SwContent(1) ); + std::unique_ptr<SwContent> p2( new SwContent(2) ); + SwContent *p3 = new SwContent(3); + std::unique_ptr<SwContent> p4( new SwContent(4) ); + + // insert p3, p1 -> not present -> second is true + CPPUNIT_ASSERT( aVec.insert(p3).second ); + CPPUNIT_ASSERT( aVec.insert(p1.get()).second ); + // insert p3 again -> already present -> second is false + CPPUNIT_ASSERT( !aVec.insert(p3).second ); + + // 2 element should be present + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(2), aVec.size() ); + + // check the order -> should be p1, p3 + // by index access + CPPUNIT_ASSERT_EQUAL( p1.get(), aVec[0] ); + CPPUNIT_ASSERT_EQUAL( p3, aVec[1] ); + // by begin, end + CPPUNIT_ASSERT_EQUAL( p1.get(), *aVec.begin() ); + CPPUNIT_ASSERT_EQUAL( p3, *(aVec.end()-1) ); + // by front, back + CPPUNIT_ASSERT_EQUAL( p1.get(), aVec.front() ); + CPPUNIT_ASSERT_EQUAL( p3, aVec.back() ); + + // find elements + CPPUNIT_ASSERT( aVec.find(p1.get()) != aVec.end() ); + CPPUNIT_ASSERT_EQUAL( static_cast<std::ptrdiff_t>(0), aVec.find(p1.get()) - aVec.begin() ); + CPPUNIT_ASSERT( aVec.find(p3) != aVec.end() ); + CPPUNIT_ASSERT_EQUAL( static_cast<std::ptrdiff_t>(1), aVec.find(p3) - aVec.begin() ); + CPPUNIT_ASSERT( bool(aVec.find(p2.get()) == aVec.end()) ); + CPPUNIT_ASSERT( bool(aVec.find(p4.get()) == aVec.end()) ); + + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.erase(p1.get()) ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.size() ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.erase(p2.get()) ); + + aVec.DeleteAndDestroyAll(); + } + + void testErase() + { + o3tl::sorted_vector<SwContent*, o3tl::less_ptr_to<SwContent> > aVec; + SwContent *p1 = new SwContent(1); + SwContent *p2 = new SwContent(2); + SwContent *p3 = new SwContent(3); + std::unique_ptr<SwContent> p4( new SwContent(4) ); + + aVec.insert(p1); + aVec.insert(p2); + aVec.insert(p3); + + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.erase(p1) ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(2), aVec.size() ); + + aVec.erase(1); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.size() ); + + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.erase(p4.get()) ); + + aVec.clear(); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.size() ); + + aVec.insert(p1); + aVec.insert(p2); + aVec.insert(p3); + aVec.DeleteAndDestroyAll(); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.size() ); + } + + void testInsertRange() + { + o3tl::sorted_vector<SwContent*, o3tl::less_ptr_to<SwContent> > aVec1; + std::unique_ptr<SwContent> p1( new SwContent(1) ); + std::unique_ptr<SwContent> p2( new SwContent(2) ); + std::unique_ptr<SwContent> p3( new SwContent(3) ); + + aVec1.insert(p1.get()); + aVec1.insert(p2.get()); + aVec1.insert(p3.get()); + + o3tl::sorted_vector<SwContent*, o3tl::less_ptr_to<SwContent> > aVec2; + aVec2.insert( aVec1 ); + + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(3), aVec2.size() ); + } + + void testLowerBound() + { + o3tl::sorted_vector<SwContent*, o3tl::less_ptr_to<SwContent> > aVec; + std::unique_ptr<SwContent> p1( new SwContent(1) ); + std::unique_ptr<SwContent> p2( new SwContent(2) ); + std::unique_ptr<SwContent> p3( new SwContent(3) ); + std::unique_ptr<SwContent> p4( new SwContent(4) ); + + aVec.insert(p1.get()); + aVec.insert(p2.get()); + aVec.insert(p3.get()); + + CPPUNIT_ASSERT( bool(aVec.lower_bound(p1.get()) == aVec.begin()) ); + CPPUNIT_ASSERT( bool(aVec.lower_bound(p4.get()) == aVec.end()) ); + } + + void testBasics_FindPtr() + { + o3tl::sorted_vector<SwContent*, o3tl::less_ptr_to<SwContent>, + o3tl::find_partialorder_ptrequals> aVec; + std::unique_ptr<SwContent> p1( new SwContent(1) ); + std::unique_ptr<SwContent> p2( new SwContent(2) ); + SwContent *p2_2 = new SwContent(2); + std::unique_ptr<SwContent> p2_3( new SwContent(2) ); + SwContent *p2_4 = new SwContent(2); + SwContent *p3 = new SwContent(3); + std::unique_ptr<SwContent> p4( new SwContent(4) ); + + CPPUNIT_ASSERT( aVec.insert(p3).second ); + CPPUNIT_ASSERT( aVec.insert(p1.get()).second ); + CPPUNIT_ASSERT( !aVec.insert(p3).second ); + + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(2), aVec.size() ); + + CPPUNIT_ASSERT_EQUAL( p1.get(), aVec[0] ); + CPPUNIT_ASSERT_EQUAL( p3, aVec[1] ); + + CPPUNIT_ASSERT( aVec.insert(p2_2).second ); + CPPUNIT_ASSERT( aVec.insert(p2_3.get()).second ); + CPPUNIT_ASSERT( !aVec.insert(p2_2).second ); + CPPUNIT_ASSERT( aVec.insert(p2_4).second ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(5), aVec.size() ); + + CPPUNIT_ASSERT_EQUAL( p1.get(), *aVec.begin() ); + CPPUNIT_ASSERT_EQUAL( p3, *(aVec.end()-1) ); + + CPPUNIT_ASSERT_EQUAL( p1.get(), aVec.front() ); + CPPUNIT_ASSERT_EQUAL( p3, aVec.back() ); + + CPPUNIT_ASSERT( aVec.find(p1.get()) != aVec.end() ); + CPPUNIT_ASSERT_EQUAL( static_cast<std::ptrdiff_t>(0), aVec.find(p1.get()) - aVec.begin() ); + CPPUNIT_ASSERT( aVec.find(p3) != aVec.end() ); + CPPUNIT_ASSERT_EQUAL( static_cast<std::ptrdiff_t>(4), aVec.find(p3) - aVec.begin() ); + CPPUNIT_ASSERT( bool(aVec.find(p2.get()) == aVec.end()) ); + CPPUNIT_ASSERT( bool(aVec.find(p4.get()) == aVec.end()) ); + CPPUNIT_ASSERT( aVec.find(p2_2) != aVec.end() ); + CPPUNIT_ASSERT( aVec.find(p2_2) - aVec.begin() >= 1 ); + CPPUNIT_ASSERT( aVec.find(p2_2) - aVec.begin() < 4 ); + CPPUNIT_ASSERT( aVec.find(p2_3.get()) != aVec.end() ); + CPPUNIT_ASSERT( aVec.find(p2_3.get()) - aVec.begin() >= 1 ); + CPPUNIT_ASSERT( aVec.find(p2_3.get()) - aVec.begin() < 4 ); + CPPUNIT_ASSERT( aVec.find(p2_4) != aVec.end() ); + CPPUNIT_ASSERT( aVec.find(p2_4) - aVec.begin() >= 1 ); + CPPUNIT_ASSERT( aVec.find(p2_4) - aVec.begin() < 4 ); + + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.erase(p1.get()) ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(4), aVec.size() ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.erase(p2.get()) ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.erase(p2_3.get()) ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(3), aVec.size() ); + + aVec.DeleteAndDestroyAll(); + } + + void testErase_FindPtr() + { + o3tl::sorted_vector<SwContent*, o3tl::less_ptr_to<SwContent>, + o3tl::find_partialorder_ptrequals> aVec; + std::unique_ptr<SwContent> p1( new SwContent(1) ); + SwContent *p1_2 = new SwContent(1); + std::unique_ptr<SwContent> p1_3( new SwContent(1) ); + SwContent *p2 = new SwContent(2); + SwContent *p3 = new SwContent(3); + std::unique_ptr<SwContent> p4( new SwContent(4) ); + + aVec.insert(p1.get()); + aVec.insert(p2); + aVec.insert(p3); + + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.erase(p1.get()) ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(2), aVec.size() ); + + aVec.erase(1); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.size() ); + + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.erase(p4.get()) ); + + aVec.clear(); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.size() ); + + aVec.insert(p1.get()); + aVec.insert(p2); + aVec.insert(p3); + aVec.insert(p1_2); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(4), aVec.size() ); + aVec.insert(p1_3.get()); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(5), aVec.size() ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.erase(p1.get()) ); + CPPUNIT_ASSERT( bool(aVec.find(p1.get()) == aVec.end()) ); + CPPUNIT_ASSERT( aVec.find(p1_2) != aVec.end() ); + CPPUNIT_ASSERT( aVec.find(p1_3.get()) != aVec.end() ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(1), aVec.erase(p1_3.get()) ); + CPPUNIT_ASSERT( bool(aVec.find(p1.get()) == aVec.end()) ); + CPPUNIT_ASSERT( aVec.find(p1_2) != aVec.end() ); + CPPUNIT_ASSERT( bool(aVec.find(p1_3.get()) == aVec.end()) ); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.erase(p1_3.get()) ); + CPPUNIT_ASSERT( bool(aVec.find(p1.get()) == aVec.end()) ); + CPPUNIT_ASSERT( aVec.find(p1_2) != aVec.end() ); + CPPUNIT_ASSERT( bool(aVec.find(p1_3.get()) == aVec.end()) ); + + aVec.DeleteAndDestroyAll(); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), aVec.size() ); + } + + void testUniquePtr1() + { + o3tl::sorted_vector<std::unique_ptr<OUString>, o3tl::less_uniqueptr_to<OUString>> aVec; + + auto str_c = aVec.insert(std::make_unique<OUString>("c")).first->get(); + auto str_b1 = aVec.insert(std::make_unique<OUString>("b")).first->get(); + CPPUNIT_ASSERT(!aVec.insert(std::make_unique<OUString>("b")).second); + aVec.insert(std::make_unique<OUString>("a")); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(3), aVec.size() ); + CPPUNIT_ASSERT_EQUAL( OUString("a"), *aVec[0] ); + CPPUNIT_ASSERT_EQUAL( OUString("b"), *aVec[1] ); + CPPUNIT_ASSERT_EQUAL( OUString("c"), *aVec[2] ); + + CPPUNIT_ASSERT( aVec.find(str_c) != aVec.end() ); + CPPUNIT_ASSERT( aVec.find(str_b1) != aVec.end() ); + + OUString tmp("b"); + CPPUNIT_ASSERT( aVec.find(&tmp) != aVec.end() ); + OUString tmp2("z"); + CPPUNIT_ASSERT( bool(aVec.find(&tmp2) == aVec.end()) ); + } + + void testUniquePtr2() + { + o3tl::sorted_vector<std::unique_ptr<OUString>, o3tl::less_uniqueptr_to<OUString>, + o3tl::find_partialorder_ptrequals> aVec; + + auto str_c = aVec.insert(std::make_unique<OUString>("c")).first->get(); + auto str_b1 = aVec.insert(std::make_unique<OUString>("b")).first->get(); + auto str_b2 = aVec.insert(std::make_unique<OUString>("b")).first->get(); + aVec.insert(std::make_unique<OUString>("a")); + CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(4), aVec.size() ); + CPPUNIT_ASSERT_EQUAL( OUString("a"), *aVec[0] ); + CPPUNIT_ASSERT_EQUAL( OUString("b"), *aVec[1] ); + CPPUNIT_ASSERT_EQUAL( OUString("b"), *aVec[2] ); + CPPUNIT_ASSERT_EQUAL( OUString("c"), *aVec[3] ); + + CPPUNIT_ASSERT( aVec.find(str_c) != aVec.end() ); + CPPUNIT_ASSERT( aVec.find(str_b1) != aVec.end() ); + CPPUNIT_ASSERT( aVec.find(str_b2) != aVec.end() ); + + OUString tmp2("z"); + CPPUNIT_ASSERT( bool(aVec.find(&tmp2) == aVec.end()) ); + } + + // Change the following lines only, if you add, remove or rename + // member functions of the current class, + // because these macros are need by auto register mechanism. + + CPPUNIT_TEST_SUITE(sorted_vector_test); + CPPUNIT_TEST(testBasics); + CPPUNIT_TEST(testErase); + CPPUNIT_TEST(testInsertRange); + CPPUNIT_TEST(testLowerBound); + CPPUNIT_TEST(testBasics_FindPtr); + CPPUNIT_TEST(testErase_FindPtr); + CPPUNIT_TEST(testUniquePtr1); + CPPUNIT_TEST(testUniquePtr2); + CPPUNIT_TEST_SUITE_END(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(sorted_vector_test); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/o3tl/qa/test-span.cxx b/o3tl/qa/test-span.cxx new file mode 100644 index 000000000..26eedfc21 --- /dev/null +++ b/o3tl/qa/test-span.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <sal/config.h> + +#include <cstddef> +#include <utility> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <o3tl/span.hxx> + +namespace { + +class Test: public CppUnit::TestFixture { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testOperations); + CPPUNIT_TEST_SUITE_END(); + + + void testOperations() { + int const some_data[] { 1, 2, 3 }; + o3tl::span<int const> v(some_data); + + CPPUNIT_ASSERT_EQUAL(1, *v.begin()); + CPPUNIT_ASSERT_EQUAL( + o3tl::span<int>::difference_type(3), v.end() - v.begin()); + CPPUNIT_ASSERT_EQUAL(3, *v.rbegin()); + CPPUNIT_ASSERT_EQUAL( + o3tl::span<int>::difference_type(3), v.rend() - v.rbegin()); + CPPUNIT_ASSERT_EQUAL(std::size_t(3), v.size()); + CPPUNIT_ASSERT(!v.empty()); + CPPUNIT_ASSERT_EQUAL(2, v[1]); + CPPUNIT_ASSERT_EQUAL(1, *v.data()); + { + int const d1[] { 1, 2 }; + int const d2[] { 3, 4, 5, 6 }; + o3tl::span<int const> v1( d1 ); + o3tl::span<int const> v2( d2 ); + std::swap(v1, v2); + CPPUNIT_ASSERT_EQUAL(std::size_t(4), v1.size()); + CPPUNIT_ASSERT_EQUAL(std::size_t(2), v2.size()); + } + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/o3tl/qa/test-typed_flags.cxx b/o3tl/qa/test-typed_flags.cxx new file mode 100644 index 000000000..ef6e4faae --- /dev/null +++ b/o3tl/qa/test-typed_flags.cxx @@ -0,0 +1,71 @@ +/* -*- 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 <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <o3tl/typed_flags_set.hxx> + +using namespace ::o3tl; + +namespace { + +enum class ConfigurationChangedHint { NONE, ONE, TWO }; + +} + +namespace o3tl +{ + template<> struct typed_flags< ConfigurationChangedHint> : is_typed_flags< ConfigurationChangedHint, 0xFF> {}; +} + +class typed_flags_test : public CppUnit::TestFixture +{ +public: + void testBasics() + { + ConfigurationChangedHint nHint = ConfigurationChangedHint::ONE; + + CPPUNIT_ASSERT( ConfigurationChangedHint::ONE & ConfigurationChangedHint::ONE ); + CPPUNIT_ASSERT( nHint & ConfigurationChangedHint::ONE ); + CPPUNIT_ASSERT( ConfigurationChangedHint::ONE & nHint ); + + CPPUNIT_ASSERT( ConfigurationChangedHint::ONE | ConfigurationChangedHint::ONE ); + CPPUNIT_ASSERT( nHint | ConfigurationChangedHint::ONE ); + CPPUNIT_ASSERT( ConfigurationChangedHint::ONE | nHint ); + + CPPUNIT_ASSERT( ~nHint ); + CPPUNIT_ASSERT( ~ConfigurationChangedHint::ONE ); + + nHint |= ConfigurationChangedHint::ONE; + CPPUNIT_ASSERT( bool(nHint |= ConfigurationChangedHint::ONE) ); + + nHint &= ConfigurationChangedHint::ONE; + CPPUNIT_ASSERT( bool(nHint &= ConfigurationChangedHint::ONE) ); + + CPPUNIT_ASSERT( + !((ConfigurationChangedHint::NONE | ConfigurationChangedHint::ONE) + & (ConfigurationChangedHint::NONE + | ConfigurationChangedHint::TWO))); + } + + // Change the following lines only, if you add, remove or rename + // member functions of the current class, + // because these macros are need by auto register mechanism. + + CPPUNIT_TEST_SUITE(typed_flags_test); + CPPUNIT_TEST(testBasics); + CPPUNIT_TEST_SUITE_END(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(typed_flags_test); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/o3tl/qa/test-vector_pool.cxx b/o3tl/qa/test-vector_pool.cxx new file mode 100644 index 000000000..78975e4d5 --- /dev/null +++ b/o3tl/qa/test-vector_pool.cxx @@ -0,0 +1,89 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/types.h> +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <o3tl/vector_pool.hxx> + +using namespace ::o3tl; + +class vector_pool_test : public CppUnit::TestFixture +{ +public: + void testPoolBasics() + { + vector_pool<int> aPool; + + std::ptrdiff_t nIdx1 = aPool.alloc(); + std::ptrdiff_t nIdx2 = aPool.alloc(); + std::ptrdiff_t nIdx3 = aPool.alloc(); + + CPPUNIT_ASSERT_MESSAGE("allocator idx order 1", nIdx1 < nIdx2 ); + CPPUNIT_ASSERT_MESSAGE("allocator idx order 2", nIdx2 < nIdx3 ); + + aPool.free(nIdx2); + aPool.free(nIdx3); + + nIdx2 = aPool.alloc(); + nIdx3 = aPool.alloc(); + + CPPUNIT_ASSERT_MESSAGE("allocator idx order 1 after fragmentation", nIdx1 < nIdx3 ); + CPPUNIT_ASSERT_MESSAGE("allocator idx order 2 after fragmentation", nIdx3 < nIdx2 ); + } + + void testPoolValueSemantics() + { + vector_pool<int> aPool; + + std::ptrdiff_t nIdx1 = aPool.store(0); + CPPUNIT_ASSERT_EQUAL_MESSAGE("allocator value semantics 1", 0, aPool.get(nIdx1) ); + + std::ptrdiff_t nIdx2 = aPool.store(1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("allocator value semantics 2", 1, aPool.get(nIdx2) ); + + std::ptrdiff_t nIdx3 = aPool.store(2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("allocator value semantics 3", 2, aPool.get(nIdx3) ); + + aPool.free(nIdx2); + aPool.free(nIdx3); + + nIdx2 = aPool.store(1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("allocator value semantics 2 after fragmentation", 1, aPool.get(nIdx2) ); + + nIdx3 = aPool.store(2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("allocator value semantics 3 after fragmentation", 2, aPool.get(nIdx3) ); + } + + // Change the following lines only, if you add, remove or rename + // member functions of the current class, + // because these macros are need by auto register mechanism. + + CPPUNIT_TEST_SUITE(vector_pool_test); + CPPUNIT_TEST(testPoolBasics); + CPPUNIT_TEST(testPoolValueSemantics); + CPPUNIT_TEST_SUITE_END(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(vector_pool_test); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |