#include"formatted_string_builder.h" #include"putilimp.h" #include"unicode/ustring.h" #include"unicode/utf16.h" #include"unicode/unum.h"// for UNumberFormatFields literals
namespace {
// A version of uprv_memcpy that checks for length 0. // By default, uprv_memcpy requires a length of at least 1. inlinevoid uprv_memcpy2(void* dest, constvoid* src, size_t len) { if (len > 0) {
uprv_memcpy(dest, src, len);
}
}
// A version of uprv_memmove that checks for length 0. // By default, uprv_memmove requires a length of at least 1. inlinevoid uprv_memmove2(void* dest, constvoid* src, size_t len) { if (len > 0) {
uprv_memmove(dest, src, len);
}
}
} // namespace
U_NAMESPACE_BEGIN
FormattedStringBuilder::FormattedStringBuilder() { #if U_DEBUG // Initializing the memory to non-zero helps catch some bugs that involve // reading from an improperly terminated string. for (int32_t i=0; i<getCapacity(); i++) {
getCharPtr()[i] = 1;
} #endif
}
FormattedStringBuilder::~FormattedStringBuilder() { if (fUsingHeap) {
uprv_free(fChars.heap.ptr);
uprv_free(fFields.heap.ptr);
}
}
int32_t FormattedStringBuilder::prepareForInsertHelper(int32_t index, int32_t count, UErrorCode &status) {
int32_t oldCapacity = getCapacity();
int32_t oldZero = fZero;
char16_t *oldChars = getCharPtr();
Field *oldFields = getFieldPtr();
int32_t newLength; if (uprv_add32_overflow(fLength, count, &newLength)) {
status = U_INPUT_TOO_LONG_ERROR; return -1;
}
int32_t newZero; if (newLength > oldCapacity) { if (newLength > INT32_MAX / 2) { // We do not support more than 1G char16_t in this code because // dealing with >2G *bytes* can cause subtle bugs.
status = U_INPUT_TOO_LONG_ERROR; return -1;
} // Keep newCapacity also to at most 1G char16_t.
int32_t newCapacity = newLength * 2;
newZero = (newCapacity - newLength) / 2;
// C++ note: malloc appears in two places: here and in the assignment operator. auto* newChars = static_cast<char16_t*>(uprv_malloc(sizeof(char16_t) * static_cast<size_t>(newCapacity))); auto* newFields = static_cast<Field*>(uprv_malloc(sizeof(Field) * static_cast<size_t>(newCapacity))); if (newChars == nullptr || newFields == nullptr) {
uprv_free(newChars);
uprv_free(newFields);
status = U_MEMORY_ALLOCATION_ERROR; return -1;
}
// First copy the prefix and then the suffix, leaving room for the new chars that the // caller wants to insert. // C++ note: memcpy is OK because the src and dest do not overlap.
uprv_memcpy2(newChars + newZero, oldChars + oldZero, sizeof(char16_t) * index);
uprv_memcpy2(newChars + newZero + index + count,
oldChars + oldZero + index, sizeof(char16_t) * (fLength - index));
uprv_memcpy2(newFields + newZero, oldFields + oldZero, sizeof(Field) * index);
uprv_memcpy2(newFields + newZero + index + count,
oldFields + oldZero + index, sizeof(Field) * (fLength - index));
// C++ note: memmove is required because src and dest may overlap. // First copy the entire string to the location of the prefix, and then move the suffix // to make room for the new chars that the caller wants to insert.
uprv_memmove2(oldChars + newZero, oldChars + oldZero, sizeof(char16_t) * fLength);
uprv_memmove2(oldChars + newZero + index + count,
oldChars + newZero + index, sizeof(char16_t) * (fLength - index));
uprv_memmove2(oldFields + newZero, oldFields + oldZero, sizeof(Field) * fLength);
uprv_memmove2(oldFields + newZero + index + count,
oldFields + newZero + index, sizeof(Field) * (fLength - index));
}
fZero = newZero;
fLength = newLength; return fZero + index;
}
int32_t position = index + fZero; // TODO: Reset the heap here? (If the string after removal can fit on stack?)
uprv_memmove2(getCharPtr() + position,
getCharPtr() + position + count, sizeof(char16_t) * (fLength - index - count));
uprv_memmove2(getFieldPtr() + position,
getFieldPtr() + position + count, sizeof(Field) * (fLength - index - count));
fLength -= count; return position;
}
UnicodeString FormattedStringBuilder::toDebugString() const {
UnicodeString sb;
sb.append(u", -1);
sb.append(toUnicodeString());
sb.append(u"] [", -1); for (int i = 0; i < fLength; i++) { if (fieldAt(i) == kUndefinedField) {
sb.append(u'n');
} elseif (fieldAt(i).getCategory() == UFIELD_CATEGORY_NUMBER) {
char16_t c; switch (fieldAt(i).getField()) { case UNUM_SIGN_FIELD:
c = u'-'; break; case UNUM_INTEGER_FIELD:
c = u'i'; break; case UNUM_FRACTION_FIELD:
c = u'f'; break; case UNUM_EXPONENT_FIELD:
c = u'e'; break; case UNUM_EXPONENT_SIGN_FIELD:
c = u'+'; break; case UNUM_EXPONENT_SYMBOL_FIELD:
c = u'E'; break; case UNUM_DECIMAL_SEPARATOR_FIELD:
c = u'.'; break; case UNUM_GROUPING_SEPARATOR_FIELD:
c = u','; break; case UNUM_PERCENT_FIELD:
c = u'%'; break; case UNUM_PERMILL_FIELD:
c = u'‰'; break; case UNUM_CURRENCY_FIELD:
c = u'$'; break; default:
c = u'0' + fieldAt(i).getField(); break;
}
sb.append(c);
} else {
sb.append(u'0' + fieldAt(i).getCategory());
}
}
sb.append(u"]>", -1); return sb;
}
bool FormattedStringBuilder::contentEquals(const FormattedStringBuilder &other) const { if (fLength != other.fLength) { returnfalse;
} for (int32_t i = 0; i < fLength; i++) { if (charAt(i) != other.charAt(i) || fieldAt(i) != other.fieldAt(i)) { returnfalse;
}
} returntrue;
}
bool FormattedStringBuilder::containsField(Field field) const { for (int32_t i = 0; i < fLength; i++) { if (field == fieldAt(i)) { returntrue;
}
} returnfalse;
}
U_NAMESPACE_END
#endif/* #if !UCONFIG_NO_FORMATTING */
Messung V0.5
¤ 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.0.16Bemerkung:
Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können
¤
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.