Program Listing for File base_string.hpp

Return to documentation for file (/tmp/ws/src/apex_containers/apex_containers/include/string/base_string.hpp)

// Copyright 2017-2018 Apex.AI, Inc.
//
// Licensed 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


#ifndef STRING__BASE_STRING_HPP_
#define STRING__BASE_STRING_HPP_

#include <apexutils/apexdef.h>
#include <apex_containers/visibility_control.hpp>

#include <stdexcept>
#include <climits>
#include <cstring>
#include <algorithm>
#include <istream>
#include <ostream>
#include <string>

namespace apex
{

template<::size64_t BUFFER_SIZE>
class BaseString
{
public:
  using char_type = char8_t;

  BaseString(void) noexcept
  {
    // Ignore unneeded pointer to destination
    (void)::memset(&(this->m_string[0U]), 0, this->get_buffer_size());
  }

  constexpr static const ::size64_t npos = ULLONG_MAX;

  constexpr const ::char8_t * data() const noexcept
  {
    return &(m_string[0U]);
  }

  BaseString substr(const ::size64_t pos = 0U, const ::size64_t len = npos) const
  {
    BaseString retval;
    ::size64_t my_size = size();
    if (pos > my_size) {
      throw std::out_of_range("pos > my_size");
    }
    if (pos != my_size) {
      const ::size64_t chars_to_copy = std::min(my_size - pos, len);
      // Ignore unneeded returned pointer
      (void)memmove(retval.m_string, m_string + pos, chars_to_copy);
    }
    return retval;
  }

  // Comparisons

  int32_t compare(
    const ::size64_t pos1,
    const ::size64_t count1,
    const ::char8_t * const s,
    const ::size64_t count2 = npos) const
  {
    if (nullptr == s) {
      throw std::invalid_argument("s == NULL");
    }

    const ::size64_t my_size = length();
    if (pos1 > my_size) {
      throw std::out_of_range("pos > my_len");
    }

    const ::size64_t _count1 = (npos == count1) ? my_size : count1;
    ::size64_t n_str = count2;
    if (npos == count2) {
      n_str = ::strnlen(s, APEX_STRING_SIZE);
    }

    const ::size64_t rlen = std::min(_count1, my_size - pos1);
    int32_t cmp_retval = ::strncmp(data() + pos1, s, std::min(rlen, n_str));

    if (cmp_retval == 0) {
      if (rlen < n_str) {
        cmp_retval = -1;
      }
      if (rlen > n_str) {
        cmp_retval = 1;
      }
    }
    return cmp_retval;
  }

  inline int32_t compare(const ::char8_t * const s) const
  {
    return this->compare(0U, npos, s);
  }

  bool operator==(const char8_t * const rhs) const
  {
    return this->compare(rhs) == 0;
  }

  template<::size64_t LEN>
  int32_t compare(
    const ::size64_t pos1,
    const ::size64_t count1,
    const BaseString<LEN> & str) const
  {
    return compare(pos1, count1, str.c_str());
  }

  int32_t compare(
    const ::size64_t pos1,
    const ::size64_t count1,
    const std::string & str) const
  {
    return compare(pos1, count1, str.c_str());
  }

  template<::size64_t LEN>
  int32_t compare(const BaseString<LEN> & str) const
  {
    return compare(0U, npos, str);
  }

  int32_t compare(const std::string & str) const
  {
    return compare(0U, npos, str);
  }

  template<::size64_t LEN>
  bool operator==(const BaseString<LEN> & rhs) const
  {
    const int32_t cmp_retval = compare(0U, npos, rhs);
    return cmp_retval == 0;
  }

  bool operator==(const std::string & rhs) const
  {
    const int32_t cmp_retval = compare(0U, npos, rhs.c_str());
    return cmp_retval == 0;
  }

  bool operator!=(const char8_t * const rhs) const
  {
    return !operator==(rhs);
  }

  template<::size64_t LEN>
  bool operator!=(const BaseString<LEN> & rhs) const
  {
    return !operator==(rhs);
  }

  bool operator!=(const std::string & rhs) const
  {
    return !operator==(rhs);
  }

  bool operator<(const char8_t * const rhs) const
  {
    return this->compare(rhs) < 0;
  }

  template<::size64_t LEN>
  bool operator<(const BaseString<LEN> & rhs) const
  {
    const int32_t cmp_retval = compare(0U, npos, rhs);
    return cmp_retval < 0;
  }

  bool operator<(const std::string & rhs) const
  {
    const int32_t cmp_retval = compare(0U, npos, rhs);
    return cmp_retval < 0;
  }

  bool operator<=(const char8_t * const rhs) const
  {
    return !operator>(rhs);
  }

  template<::size64_t LEN>
  bool operator<=(const BaseString<LEN> & rhs) const
  {
    return !operator>(rhs);
  }

  bool operator<=(const std::string & rhs) const
  {
    return !operator>(rhs);
  }

  bool operator>(const char8_t * const rhs) const
  {
    return this->compare(rhs) > 0;
  }

  template<::size64_t LEN>
  bool operator>(const BaseString<LEN> & rhs) const
  {
    const int32_t cmp_retval = compare(0U, npos, rhs);
    return cmp_retval > 0;
  }

  bool operator>(const std::string & rhs) const
  {
    const int32_t cmp_retval = compare(0U, npos, rhs);
    return cmp_retval > 0;
  }

  bool operator>=(const char8_t * const rhs) const
  {
    return !operator<(rhs);
  }

  template<size64_t LEN>
  bool operator>=(const BaseString<LEN> & rhs) const
  {
    return !operator<(rhs);
  }

  bool operator>=(const std::string & rhs) const
  {
    return !operator<(rhs);
  }

  // Getters

  bool empty() const noexcept {return m_string[0U] == '\0';}

  const char8_t * c_str() const noexcept
  {
    return m_string;
  }

  char8_t * data() noexcept
  {
    return &m_string[0];
  }

  inline constexpr size64_t capacity() const
  {
    return get_buffer_size() - 1U;
  }

  size64_t size() const noexcept
  {
    return ::strnlen(m_string, this->capacity());
  }

  size64_t length() const noexcept
  {
    return size();
  }

  char8_t & operator[](size64_t idx)
  {
    if (idx >= get_buffer_size()) {
      throw std::out_of_range("idx >= get_buffer_size()");
    }
    return m_string[idx];
  }

  char8_t operator[](size64_t idx) const
  {
    if (idx >= get_buffer_size()) {
      throw std::out_of_range("idx >= get_buffer_size()");
    }
    return m_string[idx];
  }

  inline constexpr ::size64_t get_buffer_size() const noexcept
  {
    return BUFFER_SIZE;
  }

  static inline constexpr ::size64_t get_buffer_size_static() noexcept
  {
    return BUFFER_SIZE;
  }

  operator std::string() const
  {
    return std::string(this->m_string);
  }

  // Removes all elements.
  void clear() noexcept
  {
    (void)std::memset(&(this->m_string[0U]), 0, this->get_buffer_size());
  }

protected:
  // The apex::BaseString iterator abs_iterator class below is based on
  // stackoverflow.com/questions/12092448/code-for-a-basic-random-access-iterator-based-on-pointers
  // This class is for internal apex::string use only
  template<typename Type>
  class abs_iterator : public std::iterator<std::random_access_iterator_tag, Type>
  {
public:
    using difference_type =
      typename std::iterator<std::random_access_iterator_tag, Type>::difference_type;

    abs_iterator()
    : m_ptr(nullptr)
    {
    }
    explicit abs_iterator(Type * rhs)
    : m_ptr(rhs)
    {
    }
    abs_iterator(const abs_iterator & rhs)
    : m_ptr(rhs.m_ptr)
    {
    }
    inline abs_iterator & operator+=(difference_type rhs)
    {
      m_ptr += rhs; return *this;
    }
    inline abs_iterator & operator-=(difference_type rhs)
    {
      m_ptr -= rhs; return *this;
    }
    inline Type & operator*() const
    {
      return *m_ptr;
    }
    inline Type * operator->() const
    {
      return m_ptr;
    }
    inline Type & operator[](difference_type rhs)
    {
      return m_ptr[rhs];
    }
    inline const Type & operator[](difference_type rhs) const
    {
      return m_ptr[rhs];
    }
    inline abs_iterator & operator++()
    {
      ++m_ptr; return *this;
    }
    inline abs_iterator & operator--()
    {
      --m_ptr; return *this;
    }
    inline abs_iterator operator++(int)
    {
      abs_iterator tmp(*this); ++m_ptr; return tmp;
    }
    inline abs_iterator operator--(int)
    {
      abs_iterator tmp(*this); --m_ptr; return tmp;
    }
    inline difference_type operator-(const abs_iterator & rhs) const
    {
      return difference_type(m_ptr - rhs.m_ptr);
    }
    inline abs_iterator operator+(difference_type rhs) const
    {
      return abs_iterator(m_ptr + rhs);
    }
    inline abs_iterator operator-(difference_type rhs) const
    {
      return abs_iterator(m_ptr - rhs);
    }
    friend inline abs_iterator operator+(difference_type lhs, const abs_iterator & rhs)
    {
      return abs_iterator(lhs + rhs.m_ptr);
    }
    friend inline abs_iterator operator-(difference_type lhs, const abs_iterator & rhs)
    {
      return abs_iterator(lhs - rhs.m_ptr);
    }
    inline bool operator==(const abs_iterator & rhs) const
    {
      return m_ptr == rhs.m_ptr;
    }
    inline bool operator!=(const abs_iterator & rhs) const
    {
      return m_ptr != rhs.m_ptr;
    }
    inline bool operator>(const abs_iterator & rhs) const
    {
      return m_ptr > rhs.m_ptr;
    }
    inline bool operator<(const abs_iterator & rhs) const
    {
      return m_ptr < rhs.m_ptr;
    }
    inline bool operator>=(const abs_iterator & rhs) const
    {
      return m_ptr >= rhs.m_ptr;
    }
    inline bool operator<=(const abs_iterator & rhs) const
    {
      return m_ptr <= rhs.m_ptr;
    }

private:
    Type * m_ptr;
  };

  char8_t m_string[BUFFER_SIZE];
};

template<size64_t STRING_BUFFER_SIZE>
typename ::std::basic_ostream<char8_t> & operator<<(
  std::basic_ostream<char8_t> & out_stream,
  const apex::BaseString<STRING_BUFFER_SIZE> & str)
{
  return out_stream.write(str.c_str(), static_cast<std::streamsize>(str.size()));
}


template<::size64_t STRING_BUFFER_SIZE>
inline ::float32_t stof(const apex::BaseString<STRING_BUFFER_SIZE> & str) noexcept
{
  const float32_t value = strtof(str.c_str(), nullptr);
  return value;
}

template<::size64_t STRING_BUFFER_SIZE>
inline ::float64_t stod(const apex::BaseString<STRING_BUFFER_SIZE> & str) noexcept
{
  const float64_t value = strtod(str.c_str(), nullptr);
  return value;
}

template<::size64_t STRING_BUFFER_SIZE>
inline ::int32_t stol(const apex::BaseString<STRING_BUFFER_SIZE> & str) noexcept
{
  ::int64_t value = ::strtol(str.c_str(), nullptr, 10);
  if (value < static_cast<int64_t>(INT32_MIN)) {
    value = static_cast<int64_t>(INT32_MIN);
  }

  if (value > static_cast<int64_t>(INT32_MAX)) {
    value = static_cast<int64_t>(INT32_MAX);
  }
  return static_cast<int32_t>(value);
}

template<::size64_t STRING_BUFFER_SIZE>
inline ::int64_t stoll(const apex::BaseString<STRING_BUFFER_SIZE> & str) noexcept
{
  ::int64_t value = ::strtoll(str.c_str(), nullptr, 10);
  return value;
}

template<::size64_t STRING_BUFFER_SIZE>
inline ::uint32_t stoul(const apex::BaseString<STRING_BUFFER_SIZE> & str) noexcept
{
  ::uint64_t value = ::strtoul(str.c_str(), nullptr, 10);
  if (value > static_cast<uint64_t>(UINT32_MAX)) {
    value = static_cast<uint64_t>(UINT32_MAX);
  }
  return static_cast<uint32_t>(value & UINT32_MAX);
}

template<::size64_t STRING_BUFFER_SIZE>
inline ::uint64_t stoull(const apex::BaseString<STRING_BUFFER_SIZE> & str) noexcept
{
  ::uint64_t value = ::strtoull(str.c_str(), nullptr, 10);
  return value;
}

}  // namespace apex

// Extending std::hash for apex::BaseString<Buffer_Size>
// cppcheck-suppress syntaxError
namespace std
{
// hash combine function based on the boost implementation:
// https://www.boost.org/doc/libs/1_68_0/boost/container_hash/hash.hpp
template<size64_t SizeN>
struct hash<apex::BaseString<SizeN>>
{
  size_t operator()(const apex::BaseString<SizeN> & str) const noexcept
  {
    size64_t seed = str.size();
    for (size64_t idx = 0U; idx < str.size(); idx++) {
      // cast char to unsigned char to size64_t for int array hashing
      seed ^= static_cast<size64_t>(static_cast<uint8_t>(str[idx])) + 0x9e3779b9U +
        (seed << 6U) + (seed >> 2U);
    }
    return seed;
  }
};

}  // namespace std

#endif  // STRING__BASE_STRING_HPP_