]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/scriptset.cpp
ICU-511.25.tar.gz
[apple/icu.git] / icuSources / i18n / scriptset.cpp
diff --git a/icuSources/i18n/scriptset.cpp b/icuSources/i18n/scriptset.cpp
new file mode 100644 (file)
index 0000000..809e5f6
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+**********************************************************************
+*   Copyright (C) 2013, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+**********************************************************************
+*
+* scriptset.cpp
+*
+* created on: 2013 Jan 7
+* created by: Andy Heninger
+*/
+
+#include "unicode/utypes.h"
+
+#include "unicode/uchar.h"
+#include "unicode/unistr.h"
+
+#include "scriptset.h"
+#include "uassert.h"
+
+U_NAMESPACE_BEGIN
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+//----------------------------------------------------------------------------
+//
+//  ScriptSet implementation
+//
+//----------------------------------------------------------------------------
+ScriptSet::ScriptSet() {
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        bits[i] = 0;
+    }
+}
+
+ScriptSet::~ScriptSet() {
+}
+
+ScriptSet::ScriptSet(const ScriptSet &other) {
+    *this = other;
+}
+    
+
+ScriptSet & ScriptSet::operator =(const ScriptSet &other) {
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        bits[i] = other.bits[i];
+    }
+    return *this;
+}
+
+
+UBool ScriptSet::operator == (const ScriptSet &other) const {
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        if (bits[i] != other.bits[i]) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+UBool ScriptSet::test(UScriptCode script, UErrorCode &status) const {
+    if (U_FAILURE(status)) {
+        return FALSE;
+    }
+    if (script < 0 || script >= (int32_t)sizeof(bits) * 8) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return FALSE;
+    }
+    uint32_t index = script / 32;
+    uint32_t bit   = 1 << (script & 31);
+    return ((bits[index] & bit) != 0);
+}
+
+
+ScriptSet &ScriptSet::set(UScriptCode script, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return *this;
+    }
+    if (script < 0 || script >= (int32_t)sizeof(bits) * 8) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return *this;
+    }
+    uint32_t index = script / 32;
+    uint32_t bit   = 1 << (script & 31);
+    bits[index] |= bit;
+    return *this;
+}
+
+ScriptSet &ScriptSet::reset(UScriptCode script, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return *this;
+    }
+    if (script < 0 || script >= (int32_t)sizeof(bits) * 8) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return *this;
+    }
+    uint32_t index = script / 32;
+    uint32_t bit   = 1 << (script & 31);
+    bits[index] &= ~bit;
+    return *this;
+}
+
+
+
+ScriptSet &ScriptSet::Union(const ScriptSet &other) {
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        bits[i] |= other.bits[i];
+    }
+    return *this;
+}
+
+ScriptSet &ScriptSet::intersect(const ScriptSet &other) {
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        bits[i] &= other.bits[i];
+    }
+    return *this;
+}
+
+ScriptSet &ScriptSet::intersect(UScriptCode script, UErrorCode &status) {
+    ScriptSet t;
+    t.set(script, status);
+    if (U_SUCCESS(status)) {
+        this->intersect(t);
+    }
+    return *this;
+}
+    
+UBool ScriptSet::intersects(const ScriptSet &other) const {
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        if ((bits[i] & other.bits[i]) != 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+UBool ScriptSet::contains(const ScriptSet &other) const {
+    ScriptSet t(*this);
+    t.intersect(other);
+    return (t == other);
+}
+
+
+ScriptSet &ScriptSet::setAll() {
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        bits[i] = 0xffffffffu;
+    }
+    return *this;
+}
+
+
+ScriptSet &ScriptSet::resetAll() {
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        bits[i] = 0;
+    }
+    return *this;
+}
+
+int32_t ScriptSet::countMembers() const {
+    // This bit counter is good for sparse numbers of '1's, which is
+    //  very much the case that we will usually have.
+    int32_t count = 0;
+    for (uint32_t i=0; i<LENGTHOF(bits); i++) {
+        uint32_t x = bits[i];
+        while (x > 0) {
+            count++;
+            x &= (x - 1);    // and off the least significant one bit.
+        }
+    }
+    return count;
+}
+
+int32_t ScriptSet::hashCode() const {
+    int32_t hash = 0;
+    for (int32_t i=0; i<LENGTHOF(bits); i++) {
+        hash ^= bits[i];
+    }
+    return hash;
+}
+
+int32_t ScriptSet::nextSetBit(int32_t fromIndex) const {
+    // TODO: Wants a better implementation.
+    if (fromIndex < 0) {
+        return -1;
+    }
+    UErrorCode status = U_ZERO_ERROR;
+    for (int32_t scriptIndex = fromIndex; scriptIndex < (int32_t)sizeof(bits)*8; scriptIndex++) {
+        if (test((UScriptCode)scriptIndex, status)) {
+            return scriptIndex;
+        }
+    }
+    return -1;
+}
+
+UnicodeString &ScriptSet::displayScripts(UnicodeString &dest) const {
+    UBool firstTime = TRUE;
+    for (int32_t i = nextSetBit(0); i >= 0; i = nextSetBit(i + 1)) {
+        if (!firstTime) {
+            dest.append(0x20);
+        }
+        firstTime = FALSE;
+        const char *scriptName = uscript_getShortName((UScriptCode(i)));
+        dest.append(UnicodeString(scriptName, -1, US_INV));
+    }
+    return dest;
+}
+
+ScriptSet &ScriptSet::parseScripts(const UnicodeString &scriptString, UErrorCode &status) {
+    resetAll();
+    if (U_FAILURE(status)) {
+        return *this;
+    }
+    UnicodeString oneScriptName;
+    for (int32_t i=0; i<scriptString.length();) {
+        UChar32 c = scriptString.char32At(i);
+        i = scriptString.moveIndex32(i, 1);
+        if (!u_isUWhiteSpace(c)) {
+            oneScriptName.append(c);
+            if (i < scriptString.length()) {
+                continue;
+            }
+        }
+        if (oneScriptName.length() > 0) {
+            char buf[40];
+            oneScriptName.extract(0, oneScriptName.length(), buf, sizeof(buf)-1, US_INV);
+            buf[sizeof(buf)-1] = 0;
+            int32_t sc = u_getPropertyValueEnum(UCHAR_SCRIPT, buf);
+            if (sc == UCHAR_INVALID_CODE) {
+                status = U_ILLEGAL_ARGUMENT_ERROR;
+            } else {
+                this->set((UScriptCode)sc, status);
+            }
+            if (U_FAILURE(status)) {
+                return *this;
+            }
+            oneScriptName.remove();
+        }
+    }
+    return *this;
+}
+
+U_NAMESPACE_END
+
+U_CAPI UBool U_EXPORT2
+uhash_equalsScriptSet(const UElement key1, const UElement key2) {
+    icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
+    icu::ScriptSet *s2 = static_cast<icu::ScriptSet *>(key2.pointer);
+    return (*s1 == *s2);
+}
+
+U_CAPI int8_t U_EXPORT2
+uhash_compareScriptSet(UElement key0, UElement key1) {
+    icu::ScriptSet *s0 = static_cast<icu::ScriptSet *>(key0.pointer);
+    icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
+    int32_t diff = s0->countMembers() - s1->countMembers();
+    if (diff != 0) return diff;
+    int32_t i0 = s0->nextSetBit(0);
+    int32_t i1 = s1->nextSetBit(0);
+    while ((diff = i0-i1) == 0 && i0 > 0) {
+        i0 = s0->nextSetBit(i0+1);
+        i1 = s1->nextSetBit(i1+1);
+    }
+    return (int8_t)diff;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashScriptSet(const UElement key) {
+    icu::ScriptSet *s = static_cast<icu::ScriptSet *>(key.pointer);
+    return s->hashCode();
+}
+
+U_CAPI void U_EXPORT2
+uhash_deleteScriptSet(void *obj) {
+    icu::ScriptSet *s = static_cast<icu::ScriptSet *>(obj);
+    delete s;
+}