summaryrefslogtreecommitdiffstats
path: root/o3tl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /o3tl
parentInitial commit. (diff)
downloadlibreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz
libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'o3tl')
-rw-r--r--o3tl/CompilerTest_o3tl_temporary.mk16
-rw-r--r--o3tl/CompilerTest_o3tl_unsafe_downcast.mk16
-rw-r--r--o3tl/CppunitTest_o3tl_tests.mk40
-rw-r--r--o3tl/Makefile7
-rw-r--r--o3tl/Module_o3tl.mk31
-rw-r--r--o3tl/README30
-rw-r--r--o3tl/qa/compile-temporary.cxx25
-rw-r--r--o3tl/qa/compile-unsafe_downcast.cxx32
-rw-r--r--o3tl/qa/cow_wrapper_clients.cxx296
-rw-r--r--o3tl/qa/cow_wrapper_clients.hxx210
-rw-r--r--o3tl/qa/test-cow_wrapper.cxx263
-rw-r--r--o3tl/qa/test-enumarray.cxx48
-rw-r--r--o3tl/qa/test-lru_map.cxx318
-rw-r--r--o3tl/qa/test-safeint.cxx119
-rw-r--r--o3tl/qa/test-sorted_vector.cxx321
-rw-r--r--o3tl/qa/test-span.cxx60
-rw-r--r--o3tl/qa/test-typed_flags.cxx71
-rw-r--r--o3tl/qa/test-vector_pool.cxx89
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: */