summaryrefslogtreecommitdiffstats
path: root/o3tl
diff options
context:
space:
mode:
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.mk42
-rw-r--r--o3tl/IwyuFilter_o3tl.yaml2
-rw-r--r--o3tl/Makefile7
-rw-r--r--o3tl/Module_o3tl.mk31
-rw-r--r--o3tl/README.md34
-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.cxx46
-rw-r--r--o3tl/qa/test-lru_map.cxx338
-rw-r--r--o3tl/qa/test-safeint.cxx121
-rw-r--r--o3tl/qa/test-sorted_vector.cxx321
-rw-r--r--o3tl/qa/test-string_view.cxx753
-rw-r--r--o3tl/qa/test-temporary.cxx47
-rw-r--r--o3tl/qa/test-typed_flags.cxx71
-rw-r--r--o3tl/qa/test-unit_conversion.cxx883
-rw-r--r--o3tl/qa/test-vector_pool.cxx88
21 files changed, 3642 insertions, 0 deletions
diff --git a/o3tl/CompilerTest_o3tl_temporary.mk b/o3tl/CompilerTest_o3tl_temporary.mk
new file mode 100644
index 0000000000..fe8a830e03
--- /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 0000000000..0fbc8a2475
--- /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 0000000000..4f7ab02b1d
--- /dev/null
+++ b/o3tl/CppunitTest_o3tl_tests.mk
@@ -0,0 +1,42 @@
+# -*- 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-string_view \
+ o3tl/qa/test-temporary \
+ o3tl/qa/test-typed_flags \
+ o3tl/qa/test-unit_conversion \
+ o3tl/qa/test-vector_pool \
+))
+
+# vim: set noet sw=4:
diff --git a/o3tl/IwyuFilter_o3tl.yaml b/o3tl/IwyuFilter_o3tl.yaml
new file mode 100644
index 0000000000..15a5a2a0d2
--- /dev/null
+++ b/o3tl/IwyuFilter_o3tl.yaml
@@ -0,0 +1,2 @@
+---
+assumeFilename: o3tl/qa/test-cow_wrapper.cxx
diff --git a/o3tl/Makefile b/o3tl/Makefile
new file mode 100644
index 0000000000..ccb1c85a04
--- /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 0000000000..66f7d7a1cd
--- /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.md b/o3tl/README.md
new file mode 100644
index 0000000000..dccfc6028d
--- /dev/null
+++ b/o3tl/README.md
@@ -0,0 +1,34 @@
+# LibreOffice Template Library
+
+Very basic template functionality, a bit like boost or STL, but specific to LibreOffice.
+
+o3tl stands for "OOo [o3, get it?] template library", in which OOo stands for OpenOffice.org,
+predecessor of LibreOffice.
+
+From <https://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:include/o3tl/cow_wrapper.hxx]`
+
+ A copy-on-write wrapper.
+
+- `[git:include/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:include/o3tl/vector_pool.hxx]`
+
+ Simple vector-based memory pool allocator.
+
+- `[git:include/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 0000000000..1d8d84bd5f
--- /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 0000000000..8471fc250e
--- /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 0000000000..913165c83c
--- /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 0000000000..d0e416c963
--- /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 <assert.h>
+#include <iostream>
+
+/* 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 0000000000..b5d4936d5d
--- /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 0000000000..f54a923941
--- /dev/null
+++ b/o3tl/qa/test-enumarray.cxx
@@ -0,0 +1,46 @@
+/* -*- 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 <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 0000000000..c99a803b31
--- /dev/null
+++ b/o3tl/qa/test-lru_map.cxx
@@ -0,0 +1,338 @@
+/* -*- 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/lru_map.hxx>
+
+#include <o3tl/hash_combine.hxx>
+
+using namespace ::o3tl;
+
+class lru_map_test : public CppUnit::TestFixture
+{
+public:
+ void testBaseUsage();
+ void testReplaceKey();
+ void testReplaceValue();
+ void testLruRemoval();
+ void testCustomHash();
+ void testRemoveIf();
+ void testChangeMaxSize();
+ void testCustomItemSize();
+
+ 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(testChangeMaxSize);
+ CPPUNIT_TEST(testCustomItemSize);
+ 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;
+ o3tl::hash_combine(seed, aKey.mA);
+ o3tl::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::testChangeMaxSize()
+{
+ o3tl::lru_map<int, int> lru(3);
+ CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size());
+ lru.insert({ 0, 0 });
+ lru.insert({ 1, 1 });
+ lru.insert({ 2, 2 });
+ CPPUNIT_ASSERT_EQUAL(size_t(3), lru.size());
+ lru.setMaxSize(1);
+ CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size());
+}
+
+void lru_map_test::testCustomItemSize()
+{
+ struct cost_is_value
+ {
+ size_t operator()(int i) { return i; };
+ };
+ o3tl::lru_map<int, int, std::hash<int>, std::equal_to<int>, cost_is_value> lru(5);
+ lru.insert({ 1, 1 });
+ lru.insert({ 2, 2 });
+ // Adding this one will remove the first one, since then the total
+ // cost would be 6, more than the maximum 5.
+ lru.insert({ 3, 3 });
+ CPPUNIT_ASSERT_EQUAL(size_t(2), lru.size());
+ CPPUNIT_ASSERT_EQUAL(size_t(5), lru.total_size());
+ // Drop the last item.
+ lru.remove_if([](std::pair<int, int> i) { return i.first == 3; });
+ CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size());
+ CPPUNIT_ASSERT_EQUAL(size_t(2), lru.total_size());
+ // This should drop everything except for keeping this one (an exception that
+ // keeps the last item inserted regardless of limit).
+ lru.insert({ 4, 4 });
+ CPPUNIT_ASSERT_EQUAL(size_t(1), lru.size());
+ CPPUNIT_ASSERT_EQUAL(size_t(4), lru.total_size());
+ lru.clear();
+ CPPUNIT_ASSERT_EQUAL(size_t(0), lru.size());
+ CPPUNIT_ASSERT_EQUAL(size_t(0), lru.total_size());
+}
+
+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 0000000000..4c4333082f
--- /dev/null
+++ b/o3tl/qa/test-safeint.cxx
@@ -0,0 +1,121 @@
+/* -*- 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 0000000000..c7fdb0c045
--- /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_at(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_at(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-string_view.cxx b/o3tl/qa/test-string_view.cxx
new file mode 100644
index 0000000000..f32537aa35
--- /dev/null
+++ b/o3tl/qa/test-string_view.cxx
@@ -0,0 +1,753 @@
+/* -*- 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 <string_view>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <rtl/string.hxx>
+#include <rtl/ustring.hxx>
+
+template <>
+inline std::string
+CppUnit::assertion_traits<std::u16string_view>::toString(std::u16string_view const& x)
+{
+ return std::string(OUStringToOString(x, RTL_TEXTENCODING_UTF8));
+}
+
+namespace
+{
+OString ostringEmpty() { return {}; } // avoid loplugin:stringview
+OString ostringDoof() { return "doof"_ostr; } // avoid loplugin:stringview
+OString ostringFoo() { return "foo"_ostr; } // avoid loplugin:stringview
+OString ostringFoobars() { return "foobars"_ostr; } // avoid loplugin:stringview
+OString ostringFood() { return "food"_ostr; } // avoid loplugin:stringview
+OString ostringOof() { return "oof"_ostr; } // avoid loplugin:stringview
+OString ostringSraboof() { return "sraboof"_ostr; } // avoid loplugin:stringview
+OUString oustringEmpty() { return {}; } // avoid loplugin:stringview
+OUString oustringDoof() { return "doof"; } // avoid loplugin:stringview
+OUString oustringFoo() { return "foo"; } // avoid loplugin:stringview
+OUString oustringFoobars() { return "foobars"; } // avoid loplugin:stringview
+OUString oustringFood() { return "food"; } // avoid loplugin:stringview
+OUString oustringOof() { return "oof"; } // avoid loplugin:stringview
+OUString oustringSraboof() { return "sraboof"; } // avoid loplugin:stringview
+
+class Test : public CppUnit::TestFixture
+{
+private:
+ CPPUNIT_TEST_SUITE(Test);
+ CPPUNIT_TEST(testStartsWith);
+ CPPUNIT_TEST(testStartsWithRest);
+ CPPUNIT_TEST(testEndsWith);
+ CPPUNIT_TEST(testEndsWithRest);
+ CPPUNIT_TEST(testEqualsIgnoreAsciiCase);
+ CPPUNIT_TEST(testGetToken);
+ CPPUNIT_TEST(testIterateCodePoints);
+ CPPUNIT_TEST_SUITE_END();
+
+ void testStartsWith()
+ {
+ using namespace std::string_view_literals;
+ CPPUNIT_ASSERT(o3tl::starts_with(""sv, ""sv));
+ CPPUNIT_ASSERT(!o3tl::starts_with(""sv, "foo"sv));
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, ""sv));
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, "foo"sv));
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, "food"sv));
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, "foobars"sv));
+ CPPUNIT_ASSERT(!o3tl::starts_with(""sv, 'f'));
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, 'f'));
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, 'g'));
+ CPPUNIT_ASSERT(o3tl::starts_with(""sv, ""));
+ CPPUNIT_ASSERT(!o3tl::starts_with(""sv, "foo"));
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, ""));
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, "foo"));
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, "food"));
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, "foobars"));
+ CPPUNIT_ASSERT(o3tl::starts_with(""sv, ostringEmpty()));
+ CPPUNIT_ASSERT(!o3tl::starts_with(""sv, ostringFoo()));
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, ostringEmpty()));
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, ostringFoo()));
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, ostringFood()));
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, ostringFoobars()));
+ CPPUNIT_ASSERT(o3tl::starts_with(u""sv, u""sv));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u""sv, u"foo"sv));
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u""sv));
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u"foo"sv));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u"food"sv));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u"foobars"sv));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u""sv, u'f'));
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u'f'));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u'g'));
+ CPPUNIT_ASSERT(o3tl::starts_with(u""sv, u""));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u""sv, u"foo"));
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u""));
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u"foo"));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u"food"));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u"foobars"));
+ CPPUNIT_ASSERT(o3tl::starts_with(u""sv, oustringEmpty()));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u""sv, oustringFoo()));
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, oustringEmpty()));
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, oustringFoo()));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, oustringFood()));
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, oustringFoobars()));
+ }
+
+ void testStartsWithRest()
+ {
+ using namespace std::string_view_literals;
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(""sv, ""sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(""sv, "foo"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, ""sv, &rest));
+ CPPUNIT_ASSERT_EQUAL("foobar"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, "foo"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL("bar"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, "food"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, "foobars"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(""sv, 'f', &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, 'f', &rest));
+ CPPUNIT_ASSERT_EQUAL("oobar"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, 'g', &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(""sv, "", &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(""sv, "foo", &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, "", &rest));
+ CPPUNIT_ASSERT_EQUAL("foobar"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, "foo", &rest));
+ CPPUNIT_ASSERT_EQUAL("bar"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, "food", &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, "foobars", &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(""sv, ostringEmpty(), &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(""sv, ostringFoo(), &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, ostringEmpty(), &rest));
+ CPPUNIT_ASSERT_EQUAL("foobar"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with("foobar"sv, ostringFoo(), &rest));
+ CPPUNIT_ASSERT_EQUAL("bar"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, ostringFood(), &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with("foobar"sv, ostringFoobars(), &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u""sv, u""sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u""sv, u"foo"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u""sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u"foobar"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u"foo"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u"bar"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u"food"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u"foobars"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u""sv, u'f', &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u'f', &rest));
+ CPPUNIT_ASSERT_EQUAL(u"oobar"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u'g', &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u""sv, u"", &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u""sv, u"foo", &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u"", &rest));
+ CPPUNIT_ASSERT_EQUAL(u"foobar"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, u"foo", &rest));
+ CPPUNIT_ASSERT_EQUAL(u"bar"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u"food", &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, u"foobars", &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u""sv, oustringEmpty(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u""sv, oustringFoo(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, oustringEmpty(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u"foobar"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::starts_with(u"foobar"sv, oustringFoo(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u"bar"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, oustringFood(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::starts_with(u"foobar"sv, oustringFoobars(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ }
+
+ void testEndsWith()
+ {
+ using namespace std::string_view_literals;
+ CPPUNIT_ASSERT(o3tl::ends_with(""sv, ""sv));
+ CPPUNIT_ASSERT(!o3tl::ends_with(""sv, "oof"sv));
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, ""sv));
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, "oof"sv));
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, "doof"sv));
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, "sraboof"sv));
+ CPPUNIT_ASSERT(!o3tl::ends_with(""sv, 'f'));
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, 'f'));
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, 'g'));
+ CPPUNIT_ASSERT(o3tl::ends_with(""sv, ""));
+ CPPUNIT_ASSERT(!o3tl::ends_with(""sv, "oof"));
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, ""));
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, "oof"));
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, "doof"));
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, "sraboof"));
+ CPPUNIT_ASSERT(o3tl::ends_with(""sv, ostringEmpty()));
+ CPPUNIT_ASSERT(!o3tl::ends_with(""sv, ostringOof()));
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, ostringEmpty()));
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, ostringOof()));
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, ostringDoof()));
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, ostringSraboof()));
+ CPPUNIT_ASSERT(o3tl::ends_with(u""sv, u""sv));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u""sv, u"oof"sv));
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u""sv));
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u"oof"sv));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u"doof"sv));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u"sraboof"sv));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u""sv, u'f'));
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u'f'));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u'g'));
+ CPPUNIT_ASSERT(o3tl::ends_with(u""sv, u""));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u""sv, u"oof"));
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u""));
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u"oof"));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u"doof"));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u"sraboof"));
+ CPPUNIT_ASSERT(o3tl::ends_with(u""sv, oustringEmpty()));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u""sv, oustringOof()));
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, oustringEmpty()));
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, oustringOof()));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, oustringDoof()));
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, oustringSraboof()));
+ }
+
+ void testEndsWithRest()
+ {
+ using namespace std::string_view_literals;
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(""sv, ""sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(""sv, "oof"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, ""sv, &rest));
+ CPPUNIT_ASSERT_EQUAL("raboof"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, "oof"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL("rab"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, "doof"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, "sraboof"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(""sv, 'f', &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, 'f', &rest));
+ CPPUNIT_ASSERT_EQUAL("raboo"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, 'g', &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(""sv, "", &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(""sv, "oof", &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, "", &rest));
+ CPPUNIT_ASSERT_EQUAL("raboof"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, "oof", &rest));
+ CPPUNIT_ASSERT_EQUAL("rab"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, "doof", &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, "sraboof", &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(""sv, ostringEmpty(), &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(""sv, ostringOof(), &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, ostringEmpty(), &rest));
+ CPPUNIT_ASSERT_EQUAL("raboof"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with("raboof"sv, ostringOof(), &rest));
+ CPPUNIT_ASSERT_EQUAL("rab"sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, ostringDoof(), &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with("raboof"sv, ostringSraboof(), &rest));
+ CPPUNIT_ASSERT_EQUAL(""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u""sv, u""sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u""sv, u"oof"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u""sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u"raboof"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u"oof"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u"rab"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u"doof"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u"sraboof"sv, &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u""sv, u'f', &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u'f', &rest));
+ CPPUNIT_ASSERT_EQUAL(u"raboo"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u'g', &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u""sv, u"", &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u""sv, u"oof", &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u"", &rest));
+ CPPUNIT_ASSERT_EQUAL(u"raboof"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, u"oof", &rest));
+ CPPUNIT_ASSERT_EQUAL(u"rab"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u"doof", &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, u"sraboof", &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u""sv, oustringEmpty(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u""sv, oustringOof(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, oustringEmpty(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u"raboof"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(o3tl::ends_with(u"raboof"sv, oustringOof(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u"rab"sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, oustringDoof(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ {
+ std::u16string_view rest;
+ CPPUNIT_ASSERT(!o3tl::ends_with(u"raboof"sv, oustringSraboof(), &rest));
+ CPPUNIT_ASSERT_EQUAL(u""sv, rest);
+ }
+ }
+
+ void testEqualsIgnoreAsciiCase()
+ {
+ using namespace std::string_view_literals;
+ CPPUNIT_ASSERT(o3tl::equalsIgnoreAsciiCase(u"test"sv, u"test"sv));
+ CPPUNIT_ASSERT(!o3tl::equalsIgnoreAsciiCase(u"test"sv, u"test2"sv));
+
+ CPPUNIT_ASSERT_EQUAL(0, o3tl::compareToIgnoreAsciiCase(u"test"sv, u"test"sv));
+ CPPUNIT_ASSERT_GREATER(0, o3tl::compareToIgnoreAsciiCase(u"zest"sv, u"test"sv));
+ CPPUNIT_ASSERT_LESS(0, o3tl::compareToIgnoreAsciiCase(u"test"sv, u"test2"sv));
+ }
+
+ void testGetToken()
+ {
+ {
+ // Explicit initialization of suTokenStr to avoid an unhelpful loplugin:stringviewvar;
+ // it is the o3tl::getToken overload taking OUString that we want to test here:
+ OUString suTokenStr("");
+ sal_Int32 nIndex = 0;
+ do
+ {
+ o3tl::getToken(suTokenStr, 0, ';', nIndex);
+ } while (nIndex >= 0);
+ // should not GPF
+ }
+ {
+ OUString suTokenStr("a;b");
+
+ sal_Int32 nIndex = 0;
+
+ std::u16string_view suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'a'", std::u16string_view(u"a"),
+ suToken);
+
+ suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'b'", std::u16string_view(u"b"),
+ suToken);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", static_cast<sal_Int32>(-1),
+ nIndex);
+ }
+ {
+ std::u16string_view suTokenStr(u"a;b.c");
+
+ sal_Int32 nIndex = 0;
+
+ std::u16string_view suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'a'", std::u16string_view(u"a"),
+ suToken);
+
+ suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'b'", std::u16string_view(u"b"),
+ suToken);
+
+ suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'c'", std::u16string_view(u"c"),
+ suToken);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", static_cast<sal_Int32>(-1),
+ nIndex);
+ }
+ {
+ std::u16string_view suTokenStr(u"a;;b");
+
+ sal_Int32 nIndex = 0;
+
+ std::u16string_view suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'a'", std::u16string_view(u"a"),
+ suToken);
+
+ suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+ CPPUNIT_ASSERT_MESSAGE("Token should be empty", suToken.empty());
+
+ suToken = o3tl::getToken(suTokenStr, 0, ';', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be a 'b'", std::u16string_view(u"b"),
+ suToken);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", static_cast<sal_Int32>(-1),
+ nIndex);
+ }
+ {
+ std::u16string_view suTokenStr(u"longer.then.ever.");
+
+ sal_Int32 nIndex = 0;
+
+ std::u16string_view suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be 'longer'", std::u16string_view(u"longer"),
+ suToken);
+
+ suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be 'then'", std::u16string_view(u"then"),
+ suToken);
+
+ suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Token should be 'ever'", std::u16string_view(u"ever"),
+ suToken);
+
+ suToken = o3tl::getToken(suTokenStr, 0, '.', nIndex);
+ CPPUNIT_ASSERT_MESSAGE("Token should be empty", suToken.empty());
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("index should be negative", static_cast<sal_Int32>(-1),
+ nIndex);
+ }
+ {
+ std::u16string_view ab(u"ab");
+ sal_Int32 n = 0;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("token should be 'ab'", ab, o3tl::getToken(ab, 0, '-', n));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("n should be -1", static_cast<sal_Int32>(-1), n);
+ CPPUNIT_ASSERT_MESSAGE("token should be empty", o3tl::getToken(ab, 0, '-', n).empty());
+ }
+ {
+ std::u16string_view suTokenStr;
+ auto pTokenStr = suTokenStr.data();
+ sal_uInt64 n64 = reinterpret_cast<sal_uInt64>(pTokenStr) / sizeof(sal_Unicode);
+ // Point either to 0x0, or to some random address -4GiB away from this string
+ sal_Int32 n = n64 > o3tl::make_unsigned(SAL_MAX_INT32) ? -SAL_MAX_INT32
+ : -static_cast<sal_Int32>(n64);
+ o3tl::getToken(suTokenStr, 0, ';', n);
+ // should not GPF with negative index
+ }
+ {
+ CPPUNIT_ASSERT_MESSAGE("compareToAscii",
+ u"aaa"_ustr.compareToAscii("aa")
+ > 0); // just for comparison to following line
+ CPPUNIT_ASSERT_MESSAGE("compareToAscii", o3tl::compareToAscii(u"aaa", "aa") > 0);
+
+ OUString aa(u"aa"_ustr);
+ CPPUNIT_ASSERT_MESSAGE("compareToAscii",
+ aa.compareToAscii("aaa")
+ < 0); // just for comparison to following line
+ CPPUNIT_ASSERT_MESSAGE("compareToAscii", o3tl::compareToAscii(u"aa", "aaa") < 0);
+
+ CPPUNIT_ASSERT_MESSAGE(
+ "equalsIgnoreAsciiCase",
+ aa.equalsIgnoreAsciiCase("AA")); // just for comparison to following line
+ CPPUNIT_ASSERT_MESSAGE("equalsIgnoreAsciiCase",
+ o3tl::equalsIgnoreAsciiCase(u"aa", "AA"));
+
+ CPPUNIT_ASSERT_MESSAGE(
+ "matchIgnoreAsciiCase",
+ aa.matchIgnoreAsciiCase("a")); // just for comparison to following line
+ CPPUNIT_ASSERT_MESSAGE("matchIgnoreAsciiCase", o3tl::matchIgnoreAsciiCase(u"aa", "a"));
+
+ CPPUNIT_ASSERT_MESSAGE(
+ "endsWithIgnoreAsciiCase",
+ aa.endsWithIgnoreAsciiCase("a")); // just for comparison to following line
+ CPPUNIT_ASSERT_MESSAGE("endsWithIgnoreAsciiCase",
+ o3tl::endsWithIgnoreAsciiCase(u"aa", "a"));
+ CPPUNIT_ASSERT_MESSAGE("endsWithIgnoreAsciiCase",
+ o3tl::endsWithIgnoreAsciiCase(u"aa", u"a"));
+ }
+ }
+
+ void testIterateCodePoints()
+ {
+ {
+ sal_Int32 i = 1;
+ auto const c = o3tl::iterateCodePoints(u"\U00010000", &i, 1);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), i);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(0xDC00), c);
+ }
+ {
+ sal_Int32 i = 2;
+ auto const c = o3tl::iterateCodePoints(u"a\U00010000", &i, -1);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), i);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(0x10000), c);
+ }
+ }
+};
+
+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-temporary.cxx b/o3tl/qa/test-temporary.cxx
new file mode 100644
index 0000000000..6f775de847
--- /dev/null
+++ b/o3tl/qa/test-temporary.cxx
@@ -0,0 +1,47 @@
+/* -*- 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 <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <o3tl/temporary.hxx>
+
+namespace
+{
+void modify(int& n) { n = 1; }
+
+class Test : public CppUnit::TestFixture
+{
+private:
+ CPPUNIT_TEST_SUITE(Test);
+ CPPUNIT_TEST(testLvalue);
+ CPPUNIT_TEST_SUITE_END();
+
+ void testLvalue()
+ {
+ {
+ int n = 0;
+ modify(n);
+ CPPUNIT_ASSERT_EQUAL(1, n);
+ }
+ {
+ int n = 0;
+ modify(o3tl::temporary(int(n)));
+ CPPUNIT_ASSERT_EQUAL(0, n);
+ }
+ }
+};
+
+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 0000000000..ef6e4faaed
--- /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-unit_conversion.cxx b/o3tl/qa/test-unit_conversion.cxx
new file mode 100644
index 0000000000..d140f1da7e
--- /dev/null
+++ b/o3tl/qa/test-unit_conversion.cxx
@@ -0,0 +1,883 @@
+/* -*- 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/unit_conversion.hxx>
+
+// Just some static asserts
+
+namespace
+{
+constexpr double const_abs(double f) { return f >= 0 ? f : -f; }
+constexpr bool eq(double a, double b) { return const_abs(a - b) < 1E-6; }
+bool eq(sal_Int64, double) = delete;
+}
+
+// testing floating-point conversion
+
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm100, o3tl::Length::mm100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::mm100), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm100), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm100), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm100), 100000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm100), 100E6));
+static_assert(eq(o3tl::convert(360.0, o3tl::Length::emu, o3tl::Length::mm100), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::twip, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(18.0, o3tl::Length::pt, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::mm100), 1270));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in1000, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in100, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::mm100), 254));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::mm100), 2540));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::mm100), 30480));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm100), 160934400));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::master, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::px, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::ch, o3tl::Length::mm100), 4445));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::mm100), 1651));
+
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm100, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm10), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm10), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm10), 10000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm10), 10E6));
+static_assert(eq(o3tl::convert(3600.0, o3tl::Length::emu, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(720.0, o3tl::Length::twip, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::pt, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in1000, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in100, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::mm10), 254));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::mm10), 3048));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm10), 16093440));
+static_assert(eq(o3tl::convert(288.0, o3tl::Length::master, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::px, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::ch, o3tl::Length::mm10), 889));
+static_assert(eq(o3tl::convert(30.0, o3tl::Length::line, o3tl::Length::mm10), 1651));
+
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::mm100, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm10, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm), 1E6));
+static_assert(eq(o3tl::convert(36000.0, o3tl::Length::emu, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(7200.0, o3tl::Length::twip, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(360.0, o3tl::Length::pt, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(30.0, o3tl::Length::pc, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in1000, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in100, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in10, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::ft, o3tl::Length::mm), 1524));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm), 1609344));
+static_assert(eq(o3tl::convert(2880.0, o3tl::Length::master, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(480.0, o3tl::Length::px, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(240.0, o3tl::Length::ch, o3tl::Length::mm), 889));
+static_assert(eq(o3tl::convert(300.0, o3tl::Length::line, o3tl::Length::mm), 1651));
+
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::mm100, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::mm10, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::cm), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::cm), 100000));
+static_assert(eq(o3tl::convert(360000.0, o3tl::Length::emu, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(72000.0, o3tl::Length::twip, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(3600.0, o3tl::Length::pt, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(300.0, o3tl::Length::pc, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(50000.0, o3tl::Length::in1000, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in100, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in10, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::ft, o3tl::Length::cm), 762));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::mi, o3tl::Length::cm), 804672));
+static_assert(eq(o3tl::convert(28800.0, o3tl::Length::master, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(4800.0, o3tl::Length::px, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(2400.0, o3tl::Length::ch, o3tl::Length::cm), 889));
+static_assert(eq(o3tl::convert(3000.0, o3tl::Length::line, o3tl::Length::cm), 1651));
+
+static_assert(eq(o3tl::convert(100000.0, o3tl::Length::mm100, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(10000.0, o3tl::Length::mm10, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::mm, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::cm, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::m), 1000));
+static_assert(eq(o3tl::convert(36E6, o3tl::Length::emu, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(7200000.0, o3tl::Length::twip, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(360000.0, o3tl::Length::pt, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(30000.0, o3tl::Length::pc, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(5000000.0, o3tl::Length::in1000, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(500000.0, o3tl::Length::in100, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(50000.0, o3tl::Length::in10, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(1250.0, o3tl::Length::ft, o3tl::Length::m), 381));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::mi, o3tl::Length::m), 201168));
+static_assert(eq(o3tl::convert(2880000.0, o3tl::Length::master, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(480000.0, o3tl::Length::px, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(240000.0, o3tl::Length::ch, o3tl::Length::m), 889));
+static_assert(eq(o3tl::convert(300000.0, o3tl::Length::line, o3tl::Length::m), 1651));
+
+static_assert(eq(o3tl::convert(100E6, o3tl::Length::mm100, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(10E6, o3tl::Length::mm10, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1E6, o3tl::Length::mm, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(100000.0, o3tl::Length::cm, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::m, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(36E9, o3tl::Length::emu, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(7200E6, o3tl::Length::twip, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(360E6, o3tl::Length::pt, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(30E6, o3tl::Length::pc, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(5E9, o3tl::Length::in1000, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(500E6, o3tl::Length::in100, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(50E6, o3tl::Length::in10, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(5E6, o3tl::Length::in, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(1250000.0, o3tl::Length::ft, o3tl::Length::km), 381));
+static_assert(eq(o3tl::convert(15625.0, o3tl::Length::mi, o3tl::Length::km), 25146));
+static_assert(eq(o3tl::convert(2880E6, o3tl::Length::master, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(480E6, o3tl::Length::px, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(240E6, o3tl::Length::ch, o3tl::Length::km), 889));
+static_assert(eq(o3tl::convert(300E6, o3tl::Length::line, o3tl::Length::km), 1651));
+
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm100, o3tl::Length::emu), 360));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::emu), 3600));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::emu), 36000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::emu), 360000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::emu), 36E6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::emu), 36E9));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::emu), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::emu), 635));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::emu), 12700));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::emu), 152400));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in1000, o3tl::Length::emu), 4572));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::emu), 9144));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::emu), 91440));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::emu), 914400));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::emu), 10972800));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::emu), 57936384000));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::master, o3tl::Length::emu), 3175));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::emu), 9525));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::emu), 133350));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::emu), 198120));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::twip), 72));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::twip), 720));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::twip), 7200));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::twip), 72000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::twip), 7200000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::twip), 7200E6));
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::emu, o3tl::Length::twip), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::twip), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::twip), 20));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::twip), 240));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in1000, o3tl::Length::twip), 36));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in100, o3tl::Length::twip), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::twip), 144));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::twip), 1440));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::twip), 17280));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::twip), 91238400));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::master, o3tl::Length::twip), 5));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::twip), 15));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::twip), 210));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::twip), 312));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::pt), 18));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::pt), 36));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::pt), 360));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::pt), 3600));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::pt), 360000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::pt), 360E6));
+static_assert(eq(o3tl::convert(12700.0, o3tl::Length::emu, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(20.0, o3tl::Length::twip, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::pt), 12));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::pt), 9));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::pt), 18));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::pt), 36));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::pt), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::pt), 864));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::pt), 4561920));
+static_assert(eq(o3tl::convert(8.0, o3tl::Length::master, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(4.0, o3tl::Length::px, o3tl::Length::pt), 3));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::ch, o3tl::Length::pt), 21));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::pt), 78));
+
+static_assert(eq(o3tl::convert(1270.0, o3tl::Length::mm100, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::pc), 30));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::pc), 300));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::pc), 30000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::pc), 30E6));
+static_assert(eq(o3tl::convert(152400.0, o3tl::Length::emu, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(240.0, o3tl::Length::twip, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::pt, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in1000, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in100, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::pc), 6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::pc), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::pc), 380160));
+static_assert(eq(o3tl::convert(96.0, o3tl::Length::master, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(16.0, o3tl::Length::px, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(8.0, o3tl::Length::ch, o3tl::Length::pc), 7));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::line, o3tl::Length::pc), 13));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::in1000), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in1000), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in1000), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in1000), 50000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in1000), 5E6));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in1000), 5E9));
+static_assert(eq(o3tl::convert(4572.0, o3tl::Length::emu, o3tl::Length::in1000), 5));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::twip, o3tl::Length::in1000), 25));
+static_assert(eq(o3tl::convert(9.0, o3tl::Length::pt, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in1000), 500));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in1000, o3tl::Length::in1000), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::in1000), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in1000), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in1000), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in1000), 12000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in1000), 63360000));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::master, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::px, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::ch, o3tl::Length::in1000), 875));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::in1000), 650));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::in100), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in100), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in100), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in100), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in100), 500000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in100), 500E6));
+static_assert(eq(o3tl::convert(9144.0, o3tl::Length::emu, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::twip, o3tl::Length::in100), 5));
+static_assert(eq(o3tl::convert(18.0, o3tl::Length::pt, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in100), 50));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in1000, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in100), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in100), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in100), 1200));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in100), 6336000));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::master, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::px, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::ch, o3tl::Length::in100), 175));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::in100), 65));
+
+static_assert(eq(o3tl::convert(254.0, o3tl::Length::mm100, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in10), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in10), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in10), 50000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in10), 50E6));
+static_assert(eq(o3tl::convert(91440.0, o3tl::Length::emu, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::twip, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::pt, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::in1000, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in100, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in10), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in10), 120));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in10), 633600));
+static_assert(eq(o3tl::convert(288.0, o3tl::Length::master, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::px, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::ch, o3tl::Length::in10), 35));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::line, o3tl::Length::in10), 13));
+
+static_assert(eq(o3tl::convert(2540.0, o3tl::Length::mm100, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(254.0, o3tl::Length::mm10, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in), 5E6));
+static_assert(eq(o3tl::convert(914400.0, o3tl::Length::emu, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1440.0, o3tl::Length::twip, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::pt, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::pc, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::in1000, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::in100, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in10, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in), 12));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in), 63360));
+static_assert(eq(o3tl::convert(576.0, o3tl::Length::master, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(96.0, o3tl::Length::px, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::ch, o3tl::Length::in), 7));
+static_assert(eq(o3tl::convert(60.0, o3tl::Length::line, o3tl::Length::in), 13));
+
+static_assert(eq(o3tl::convert(30480.0, o3tl::Length::mm100, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(3048.0, o3tl::Length::mm10, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1524.0, o3tl::Length::mm, o3tl::Length::ft), 5));
+static_assert(eq(o3tl::convert(762.0, o3tl::Length::cm, o3tl::Length::ft), 25));
+static_assert(eq(o3tl::convert(381.0, o3tl::Length::m, o3tl::Length::ft), 1250));
+static_assert(eq(o3tl::convert(381.0, o3tl::Length::km, o3tl::Length::ft), 1250000));
+static_assert(eq(o3tl::convert(10972800.0, o3tl::Length::emu, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(17280.0, o3tl::Length::twip, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(864.0, o3tl::Length::pt, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::pc, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(12000.0, o3tl::Length::in1000, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1200.0, o3tl::Length::in100, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(120.0, o3tl::Length::in10, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::in, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::ft), 5280));
+static_assert(eq(o3tl::convert(6912.0, o3tl::Length::master, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1152.0, o3tl::Length::px, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(576.0, o3tl::Length::ch, o3tl::Length::ft), 7));
+static_assert(eq(o3tl::convert(720.0, o3tl::Length::line, o3tl::Length::ft), 13));
+
+static_assert(eq(o3tl::convert(160934400.0, o3tl::Length::mm100, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(16093440.0, o3tl::Length::mm10, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(1609344.0, o3tl::Length::mm, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(804672.0, o3tl::Length::cm, o3tl::Length::mi), 5));
+static_assert(eq(o3tl::convert(201168.0, o3tl::Length::m, o3tl::Length::mi), 125));
+static_assert(eq(o3tl::convert(25146.0, o3tl::Length::km, o3tl::Length::mi), 15625));
+static_assert(eq(o3tl::convert(57936384000.0, o3tl::Length::emu, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(91238400.0, o3tl::Length::twip, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(4561920.0, o3tl::Length::pt, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(380160.0, o3tl::Length::pc, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(63360000.0, o3tl::Length::in1000, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(6336000.0, o3tl::Length::in100, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(633600.0, o3tl::Length::in10, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(63360.0, o3tl::Length::in, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(5280.0, o3tl::Length::ft, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(36495360.0, o3tl::Length::master, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(6082560.0, o3tl::Length::px, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(3041280.0, o3tl::Length::ch, o3tl::Length::mi), 7));
+static_assert(eq(o3tl::convert(3801600.0, o3tl::Length::line, o3tl::Length::mi), 13));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::master), 144));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::master), 288));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::master), 2880));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::master), 28800));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::master), 2880000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::master), 2880E6));
+static_assert(eq(o3tl::convert(3175.0, o3tl::Length::emu, o3tl::Length::master), 2));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::twip, o3tl::Length::master), 2));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::master), 8));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::master), 96));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::master), 72));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::master), 144));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::master), 288));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::master), 576));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::master), 6912));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::master), 36495360));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::master, o3tl::Length::master), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::master), 6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::master), 84));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::master), 624));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::px), 24));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::px), 48));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::px), 480));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::px), 4800));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::px), 480000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::px), 480E6));
+static_assert(eq(o3tl::convert(9525.0, o3tl::Length::emu, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(15.0, o3tl::Length::twip, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pt, o3tl::Length::px), 4));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::px), 16));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::px), 12));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::px), 24));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::px), 48));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::px), 96));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::px), 1152));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::px), 6082560));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::master, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::px), 14));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::px), 104));
+
+static_assert(eq(o3tl::convert(4445.0, o3tl::Length::mm100, o3tl::Length::ch), 12));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::mm10, o3tl::Length::ch), 24));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::mm, o3tl::Length::ch), 240));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::cm, o3tl::Length::ch), 2400));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::m, o3tl::Length::ch), 240000));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::km, o3tl::Length::ch), 240E6));
+static_assert(eq(o3tl::convert(133350.0, o3tl::Length::emu, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(210.0, o3tl::Length::twip, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(21.0, o3tl::Length::pt, o3tl::Length::ch), 2));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::pc, o3tl::Length::ch), 8));
+static_assert(eq(o3tl::convert(875.0, o3tl::Length::in1000, o3tl::Length::ch), 6));
+static_assert(eq(o3tl::convert(175.0, o3tl::Length::in100, o3tl::Length::ch), 12));
+static_assert(eq(o3tl::convert(35.0, o3tl::Length::in10, o3tl::Length::ch), 24));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::in, o3tl::Length::ch), 48));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::ft, o3tl::Length::ch), 576));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::mi, o3tl::Length::ch), 3041280));
+static_assert(eq(o3tl::convert(84.0, o3tl::Length::master, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(14.0, o3tl::Length::px, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(35.0, o3tl::Length::line, o3tl::Length::ch), 52));
+
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm100, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm10, o3tl::Length::line), 30));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm, o3tl::Length::line), 300));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::cm, o3tl::Length::line), 3000));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::m, o3tl::Length::line), 300000));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::km, o3tl::Length::line), 300E6));
+static_assert(eq(o3tl::convert(198120.0, o3tl::Length::emu, o3tl::Length::line), 1));
+static_assert(eq(o3tl::convert(312.0, o3tl::Length::twip, o3tl::Length::line), 1));
+static_assert(eq(o3tl::convert(78.0, o3tl::Length::pt, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::pc, o3tl::Length::line), 10));
+static_assert(eq(o3tl::convert(650.0, o3tl::Length::in1000, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(65.0, o3tl::Length::in100, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::in10, o3tl::Length::line), 6));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::in, o3tl::Length::line), 60));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::ft, o3tl::Length::line), 720));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::mi, o3tl::Length::line), 3801600));
+static_assert(eq(o3tl::convert(624.0, o3tl::Length::master, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(104.0, o3tl::Length::px, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(52.0, o3tl::Length::ch, o3tl::Length::line), 35));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::line), 1));
+
+// testing integral conversion
+
+static_assert(o3tl::convert(100, o3tl::Length::mm100, o3tl::Length::mm100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::mm100) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm100) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm100) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm100) == 10000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm100) == 10000000000);
+static_assert(o3tl::convert(36000, o3tl::Length::emu, o3tl::Length::mm100) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::twip, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(1800, o3tl::Length::pt, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::mm100) == 127000);
+static_assert(o3tl::convert(5000, o3tl::Length::in1000, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in100, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::mm100) == 25400);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::mm100) == 254000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::mm100) == 3048000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm100) == 16093440000);
+static_assert(o3tl::convert(14400, o3tl::Length::master, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(2400, o3tl::Length::px, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(1200, o3tl::Length::ch, o3tl::Length::mm100) == 444500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::mm100) == 165100);
+
+static_assert(o3tl::convert(1000, o3tl::Length::mm100, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm10) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm10) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm10) == 1000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm10) == 1000000000);
+static_assert(o3tl::convert(360000, o3tl::Length::emu, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(72000, o3tl::Length::twip, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(3600, o3tl::Length::pt, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in1000, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in100, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::mm10) == 25400);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::mm10) == 304800);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm10) == 1609344000);
+static_assert(o3tl::convert(28800, o3tl::Length::master, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(4800, o3tl::Length::px, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(2400, o3tl::Length::ch, o3tl::Length::mm10) == 88900);
+static_assert(o3tl::convert(3000, o3tl::Length::line, o3tl::Length::mm10) == 165100);
+
+static_assert(o3tl::convert(10000, o3tl::Length::mm100, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::mm10, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm) == 100000000);
+static_assert(o3tl::convert(3600000, o3tl::Length::emu, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(720000, o3tl::Length::twip, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(36000, o3tl::Length::pt, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(3000, o3tl::Length::pc, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in1000, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in100, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in10, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::ft, o3tl::Length::mm) == 152400);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm) == 160934400);
+static_assert(o3tl::convert(288000, o3tl::Length::master, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(48000, o3tl::Length::px, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(24000, o3tl::Length::ch, o3tl::Length::mm) == 88900);
+static_assert(o3tl::convert(30000, o3tl::Length::line, o3tl::Length::mm) == 165100);
+
+static_assert(o3tl::convert(100000, o3tl::Length::mm100, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::mm10, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::mm, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::cm) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::cm) == 10000000);
+static_assert(o3tl::convert(36000000, o3tl::Length::emu, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(7200000, o3tl::Length::twip, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(360000, o3tl::Length::pt, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(30000, o3tl::Length::pc, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(5000000, o3tl::Length::in1000, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in100, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in10, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(2500, o3tl::Length::ft, o3tl::Length::cm) == 76200);
+static_assert(o3tl::convert(500, o3tl::Length::mi, o3tl::Length::cm) == 80467200);
+static_assert(o3tl::convert(2880000, o3tl::Length::master, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(480000, o3tl::Length::px, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(240000, o3tl::Length::ch, o3tl::Length::cm) == 88900);
+static_assert(o3tl::convert(300000, o3tl::Length::line, o3tl::Length::cm) == 165100);
+
+static_assert(o3tl::convert(10000000, o3tl::Length::mm100, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(1000000, o3tl::Length::mm10, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::mm, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::cm, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::m) == 100000);
+static_assert(o3tl::convert(3600000000, o3tl::Length::emu, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(720000000, o3tl::Length::twip, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(36000000, o3tl::Length::pt, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(3000000, o3tl::Length::pc, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(500000000, o3tl::Length::in1000, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(50000000, o3tl::Length::in100, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(5000000, o3tl::Length::in10, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(125000, o3tl::Length::ft, o3tl::Length::m) == 38100);
+static_assert(o3tl::convert(12500, o3tl::Length::mi, o3tl::Length::m) == 20116800);
+static_assert(o3tl::convert(288000000, o3tl::Length::master, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(48000000, o3tl::Length::px, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(24000000, o3tl::Length::ch, o3tl::Length::m) == 88900);
+static_assert(o3tl::convert(30000000, o3tl::Length::line, o3tl::Length::m) == 165100);
+
+static_assert(o3tl::convert(10000000000, o3tl::Length::mm100, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(1000000000, o3tl::Length::mm10, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100000000, o3tl::Length::mm, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(10000000, o3tl::Length::cm, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::m, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(3600000000000, o3tl::Length::emu, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(720000000000, o3tl::Length::twip, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(36000000000, o3tl::Length::pt, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(3000000000, o3tl::Length::pc, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(500000000000, o3tl::Length::in1000, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(50000000000, o3tl::Length::in100, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(5000000000, o3tl::Length::in10, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(500000000, o3tl::Length::in, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(125000000, o3tl::Length::ft, o3tl::Length::km) == 38100);
+static_assert(o3tl::convert(1562500, o3tl::Length::mi, o3tl::Length::km) == 2514600);
+static_assert(o3tl::convert(288000000000, o3tl::Length::master, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(48000000000, o3tl::Length::px, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(24000000000, o3tl::Length::ch, o3tl::Length::km) == 88900);
+static_assert(o3tl::convert(30000000000, o3tl::Length::line, o3tl::Length::km) == 165100);
+
+static_assert(o3tl::convert(100, o3tl::Length::mm100, o3tl::Length::emu) == 36000);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::emu) == 360000);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::emu) == 3600000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::emu) == 36000000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::emu) == 3600000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::emu) == 3600000000000);
+static_assert(o3tl::convert(100, o3tl::Length::emu, o3tl::Length::emu) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::twip, o3tl::Length::emu) == 63500);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::emu) == 1270000);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::emu) == 15240000);
+static_assert(o3tl::convert(500, o3tl::Length::in1000, o3tl::Length::emu) == 457200);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::emu) == 914400);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::emu) == 9144000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::emu) == 91440000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::emu) == 1097280000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::emu) == 5793638400000);
+static_assert(o3tl::convert(200, o3tl::Length::master, o3tl::Length::emu) == 317500);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::emu) == 952500);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::emu) == 13335000);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::emu) == 19812000);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::twip) == 7200);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::twip) == 72000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::twip) == 720000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::twip) == 7200000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::twip) == 720000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::twip) == 720000000000);
+static_assert(o3tl::convert(63500, o3tl::Length::emu, o3tl::Length::twip) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::twip, o3tl::Length::twip) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::twip) == 2000);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::twip) == 24000);
+static_assert(o3tl::convert(2500, o3tl::Length::in1000, o3tl::Length::twip) == 3600);
+static_assert(o3tl::convert(500, o3tl::Length::in100, o3tl::Length::twip) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::twip) == 14400);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::twip) == 144000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::twip) == 1728000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::twip) == 9123840000);
+static_assert(o3tl::convert(200, o3tl::Length::master, o3tl::Length::twip) == 500);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::twip) == 1500);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::twip) == 21000);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::twip) == 31200);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::pt) == 1800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::pt) == 3600);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::pt) == 36000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::pt) == 360000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::pt) == 36000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::pt) == 36000000000);
+static_assert(o3tl::convert(1270000, o3tl::Length::emu, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(2000, o3tl::Length::twip, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::pt) == 1200);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::pt) == 900);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::pt) == 1800);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::pt) == 3600);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::pt) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::pt) == 86400);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::pt) == 456192000);
+static_assert(o3tl::convert(800, o3tl::Length::master, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(400, o3tl::Length::px, o3tl::Length::pt) == 300);
+static_assert(o3tl::convert(200, o3tl::Length::ch, o3tl::Length::pt) == 2100);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::pt) == 7800);
+
+static_assert(o3tl::convert(127000, o3tl::Length::mm100, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::pc) == 3000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::pc) == 30000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::pc) == 3000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::pc) == 3000000000);
+static_assert(o3tl::convert(15240000, o3tl::Length::emu, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(24000, o3tl::Length::twip, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(1200, o3tl::Length::pt, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(50000, o3tl::Length::in1000, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(5000, o3tl::Length::in100, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::pc) == 600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::pc) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::pc) == 38016000);
+static_assert(o3tl::convert(9600, o3tl::Length::master, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(1600, o3tl::Length::px, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(800, o3tl::Length::ch, o3tl::Length::pc) == 700);
+static_assert(o3tl::convert(1000, o3tl::Length::line, o3tl::Length::pc) == 1300);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::in1000) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in1000) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in1000) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in1000) == 5000000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in1000) == 500000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in1000) == 500000000000);
+static_assert(o3tl::convert(457200, o3tl::Length::emu, o3tl::Length::in1000) == 500);
+static_assert(o3tl::convert(3600, o3tl::Length::twip, o3tl::Length::in1000) == 2500);
+static_assert(o3tl::convert(900, o3tl::Length::pt, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in1000) == 50000);
+static_assert(o3tl::convert(100, o3tl::Length::in1000, o3tl::Length::in1000) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::in1000) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in1000) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in1000) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in1000) == 1200000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in1000) == 6336000000);
+static_assert(o3tl::convert(7200, o3tl::Length::master, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(1200, o3tl::Length::px, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(600, o3tl::Length::ch, o3tl::Length::in1000) == 87500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::in1000) == 65000);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::in100) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in100) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in100) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in100) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in100) == 50000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in100) == 50000000000);
+static_assert(o3tl::convert(914400, o3tl::Length::emu, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::twip, o3tl::Length::in100) == 500);
+static_assert(o3tl::convert(1800, o3tl::Length::pt, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in100) == 5000);
+static_assert(o3tl::convert(1000, o3tl::Length::in1000, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in100) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in100) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in100) == 120000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in100) == 633600000);
+static_assert(o3tl::convert(14400, o3tl::Length::master, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(2400, o3tl::Length::px, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(1200, o3tl::Length::ch, o3tl::Length::in100) == 17500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::in100) == 6500);
+
+static_assert(o3tl::convert(25400, o3tl::Length::mm100, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in10) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in10) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in10) == 5000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in10) == 5000000000);
+static_assert(o3tl::convert(9144000, o3tl::Length::emu, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(14400, o3tl::Length::twip, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(3600, o3tl::Length::pt, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(10000, o3tl::Length::in1000, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::in100, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in10) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in10) == 12000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in10) == 63360000);
+static_assert(o3tl::convert(28800, o3tl::Length::master, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(4800, o3tl::Length::px, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(2400, o3tl::Length::ch, o3tl::Length::in10) == 3500);
+static_assert(o3tl::convert(600, o3tl::Length::line, o3tl::Length::in10) == 1300);
+
+static_assert(o3tl::convert(254000, o3tl::Length::mm100, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(25400, o3tl::Length::mm10, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in) == 500000000);
+static_assert(o3tl::convert(91440000, o3tl::Length::emu, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(144000, o3tl::Length::twip, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::pt, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(600, o3tl::Length::pc, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::in1000, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::in100, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::in10, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in) == 1200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in) == 6336000);
+static_assert(o3tl::convert(57600, o3tl::Length::master, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(9600, o3tl::Length::px, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(4800, o3tl::Length::ch, o3tl::Length::in) == 700);
+static_assert(o3tl::convert(6000, o3tl::Length::line, o3tl::Length::in) == 1300);
+
+static_assert(o3tl::convert(3048000, o3tl::Length::mm100, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(304800, o3tl::Length::mm10, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(152400, o3tl::Length::mm, o3tl::Length::ft) == 500);
+static_assert(o3tl::convert(76200, o3tl::Length::cm, o3tl::Length::ft) == 2500);
+static_assert(o3tl::convert(38100, o3tl::Length::m, o3tl::Length::ft) == 125000);
+static_assert(o3tl::convert(38100, o3tl::Length::km, o3tl::Length::ft) == 125000000);
+static_assert(o3tl::convert(1097280000, o3tl::Length::emu, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1728000, o3tl::Length::twip, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(86400, o3tl::Length::pt, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::pc, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1200000, o3tl::Length::in1000, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(120000, o3tl::Length::in100, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(12000, o3tl::Length::in10, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1200, o3tl::Length::in, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::ft) == 528000);
+static_assert(o3tl::convert(691200, o3tl::Length::master, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(115200, o3tl::Length::px, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(57600, o3tl::Length::ch, o3tl::Length::ft) == 700);
+static_assert(o3tl::convert(72000, o3tl::Length::line, o3tl::Length::ft) == 1300);
+
+static_assert(o3tl::convert(16093440000, o3tl::Length::mm100, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(1609344000, o3tl::Length::mm10, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(160934400, o3tl::Length::mm, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(80467200, o3tl::Length::cm, o3tl::Length::mi) == 500);
+static_assert(o3tl::convert(20116800, o3tl::Length::m, o3tl::Length::mi) == 12500);
+static_assert(o3tl::convert(2514600, o3tl::Length::km, o3tl::Length::mi) == 1562500);
+static_assert(o3tl::convert(5793638400000, o3tl::Length::emu, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(9123840000, o3tl::Length::twip, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(456192000, o3tl::Length::pt, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(38016000, o3tl::Length::pc, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(6336000000, o3tl::Length::in1000, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(633600000, o3tl::Length::in100, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(63360000, o3tl::Length::in10, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(6336000, o3tl::Length::in, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(528000, o3tl::Length::ft, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(3649536000, o3tl::Length::master, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(608256000, o3tl::Length::px, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(304128000, o3tl::Length::ch, o3tl::Length::mi) == 700);
+static_assert(o3tl::convert(380160000, o3tl::Length::line, o3tl::Length::mi) == 1300);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::master) == 14400);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::master) == 28800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::master) == 288000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::master) == 2880000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::master) == 288000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::master) == 288000000000);
+static_assert(o3tl::convert(317500, o3tl::Length::emu, o3tl::Length::master) == 200);
+static_assert(o3tl::convert(500, o3tl::Length::twip, o3tl::Length::master) == 200);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::master) == 800);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::master) == 9600);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::master) == 7200);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::master) == 14400);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::master) == 28800);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::master) == 57600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::master) == 691200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::master) == 3649536000);
+static_assert(o3tl::convert(100, o3tl::Length::master, o3tl::Length::master) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::master) == 600);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::master) == 8400);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::master) == 62400);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::px) == 2400);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::px) == 4800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::px) == 48000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::px) == 480000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::px) == 48000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::px) == 48000000000);
+static_assert(o3tl::convert(952500, o3tl::Length::emu, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(1500, o3tl::Length::twip, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(300, o3tl::Length::pt, o3tl::Length::px) == 400);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::px) == 1600);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::px) == 1200);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::px) == 2400);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::px) == 4800);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::px) == 9600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::px) == 115200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::px) == 608256000);
+static_assert(o3tl::convert(600, o3tl::Length::master, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::px) == 1400);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::px) == 10400);
+
+static_assert(o3tl::convert(444500, o3tl::Length::mm100, o3tl::Length::ch) == 1200);
+static_assert(o3tl::convert(88900, o3tl::Length::mm10, o3tl::Length::ch) == 2400);
+static_assert(o3tl::convert(88900, o3tl::Length::mm, o3tl::Length::ch) == 24000);
+static_assert(o3tl::convert(88900, o3tl::Length::cm, o3tl::Length::ch) == 240000);
+static_assert(o3tl::convert(88900, o3tl::Length::m, o3tl::Length::ch) == 24000000);
+static_assert(o3tl::convert(88900, o3tl::Length::km, o3tl::Length::ch) == 24000000000);
+static_assert(o3tl::convert(13335000, o3tl::Length::emu, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(21000, o3tl::Length::twip, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(2100, o3tl::Length::pt, o3tl::Length::ch) == 200);
+static_assert(o3tl::convert(700, o3tl::Length::pc, o3tl::Length::ch) == 800);
+static_assert(o3tl::convert(87500, o3tl::Length::in1000, o3tl::Length::ch) == 600);
+static_assert(o3tl::convert(17500, o3tl::Length::in100, o3tl::Length::ch) == 1200);
+static_assert(o3tl::convert(3500, o3tl::Length::in10, o3tl::Length::ch) == 2400);
+static_assert(o3tl::convert(700, o3tl::Length::in, o3tl::Length::ch) == 4800);
+static_assert(o3tl::convert(700, o3tl::Length::ft, o3tl::Length::ch) == 57600);
+static_assert(o3tl::convert(700, o3tl::Length::mi, o3tl::Length::ch) == 304128000);
+static_assert(o3tl::convert(8400, o3tl::Length::master, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(1400, o3tl::Length::px, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(3500, o3tl::Length::line, o3tl::Length::ch) == 5200);
+
+static_assert(o3tl::convert(165100, o3tl::Length::mm100, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(165100, o3tl::Length::mm10, o3tl::Length::line) == 3000);
+static_assert(o3tl::convert(165100, o3tl::Length::mm, o3tl::Length::line) == 30000);
+static_assert(o3tl::convert(165100, o3tl::Length::cm, o3tl::Length::line) == 300000);
+static_assert(o3tl::convert(165100, o3tl::Length::m, o3tl::Length::line) == 30000000);
+static_assert(o3tl::convert(165100, o3tl::Length::km, o3tl::Length::line) == 30000000000);
+static_assert(o3tl::convert(19812000, o3tl::Length::emu, o3tl::Length::line) == 100);
+static_assert(o3tl::convert(31200, o3tl::Length::twip, o3tl::Length::line) == 100);
+static_assert(o3tl::convert(7800, o3tl::Length::pt, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(1300, o3tl::Length::pc, o3tl::Length::line) == 1000);
+static_assert(o3tl::convert(65000, o3tl::Length::in1000, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(6500, o3tl::Length::in100, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(1300, o3tl::Length::in10, o3tl::Length::line) == 600);
+static_assert(o3tl::convert(1300, o3tl::Length::in, o3tl::Length::line) == 6000);
+static_assert(o3tl::convert(1300, o3tl::Length::ft, o3tl::Length::line) == 72000);
+static_assert(o3tl::convert(1300, o3tl::Length::mi, o3tl::Length::line) == 380160000);
+static_assert(o3tl::convert(62400, o3tl::Length::master, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(10400, o3tl::Length::px, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(5200, o3tl::Length::ch, o3tl::Length::line) == 3500);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::line) == 100);
+
+// Integral rounding
+
+static_assert(o3tl::convert(49, o3tl::Length::mm100, o3tl::Length::mm) == 0);
+static_assert(o3tl::convert(50, o3tl::Length::mm100, o3tl::Length::mm) == 1);
+
+// Conversions used in the code - to make sure they produce the expected and unchanged result
+
+static_assert(o3tl::toTwips(25, o3tl::Length::in100) == 1440 / 4);
+static_assert(o3tl::toTwips(15, o3tl::Length::in100) == 216);
+// the following twip value used to the constant for 20mm
+static_assert(o3tl::toTwips(20, o3tl::Length::mm) == 1134);
+// 847 100thmm used to represent 24pt
+static_assert(o3tl::convert(24, o3tl::Length::pt, o3tl::Length::mm100) == 847);
+
+static_assert(o3tl::convertSaturate(SAL_MAX_INT64, 72, 127) == 5228998320106644552); // no overflow
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/o3tl/qa/test-vector_pool.cxx b/o3tl/qa/test-vector_pool.cxx
new file mode 100644
index 0000000000..6e739ebcd1
--- /dev/null
+++ b/o3tl/qa/test-vector_pool.cxx
@@ -0,0 +1,88 @@
+/* -*- 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 <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: */