diff --git a/.github/workflows/build-and-test-rh.yml b/.github/workflows/build-and-test-rh.yml index 90f0773..64fc2f0 100644 --- a/.github/workflows/build-and-test-rh.yml +++ b/.github/workflows/build-and-test-rh.yml @@ -41,7 +41,7 @@ jobs: strategy: fail-fast: false matrix: - image: [ 'centos:7', 'quay.io/centos/centos:stream9', 'fedora:35', 'fedora:36', 'fedora:38' ] + image: [ 'centos:7', 'quay.io/centos/centos:stream9', 'fedora:35', 'fedora:36'] env: [ {CC: gcc, CXX: g++}, {CC: clang, CXX: clang++} ] shared: [ on, off ] container: ${{ matrix.image }} diff --git a/include/sexpp/sexp.h b/include/sexpp/sexp.h index bb6ae4e..3ffb735 100644 --- a/include/sexpp/sexp.h +++ b/include/sexpp/sexp.h @@ -44,8 +44,93 @@ #include "sexp-public.h" #include "sexp-error.h" +// We are implementing char traits for octet_t with trhe following restrictions +// -- limit visibility so that other traits for unsigned char are still possible +// -- create template specializatio in std workspace (use workspace specialization +// is not specified and causes issues at least with gcc 4.8 + namespace sexp { +using octet_t = uint8_t; +} // namespace sexp + +namespace std { + +template <> struct char_traits { + typedef sexp::octet_t char_type; + typedef int int_type; + typedef std::streampos pos_type; + typedef std::streamoff off_type; + typedef mbstate_t state_type; + + static void assign(char_type &__c1, const char_type &__c2) noexcept { __c1 = __c2; } + + static constexpr bool eq(const char_type &__c1, const char_type &__c2) noexcept + { + return __c1 == __c2; + } + + static constexpr bool lt(const char_type &__c1, const char_type &__c2) noexcept + { + return __c1 < __c2; + } + + static int compare(const char_type *__s1, const char_type *__s2, size_t __n) + { + return memcmp(__s1, __s2, __n); + } + + static size_t length(const char_type *__s) + { + return strlen(reinterpret_cast(__s)); + } + + static const char_type *find(const char_type *__s, size_t __n, const char_type &__a) + { + return static_cast(memchr(__s, __a, __n)); + } + + static char_type *move(char_type *__s1, const char_type *__s2, size_t __n) + { + return static_cast(memmove(__s1, __s2, __n)); + } + + static char_type *copy(char_type *__s1, const char_type *__s2, size_t __n) + { + return static_cast(memcpy(__s1, __s2, __n)); + } + + static char_type *assign(char_type *__s, size_t __n, char_type __a) + { + return static_cast(memset(__s, __a, __n)); + } + + static constexpr char_type to_char_type(const int_type &__c) noexcept + { + return static_cast(__c); + } + + // To keep both the byte 0xff and the eof symbol 0xffffffff + // from ending up as 0xffffffff. + static constexpr int_type to_int_type(const char_type &__c) noexcept + { + return static_cast(static_cast(__c)); + } + + static constexpr bool eq_int_type(const int_type &__c1, const int_type &__c2) noexcept + { + return __c1 == __c2; + } + + static constexpr int_type eof() noexcept { return static_cast(0xFFFFFFFF); } + static constexpr int_type not_eof(const int_type &__c) noexcept + { + return (__c == eof()) ? 0 : __c; + } +}; +} // namespace std + +namespace sexp { /* * SEXP octet_t definitions * We maintain some presumable redundancy with ctype @@ -99,14 +184,14 @@ class sexp_input_stream_t; * SEXP simple string */ -typedef uint8_t octet_t; +using octet_traits = std::char_traits; +using octet_string = std::basic_string; -class SEXP_PUBLIC_SYMBOL sexp_simple_string_t : public std::basic_string, - private sexp_char_defs_t { +class SEXP_PUBLIC_SYMBOL sexp_simple_string_t : public octet_string, private sexp_char_defs_t { public: sexp_simple_string_t(void) = default; - sexp_simple_string_t(const octet_t *dt) : std::basic_string{dt} {} - sexp_simple_string_t(const octet_t *bt, size_t ln) : std::basic_string{bt, ln} {} + sexp_simple_string_t(const octet_t *dt) : octet_string{dt} {} + sexp_simple_string_t(const octet_t *bt, size_t ln) : octet_string{bt, ln} {} sexp_simple_string_t &append(int c) { (*this) += (octet_t)(c & 0xFF); diff --git a/tests/src/traits-tests.cpp b/tests/src/traits-tests.cpp new file mode 100644 index 0000000..52e1019 --- /dev/null +++ b/tests/src/traits-tests.cpp @@ -0,0 +1,116 @@ +/** + * + * Copyright 2024 Ribose Inc. (https://www.ribose.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "sexp-tests.h" + +using namespace sexp; + +namespace { + +TEST(OctetTraitsTest, Assign) +{ + octet_t a = 0x12; + octet_t b = 0x34; + octet_traits::assign(a, b); + EXPECT_EQ(a, b); +} + +TEST(OctetTraitsTest, Eq) +{ + octet_t a = 0x12; + octet_t b = 0x12; + EXPECT_TRUE(octet_traits::eq(a, b)); +} + +TEST(OctetTraitsTest, Lt) +{ + octet_t a = 0x12; + octet_t b = 0x34; + EXPECT_TRUE(octet_traits::lt(a, b)); +} + +TEST(OctetTraitsTest, Compare) +{ + octet_t s1[] = {0x12, 0x34, 0x56}; + octet_t s2[] = {0x12, 0x34, 0x57}; + EXPECT_LT(octet_traits::compare(s1, s2, 3), 0); +} + +TEST(OctetTraitsTest, Find) +{ + octet_t s[] = {0x12, 0x34, 0x56}; + octet_t a = 0x34; + EXPECT_EQ(octet_traits::find(s, 3, a), s + 1); +} + +TEST(OctetTraitsTest, Move) +{ + octet_t s1[] = {0x12, 0x34, 0x56}; + octet_t s2[3]; + octet_traits::move(s2, s1, 3); + EXPECT_EQ(memcmp(s1, s2, 3), 0); +} + +TEST(OctetTraitsTest, Copy) +{ + octet_t s1[] = {0x12, 0x34, 0x56}; + octet_t s2[3]; + octet_traits::copy(s2, s1, 3); + EXPECT_EQ(memcmp(s1, s2, 3), 0); +} + +TEST(OctetTraitsTest, AssignMultiple) +{ + octet_t s[3]; + octet_t a = 0x12; + octet_traits::assign(s, 3, a); + for (int i = 0; i < 3; i++) { + EXPECT_EQ(s[i], a); + } +} + +TEST(OctetTraitsTest, ToCharType) +{ + octet_traits::int_type a = 0x12; + EXPECT_EQ(octet_traits::to_char_type(a), 0x12); +} + +TEST(OctetTraitsTest, ToIntType) +{ + octet_t a = 0x12; + EXPECT_EQ(octet_traits::to_int_type(a), 0x12); +} + +TEST(OctetTraitsTest, EqIntType) +{ + octet_traits::int_type a = 0x12; + octet_traits::int_type b = 0x12; + EXPECT_TRUE(octet_traits::eq_int_type(a, b)); +} + +TEST(OctetTraitsTest, NotEof) +{ + octet_traits::int_type a = 0x12; + EXPECT_EQ(octet_traits::not_eof(a), 0x12); +} +} // namespace diff --git a/version.txt b/version.txt index 1e9b46b..6201b5f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.8.7 +0.8.8