当前位置: 首页 > 工具软件 > Hippy > 使用案例 >

Hippy项目源码分析补充(二)

袁帅
2023-12-01

2021SC@SDUSC

#pragma once

#include <codecvt>
#include <locale>
#include <string>
#include <utility>

#include "base/logging.h"
#include "base/unicode_string_view.h"

#define EXTEND_LITERAL(ch) ch, ch, u##ch, U##ch

namespace hippy {
namespace base {

class StringViewUtils {
 public:
  using unicode_string_view = tdf::base::unicode_string_view;
  using u8string = unicode_string_view::u8string;
  using char8_t_ = unicode_string_view::char8_t_;

  inline static bool IsEmpty(const unicode_string_view& str_view) {
    unicode_string_view::Encoding encoding = str_view.encoding();
    switch (encoding) {
      case unicode_string_view::Encoding::Unkown: {
        return true;
      }
      case unicode_string_view::Encoding::Latin1: {
        return str_view.latin1_value().empty();
      }
      case unicode_string_view::Encoding::Utf16: {
        return str_view.utf16_value().empty();
      }
      case unicode_string_view::Encoding::Utf32: {
        return str_view.utf32_value().empty();
      }
      case unicode_string_view::Encoding::Utf8: {
        return str_view.utf8_value().empty();
      }
      default:
        break;
    }

    TDF_BASE_NOTREACHED();
  }

  static unicode_string_view CovertToLatin(
      const unicode_string_view& str_view,
      unicode_string_view::Encoding src_encoding) {
    switch (src_encoding) {
      case unicode_string_view::Encoding::Latin1: {
        return unicode_string_view(str_view.latin1_value());
      }
      case unicode_string_view::Encoding::Utf16:
      case unicode_string_view::Encoding::Utf32:
      case unicode_string_view::Encoding::Utf8:
      default: {
        TDF_BASE_NOTREACHED();
      }
    }
    TDF_BASE_NOTREACHED();
  }

  static unicode_string_view CovertToUtf16(
      const unicode_string_view& str_view,
      unicode_string_view::Encoding src_encoding) {
    switch (src_encoding) {
      case unicode_string_view::Encoding::Latin1: {
        return unicode_string_view(
            CopyChars<char, char16_t>(str_view.latin1_value()));
      }
      case unicode_string_view::Encoding::Utf16: {
        return unicode_string_view(str_view.utf16_value());
      }
      case unicode_string_view::Encoding::Utf32: {
        return unicode_string_view(U32ToU16(str_view.utf32_value()));
      }
      case unicode_string_view::Encoding::Utf8: {
        return unicode_string_view(U8ToU16(str_view.utf8_value()));
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }
    TDF_BASE_NOTREACHED();
  }

  static unicode_string_view CovertToUtf32(
      const unicode_string_view& str_view,
      unicode_string_view::Encoding src_encoding) {
    switch (src_encoding) {
      case unicode_string_view::Encoding::Latin1: {
        return unicode_string_view(
            CopyChars<char, char32_t>(str_view.latin1_value()));
      }
      case unicode_string_view::Encoding::Utf16: {
        return unicode_string_view(U16ToU32(str_view.utf16_value()));
      }
      case unicode_string_view::Encoding::Utf32: {
        return unicode_string_view(str_view.utf32_value());
      }
      case unicode_string_view::Encoding::Utf8: {
        return unicode_string_view(U8ToU32(str_view.utf8_value()));
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }
    TDF_BASE_NOTREACHED();
  }

  static unicode_string_view CovertToUtf8(
      const unicode_string_view& str_view,
      unicode_string_view::Encoding src_encoding) {
    switch (src_encoding) {
      case unicode_string_view::Encoding::Latin1: {
        const auto& str = str_view.latin1_value();
        auto ptr =
            reinterpret_cast<const unicode_string_view::char8_t_*>(str.c_str());
        return unicode_string_view(ptr, str.length());
      }
      case unicode_string_view::Encoding::Utf16: {
        return unicode_string_view(U16ToU8(str_view.utf16_value()));
      }
      case unicode_string_view::Encoding::Utf32: {
        return unicode_string_view(U32ToU8(str_view.utf32_value()));
      }
      case unicode_string_view::Encoding::Utf8: {
        return unicode_string_view(str_view.utf8_value());
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }
    TDF_BASE_NOTREACHED();
  }

  static unicode_string_view Convert(
      const unicode_string_view& str_view,
      unicode_string_view::Encoding dst_encoding) {
    unicode_string_view::Encoding src_encoding = str_view.encoding();
    switch (dst_encoding) {
      case unicode_string_view::Encoding::Latin1: {
        return CovertToLatin(str_view, src_encoding);
      }
      case unicode_string_view::Encoding::Utf16: {
        return CovertToUtf16(str_view, src_encoding);
      }
      case unicode_string_view::Encoding::Utf32: {
        return CovertToUtf32(str_view, src_encoding);
      }
      case unicode_string_view::Encoding::Utf8: {
        return CovertToUtf8(str_view, src_encoding);
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }
    TDF_BASE_NOTREACHED();
  }

  inline static const char* U8ToConstCharPointer(
      const unicode_string_view::char8_t_* p) {
    return reinterpret_cast<const char*>(p);
  }

  inline static const unicode_string_view::char8_t_* ToU8Pointer(
      const char* p) {
    return reinterpret_cast<const unicode_string_view::char8_t_*>(p);
  }

  inline static const char* ToConstCharPointer(
      const unicode_string_view& str_view,
      unicode_string_view& view_owner) {
    TDF_BASE_DCHECK(view_owner.encoding() ==
                    unicode_string_view::Encoding::Utf8);
    unicode_string_view::Encoding encoding = str_view.encoding();
    switch (encoding) {
      case unicode_string_view::Encoding::Latin1: {
        return str_view.latin1_value().c_str();
      }
      case unicode_string_view::Encoding::Utf8: {
        return U8ToConstCharPointer(str_view.utf8_value().c_str());
      }
      case unicode_string_view::Encoding::Utf16:
      case unicode_string_view::Encoding::Utf32: {
        unicode_string_view::u8string& ref = view_owner.utf8_value();
        ref =
            Convert(str_view, unicode_string_view::Encoding::Utf8).utf8_value();
        return U8ToConstCharPointer(ref.c_str());
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }
    TDF_BASE_NOTREACHED();
  }

  inline static unicode_string_view ConstCharPointerToStrView(const char* p,
                                                              size_t len = -1) {
    size_t length;
    if (len == -1) {
      length = strlen(p);
    } else {
      length = len;
    }
    return unicode_string_view(
        reinterpret_cast<const unicode_string_view::char8_t_*>(p), length);
  }

  inline static std::string ToU8StdStr(const unicode_string_view& str_view) {
    unicode_string_view::u8string str =
        Convert(str_view, unicode_string_view::Encoding::Utf8).utf8_value();
    return std::string(U8ToConstCharPointer(str.c_str()), str.length());
  }

  inline static size_t FindLastOf(const unicode_string_view& str_view,
                                  unicode_string_view::char8_t_ u8_ch,
                                  char ch,
                                  char16_t u16_ch,
                                  char32_t u32_ch) {
    unicode_string_view::Encoding encoding = str_view.encoding();
    switch (encoding) {
      case unicode_string_view::Encoding::Latin1: {
        const std::string& str = str_view.latin1_value();
        return str.find_last_of(ch);
      }
      case unicode_string_view::Encoding::Utf16: {
        const std::u16string& str = str_view.utf16_value();
        return str.find_last_of(u16_ch);
      }
      case unicode_string_view::Encoding::Utf32: {
        const std::u32string& str = str_view.utf32_value();
        return str.find_last_of(u32_ch);
      }
      case unicode_string_view::Encoding::Utf8: {
        const unicode_string_view::u8string& str = str_view.utf8_value();
        return str.find_last_of(u8_ch);
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }

    TDF_BASE_NOTREACHED();
  }

  inline static unicode_string_view SubStr(const unicode_string_view& str_view,
                                           size_t pos,
                                           size_t n) {
    unicode_string_view::Encoding encoding = str_view.encoding();
    switch (encoding) {
      case unicode_string_view::Encoding::Latin1: {
        const std::string& str = str_view.latin1_value();
        return unicode_string_view(str.substr(pos, n));
      }
      case unicode_string_view::Encoding::Utf16: {
        const std::u16string& str = str_view.utf16_value();
        return unicode_string_view(str.substr(pos, n));
      }
      case unicode_string_view::Encoding::Utf32: {
        const std::u32string& str = str_view.utf32_value();
        return unicode_string_view(str.substr(pos, n));
      }
      case unicode_string_view::Encoding::Utf8: {
        const unicode_string_view::u8string& str = str_view.utf8_value();
        return unicode_string_view(str.substr(pos, n));
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }

    TDF_BASE_NOTREACHED();
  }

  inline static size_t GetLength(const unicode_string_view& str_view) {
    unicode_string_view::Encoding encoding = str_view.encoding();
    switch (encoding) {
      case unicode_string_view::Encoding::Latin1: {
        const std::string& str = str_view.latin1_value();
        return str.length();
      }
      case unicode_string_view::Encoding::Utf16: {
        const std::u16string& str = str_view.utf16_value();
        return str.length();
      }
      case unicode_string_view::Encoding::Utf32: {
        const std::u32string& str = str_view.utf32_value();
        return str.length();
      }
      case unicode_string_view::Encoding::Utf8: {
        const unicode_string_view::u8string& str = str_view.utf8_value();
        return str.length();
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }

    TDF_BASE_NOTREACHED();
  }

 private:
  template <typename SrcChar, typename DstChar>
  inline static std::basic_string<DstChar> CopyChars(
      const std::basic_string<SrcChar>& src) {
    static_assert(sizeof(SrcChar) <= sizeof(DstChar), "copy downgrade");

    size_t len = src.length();
    std::basic_string<DstChar> dst;
    dst.resize(len);
    std::copy_n(src.c_str(), len, &dst[0]);
    return dst;
  }

  inline static unicode_string_view::u8string U32ToU8(
      const std::u32string& str) {
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
    std::string bytes = conv.to_bytes(str);
    const unicode_string_view::char8_t_* ptr =
        reinterpret_cast<const unicode_string_view::char8_t_*>(bytes.data());
    return unicode_string_view::u8string(ptr, bytes.length());
  }

  inline static std::u32string U8ToU32(
      const unicode_string_view::u8string& str) {
    const char* ptr = reinterpret_cast<const char*>(str.c_str());
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
    return conv.from_bytes(ptr, ptr + str.length());
  }

  inline static unicode_string_view::u8string U16ToU8(
      const std::u16string& str) {
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
    std::string bytes = convert.to_bytes(str);
    const unicode_string_view::char8_t_* ptr =
        reinterpret_cast<const unicode_string_view::char8_t_*>(bytes.data());
    return unicode_string_view::u8string(ptr, bytes.length());
  }

  inline static std::u16string U8ToU16(
      const unicode_string_view::u8string& str) {
    const char* ptr = reinterpret_cast<const char*>(str.c_str());
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
    return convert.from_bytes(ptr, ptr + str.length());
  }

  inline static std::u16string U32ToU16(const std::u32string& str) {
    std::wstring_convert<std::codecvt_utf16<char32_t>, char32_t> convert;
    std::string bytes = convert.to_bytes(str);
    return std::u16string(reinterpret_cast<const char16_t*>(bytes.c_str()),
                          bytes.length() / sizeof(char16_t));
  }

  inline static std::u32string U16ToU32(const std::u16string& str) {
    const char16_t* ptr = str.c_str();
    std::wstring_convert<std::codecvt_utf16<char32_t>, char32_t> convert;
    return convert.from_bytes(
        reinterpret_cast<const char*>(ptr),
        reinterpret_cast<const char*>(ptr + str.length()));
  }
};

}  // namespace base
}  // namespace hippy

namespace tdf {
namespace base {

inline unicode_string_view operator+(const unicode_string_view& lhs,
                                     const unicode_string_view& rhs) {
  using StringViewUtils = hippy::base::StringViewUtils;
  unicode_string_view::unicode_string_view::Encoding lhs_encoding =
      lhs.encoding();
  unicode_string_view::Encoding rhs_encoding = rhs.encoding();
  if (lhs_encoding <= rhs_encoding) {
    switch (rhs_encoding) {
      case unicode_string_view::Encoding::Latin1: {
        return unicode_string_view(
            StringViewUtils::Convert(lhs, rhs_encoding).latin1_value() +
            rhs.latin1_value());
      }
      case unicode_string_view::Encoding::Utf16: {
        return unicode_string_view(
            StringViewUtils::Convert(lhs, rhs_encoding).utf16_value() +
            rhs.utf16_value());
      }
      case unicode_string_view::Encoding::Utf32: {
        return unicode_string_view(
            StringViewUtils::Convert(lhs, rhs_encoding).utf32_value() +
            rhs.utf32_value());
      }
      case unicode_string_view::Encoding::Utf8: {
        return unicode_string_view(
            StringViewUtils::Convert(lhs, rhs_encoding).utf8_value() +
            rhs.utf8_value());
      }
      default: {
        TDF_BASE_NOTREACHED();
      }
    }
  }

  switch (lhs_encoding) {
    case unicode_string_view::Encoding::Latin1: {
      return unicode_string_view(
          lhs.latin1_value() +
          StringViewUtils::Convert(rhs, lhs_encoding).latin1_value());
    }
    case unicode_string_view::Encoding::Utf16: {
      return unicode_string_view(
          lhs.utf16_value() +
          StringViewUtils::Convert(rhs, lhs_encoding).utf16_value());
    }
    case unicode_string_view::Encoding::Utf32: {
      return unicode_string_view(
          lhs.utf32_value() +
          StringViewUtils::Convert(rhs, lhs_encoding).utf32_value());
    }
    case unicode_string_view::Encoding::Utf8: {
      return unicode_string_view(
          lhs.utf8_value() +
          StringViewUtils::Convert(rhs, lhs_encoding).utf8_value());
    }
    default: {
      TDF_BASE_NOTREACHED();
    }
  }
  TDF_BASE_NOTREACHED();
}

}  // namespace base
}  // namespace tdf

C++17 string_view简析:

string_view是c++17标准库提供的一个类,它提供一个字符串的视图,即可以通过这个类以各种方法“观测”字符串,但不允许修改字符串。

构造和求substr都是O(1)的复杂度

std的string的构造不可避免的会设计内存分配和拷贝。而string_view只是一个字符串的视图,构造函数可以避免拷贝,做到O(1)复杂度。

const std::basic_string<char, std::char_traits<char>, Allocator>& str) noexcept 
    : ptr_(str.data()), length_(CheckLengthInternal(str.size())) {}

从上面的代码可以看出,string_view的构造函数,仅仅是记录的字符串的指针地址和字符串长度,并未进行拷贝。

string_view::substr的原理类似,只是指针移动操作,返回一个子string_view。

有效性:

在string_view面世之前,一个接受const char*的函数, 加入想要传入string, 还需要把string使用c_str()转换才行。而现在,string_view可以完全兼容两者。

注意事项:

1.string_view并没有尾0 ('\0),所以在输出的时候,要注意边界。
2.因为string_view并不拷贝内存,所以要特别注意它所指向的字符串的生命周期。string_view指向的字符串,不能再string_view死亡之前被回收。



 

 类似资料: