From 821af09916878cc088b71e380980a75dc1017e10 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 15 Jan 2024 16:25:29 -0500 Subject: [PATCH] cpp-common/bt2c: add CStringView equality and non-equality operators Add `operator==` and `operator!=` functions to check equality or non-equality between `CStringView` and another `CStringView`, `const char *` and `std::string`. Add a test to exercise those. Change-Id: I2463966aae50792bb3e21ae65f9f124b08114499 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/11681 Tested-by: jenkins Reviewed-by: Philippe Proulx --- src/cpp-common/bt2c/c-string-view.hpp | 63 +++++++++++++++++++ tests/Makefile.am | 23 +++++++ tests/cpp-common/test-c-string-view.cpp | 84 +++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 tests/cpp-common/test-c-string-view.cpp diff --git a/src/cpp-common/bt2c/c-string-view.hpp b/src/cpp-common/bt2c/c-string-view.hpp index a7b54e70..54c87de9 100644 --- a/src/cpp-common/bt2c/c-string-view.hpp +++ b/src/cpp-common/bt2c/c-string-view.hpp @@ -15,6 +15,8 @@ #include "cpp-common/bt2s/string-view.hpp" #include "cpp-common/vendor/fmt/format.h" +#include "type-traits.hpp" + namespace bt2c { /* @@ -183,6 +185,67 @@ static inline const char *format_as(const CStringView& str) return str ? *str : "(null)"; } +namespace internal { + +template +const char *asConstCharPtr(StrT&& val) noexcept +{ + return val.data(); +} + +inline const char *asConstCharPtr(const char * const val) noexcept +{ + return val; +} + +template +using ComparableWithCStringView = + IsOneOf::type, CStringView, std::string, const char *>; + +} /* namespace internal */ + +/* + * Returns true if `lhs` is equal to `rhs`. + * + * `LhsT` and `RhsT` may be any of: + * + * • `const char *` + * • `std::string` + * • `CStringView` + * + * Both `lhs` and `rhs` must not have an underlying `nullptr` raw data. + */ +template < + typename LhsT, typename RhsT, + typename = typename std::enable_if::value>::type, + typename = typename std::enable_if::value>::type> +bool operator==(LhsT&& lhs, RhsT&& rhs) noexcept +{ + const auto rawLhs = internal::asConstCharPtr(lhs); + const auto rawRhs = internal::asConstCharPtr(rhs); + + BT_ASSERT_DBG(rawLhs); + BT_ASSERT_DBG(rawRhs); + return std::strcmp(rawLhs, rawRhs) == 0; +} + +/* + * Returns true if `lhs` is not equal to `rhs`. + * + * `LhsT` and `RhsT` may be any of: + * + * • `const char *` + * • `std::string` + * • `CStringView` + * + * Both `lhs` and `rhs` must not have an underlying `nullptr` raw data. + */ +template +bool operator!=(LhsT&& lhs, RhsT&& rhs) noexcept +{ + return !(std::forward(lhs) == std::forward(rhs)); +} + } /* namespace bt2c */ #endif /* BABELTRACE_CPP_COMMON_BT2C_C_STRING_VIEW_HPP */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 90382fb4..a24f3208 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -8,6 +8,13 @@ SUBDIRS = \ plugins \ param-validation +AM_CPPFLAGS += -I$(top_srcdir)/tests/utils + +COMMON_TEST_LDADD = \ + $(top_builddir)/tests/utils/tap/libtap.la \ + $(top_builddir)/src/common/libcommon.la \ + $(top_builddir)/src/logging/liblogging.la + # Directories added to EXTRA_DIST will be recursively copied to the distribution. EXTRA_DIST = $(srcdir)/data \ bindings/python/bt2/.coveragerc @@ -63,6 +70,8 @@ dist_check_SCRIPTS = \ python-plugin-provider/test-python-plugin-provider.sh \ python-plugin-provider/test_python_plugin_provider.py +noinst_PROGRAMS = + TESTS_BINDINGS = if ENABLE_PYTHON_BINDINGS @@ -80,6 +89,18 @@ TESTS_CLI = \ cli/test-trace-read.sh \ cli/test-trimmer.sh +noinst_PROGRAMS += \ + cpp-common/test-c-string-view + +cpp_common_test_c_string_view_SOURCES = \ + cpp-common/test-c-string-view.cpp + +cpp_common_test_c_string_view_LDADD = \ + $(COMMON_TEST_LDADD) + +TESTS_CPP_COMMON = \ + cpp-common/test-c-string-view + TESTS_LIB = \ lib/test-bt-uuid \ lib/test-bt-values \ @@ -176,6 +197,7 @@ LOG_DRIVER = env AM_TAP_AWK='$(AWK)' \ TESTS_NO_BITFIELD = \ $(TESTS_BINDINGS) \ $(TESTS_CLI) \ + $(TESTS_CPP_COMMON) \ $(TESTS_CTF_WRITER) \ $(TESTS_LIB) \ $(TESTS_PARAM_VALIDATION) \ @@ -192,6 +214,7 @@ endef $(eval $(call check_target,bindings,$(TESTS_BINDINGS))) $(eval $(call check_target,bitfield,$(TESTS_BITFIELD))) $(eval $(call check_target,cli,$(TESTS_CLI))) +$(eval $(call check_target,cpp-common,$(TESTS_CPP_COMMON))) $(eval $(call check_target,ctf-writer,$(TESTS_CTF_WRITER))) $(eval $(call check_target,lib,$(TESTS_LIB))) $(eval $(call check_target,plugins,$(TESTS_PLUGINS))) diff --git a/tests/cpp-common/test-c-string-view.cpp b/tests/cpp-common/test-c-string-view.cpp new file mode 100644 index 00000000..d137763c --- /dev/null +++ b/tests/cpp-common/test-c-string-view.cpp @@ -0,0 +1,84 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2024 EfficiOS, Inc. + */ + +#include + +#include "cpp-common/bt2c/c-string-view.hpp" + +#include "tap/tap.h" + +namespace { + +template +const char *asConstCharPtr(StrT&& val) +{ + return val.data(); +} + +const char *asConstCharPtr(const char * const val) +{ + return val; +} + +const char *typeName(bt2c::CStringView) +{ + return "bt2c::CStringView"; +} + +const char *typeName(const char *) +{ + return "const char *"; +} + +const char *typeName(const std::string&) +{ + return "std::string"; +} + +template +void testEq(Str1T&& lhs, Str2T&& rhs) +{ + BT_ASSERT(asConstCharPtr(lhs) != asConstCharPtr(rhs)); + ok(lhs == rhs, "`%s` == `%s`", typeName(lhs), typeName(rhs)); +} + +template +void testNe(Str1T&& lhs, Str2T&& rhs) +{ + BT_ASSERT(asConstCharPtr(lhs) != asConstCharPtr(rhs)); + ok(lhs != rhs, "`%s` != `%s`", typeName(lhs), typeName(rhs)); +} + +void testEquality() +{ + const std::string foo1 = "foo", foo2 = "foo"; + const std::string bar = "bar"; + + /* `CStringView` vs `CStringView` */ + testEq(bt2c::CStringView {foo1}, bt2c::CStringView {foo2}); + testNe(bt2c::CStringView {foo1}, bt2c::CStringView {bar}); + + /* `CStringView` vs `const char *` */ + testEq(bt2c::CStringView {foo1}, foo2.c_str()); + testNe(bt2c::CStringView {foo1}, bar.c_str()); + testEq(foo1.c_str(), bt2c::CStringView {foo2}); + testNe(foo1.c_str(), bt2c::CStringView {bar}); + + /* `StringView` vs `std::string` */ + testEq(bt2c::CStringView {foo1}, foo2); + testNe(bt2c::CStringView {foo1}, bar); + testEq(foo1, bt2c::CStringView {foo2}); + testNe(foo1, bt2c::CStringView {bar}); +} + +} // namespace + +int main() +{ + plan_tests(10); + testEquality(); + return exit_status(); +} -- 2.34.1