content: #
  # Copyright 2023 EA Authors.
  #
  # 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
  #
  #    https://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.
  #
  
  @pure
  @C
  def strlen(a: cobj) -> int:
      pass
  
  @extend
  class str:
      @__internal__
      def __new__(l: int, p: Ptr[byte]) -> str:
          pass
  
      def __new__(p: Ptr[byte], l: int) -> str:
          return str(l, p)
  
      def __new__() -> str:
          return str(Ptr[byte](), 0)
  
      def __new__(what) -> str:
          if isinstance(what, Union):
              return __internal__.union_str(what)
          elif hasattr(what, "__str__"):
              return what.__str__()
          else:
              return what.__repr__()
  
      def __str__(what: str) -> str:
          return what
  
      def __len__(self) -> int:
          return self.len
  
      def __bool__(self) -> bool:
          return self.len != 0
  
      def __copy__(self) -> str:
          return self
  
      def __deepcopy__(self) -> str:
          return self
  
      def __ptrcopy__(self) -> str:
          n = self.len
          p = cobj(n)
          str.memcpy(p, self.ptr, n)
          return str(p, n)
  
      @llvm
      def memcpy(dest: Ptr[byte], src: Ptr[byte], len: int) -> None:
          declare void @llvm.memcpy.p0i8.p0i8.i64(ptr %dest, ptr %src, i64 %len, i32 %align, i1 %isvolatile)
          call void @llvm.memcpy.p0i8.p0i8.i64(ptr %dest, ptr %src, i64 %len, i32 0, i1 false)
          ret {} {}
  
      @llvm
      def memmove(dest: Ptr[byte], src: Ptr[byte], len: int) -> None:
          declare void @llvm.memmove.p0i8.p0i8.i64(ptr %dest, ptr %src, i64 %len, i32 %align, i1 %isvolatile)
          call void @llvm.memmove.p0i8.p0i8.i64(ptr %dest, ptr %src, i64 %len, i32 0, i1 false)
          ret {} {}
  
      @llvm
      def memset(dest: Ptr[byte], val: byte, len: int) -> None:
          declare void @llvm.memset.p0i8.i64(ptr %dest, i8 %val, i64 %len, i32 %align, i1 %isvolatile)
          call void @llvm.memset.p0i8.i64(ptr %dest, i8 %val, i64 %len, i32 0, i1 false)
          ret {} {}
  
      def __add__(self, other: str) -> str:
          len1 = self.len
          len2 = other.len
          len3 = len1 + len2
          p = Ptr[byte](len3)
          str.memcpy(p, self.ptr, len1)
          str.memcpy(p + len1, other.ptr, len2)
          return str(p, len3)
  
      def c_str(self) -> cobj:
          n = self.__len__()
          p = cobj(n + 1)
          str.memcpy(p, self.ptr, n)
          p[n] = byte(0)
          return p
  
      def from_ptr(t: cobj) -> str:
          n = strlen(t)
          p = Ptr[byte](n)
          str.memcpy(p, t, n)
          return str(p, n)
  
      def __eq__(self, other: str) -> bool:
          if self.len != other.len:
              return False
          i = 0
          while i < self.len:
              if self.ptr[i] != other.ptr[i]:
                  return False
              i += 1
          return True
  
      def __match__(self, obj: str) -> bool:
          return self.__eq__(obj)
  
      def __ne__(self, other: str) -> bool:
          return not self.__eq__(other)
  
      def cat(*args) -> str:
          total = 0
          if (
              staticlen(args) == 1
              and hasattr(args[0], "__iter__")
              and hasattr(args[0], "__len__")
          ):
              for s in args[0]:
                  if not isinstance(s, str):
                      compile_error("not a string")
                  total += s.len
              p = cobj(total)
              n = 0
              for s in args[0]:
                  str.memcpy(p + n, s.ptr, s.len)
                  n += s.len
              return str(p, total)
          elif staticlen(args) == 1 and hasattr(args[0], "__iter__"):
              sz = 10
              p = cobj(sz)
              n = 0
              for s in args[0]:
                  if not isinstance(s, str):
                      compile_error("not a string")
                  if n + s.len > sz:
                      sz = 1 + 3 * (n + s.len) // 2
                      pp = cobj(sz)
                      str.memcpy(pp, p, n)
                      p = pp
                  str.memcpy(p + n, s.ptr, s.len)
                  n += s.len
              return str(p, n)
          else:
              total = 0
              for i in args:
                  if not isinstance(i, str):
                      compile_error("not a string")
                  total += i.len
              p = cobj(total)
              n = 0
              for i in args:
                  str.memcpy(p + n, i.ptr, i.len)
                  n += i.len
              return str(p, total)
  
      def __prefix_b__(s: str, N: Static[int]):
          # Currently a no-op, as Hercules str's are just bytes
          return s
  