Update ConvertUTF,poly2tri [ci build]

This commit is contained in:
halx99 2021-06-01 11:47:19 +08:00
parent b30a6789b9
commit e0beb6cf27
15 changed files with 354 additions and 353 deletions

View File

@ -30,9 +30,12 @@
#include "ConvertUTF.h" #include "ConvertUTF.h"
#include <limits> #include <limits>
using namespace llvm;
NS_CC_BEGIN NS_CC_BEGIN
namespace StringUtils { namespace StringUtils {
std::string CC_DLL format(const char* format, ...) std::string CC_DLL format(const char* format, ...)
{ {
va_list args; va_list args;
@ -393,6 +396,24 @@ long getCharacterCountInUTF8String(const std::string& utf8)
return getUTF8StringLength((const UTF8*)utf8.c_str()); return getUTF8StringLength((const UTF8*)utf8.c_str());
} }
bool hasNonAsciiUTF8(const char* str, size_t len) {
for (size_t i = 0; i < len;)
{
int numByte = getNumBytesForUTF8(str[i]);
if (numByte > 1)
{ // byte=1, is ascii character
if (isLegalUTF8Sequence((const UTF8*) &str[i], (const UTF8*) &str[i] + numByte))
return true;
}
i += numByte;
}
return false;
}
bool isLegalUTF8String(const char* str, size_t len) {
return ::isLegalUTF8String((const UTF8**)&str, (const UTF8*)str + len);
}
StringUTF8::StringUTF8() StringUTF8::StringUTF8()
{ {

View File

@ -213,7 +213,15 @@ CC_DLL unsigned int getIndexOfLastNotChar16(const std::vector<char16_t>& str, ch
*/ */
CC_DLL std::vector<char16_t> getChar16VectorFromUTF16String(const std::u16string& utf16); CC_DLL std::vector<char16_t> getChar16VectorFromUTF16String(const std::u16string& utf16);
/**
* @brief Whether has non-ascii utf-8 characters
*/
CC_DLL bool hasNonAsciiUTF8(const char* str, size_t len);
/**
* @brief isLegalUTF8String, contains ascii characters
*/
CC_DLL bool isLegalUTF8String(const char* str, size_t len);
/** /**
* Utf8 sequence * Utf8 sequence

View File

@ -167,7 +167,7 @@ if(BUILD_EXT_EDTAA3FUNC)
endif(BUILD_EXT_EDTAA3FUNC) endif(BUILD_EXT_EDTAA3FUNC)
if(BUILD_EXT_CONVERTUTF) if(BUILD_EXT_CONVERTUTF)
add_subdirectory(ConvertUTF) add_subdirectory(ConvertUTF)
target_link_libraries(external convertUTF) target_link_libraries(external ConvertUTF)
endif(BUILD_EXT_CONVERTUTF) endif(BUILD_EXT_CONVERTUTF)
if(BUILD_EXT_POLY2TRI) if(BUILD_EXT_POLY2TRI)
add_subdirectory(poly2tri) add_subdirectory(poly2tri)

View File

@ -1,12 +1,11 @@
set(lib_name convertUTF) set(lib_name ConvertUTF)
set(target_name ${lib_name}) set(target_name ${lib_name})
project(${lib_name}) project(${lib_name})
add_library(${target_name} STATIC add_library(${target_name} STATIC
ConvertUTF.c ConvertUTF.cpp
ConvertUTFWrapper.cpp
) )
target_include_directories(${target_name} PUBLIC .) target_include_directories(${target_name} PUBLIC .)

View File

@ -1,9 +1,8 @@
/*===--- ConvertUTF.c - Universal Character Names conversions ---------------=== /*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
* *
* The LLVM Compiler Infrastructure * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* * See https://llvm.org/LICENSE.txt for license information.
* This file is distributed under the University of Illinois Open Source * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
* License. See LICENSE.TXT for details.
* *
*===------------------------------------------------------------------------=*/ *===------------------------------------------------------------------------=*/
/* /*
@ -46,13 +45,41 @@
------------------------------------------------------------------------ */ ------------------------------------------------------------------------ */
#include "ConvertUTF.h" #include "ConvertUTF.h"
#ifdef CVTUTF_DEBUG #ifdef CVTUTF_DEBUG
#include <stdio.h> #include <stdio.h>
#endif #endif
#include <assert.h>
#include <string.h> /*
* This code extensively uses fall-through switches.
* Keep the compiler from warning about that.
*/
#if defined(__clang__) && defined(__has_warning)
# if __has_warning("-Wimplicit-fallthrough")
# define ConvertUTF_DISABLE_WARNINGS \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"")
# define ConvertUTF_RESTORE_WARNINGS \
_Pragma("clang diagnostic pop")
# endif
#elif defined(__GNUC__) && __GNUC__ > 6
# define ConvertUTF_DISABLE_WARNINGS \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
# define ConvertUTF_RESTORE_WARNINGS \
_Pragma("GCC diagnostic pop")
#endif
#ifndef ConvertUTF_DISABLE_WARNINGS
# define ConvertUTF_DISABLE_WARNINGS
#endif
#ifndef ConvertUTF_RESTORE_WARNINGS
# define ConvertUTF_RESTORE_WARNINGS
#endif
ConvertUTF_DISABLE_WARNINGS
namespace llvm {
static const int halfShift = 10; /* used for shifting by 10 bits */ static const int halfShift = 10; /* used for shifting by 10 bits */
@ -63,8 +90,6 @@ static const UTF32 halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_END (UTF32)0xDBFF #define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00 #define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF #define UNI_SUR_LOW_END (UTF32)0xDFFF
#define false 0
#define true 1
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@ -394,6 +419,99 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static unsigned
findMaximalSubpartOfIllFormedUTF8Sequence(const UTF8 *source,
const UTF8 *sourceEnd) {
UTF8 b1, b2, b3;
assert(!isLegalUTF8Sequence(source, sourceEnd));
/*
* Unicode 6.3.0, D93b:
*
* Maximal subpart of an ill-formed subsequence: The longest code unit
* subsequence starting at an unconvertible offset that is either:
* a. the initial subsequence of a well-formed code unit sequence, or
* b. a subsequence of length one.
*/
if (source == sourceEnd)
return 0;
/*
* Perform case analysis. See Unicode 6.3.0, Table 3-7. Well-Formed UTF-8
* Byte Sequences.
*/
b1 = *source;
++source;
if (b1 >= 0xC2 && b1 <= 0xDF) {
/*
* First byte is valid, but we know that this code unit sequence is
* invalid, so the maximal subpart has to end after the first byte.
*/
return 1;
}
if (source == sourceEnd)
return 1;
b2 = *source;
++source;
if (b1 == 0xE0) {
return (b2 >= 0xA0 && b2 <= 0xBF) ? 2 : 1;
}
if (b1 >= 0xE1 && b1 <= 0xEC) {
return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1;
}
if (b1 == 0xED) {
return (b2 >= 0x80 && b2 <= 0x9F) ? 2 : 1;
}
if (b1 >= 0xEE && b1 <= 0xEF) {
return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1;
}
if (b1 == 0xF0) {
if (b2 >= 0x90 && b2 <= 0xBF) {
if (source == sourceEnd)
return 2;
b3 = *source;
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
}
return 1;
}
if (b1 >= 0xF1 && b1 <= 0xF3) {
if (b2 >= 0x80 && b2 <= 0xBF) {
if (source == sourceEnd)
return 2;
b3 = *source;
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
}
return 1;
}
if (b1 == 0xF4) {
if (b2 >= 0x80 && b2 <= 0x8F) {
if (source == sourceEnd)
return 2;
b3 = *source;
return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2;
}
return 1;
}
assert((b1 >= 0x80 && b1 <= 0xC1) || b1 >= 0xF5);
/*
* There are no valid sequences that start with these bytes. Maximal subpart
* is defined to have length 1 in these cases.
*/
return 1;
}
/* --------------------------------------------------------------------- */
/* /*
* Exported function to return the total number of bytes in a codepoint * Exported function to return the total number of bytes in a codepoint
* represented in UTF-8, given the value of the first byte. * represented in UTF-8, given the value of the first byte.
@ -402,22 +520,6 @@ unsigned getNumBytesForUTF8(UTF8 first) {
return trailingBytesForUTF8[first] + 1; return trailingBytesForUTF8[first] + 1;
} }
int getUTF8StringLength(const UTF8* utf8)
{
const UTF8** source = &utf8;
const UTF8* sourceEnd = utf8 + strlen((const char*)utf8);
int ret = 0;
while (*source != sourceEnd) {
int length = trailingBytesForUTF8[**source] + 1;
if (length > sourceEnd - *source || !isLegalUTF8(*source, length))
return 0;
*source += length;
++ret;
}
return ret;
}
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* /*
@ -509,9 +611,10 @@ ConversionResult ConvertUTF8toUTF16 (
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF32 ( static ConversionResult ConvertUTF8toUTF32Impl(
const UTF8** sourceStart, const UTF8* sourceEnd, const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags,
Boolean InputIsPartial) {
ConversionResult result = conversionOK; ConversionResult result = conversionOK;
const UTF8* source = *sourceStart; const UTF8* source = *sourceStart;
UTF32* target = *targetStart; UTF32* target = *targetStart;
@ -519,12 +622,42 @@ ConversionResult ConvertUTF8toUTF32 (
UTF32 ch = 0; UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (extraBytesToRead >= sourceEnd - source) { if (extraBytesToRead >= sourceEnd - source) {
result = sourceExhausted; break; if (flags == strictConversion || InputIsPartial) {
result = sourceExhausted;
break;
} else {
result = sourceIllegal;
/*
* Replace the maximal subpart of ill-formed sequence with
* replacement character.
*/
source += findMaximalSubpartOfIllFormedUTF8Sequence(source,
sourceEnd);
*target++ = UNI_REPLACEMENT_CHAR;
continue;
} }
}
if (target >= targetEnd) {
result = targetExhausted; break;
}
/* Do this check whether lenient or strict */ /* Do this check whether lenient or strict */
if (!isLegalUTF8(source, extraBytesToRead+1)) { if (!isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal; result = sourceIllegal;
if (flags == strictConversion) {
/* Abort conversion. */
break; break;
} else {
/*
* Replace the maximal subpart of ill-formed sequence with
* replacement character.
*/
source += findMaximalSubpartOfIllFormedUTF8Sequence(source,
sourceEnd);
*target++ = UNI_REPLACEMENT_CHAR;
continue;
}
} }
/* /*
* The cases all fall through. See "Note A" below. * The cases all fall through. See "Note A" below.
@ -539,10 +672,6 @@ ConversionResult ConvertUTF8toUTF32 (
} }
ch -= offsetsFromUTF8[extraBytesToRead]; ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up the source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_LEGAL_UTF32) { if (ch <= UNI_MAX_LEGAL_UTF32) {
/* /*
* UTF-16 surrogate values are illegal in UTF-32, and anything * UTF-16 surrogate values are illegal in UTF-32, and anything
@ -569,6 +698,36 @@ ConversionResult ConvertUTF8toUTF32 (
return result; return result;
} }
ConversionResult ConvertUTF8toUTF32Partial(const UTF8 **sourceStart,
const UTF8 *sourceEnd,
UTF32 **targetStart,
UTF32 *targetEnd,
ConversionFlags flags) {
return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd,
flags, /*InputIsPartial=*/true);
}
ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart,
const UTF8 *sourceEnd, UTF32 **targetStart,
UTF32 *targetEnd, ConversionFlags flags) {
return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd,
flags, /*InputIsPartial=*/false);
}
int getUTF8StringLength(const UTF8* utf8) {
const UTF8** source = &utf8;
const UTF8* sourceEnd = utf8 + strlen((const char*) utf8);
int ret = 0;
while (*source != sourceEnd) {
int length = trailingBytesForUTF8[**source] + 1;
if (length > sourceEnd - *source || !isLegalUTF8(*source, length))
return 0;
*source += length;
++ret;
}
return ret;
}
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
Note A. Note A.
@ -587,3 +746,7 @@ ConversionResult ConvertUTF8toUTF32 (
similarly unrolled loops. similarly unrolled loops.
--------------------------------------------------------------------- */ --------------------------------------------------------------------- */
} // namespace llvm
ConvertUTF_RESTORE_WARNINGS

View File

@ -1,9 +1,8 @@
/*===--- ConvertUTF.h - Universal Character Names conversions ---------------=== /*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
* *
* The LLVM Compiler Infrastructure * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* * See https://llvm.org/LICENSE.txt for license information.
* This file is distributed under the University of Illinois Open Source * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
* License. See LICENSE.TXT for details.
* *
*==------------------------------------------------------------------------==*/ *==------------------------------------------------------------------------==*/
/* /*
@ -90,7 +89,15 @@
#ifndef LLVM_SUPPORT_CONVERTUTF_H #ifndef LLVM_SUPPORT_CONVERTUTF_H
#define LLVM_SUPPORT_CONVERTUTF_H #define LLVM_SUPPORT_CONVERTUTF_H
#include <stddef.h> /* ptrdiff_t */ #include <cstddef>
#include <string>
#include <system_error>
// Wrap everything in namespace llvm so that programs can link with llvm and
// their own version of the unicode libraries.
namespace llvm {
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific. The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least The C standard does not guarantee that wchar_t has at least
@ -128,16 +135,23 @@ typedef enum {
lenientConversion lenientConversion
} ConversionFlags; } ConversionFlags;
/* This is for C++ and does no harm in C */
#ifdef __cplusplus
extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 ( ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd, const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF8toUTF32 ( /**
* Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
* incomplete code unit sequence, returns \c sourceExhausted.
*/
ConversionResult ConvertUTF8toUTF32Partial(
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
/**
* Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
* incomplete code unit sequence, returns \c sourceIllegal.
*/
ConversionResult ConvertUTF8toUTF32(
const UTF8** sourceStart, const UTF8* sourceEnd, const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
@ -163,92 +177,9 @@ Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
unsigned getNumBytesForUTF8(UTF8 firstByte); unsigned getNumBytesForUTF8(UTF8 firstByte);
// adxe-specific
int getUTF8StringLength(const UTF8* utf8); int getUTF8StringLength(const UTF8* utf8);
#ifdef __cplusplus
}
/*************************************************************************/
/* Below are LLVM-specific wrappers of the functions above. */
//#include "llvm/ADT/ArrayRef.h"
//#include "llvm/ADT/StringRef.h"
#include <vector>
#include <string>
namespace llvm {
/**
* Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on
* WideCharWidth. The converted data is written to ResultPtr, which needs to
* point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
* ResultPtr will point one after the end of the copied string. On failure,
* ResultPtr will not be changed, and ErrorPtr will be set to the location of
* the first character which could not be converted.
* \return true on success.
*/
bool ConvertUTF8toWide(unsigned WideCharWidth, const std::string& Source,
char *&ResultPtr, const UTF8 *&ErrorPtr);
/**
* Convert an Unicode code point to UTF8 sequence.
*
* \param Source a Unicode code point.
* \param [in,out] ResultPtr pointer to the output buffer, needs to be at least
* \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes. On success \c ResultPtr is
* updated one past end of the converted sequence.
*
* \returns true on success.
*/
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
/**
* Convert the first UTF8 sequence in the given source buffer to a UTF32
* code point.
*
* \param [in,out] source A pointer to the source buffer. If the conversion
* succeeds, this pointer will be updated to point to the byte just past the
* end of the converted sequence.
* \param sourceEnd A pointer just past the end of the source buffer.
* \param [out] target The converted code
* \param flags Whether the conversion is strict or lenient.
*
* \returns conversionOK on success
*
* \sa ConvertUTF8toUTF32
*/
static inline ConversionResult convertUTF8Sequence(const UTF8 **source,
const UTF8 *sourceEnd,
UTF32 *target,
ConversionFlags flags) {
if (*source == sourceEnd)
return sourceExhausted;
unsigned size = getNumBytesForUTF8(**source);
if ((ptrdiff_t)size > sourceEnd - *source)
return sourceExhausted;
return ConvertUTF8toUTF32(source, *source + size, &target, target + 1, flags);
}
/**
* Returns true if a blob of text starts with a UTF-16 big or little endian byte
* order mark.
*/
bool hasUTF16ByteOrderMark(const char* SrcBytes, size_t len);
/**
* Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
*
* \param [in] SrcBytes A buffer of what is assumed to be UTF-16 encoded text.
* \param [out] Out Converted UTF-8 is stored here on success.
* \returns true on success
*/
bool convertUTF16ToUTF8String(const std::u16string& utf16, std::string &Out);
} /* end namespace llvm */ } /* end namespace llvm */
#endif #endif
/* --------------------------------------------------------------------- */
#endif

View File

@ -1,144 +0,0 @@
//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ConvertUTF.h"
//#include "llvm/Support/SwapByteOrder.h"
#include <string>
#include <vector>
#include <stdint.h> // uint16_t
#include <assert.h>
#include <memory.h>
namespace llvm {
bool ConvertUTF8toWide(unsigned WideCharWidth, const std::string& Source,
char *&ResultPtr, const UTF8 *&ErrorPtr) {
assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
ConversionResult result = conversionOK;
// Copy the character span over.
if (WideCharWidth == 1) {
const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.data());
if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.data() + Source.length()))) {
result = sourceIllegal;
ErrorPtr = Pos;
} else {
memcpy(ResultPtr, Source.data(), Source.size());
ResultPtr += Source.size();
}
} else if (WideCharWidth == 2) {
const UTF8 *sourceStart = (const UTF8*)Source.data();
// FIXME: Make the type of the result buffer correct instead of
// using reinterpret_cast.
UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
ConversionFlags flags = strictConversion;
result = ConvertUTF8toUTF16(
&sourceStart, sourceStart + Source.size(),
&targetStart, targetStart + 2*Source.size(), flags);
if (result == conversionOK)
ResultPtr = reinterpret_cast<char*>(targetStart);
else
ErrorPtr = sourceStart;
} else if (WideCharWidth == 4) {
const UTF8 *sourceStart = (const UTF8*)Source.data();
// FIXME: Make the type of the result buffer correct instead of
// using reinterpret_cast.
UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
ConversionFlags flags = strictConversion;
result = ConvertUTF8toUTF32(
&sourceStart, sourceStart + Source.size(),
&targetStart, targetStart + 4*Source.size(), flags);
if (result == conversionOK)
ResultPtr = reinterpret_cast<char*>(targetStart);
else
ErrorPtr = sourceStart;
}
assert((result != targetExhausted)
&& "ConvertUTF8toUTFXX exhausted target buffer");
return result == conversionOK;
}
bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
const UTF32 *SourceStart = &Source;
const UTF32 *SourceEnd = SourceStart + 1;
UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr);
UTF8 *TargetEnd = TargetStart + 4;
ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd,
&TargetStart, TargetEnd,
strictConversion);
if (CR != conversionOK)
return false;
ResultPtr = reinterpret_cast<char*>(TargetStart);
return true;
}
bool hasUTF16ByteOrderMark(const char* S, size_t len) {
return (len >= 2 &&
((S[0] == '\xff' && S[1] == '\xfe') ||
(S[0] == '\xfe' && S[1] == '\xff')));
}
/// SwapByteOrder_16 - This function returns a byte-swapped representation of
/// the 16-bit argument.
inline uint16_t SwapByteOrder_16(uint16_t value) {
#if defined(_MSC_VER) && !defined(_DEBUG)
// The DLL version of the runtime lacks these functions (bug!?), but in a
// release build they're replaced with BSWAP instructions anyway.
return _byteswap_ushort(value);
#else
uint16_t Hi = value << 8;
uint16_t Lo = value >> 8;
return Hi | Lo;
#endif
}
bool convertUTF16ToUTF8String(const std::u16string& utf16, std::string &Out) {
assert(Out.empty());
// Avoid OOB by returning early on empty input.
if (utf16.empty())
return true;
const UTF16 *Src = reinterpret_cast<const UTF16 *>(utf16.data());
const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(utf16.data() + utf16.length());
// Byteswap if necessary.
std::vector<UTF16> ByteSwapped;
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
for (size_t I = 0, E = ByteSwapped.size(); I != E; ++I)
ByteSwapped[I] = SwapByteOrder_16(ByteSwapped[I]);
Src = &ByteSwapped[0];
SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
}
// Skip the BOM for conversion.
if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_NATIVE)
Src++;
// Just allocate enough space up front. We'll shrink it later.
Out.resize(utf16.length() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);
UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]);
UTF8 *DstEnd = Dst + Out.size();
ConversionResult CR =
ConvertUTF16toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
assert(CR != targetExhausted);
if (CR != conversionOK) {
Out.clear();
return false;
}
Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]);
return true;
}
} // end namespace llvm

4
external/README.md vendored
View File

@ -36,7 +36,7 @@
## ConvertUTF ## ConvertUTF
- Upstream: https://github.com/llvm/llvm-project - Upstream: https://github.com/llvm/llvm-project
- Version: NA - Version: git 2946cd7 without LLVM-specific wrappers of the functions
- License: Apache-2.0 WITH LLVM-exception - License: Apache-2.0 WITH LLVM-exception
## curl ## curl
@ -153,7 +153,7 @@
## poly2tri ## poly2tri
- Upstream: https://github.com/jhasse/poly2tri - Upstream: https://github.com/jhasse/poly2tri
- Version: NA - Version: git 7f0487a
- License: BSD-3-Clause - License: BSD-3-Clause
## pugixml ## pugixml

View File

@ -243,6 +243,17 @@ Point* Triangle::PointCCW(const Point& point)
return nullptr; return nullptr;
} }
// The neighbor across to given point
Triangle* Triangle::NeighborAcross(const Point& point)
{
if (&point == points_[0]) {
return neighbors_[0];
} else if (&point == points_[1]) {
return neighbors_[1];
}
return neighbors_[2];
}
// The neighbor clockwise to given point // The neighbor clockwise to given point
Triangle* Triangle::NeighborCW(const Point& point) Triangle* Triangle::NeighborCW(const Point& point)
{ {
@ -349,23 +360,6 @@ void Triangle::SetDelunayEdgeCW(const Point& p, bool e)
} }
} }
// The neighbor across to given point
Triangle& Triangle::NeighborAcross(const Point& opoint)
{
Triangle* neighbor = nullptr;
if (&opoint == points_[0]) {
neighbor = neighbors_[0];
} else if (&opoint == points_[1]) {
neighbor = neighbors_[1];
} else {
neighbor = neighbors_[2];
}
if (neighbor == nullptr) {
throw std::runtime_error("NeighborAcross - null neighbor");
}
return *neighbor;
}
void Triangle::DebugPrint() void Triangle::DebugPrint()
{ {
std::cout << *points_[0] << " " << *points_[1] << " " << *points_[2] << std::endl; std::cout << *points_[0] << " " << *points_[1] << " " << *points_[2] << std::endl;

View File

@ -176,6 +176,7 @@ void MarkConstrainedEdge(Point* p, Point* q);
int Index(const Point* p); int Index(const Point* p);
int EdgeIndex(const Point* p1, const Point* p2); int EdgeIndex(const Point* p1, const Point* p2);
Triangle* NeighborAcross(const Point& point);
Triangle* NeighborCW(const Point& point); Triangle* NeighborCW(const Point& point);
Triangle* NeighborCCW(const Point& point); Triangle* NeighborCCW(const Point& point);
bool GetConstrainedEdgeCCW(const Point& p); bool GetConstrainedEdgeCCW(const Point& p);
@ -203,8 +204,6 @@ void ClearDelunayEdges();
inline bool IsInterior(); inline bool IsInterior();
inline void IsInterior(bool b); inline void IsInterior(bool b);
Triangle& NeighborAcross(const Point& opoint);
void DebugPrint(); void DebugPrint();
bool CircumcicleContains(const Point&) const; bool CircumcicleContains(const Point&) const;
@ -260,7 +259,7 @@ inline bool operator ==(const Point& a, const Point& b)
inline bool operator !=(const Point& a, const Point& b) inline bool operator !=(const Point& a, const Point& b)
{ {
return !(a.x == b.x) && !(a.y == b.y); return !(a.x == b.x) || !(a.y == b.y);
} }
/// Peform the dot product on two vectors. /// Peform the dot product on two vectors.

View File

@ -1,5 +1,5 @@
/* /*
* Poly2Tri Copyright (c) 2009-2018, Poly2Tri Contributors * Poly2Tri Copyright (c) 2009-2021, Poly2Tri Contributors
* https://github.com/jhasse/poly2tri * https://github.com/jhasse/poly2tri
* *
* All rights reserved. * All rights reserved.
@ -68,4 +68,4 @@ CDT::~CDT()
delete sweep_; delete sweep_;
} }
} } // namespace p2t

View File

@ -65,17 +65,25 @@ void Sweep::FinalizationPolygon(SweepContext& tcx)
// Get an Internal triangle to start with // Get an Internal triangle to start with
Triangle* t = tcx.front()->head()->next->triangle; Triangle* t = tcx.front()->head()->next->triangle;
Point* p = tcx.front()->head()->next->point; Point* p = tcx.front()->head()->next->point;
while (!t->GetConstrainedEdgeCW(*p)) { while (t && !t->GetConstrainedEdgeCW(*p)) {
t = t->NeighborCCW(*p); t = t->NeighborCCW(*p);
} }
// Collect interior triangles constrained by edges // Collect interior triangles constrained by edges
if (t) {
tcx.MeshClean(*t); tcx.MeshClean(*t);
}
} }
Node& Sweep::PointEvent(SweepContext& tcx, Point& point) Node& Sweep::PointEvent(SweepContext& tcx, Point& point)
{ {
Node& node = tcx.LocateNode(point); Node* node_ptr = tcx.LocateNode(point);
if (!node_ptr || !node_ptr->point || !node_ptr->next || !node_ptr->next->point)
{
throw std::runtime_error("PointEvent - null node");
}
Node& node = *node_ptr;
Node& new_node = NewFrontTriangle(tcx, point, node); Node& new_node = NewFrontTriangle(tcx, point, node);
// Only need to check +epsilon since point never have smaller // Only need to check +epsilon since point never have smaller
@ -108,6 +116,9 @@ void Sweep::EdgeEvent(SweepContext& tcx, Edge* edge, Node* node)
void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point) void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point)
{ {
if (triangle == nullptr) {
throw std::runtime_error("EdgeEvent - null triangle");
}
if (IsEdgeSideOfTriangle(*triangle, ep, eq)) { if (IsEdgeSideOfTriangle(*triangle, ep, eq)) {
return; return;
} }
@ -115,13 +126,13 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
Point* p1 = triangle->PointCCW(point); Point* p1 = triangle->PointCCW(point);
Orientation o1 = Orient2d(eq, *p1, ep); Orientation o1 = Orient2d(eq, *p1, ep);
if (o1 == COLLINEAR) { if (o1 == COLLINEAR) {
if( triangle->Contains(&eq, p1)) { if (triangle->Contains(&eq, p1)) {
triangle->MarkConstrainedEdge(&eq, p1 ); triangle->MarkConstrainedEdge(&eq, p1);
// We are modifying the constraint maybe it would be better to // We are modifying the constraint maybe it would be better to
// not change the given constraint and just keep a variable for the new constraint // not change the given constraint and just keep a variable for the new constraint
tcx.edge_event.constrained_edge->q = p1; tcx.edge_event.constrained_edge->q = p1;
triangle = &triangle->NeighborAcross(point); triangle = triangle->NeighborAcross(point);
EdgeEvent( tcx, ep, *p1, triangle, *p1 ); EdgeEvent(tcx, ep, *p1, triangle, *p1);
} else { } else {
throw std::runtime_error("EdgeEvent - collinear points not supported"); throw std::runtime_error("EdgeEvent - collinear points not supported");
} }
@ -131,13 +142,13 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
Point* p2 = triangle->PointCW(point); Point* p2 = triangle->PointCW(point);
Orientation o2 = Orient2d(eq, *p2, ep); Orientation o2 = Orient2d(eq, *p2, ep);
if (o2 == COLLINEAR) { if (o2 == COLLINEAR) {
if( triangle->Contains(&eq, p2)) { if (triangle->Contains(&eq, p2)) {
triangle->MarkConstrainedEdge(&eq, p2 ); triangle->MarkConstrainedEdge(&eq, p2);
// We are modifying the constraint maybe it would be better to // We are modifying the constraint maybe it would be better to
// not change the given constraint and just keep a variable for the new constraint // not change the given constraint and just keep a variable for the new constraint
tcx.edge_event.constrained_edge->q = p2; tcx.edge_event.constrained_edge->q = p2;
triangle = &triangle->NeighborAcross(point); triangle = triangle->NeighborAcross(point);
EdgeEvent( tcx, ep, *p2, triangle, *p2 ); EdgeEvent(tcx, ep, *p2, triangle, *p2);
} else { } else {
throw std::runtime_error("EdgeEvent - collinear points not supported"); throw std::runtime_error("EdgeEvent - collinear points not supported");
} }
@ -149,12 +160,13 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl
// that will cross edge // that will cross edge
if (o1 == CW) { if (o1 == CW) {
triangle = triangle->NeighborCCW(point); triangle = triangle->NeighborCCW(point);
} else{ } else {
triangle = triangle->NeighborCW(point); triangle = triangle->NeighborCW(point);
} }
EdgeEvent(tcx, ep, eq, triangle, point); EdgeEvent(tcx, ep, eq, triangle, point);
} else { } else {
// This triangle crosses constraint so lets flippin start! // This triangle crosses constraint so lets flippin start!
assert(triangle);
FlipEdgeEvent(tcx, ep, eq, triangle, point); FlipEdgeEvent(tcx, ep, eq, triangle, point);
} }
} }
@ -215,7 +227,6 @@ void Sweep::Fill(SweepContext& tcx, Node& node)
if (!Legalize(tcx, *triangle)) { if (!Legalize(tcx, *triangle)) {
tcx.MapTriangleToNodes(*triangle); tcx.MapTriangleToNodes(*triangle);
} }
} }
void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
@ -224,7 +235,7 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
// Fill right holes // Fill right holes
Node* node = n.next; Node* node = n.next;
while (node->next) { while (node && node->next) {
// if HoleAngle exceeds 90 degrees then break. // if HoleAngle exceeds 90 degrees then break.
if (LargeHole_DontFill(node)) break; if (LargeHole_DontFill(node)) break;
Fill(tcx, *node); Fill(tcx, *node);
@ -234,7 +245,7 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n)
// Fill left holes // Fill left holes
node = n.prev; node = n.prev;
while (node->prev) { while (node && node->prev) {
// if HoleAngle exceeds 90 degrees then break. // if HoleAngle exceeds 90 degrees then break.
if (LargeHole_DontFill(node)) break; if (LargeHole_DontFill(node)) break;
Fill(tcx, *node); Fill(tcx, *node);
@ -293,7 +304,7 @@ double Sweep::Angle(const Point* origin, const Point* pa, const Point* pb) const
*/ */
const double px = origin->x; const double px = origin->x;
const double py = origin->y; const double py = origin->y;
const double ax = pa->x- px; const double ax = pa->x - px;
const double ay = pa->y - py; const double ay = pa->y - py;
const double bx = pb->x - px; const double bx = pb->x - px;
const double by = pb->y - py; const double by = pb->y - py;
@ -586,7 +597,7 @@ void Sweep::FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) {
// Concave // Concave
FillRightConcaveEdgeEvent(tcx, edge, node); FillRightConcaveEdgeEvent(tcx, edge, node);
} else{ } else {
// Convex // Convex
FillRightConvexEdgeEvent(tcx, edge, node); FillRightConvexEdgeEvent(tcx, edge, node);
// Retry this one // Retry this one
@ -610,7 +621,6 @@ void Sweep::FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
} }
} }
} }
} }
void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
@ -619,13 +629,13 @@ void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
if (Orient2d(*node.next->point, *node.next->next->point, *node.next->next->next->point) == CCW) { if (Orient2d(*node.next->point, *node.next->next->point, *node.next->next->next->point) == CCW) {
// Concave // Concave
FillRightConcaveEdgeEvent(tcx, edge, *node.next); FillRightConcaveEdgeEvent(tcx, edge, *node.next);
} else{ } else {
// Convex // Convex
// Next above or below edge? // Next above or below edge?
if (Orient2d(*edge->q, *node.next->next->point, *edge->p) == CCW) { if (Orient2d(*edge->q, *node.next->next->point, *edge->p) == CCW) {
// Below // Below
FillRightConvexEdgeEvent(tcx, edge, *node.next); FillRightConvexEdgeEvent(tcx, edge, *node.next);
} else{ } else {
// Above // Above
} }
} }
@ -664,13 +674,13 @@ void Sweep::FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
if (Orient2d(*node.prev->point, *node.prev->prev->point, *node.prev->prev->prev->point) == CW) { if (Orient2d(*node.prev->point, *node.prev->prev->point, *node.prev->prev->prev->point) == CW) {
// Concave // Concave
FillLeftConcaveEdgeEvent(tcx, edge, *node.prev); FillLeftConcaveEdgeEvent(tcx, edge, *node.prev);
} else{ } else {
// Convex // Convex
// Next above or below edge? // Next above or below edge?
if (Orient2d(*edge->q, *node.prev->prev->point, *edge->p) == CW) { if (Orient2d(*edge->q, *node.prev->prev->point, *edge->p) == CW) {
// Below // Below
FillLeftConvexEdgeEvent(tcx, edge, *node.prev); FillLeftConvexEdgeEvent(tcx, edge, *node.prev);
} else{ } else {
// Above // Above
} }
} }
@ -686,17 +696,22 @@ void Sweep::FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node)
if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) {
// Next is concave // Next is concave
FillLeftConcaveEdgeEvent(tcx, edge, node); FillLeftConcaveEdgeEvent(tcx, edge, node);
} else{ } else {
// Next is convex // Next is convex
} }
} }
} }
} }
void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p) void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p)
{ {
Triangle& ot = t->NeighborAcross(p); assert(t);
Triangle* ot_ptr = t->NeighborAcross(p);
if (ot_ptr == nullptr)
{
throw std::runtime_error("FlipEdgeEvent - null neighbor across");
}
Triangle& ot = *ot_ptr;
Point& op = *ot.OppositePoint(*t, p); Point& op = *ot.OppositePoint(*t, p);
if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) { if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) {
@ -762,10 +777,26 @@ Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op)
void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle,
Triangle& t, Point& p) Triangle& t, Point& p)
{ {
Triangle& ot = t.NeighborAcross(p); Triangle* ot_ptr = t.NeighborAcross(p);
Point& op = *ot.OppositePoint(t, p); if (ot_ptr == nullptr) {
throw std::runtime_error("FlipScanEdgeEvent - null neighbor across");
}
if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) { Point* op_ptr = ot_ptr->OppositePoint(t, p);
if (op_ptr == nullptr) {
throw std::runtime_error("FlipScanEdgeEvent - null opposing point");
}
Point* p1 = flip_triangle.PointCCW(eq);
Point* p2 = flip_triangle.PointCW(eq);
if (p1 == nullptr || p2 == nullptr) {
throw std::runtime_error("FlipScanEdgeEvent - null on either of points");
}
Triangle& ot = *ot_ptr;
Point& op = *op_ptr;
if (InScanArea(eq, *p1, *p2, op)) {
// flip with new edge op->eq // flip with new edge op->eq
FlipEdgeEvent(tcx, eq, op, &ot, op); FlipEdgeEvent(tcx, eq, op, &ot, op);
// TODO: Actually I just figured out that it should be possible to // TODO: Actually I just figured out that it should be possible to
@ -775,7 +806,7 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle&
// also need to set a new flip_triangle first // also need to set a new flip_triangle first
// Turns out at first glance that this is somewhat complicated // Turns out at first glance that this is somewhat complicated
// so it will have to wait. // so it will have to wait.
} else{ } else {
Point& newP = NextFlipPoint(ep, eq, ot, op); Point& newP = NextFlipPoint(ep, eq, ot, op);
FlipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP); FlipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP);
} }
@ -790,5 +821,4 @@ Sweep::~Sweep() {
} }
} } // namespace p2t

View File

@ -33,7 +33,7 @@
* Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation',
* International Journal of Geographical Information Science * International Journal of Geographical Information Science
* *
* "FlipScan" Constrained Edge Algorithm invented by Thomas ?hl?n, thahlen@gmail.com * "FlipScan" Constrained Edge Algorithm invented by Thomas Åhlén, thahlen@gmail.com
*/ */
#ifndef SWEEP_H #ifndef SWEEP_H

View File

@ -87,8 +87,8 @@ void SweepContext::InitTriangulation()
double dx = kAlpha * (xmax - xmin); double dx = kAlpha * (xmax - xmin);
double dy = kAlpha * (ymax - ymin); double dy = kAlpha * (ymax - ymin);
head_ = new Point(xmax + dx, ymin - dy); head_ = new Point(xmin - dx, ymin - dy);
tail_ = new Point(xmin - dx, ymin - dy); tail_ = new Point(xmax + dx, ymin - dy);
// Sort points along y-axis // Sort points along y-axis
std::sort(points_.begin(), points_.end(), cmp); std::sort(points_.begin(), points_.end(), cmp);
@ -114,17 +114,17 @@ void SweepContext::AddToMap(Triangle* triangle)
map_.push_back(triangle); map_.push_back(triangle);
} }
Node& SweepContext::LocateNode(const Point& point) Node* SweepContext::LocateNode(const Point& point)
{ {
// TODO implement search tree // TODO implement search tree
return *front_->LocateNode(point.x); return front_->LocateNode(point.x);
} }
void SweepContext::CreateAdvancingFront() void SweepContext::CreateAdvancingFront()
{ {
// Initial triangle // Initial triangle
Triangle* triangle = new Triangle(*points_[0], *tail_, *head_); Triangle* triangle = new Triangle(*points_[0], *head_, *tail_);
map_.push_back(triangle); map_.push_back(triangle);
@ -207,4 +207,4 @@ SweepContext::~SweepContext()
} }
} } // namespace p2t

View File

@ -66,7 +66,7 @@ Point* tail() const;
size_t point_count() const; size_t point_count() const;
Node& LocateNode(const Point& point); Node* LocateNode(const Point& point);
void RemoveNode(Node* node); void RemoveNode(Node* node);