From b1904deda76b794f826c5cdfb69aa5f1618d559f Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Fri, 17 Feb 2023 22:52:47 +0100 Subject: [PATCH 1/4] use boost-cmake again this is a workaround to reduce the build time update boost example after review --- .cmake-format | 1 + README.md | 9 +++------ examples/boost/CMakeLists.txt | 21 +++++++++++---------- examples/boost/deferred.cpp | 35 +++++++++++++++++++++++++++++++++++ examples/boost/main.cpp | 26 -------------------------- 5 files changed, 50 insertions(+), 42 deletions(-) create mode 100644 examples/boost/deferred.cpp delete mode 100644 examples/boost/main.cpp diff --git a/.cmake-format b/.cmake-format index 24850af3..19b2ee88 100644 --- a/.cmake-format +++ b/.cmake-format @@ -57,6 +57,7 @@ parse: kwargs: NAME: 1 VERSION: 1 + NAMESPACE: 1 INCLUDE_DIR: 1 INCLUDE_DESTINATION: 1 BINARY_DIR: 1 diff --git a/README.md b/README.md index de3d4571..1b0c87f7 100644 --- a/README.md +++ b/README.md @@ -367,12 +367,9 @@ CPMAddPackage( ```CMake # boost is a huge project and will take a while to download # using `CPM_SOURCE_CACHE` is strongly recommended -CPMAddPackage( - NAME Boost - VERSION 1.81.0 - GITHUB_REPOSITORY "boostorg/boost" - GIT_TAG "boost-1.81.0" -) + +# using unofficial fork as boost's lacking good CMake support +CPMAddPackage("gh:ClausKlein/boost-cmake@1.79.2") ``` ### [cxxopts](https://github.com/jarro2783/cxxopts) diff --git a/examples/boost/CMakeLists.txt b/examples/boost/CMakeLists.txt index 0e1c49c3..24240ebc 100644 --- a/examples/boost/CMakeLists.txt +++ b/examples/boost/CMakeLists.txt @@ -1,21 +1,22 @@ -cmake_minimum_required(VERSION 3.14 FATAL_ERROR) +cmake_minimum_required(VERSION 3.14...3.24) project(CPMExampleBoost) # ---- Create binary ---- -add_executable(CPMExampleBoost main.cpp) -target_compile_features(CPMExampleBoost PRIVATE cxx_std_17) +add_executable(CPMExampleAsio deferred.cpp) +target_compile_features(CPMExampleAsio PRIVATE cxx_std_17) # ---- Dependencies ---- include(../../cmake/CPM.cmake) -CPMAddPackage( - NAME Boost - VERSION 1.81.0 - GITHUB_REPOSITORY "boostorg/boost" - GIT_TAG "boost-1.81.0" -) +# using unofficial fork as boost's lacking good CMake support +CPMAddPackage("gh:ClausKlein/boost-cmake@1.79.2") -target_link_libraries(CPMExampleBoost PRIVATE Boost::asio) +target_link_libraries(CPMExampleAsio PRIVATE Boost::asio) + +# ---- Testing ---- + +enable_testing() +add_test(NAME CPMExampleAsio COMMAND CPMExampleAsio) diff --git a/examples/boost/deferred.cpp b/examples/boost/deferred.cpp new file mode 100644 index 00000000..415d4054 --- /dev/null +++ b/examples/boost/deferred.cpp @@ -0,0 +1,35 @@ +// +// deferred_1.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include + +using boost::asio::experimental::deferred; + +int main() { + boost::asio::io_context ctx; + + boost::asio::steady_timer timer(ctx); + timer.expires_after(std::chrono::seconds(1)); + + auto deferred_op = timer.async_wait(deferred); + + std::move(deferred_op)([](boost::system::error_code ec) { + if (ec) + std::cout << "timer wait finished with error: " << ec.message() << "\n"; + else + std::cout << "timer wait finished.\n"; + }); + + ctx.run(); + + return 0; +} diff --git a/examples/boost/main.cpp b/examples/boost/main.cpp deleted file mode 100644 index 24aa0dee..00000000 --- a/examples/boost/main.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// -// timer.cpp -// ~~~~~~~~~ -// -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#include -#include -#include - -void print(const boost::system::error_code& /*e*/) { std::cout << "Hello, world!" << std::endl; } - -int main() { - boost::asio::io_service io; - - boost::asio::deadline_timer t(io, boost::posix_time::seconds(1)); - t.async_wait(&print); - - io.run(); - - return 0; -} \ No newline at end of file From 462f0045274d8848e1f78979131fe1fe37d813f9 Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Sat, 18 Feb 2023 00:30:41 +0100 Subject: [PATCH 2/4] Update boost-cmake tag --- examples/boost/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/boost/CMakeLists.txt b/examples/boost/CMakeLists.txt index 24240ebc..6d411974 100644 --- a/examples/boost/CMakeLists.txt +++ b/examples/boost/CMakeLists.txt @@ -12,7 +12,7 @@ target_compile_features(CPMExampleAsio PRIVATE cxx_std_17) include(../../cmake/CPM.cmake) # using unofficial fork as boost's lacking good CMake support -CPMAddPackage("gh:ClausKlein/boost-cmake@1.79.2") +CPMAddPackage("gh:ClausKlein/boost-cmake@1.79.3") target_link_libraries(CPMExampleAsio PRIVATE Boost::asio) From 772e635c92f4f2b5fe8d0479fd1bfec456cfbcbb Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Mon, 20 Feb 2023 07:33:44 +0100 Subject: [PATCH 3/4] Use Boost v1.80.0 and add regex example too --- examples/boost/CMakeLists.txt | 12 ++++++-- examples/boost/deferred.cpp | 8 ++---- examples/boost/regex.cpp | 53 +++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 examples/boost/regex.cpp diff --git a/examples/boost/CMakeLists.txt b/examples/boost/CMakeLists.txt index 6d411974..b4110de8 100644 --- a/examples/boost/CMakeLists.txt +++ b/examples/boost/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14...3.24) +cmake_minimum_required(VERSION 3.14...3.26) project(CPMExampleBoost) @@ -7,16 +7,22 @@ project(CPMExampleBoost) add_executable(CPMExampleAsio deferred.cpp) target_compile_features(CPMExampleAsio PRIVATE cxx_std_17) +add_executable(CPMExampleRegex regex.cpp) +target_compile_features(CPMExampleRegex PRIVATE cxx_std_17) + # ---- Dependencies ---- include(../../cmake/CPM.cmake) -# using unofficial fork as boost's lacking good CMake support -CPMAddPackage("gh:ClausKlein/boost-cmake@1.79.3") +# using unofficial fork as boost's lacking good CMake support for user +CPMAddPackage("gh:ClausKlein/boost-cmake@1.80.0") target_link_libraries(CPMExampleAsio PRIVATE Boost::asio) +target_link_libraries(CPMExampleRegex PRIVATE Boost::regex) # ---- Testing ---- enable_testing() + add_test(NAME CPMExampleAsio COMMAND CPMExampleAsio) +add_test(NAME CPMExampleRegex COMMAND CPMExampleAsio) diff --git a/examples/boost/deferred.cpp b/examples/boost/deferred.cpp index 415d4054..a3d56d8d 100644 --- a/examples/boost/deferred.cpp +++ b/examples/boost/deferred.cpp @@ -9,10 +9,9 @@ // #include -#include #include -using boost::asio::experimental::deferred; +using boost::asio::deferred; int main() { boost::asio::io_context ctx; @@ -23,10 +22,7 @@ int main() { auto deferred_op = timer.async_wait(deferred); std::move(deferred_op)([](boost::system::error_code ec) { - if (ec) - std::cout << "timer wait finished with error: " << ec.message() << "\n"; - else - std::cout << "timer wait finished.\n"; + std::cout << "timer wait finished: " << ec.message() << "\n"; }); ctx.run(); diff --git a/examples/boost/regex.cpp b/examples/boost/regex.cpp new file mode 100644 index 00000000..f0381c97 --- /dev/null +++ b/examples/boost/regex.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +int main() { + using namespace boost; + + std::string s + = "Some people, when confronted with a problem, think " + "\"I know, I'll use regular expressions.\" " + "Now they have two problems."; + + regex self_regex("REGULAR EXPRESSIONS", regex_constants::icase); + if (regex_search(s, self_regex)) { + std::cout << "Text contains the phrase 'regular expressions'\n"; + } + + regex nonws_regex("(\\S+)"); + regex word_regex("(\\w+)"); + sregex_iterator words_begin = sregex_iterator(s.begin(), s.end(), word_regex); + sregex_iterator words_end = sregex_iterator(); + + std::cout << "Found " << std::distance(words_begin, words_end) << " words\n"; + + constexpr int N{6}; + std::cout << "Words greater than " << N << " characters:\n"; + for (sregex_iterator i = words_begin; i != words_end; ++i) { + smatch match = *i; + std::string match_str = match.str(); + if (match_str.size() > N) { + std::cout << " " << match_str << '\n'; + } + } + + regex long_word_regex("(\\w{7,})"); + std::string new_s = regex_replace(s, long_word_regex, std::string("[$&]")); + std::cout << new_s << '\n'; + + { + std::string text = "Quick brown fox"; + regex vowel_re("a|e|i|o|u"); + + // write the results to an output iterator + regex_replace(std::ostreambuf_iterator(std::cout), text.begin(), text.end(), vowel_re, + std::string("'*'")); + + // construct a string holding the results + std::cout << '\n' << regex_replace(text, vowel_re, std::string("[$&]")) << '\n'; + } + + return 0; +} From 17ba5c6e5e3c6fdf443851b8130ddfafa298b92c Mon Sep 17 00:00:00 2001 From: ClausKlein Date: Mon, 20 Feb 2023 07:58:49 +0100 Subject: [PATCH 4/4] Add Boost::unit_test_framework example too --- examples/boost/CMakeLists.txt | 5 + examples/boost/const_string.hpp | 183 +++++++++++++++++++++++++++ examples/boost/const_string_test.cpp | 172 +++++++++++++++++++++++++ 3 files changed, 360 insertions(+) create mode 100644 examples/boost/const_string.hpp create mode 100644 examples/boost/const_string_test.cpp diff --git a/examples/boost/CMakeLists.txt b/examples/boost/CMakeLists.txt index b4110de8..7ffe5199 100644 --- a/examples/boost/CMakeLists.txt +++ b/examples/boost/CMakeLists.txt @@ -10,6 +10,9 @@ target_compile_features(CPMExampleAsio PRIVATE cxx_std_17) add_executable(CPMExampleRegex regex.cpp) target_compile_features(CPMExampleRegex PRIVATE cxx_std_17) +add_executable(CPMExampleTest const_string_test.cpp) +target_compile_features(CPMExampleTest PRIVATE cxx_std_17) + # ---- Dependencies ---- include(../../cmake/CPM.cmake) @@ -19,6 +22,7 @@ CPMAddPackage("gh:ClausKlein/boost-cmake@1.80.0") target_link_libraries(CPMExampleAsio PRIVATE Boost::asio) target_link_libraries(CPMExampleRegex PRIVATE Boost::regex) +target_link_libraries(CPMExampleTest PRIVATE Boost::unit_test_framework) # ---- Testing ---- @@ -26,3 +30,4 @@ enable_testing() add_test(NAME CPMExampleAsio COMMAND CPMExampleAsio) add_test(NAME CPMExampleRegex COMMAND CPMExampleAsio) +add_test(NAME CPMExampleTest COMMAND CPMExampleTest) diff --git a/examples/boost/const_string.hpp b/examples/boost/const_string.hpp new file mode 100644 index 00000000..75e30fd9 --- /dev/null +++ b/examples/boost/const_string.hpp @@ -0,0 +1,183 @@ +// (C) Copyright Gennadiy Rozental 2001-2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision$ +// +// Description : simple string class definition +// *************************************************************************** + +#ifndef CONST_STRING_HPP +#define CONST_STRING_HPP + +// STL +#include +#include +#include +using std::string; + +namespace common_layer { + + // ************************************************************************** + // ************** const_string ************** + // ************************************************************************** + + class const_string { + public: + // Subtypes + typedef char const* iterator; + typedef char const* const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef reverse_iterator const_reverse_iterator; + + // Constructor + const_string() : m_begin(""), m_end(m_begin) {} + + // Copy constructor is generated by compiler + + const_string(const std::string& s) : m_begin(s.c_str()), m_end(m_begin + s.length()) {} + + const_string(char const* s) + : m_begin(s ? s : ""), m_end(s ? m_begin + std::strlen(s) : m_begin) {} + + const_string(char const* s, size_t length) : m_begin(s), m_end(m_begin + length) { + if (length == 0) erase(); + } + + const_string(char const* first, char const* last) : m_begin(first), m_end(last) {} + + // data access methods + char operator[](size_t index) const { return m_begin[index]; } + char at(size_t index) const { return m_begin[index]; } + + char const* data() const { return m_begin; } + + // length operators + size_t length() const { return m_end - m_begin; } + bool is_empty() const { return m_end == m_begin; } + + void erase() { m_begin = m_end = ""; } + void resize(size_t new_len) { + if (m_begin + new_len < m_end) m_end = m_begin + new_len; + } + void rshorten(size_t shift = 1) { + m_end -= shift; + if (m_end <= m_begin) erase(); + } + void lshorten(size_t shift = 1) { + m_begin += shift; + if (m_end <= m_begin) erase(); + } + + // Assignment operators + const_string& operator=(const_string const& s); + const_string& operator=(string const& s) { return *this = const_string(s); } + const_string& operator=(char const* s) { return *this = const_string(s); } + + const_string& assign(const_string const& s) { return *this = s; } + const_string& assign(string const& s, size_t len) { + return *this = const_string(s.data(), len); + } + const_string& assign(string const& s) { return *this = const_string(s); } + const_string& assign(char const* s) { return *this = const_string(s); } + const_string& assign(char const* s, size_t len) { return *this = const_string(s, len); } + const_string& assign(char const* f, char const* l) { return *this = const_string(f, l); } + + void swap(const_string& s) { + // do not want to include alogrithm + char const* tmp1 = m_begin; + char const* tmp2 = m_end; + + m_begin = s.m_begin; + m_end = s.m_end; + + s.m_begin = tmp1; + s.m_end = tmp2; + } + + // Comparison operators + friend bool operator==(const_string const& s1, const_string const& s2) { + return s1.length() == s2.length() && std::strncmp(s1.data(), s2.data(), s1.length()) == 0; + } + friend bool operator==(const_string const& s1, char const* s2) { + return s1 == const_string(s2); + } + friend bool operator==(const_string const& s1, const string& s2) { + return s1 == const_string(s2); + } + + friend bool operator!=(const_string const& s1, const_string const& s2) { return !(s1 == s2); } + friend bool operator!=(const_string const& s1, char const* s2) { return !(s1 == s2); } + friend bool operator!=(const_string const& s1, const string& s2) { return !(s1 == s2); } + + friend bool operator==(char const* s2, const_string const& s1) { return s1 == s2; } + friend bool operator==(const string& s2, const_string const& s1) { return s1 == s2; } + + friend bool operator!=(char const* s2, const_string const& s1) { return !(s1 == s2); } + friend bool operator!=(const string& s2, const_string const& s1) { return !(s1 == s2); } + + // Iterators + iterator begin() const { return m_begin; } + iterator end() const { return m_end; } + reverse_iterator rbegin() const { return reverse_iterator(m_end); } + reverse_iterator rend() const { return reverse_iterator(m_begin); } + + private: + // Data members + char const* m_begin; + char const* m_end; + }; + + //____________________________________________________________________________ + + // first character + class first_char { + public: + char operator()(const_string source, char default_char = '\0') const { + return source.is_empty() ? default_char : *source.data(); + } + }; + + //____________________________________________________________________________ + + // last character + class last_char { + public: + char operator()(const_string source, char default_char = '\0') const { + return source.is_empty() ? default_char : *source.rbegin(); + } + }; + + //____________________________________________________________________________ + + inline const_string& const_string::operator=(const_string const& s) { + if (&s != this) { + m_begin = s.m_begin; + m_end = s.m_end; + } + + return *this; + } + + //____________________________________________________________________________ + + typedef const_string const literal; + + //____________________________________________________________________________ + + inline std::ostream& operator<<(std::ostream& os, const_string const& str) { + os << std::string(str.begin(), str.length()); + + return os; + } + + //____________________________________________________________________________ + +}; // namespace common_layer + +#endif // CONST_STRING_HPP diff --git a/examples/boost/const_string_test.cpp b/examples/boost/const_string_test.cpp new file mode 100644 index 00000000..d87318ab --- /dev/null +++ b/examples/boost/const_string_test.cpp @@ -0,0 +1,172 @@ +// (C) Copyright Gennadiy Rozental 2001-2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile: const_string_test.cpp,v $ +// +// Version : $Revision$ +// +// Description : simple string class test +// *************************************************************************** + +#define BOOST_TEST_MODULE const_string test +#include "const_string.hpp" + +#include +using common_layer::const_string; + +BOOST_AUTO_TEST_CASE(constructors_test) { + const_string cs0(""); + BOOST_CHECK_EQUAL(cs0.length(), (size_t)0); + BOOST_CHECK_EQUAL(cs0.begin(), ""); + BOOST_CHECK_EQUAL(cs0.end(), ""); + BOOST_CHECK(cs0.is_empty()); + + const_string cs01(NULL); + BOOST_CHECK_EQUAL(cs01.length(), (size_t)0); + BOOST_CHECK_EQUAL(cs01.begin(), ""); + BOOST_CHECK_EQUAL(cs01.end(), ""); + BOOST_CHECK(cs01.is_empty()); + + const_string cs1("test_string"); + BOOST_CHECK_EQUAL(std::strcmp(cs1.data(), "test_string"), 0); + BOOST_CHECK_EQUAL(cs1.length(), std::strlen("test_string")); + + std::string s("test_string"); + const_string cs2(s); + BOOST_CHECK_EQUAL(std::strcmp(cs2.data(), "test_string"), 0); + + const_string cs3(cs1); + BOOST_CHECK_EQUAL(std::strcmp(cs3.data(), "test_string"), 0); + + const_string cs4("test_string", 4); + BOOST_CHECK_EQUAL(std::strncmp(cs4.data(), "test", cs4.length()), 0); + + const_string cs5(s.data(), s.data() + s.length()); + BOOST_CHECK_EQUAL(std::strncmp(cs5.data(), "test_string", cs5.length()), 0); + + const_string cs_array[] = {"str1", "str2"}; + + BOOST_CHECK_EQUAL(cs_array[0], "str1"); + BOOST_CHECK_EQUAL(cs_array[1], "str2"); +} + +BOOST_AUTO_TEST_CASE(data_access_test) { + const_string cs1("test_string"); + BOOST_CHECK_EQUAL(std::strcmp(cs1.data(), "test_string"), 0); + + BOOST_CHECK_EQUAL(cs1[(size_t)0], 't'); + BOOST_CHECK_EQUAL(cs1[(size_t)4], '_'); + BOOST_CHECK_EQUAL(cs1[cs1.length() - 1], 'g'); + + BOOST_CHECK_EQUAL(cs1[(size_t)0], cs1.at(0)); + BOOST_CHECK_EQUAL(cs1[(size_t)2], cs1.at(5)); + BOOST_CHECK_EQUAL(cs1.at(cs1.length() - 1), 'g'); + + BOOST_CHECK_EQUAL(common_layer::first_char()(cs1), 't'); + BOOST_CHECK_EQUAL(common_layer::last_char()(cs1), 'g'); +} + +BOOST_AUTO_TEST_CASE(length_test) { + const_string cs1; + + BOOST_CHECK_EQUAL(cs1.length(), (size_t)0); + BOOST_CHECK(cs1.is_empty()); + + cs1 = ""; + BOOST_CHECK_EQUAL(cs1.length(), (size_t)0); + BOOST_CHECK(cs1.is_empty()); + + cs1 = "test_string"; + BOOST_CHECK_EQUAL(cs1.length(), (size_t)11); + + cs1.erase(); + BOOST_CHECK_EQUAL(cs1.length(), (size_t)0); + BOOST_CHECK_EQUAL(cs1.data(), ""); + + cs1 = const_string("test_string", 4); + BOOST_CHECK_EQUAL(cs1.length(), (size_t)4); + + cs1.resize(5); + BOOST_CHECK_EQUAL(cs1.length(), (size_t)4); + + cs1.resize(3); + BOOST_CHECK_EQUAL(cs1.length(), (size_t)3); + + cs1.rshorten(); + BOOST_CHECK_EQUAL(cs1.length(), (size_t)2); + BOOST_CHECK_EQUAL(cs1[(size_t)0], 't'); + + cs1.lshorten(); + BOOST_CHECK_EQUAL(cs1.length(), (size_t)1); + BOOST_CHECK_EQUAL(cs1[(size_t)0], 'e'); + + cs1.lshorten(); + BOOST_CHECK(cs1.is_empty()); + BOOST_CHECK_EQUAL(cs1.data(), ""); + + cs1 = "test_string"; + cs1.lshorten(11); + BOOST_CHECK(cs1.is_empty()); + BOOST_CHECK_EQUAL(cs1.data(), ""); +} + +BOOST_AUTO_TEST_CASE(asignment_test) { + const_string cs1; + std::string s("test_string"); + + cs1 = "test"; + BOOST_CHECK_EQUAL(std::strcmp(cs1.data(), "test"), 0); + + cs1 = s; + BOOST_CHECK_EQUAL(std::strcmp(cs1.data(), "test_string"), 0); + + cs1.assign("test"); + BOOST_CHECK_EQUAL(std::strcmp(cs1.data(), "test"), 0); + + const_string cs2("test_string"); + + cs1.swap(cs2); + BOOST_CHECK_EQUAL(std::strcmp(cs1.data(), "test_string"), 0); + BOOST_CHECK_EQUAL(std::strcmp(cs2.data(), "test"), 0); +} + +BOOST_AUTO_TEST_CASE(comparison_test) { + const_string cs1("test_string"); + const_string cs2("test_string"); + std::string s("test_string"); + + BOOST_CHECK_EQUAL(cs1, "test_string"); + BOOST_CHECK_EQUAL("test_string", cs1); + BOOST_CHECK_EQUAL(cs1, cs2); + BOOST_CHECK_EQUAL(cs1, s); + BOOST_CHECK_EQUAL(s, cs1); + + cs1.resize(4); + + BOOST_CHECK(cs1 != "test_string"); + BOOST_CHECK("test_string" != cs1); + BOOST_CHECK(cs1 != cs2); + BOOST_CHECK(cs1 != s); + BOOST_CHECK(s != cs1); + + BOOST_CHECK_EQUAL(cs1, "test"); +} + +BOOST_AUTO_TEST_CASE(iterators_test) { + const_string cs1("test_string"); + std::string s; + + std::copy(cs1.begin(), cs1.end(), std::back_inserter(s)); + BOOST_CHECK_EQUAL(cs1, s); + + s.erase(); + + std::copy(cs1.rbegin(), cs1.rend(), std::back_inserter(s)); + BOOST_CHECK_EQUAL(const_string(s), "gnirts_tset"); +} + +// EOF