Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  string.cc

  Sprache: C
 

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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.
 */


#include "string-alloc-inl.h"

#include "arch/memcmp16.h"
#include "array-alloc-inl.h"
#include "base/array_ref.h"
#include "base/casts.h"
#include "base/stl_util.h"
#include "class-inl.h"
#include "dex/descriptors_names.h"
#include "dex/utf-inl.h"
#include "gc/accounting/card_table-inl.h"
#include "handle_scope-inl.h"
#include "intern_table.h"
#include "object-inl.h"
#include "runtime.h"
#include "string-inl.h"
#include "thread.h"

namespace art HIDDEN {
namespace mirror {

int32_t String::FastIndexOf(int32_t ch, int32_t start) {
  int32_t count = GetLength();
  if (start >= count) {
    return -1;
  } else if (start < 0) {
    start = 0;
  }
  if (IsCompressed()) {
    return FastIndexOf<uint8_t>(GetValueCompressed(), ch, start);
  } else {
    return FastIndexOf<uint16_t>(GetValue(), ch, start);
  }
}

int32_t String::LastIndexOf(int32_t ch) {
  int32_t count = GetLength();
  if (count == 0) {
    return -1;
  }
  if (IsCompressed()) {
    return LastIndexOf<uint8_t>(GetValueCompressed(), ch, count - 1);
  } else {
    return LastIndexOf<uint16_t>(GetValue(), ch, count - 1);
  }
}

int32_t String::ComputeAndSetHashCode() {
  int32_t new_hash_code = ComputeHashCode();
  SetHashCode(new_hash_code);
  return new_hash_code;
}

inline bool String::AllASCIIExcept(const uint16_t* chars, int32_t length, uint16_t non_ascii) {
  DCHECK(!IsASCII(non_ascii));
  for (int32_t i = 0; i < length; ++i) {
    if (!IsASCII(chars[i]) && chars[i] != non_ascii) {
      return false;
    }
  }
  return true;
}

ObjPtr<String> String::DoReplace(Thread* self, Handle<String> src, uint16_t old_c, uint16_t new_c) {
  int32_t length = src->GetLength();
  DCHECK(src->IsCompressed()
             ? ContainsElement(ArrayRef<uint8_t>(src->value_compressed_, length), old_c)
             : ContainsElement(ArrayRef<uint16_t>(src->value_, length), old_c));
  bool compressible =
      kUseStringCompression &&
      IsASCII(new_c) &&
      (src->IsCompressed() || (!IsASCII(old_c) && AllASCIIExcept(src->value_, length, old_c)));
  gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
  const int32_t length_with_flag = String::GetFlaggedCount(length, compressible);

  auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
    SetStringCountVisitor set_string_count_visitor(length_with_flag);
    set_string_count_visitor(obj, usable_size);
    ObjPtr<String> new_string = obj->AsString();
    if (compressible) {
      auto replace = [old_c, new_c](uint16_t c) {
        return dchecked_integral_cast<uint8_t>((old_c != c) ? c : new_c);
      };
      uint8_t* out = new_string->value_compressed_;
      if (LIKELY(src->IsCompressed())) {  // LIKELY(compressible == src->IsCompressed())
        std::transform(src->value_compressed_, src->value_compressed_ + length, out, replace);
      } else {
        std::transform(src->value_, src->value_ + length, out, replace);
      }
      DCHECK(kUseStringCompression && AllASCII(out, length));
    } else {
      auto replace = [old_c, new_c](uint16_t c) {
        return (old_c != c) ? c : new_c;
      };
      uint16_t* out = new_string->value_;
      if (UNLIKELY(src->IsCompressed())) {  // LIKELY(compressible == src->IsCompressed())
        std::transform(src->value_compressed_, src->value_compressed_ + length, out, replace);
      } else {
        std::transform(src->value_, src->value_ + length, out, replace);
      }
      DCHECK_IMPLIES(kUseStringCompression, !AllASCII(out, length));
    }
  };
  return Alloc(self, length_with_flag, allocator_type, visitor);
}

ObjPtr<String> String::DoConcat(Thread* self, Handle<String> h_this, Handle<String> h_arg) {
  int32_t length_this = h_this->GetLength();
  int32_t length_arg = h_arg->GetLength();
  gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
  const bool compressible =
      kUseStringCompression && (h_this->IsCompressed() && h_arg->IsCompressed());
  const int32_t length_with_flag = String::GetFlaggedCount(length_this + length_arg, compressible);

  auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
    SetStringCountVisitor set_string_count_visitor(length_with_flag);
    set_string_count_visitor(obj, usable_size);
    ObjPtr<String> new_string = obj->AsString();
    if (compressible) {
      uint8_t* new_value = new_string->GetValueCompressed();
      memcpy(new_value, h_this->GetValueCompressed(), length_this * sizeof(uint8_t));
      memcpy(new_value + length_this, h_arg->GetValueCompressed(), length_arg * sizeof(uint8_t));
    } else {
      uint16_t* new_value = new_string->GetValue();
      if (h_this->IsCompressed()) {
        const uint8_t* value_this = h_this->GetValueCompressed();
        for (int i = 0; i < length_this; ++i) {
          new_value[i] = value_this[i];
        }
      } else {
        memcpy(new_value, h_this->GetValue(), length_this * sizeof(uint16_t));
      }
      if (h_arg->IsCompressed()) {
        const uint8_t* value_arg = h_arg->GetValueCompressed();
        for (int i = 0; i < length_arg; ++i) {
          new_value[i + length_this] = value_arg[i];
        }
      } else {
        memcpy(new_value + length_this, h_arg->GetValue(), length_arg * sizeof(uint16_t));
      }
    }
  };
  return Alloc(self, length_with_flag, allocator_type, visitor);
}

template<typename T>
static void RepeatCharacters(ObjPtr<String> new_string, Handle<String> h_this, int32_t count)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  T *new_value, *h_this_value;
  if constexpr (std::is_same_v<T, uint8_t>) {
    new_value = new_string->GetValueCompressed();
    h_this_value = h_this->GetValueCompressed();
  } else {
    new_value = new_string->GetValue();
    h_this_value = h_this->GetValue();
  }
  int32_t length_this = h_this->GetLength();
  if (length_this == 1) {
    // compiler is smart enough to use memset for uint8_t
    std::fill(new_value, new_value + count, h_this_value[0]);
  } else {
    memcpy(new_value, h_this_value, length_this * sizeof(T));
    int32_t copied = length_this;
    int32_t limit = length_this * count;
    for (; copied < limit - copied; copied <<= 1) {
      memcpy(new_value + copied, new_value, copied * sizeof(T));
    }
    memcpy(new_value + copied, new_value, (limit - copied) * sizeof(T));
  }
}

ObjPtr<String> String::DoRepeat(Thread* self, Handle<String> h_this, int32_t count) {
  int32_t length_this = h_this->GetLength();
  DCHECK_GT(count, 1);
  DCHECK_LE(length_this, std::numeric_limits<int32_t>::max() / count);
  gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
  const bool compressible = kUseStringCompression && (h_this->IsCompressed());
  const int32_t length_with_flag = String::GetFlaggedCount(length_this * count, compressible);

  auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
      SetStringCountVisitor set_string_count_visitor(length_with_flag);
      set_string_count_visitor(obj, usable_size);
      ObjPtr<String> new_string = obj->AsString();

      if (compressible) {
        RepeatCharacters<uint8_t>(new_string, h_this, count);
      } else {
        RepeatCharacters<uint16_t>(new_string, h_this, count);
      }
  };
  return Alloc(self, length_with_flag, allocator_type, visitor);
}

ObjPtr<String> String::AllocFromUtf16(Thread* self,
                                      int32_t utf16_length,
                                      const uint16_t* utf16_data_in) {
  CHECK_IMPLIES(utf16_data_in == nullptr, utf16_length == 0);
  gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
  const bool compressible = kUseStringCompression &&
                            String::AllASCII<uint16_t>(utf16_data_in, utf16_length);
  int32_t length_with_flag = String::GetFlaggedCount(utf16_length, compressible);

  auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
    SetStringCountVisitor set_string_count_visitor(length_with_flag);
    set_string_count_visitor(obj, usable_size);
    ObjPtr<String> new_string = obj->AsString();
    if (compressible) {
      uint8_t* value = new_string->GetValueCompressed();
      for (int i = 0; i < utf16_length; ++i) {
        value[i] = static_cast<uint8_t>(utf16_data_in[i]);
      }
    } else {
      memcpy(new_string->GetValue(), utf16_data_in, utf16_length * sizeof(uint16_t));
    }
  };
  return Alloc(self, length_with_flag, allocator_type, visitor);
}

ObjPtr<String> String::AllocFromModifiedUtf8(Thread* self, const char* utf) {
  DCHECK(utf != nullptr);
  size_t byte_count = strlen(utf);
  size_t char_count = CountModifiedUtf8Chars(utf, byte_count);
  return AllocFromModifiedUtf8(self, char_count, utf, byte_count);
}

ObjPtr<String> String::AllocFromModifiedUtf8(Thread* self,
                                             int32_t utf16_length,
                                             const char* utf8_data_in) {
  return AllocFromModifiedUtf8(self, utf16_length, utf8_data_in, strlen(utf8_data_in));
}

ObjPtr<String> String::AllocFromModifiedUtf8(Thread* self,
                                             int32_t utf16_length,
                                             const char* utf8_data_in,
                                             int32_t utf8_length) {
  gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
  const bool compressible = kUseStringCompression && (utf16_length == utf8_length);
  const int32_t length_with_flag = String::GetFlaggedCount(utf16_length, compressible);

  auto visitor = [=](ObjPtr<Object> obj, size_t usable_size) REQUIRES_SHARED(Locks::mutator_lock_) {
    SetStringCountVisitor set_string_count_visitor(length_with_flag);
    set_string_count_visitor(obj, usable_size);
    ObjPtr<String> new_string = obj->AsString();
    if (compressible) {
      memcpy(new_string->GetValueCompressed(), utf8_data_in, utf16_length * sizeof(uint8_t));
    } else {
      uint16_t* utf16_data_out = new_string->GetValue();
      ConvertModifiedUtf8ToUtf16(utf16_data_out, utf16_length, utf8_data_in, utf8_length);
    }
  };
  return Alloc(self, length_with_flag, allocator_type, visitor);
}

bool String::Equals(mirror::String* that) {
  if (this == that) {
    // Quick reference equality test
    return true;
  } else if (that == nullptr) {
    // Null isn't an instanceof anything
    return false;
  } else if (this->GetCount() != that->GetCount()) {
    // Quick length and compression inequality test
    return false;
  } else {
    // Note: don't short circuit on hash code as we're presumably here as the
    // hash code was already equal
    if (this->IsCompressed()) {
      return memcmp(this->GetValueCompressed(), that->GetValueCompressed(), this->GetLength()) == 0;
    } else {
      return memcmp(this->GetValue(), that->GetValue(), sizeof(uint16_t) * this->GetLength()) =0;
    }
  }
}

bool String::Equals(const char* modified_utf8) {
  const int32_t length = GetLength();
  if (IsCompressed()) {
    return strlen(modified_utf8) == dchecked_integral_cast<uint32_t>(length) &&
           memcmp(modified_utf8, GetValueCompressed(), length) == 0;
  }
  const uint16_t* value = GetValue();
  int32_t i = 0;
  while (i < length) {
    const uint32_t ch = GetUtf16FromUtf8(&modified_utf8);
    if (ch == '\0') {
      return false;
    }

    if (GetLeadingUtf16Char(ch) != value[i++]) {
      return false;
    }

    const uint16_t trailing = GetTrailingUtf16Char(ch);
    if (trailing != 0) {
      if (i == length) {
        return false;
      }

      if (value[i++] != trailing) {
        return false;
      }
    }
  }
  return *modified_utf8 == '\0';
}

// Create a modified UTF-8 encoded std::string from a java/lang/String object.
std::string String::ToModifiedUtf8() {
  if (IsCompressed()) {
    return std::string(reinterpret_cast<const char*>(GetValueCompressed()), GetLength());
  } else {
    size_t byte_count = GetModifiedUtf8Length();
    std::string result(byte_count, static_cast<char>(0));
    ConvertUtf16ToModifiedUtf8(&result[0], byte_count, GetValue(), GetLength());
    return result;
  }
}

int32_t String::CompareTo(ObjPtr<String> rhs) {
  // Quick test for comparison of a string with itself.
  ObjPtr<String> lhs = this;
  if (lhs == rhs) {
    return 0;
  }
  int32_t lhs_count = lhs->GetLength();
  int32_t rhs_count = rhs->GetLength();
  int32_t count_diff = lhs_count - rhs_count;
  int32_t min_count = (count_diff < 0) ? lhs_count : rhs_count;
  if (lhs->IsCompressed() && rhs->IsCompressed()) {
    const uint8_t* lhs_chars = lhs->GetValueCompressed();
    const uint8_t* rhs_chars = rhs->GetValueCompressed();
    for (int32_t i = 0; i < min_count; ++i) {
      int32_t char_diff = static_cast<int32_t>(lhs_chars[i]) - static_cast<int32_t>(rhs_chars[i]);
      if (char_diff != 0) {
        return char_diff;
      }
    }
  } else if (lhs->IsCompressed() || rhs->IsCompressed()) {
    const uint8_t* compressed_chars =
        lhs->IsCompressed() ? lhs->GetValueCompressed() : rhs->GetValueCompressed();
    const uint16_t* uncompressed_chars = lhs->IsCompressed() ? rhs->GetValue() : lhs->GetValue();
    for (int32_t i = 0; i < min_count; ++i) {
      int32_t char_diff =
          static_cast<int32_t>(compressed_chars[i]) - static_cast<int32_t>(uncompressed_chars[i]);
      if (char_diff != 0) {
        return lhs->IsCompressed() ? char_diff : -char_diff;
      }
    }
  } else {
    const uint16_t* lhs_chars = lhs->GetValue();
    const uint16_t* rhs_chars = rhs->GetValue();
    // FIXME: The MemCmp16() name is misleading. It returns the char difference on mismatch
    // where memcmp() only guarantees that the returned value has the same sign.
    int32_t char_diff = MemCmp16(lhs_chars, rhs_chars, min_count);
    if (char_diff != 0) {
      return char_diff;
    }
  }
  return count_diff;
}

ObjPtr<CharArray> String::ToCharArray(Handle<String> h_this, Thread* self) {
  ObjPtr<CharArray> result = CharArray::Alloc(self, h_this->GetLength());
  if (result != nullptr) {
    if (h_this->IsCompressed()) {
      int32_t length = h_this->GetLength();
      const uint8_t* src = h_this->GetValueCompressed();
      uint16_t* dest = result->GetData();
      for (int i = 0; i < length; ++i) {
        dest[i] = src[i];
      }
    } else {
      memcpy(result->GetData(), h_this->GetValue(), h_this->GetLength() * sizeof(uint16_t));
    }
  } else {
    self->AssertPendingOOMException();
  }
  return result;
}

void String::GetChars(int32_t start, int32_t end, Handle<CharArray> array, int32_t index) {
  uint16_t* data = array->GetData() + index;
  DCHECK_LE(start, end);
  int32_t length = end - start;
  if (IsCompressed()) {
    const uint8_t* value = GetValueCompressed() + start;
    for (int i = 0; i < length; ++i) {
      data[i] = value[i];
    }
  } else {
    uint16_t* value = GetValue() + start;
    memcpy(data, value, length * sizeof(uint16_t));
  }
}

void String::FillBytesLatin1(Handle<ByteArray> array, int32_t index) {
  int8_t* data = array->GetData() + index;
  int32_t length = GetLength();
  if (IsCompressed()) {
    const uint8_t* value = GetValueCompressed();
    memcpy(data, value, length * sizeof(uint8_t));
  } else {
    // Drop the high byte of the characters.
    // The caller should check that all dropped high bytes are zeros.
    const uint16_t* value = GetValue();
    for (int32_t i = 0; i < length; ++i) {
      data[i] = static_cast<int8_t>(dchecked_integral_cast<uint8_t>(value[i]));
    }
  }
}

void String::FillBytesUTF16(Handle<ByteArray> array, int32_t index) {
  int8_t* data = array->GetData() + index;
  int32_t length = GetLength();
  if (IsCompressed()) {
    const uint8_t* value = GetValueCompressed();
    uint32_t d_index = 0;
    for (int i = 0; i < length; ++i) {
      data[d_index++] = static_cast<int8_t>(value[i]);
      data[d_index++] = 0;
    }
  } else {
    const uint16_t* value = GetValue();
    memcpy(data, value, length * sizeof(uint16_t));
  }
}

bool String::IsValueNull() {
  return (IsCompressed()) ? (GetValueCompressed() == nullptr) : (GetValue() == nullptr);
}

std::string String::PrettyStringDescriptor(ObjPtr<mirror::String> java_descriptor) {
  if (java_descriptor == nullptr) {
    return "null";
  }
  return java_descriptor->PrettyStringDescriptor();
}

std::string String::PrettyStringDescriptor() {
  return PrettyDescriptor(ToModifiedUtf8().c_str());
}

ObjPtr<String> String::Intern() {
  return Runtime::Current()->GetInternTable()->InternWeak(this);
}

}  // namespace mirror
}  // namespace art

Messung V0.5 in Prozent
C=88 H=95 G=91

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik