1fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/*
2fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*******************************************************************************
31b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert* Copyright (C) 2013-2015, International Business Machines
4fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Corporation and others.  All Rights Reserved.
5fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*******************************************************************************
6fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* collationsettings.cpp
7fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*
8fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* created on: 2013feb07
9fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* created by: Markus W. Scherer
10fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*/
11fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
12fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/utypes.h"
13fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
14fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#if !UCONFIG_NO_COLLATION
15fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
16fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/ucol.h"
17fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "cmemory.h"
18fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collation.h"
191b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert#include "collationdata.h"
20fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationsettings.h"
21fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "sharedobject.h"
22fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "uassert.h"
23fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "umutex.h"
241b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert#include "uvectr32.h"
25fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
26fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_BEGIN
27fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
28fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::CollationSettings(const CollationSettings &other)
29fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        : SharedObject(other),
30fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius          options(other.options), variableTop(other.variableTop),
31fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius          reorderTable(NULL),
321b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert          minHighNoReorder(other.minHighNoReorder),
331b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert          reorderRanges(NULL), reorderRangesLength(0),
34fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius          reorderCodes(NULL), reorderCodesLength(0), reorderCodesCapacity(0),
35fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius          fastLatinOptions(other.fastLatinOptions) {
361b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    UErrorCode errorCode = U_ZERO_ERROR;
371b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    copyReorderingFrom(other, errorCode);
38fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(fastLatinOptions >= 0) {
39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uprv_memcpy(fastLatinPrimaries, other.fastLatinPrimaries, sizeof(fastLatinPrimaries));
40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
42fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
43fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::~CollationSettings() {
44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(reorderCodesCapacity != 0) {
45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uprv_free(const_cast<int32_t *>(reorderCodes));
46fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
47fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUBool
50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::operator==(const CollationSettings &other) const {
51fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(options != other.options) { return FALSE; }
52fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((options & ALTERNATE_MASK) != 0 && variableTop != other.variableTop) { return FALSE; }
53fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(reorderCodesLength != other.reorderCodesLength) { return FALSE; }
54fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    for(int32_t i = 0; i < reorderCodesLength; ++i) {
55fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(reorderCodes[i] != other.reorderCodes[i]) { return FALSE; }
56fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
57fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
58fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
59fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
60fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusint32_t
61fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::hashCode() const {
62fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t h = options << 8;
63fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((options & ALTERNATE_MASK) != 0) { h ^= variableTop; }
64fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    h ^= reorderCodesLength;
65fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    for(int32_t i = 0; i < reorderCodesLength; ++i) {
66fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        h ^= (reorderCodes[i] << i);
67fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
68fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return h;
69fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
70fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
71fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
72fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::resetReordering() {
73fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // When we turn off reordering, we want to set a NULL permutation
74fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // rather than a no-op permutation.
75fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Keep the memory via reorderCodes and its capacity.
76fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    reorderTable = NULL;
771b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    minHighNoReorder = 0;
781b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    reorderRangesLength = 0;
79fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    reorderCodesLength = 0;
80fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
81fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
82fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
831b7d32f919554dda9c193b32188251337bc756f1Fredrik RoubertCollationSettings::aliasReordering(const CollationData &data, const int32_t *codes, int32_t length,
841b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                                   const uint32_t *ranges, int32_t rangesLength,
851b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                                   const uint8_t *table, UErrorCode &errorCode) {
861b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(U_FAILURE(errorCode)) { return; }
871b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(table != NULL &&
881b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            (rangesLength == 0 ?
891b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    !reorderTableHasSplitBytes(table) :
901b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    rangesLength >= 2 &&
911b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    // The first offset must be 0. The last offset must not be 0.
921b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    (ranges[0] & 0xffff) == 0 && (ranges[rangesLength - 1] & 0xffff) != 0)) {
93fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // We need to release the memory before setting the alias pointer.
94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(reorderCodesCapacity != 0) {
95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uprv_free(const_cast<int32_t *>(reorderCodes));
96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            reorderCodesCapacity = 0;
97fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
98fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        reorderTable = table;
99fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        reorderCodes = codes;
100fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        reorderCodesLength = length;
1011b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        // Drop ranges before the first split byte. They are reordered by the table.
1021b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        // This then speeds up reordering of the remaining ranges.
1031b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        int32_t firstSplitByteRangeIndex = 0;
1041b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        while(firstSplitByteRangeIndex < rangesLength &&
1051b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                (ranges[firstSplitByteRangeIndex] & 0xff0000) == 0) {
1061b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            // The second byte of the primary limit is 0.
1071b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            ++firstSplitByteRangeIndex;
1081b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        }
1091b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        if(firstSplitByteRangeIndex == rangesLength) {
1101b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            U_ASSERT(!reorderTableHasSplitBytes(table));
1111b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            minHighNoReorder = 0;
1121b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            reorderRanges = NULL;
1131b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            reorderRangesLength = 0;
1141b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        } else {
1151b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            U_ASSERT(table[ranges[firstSplitByteRangeIndex] >> 24] == 0);
1161b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            minHighNoReorder = ranges[rangesLength - 1] & 0xffff0000;
1171b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            reorderRanges = ranges + firstSplitByteRangeIndex;
1181b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            reorderRangesLength = rangesLength - firstSplitByteRangeIndex;
1191b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        }
1201b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        return;
121fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
1221b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // Regenerate missing data.
1231b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    setReordering(data, codes, length, errorCode);
124fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
125fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
1261b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubertvoid
1271b7d32f919554dda9c193b32188251337bc756f1Fredrik RoubertCollationSettings::setReordering(const CollationData &data,
1281b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                                 const int32_t *codes, int32_t codesLength,
1291b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                                 UErrorCode &errorCode) {
1301b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(U_FAILURE(errorCode)) { return; }
1311b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(codesLength == 0 || (codesLength == 1 && codes[0] == UCOL_REORDER_CODE_NONE)) {
132fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        resetReordering();
1331b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        return;
1341b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
1351b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    UVector32 rangesList(errorCode);
1361b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    data.makeReorderRanges(codes, codesLength, rangesList, errorCode);
1371b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(U_FAILURE(errorCode)) { return; }
1381b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    int32_t rangesLength = rangesList.size();
1391b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(rangesLength == 0) {
1401b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        resetReordering();
1411b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        return;
1421b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
1431b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    const uint32_t *ranges = reinterpret_cast<uint32_t *>(rangesList.getBuffer());
1441b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // ranges[] contains at least two (limit, offset) pairs.
1451b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // The first offset must be 0. The last offset must not be 0.
1461b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // Separators (at the low end) and trailing weights (at the high end)
1471b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // are never reordered.
1481b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    U_ASSERT(rangesLength >= 2);
1491b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    U_ASSERT((ranges[0] & 0xffff) == 0 && (ranges[rangesLength - 1] & 0xffff) != 0);
1501b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    minHighNoReorder = ranges[rangesLength - 1] & 0xffff0000;
1511b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert
1521b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // Write the lead byte permutation table.
1531b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // Set a 0 for each lead byte that has a range boundary in the middle.
1541b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    uint8_t table[256];
1551b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    int32_t b = 0;
1561b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    int32_t firstSplitByteRangeIndex = -1;
1571b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    for(int32_t i = 0; i < rangesLength; ++i) {
1581b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        uint32_t pair = ranges[i];
1591b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        int32_t limit1 = (int32_t)(pair >> 24);
1601b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        while(b < limit1) {
1611b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            table[b] = (uint8_t)(b + pair);
1621b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            ++b;
1631b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        }
1641b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        // Check the second byte of the limit.
1651b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        if((pair & 0xff0000) != 0) {
1661b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            table[limit1] = 0;
1671b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            b = limit1 + 1;
1681b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            if(firstSplitByteRangeIndex < 0) {
1691b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                firstSplitByteRangeIndex = i;
170fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
171fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
172fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
1731b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    while(b <= 0xff) {
1741b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        table[b] = (uint8_t)b;
1751b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        ++b;
1761b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
1771b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(firstSplitByteRangeIndex < 0) {
1781b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        // The lead byte permutation table alone suffices for reordering.
1791b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        rangesLength = 0;
1801b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    } else {
1811b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        // Remove the ranges below the first split byte.
1821b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        ranges += firstSplitByteRangeIndex;
1831b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        rangesLength -= firstSplitByteRangeIndex;
1841b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
1851b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    setReorderArrays(codes, codesLength, ranges, rangesLength, table, errorCode);
1861b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert}
1871b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert
1881b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubertvoid
1891b7d32f919554dda9c193b32188251337bc756f1Fredrik RoubertCollationSettings::setReorderArrays(const int32_t *codes, int32_t codesLength,
1901b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                                    const uint32_t *ranges, int32_t rangesLength,
1911b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                                    const uint8_t *table, UErrorCode &errorCode) {
1921b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(U_FAILURE(errorCode)) { return; }
1931b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    int32_t *ownedCodes;
1941b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    int32_t totalLength = codesLength + rangesLength;
1951b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    U_ASSERT(totalLength > 0);
1961b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(totalLength <= reorderCodesCapacity) {
1971b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        ownedCodes = const_cast<int32_t *>(reorderCodes);
1981b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    } else {
1991b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        // Allocate one memory block for the codes, the ranges, and the 16-aligned table.
2001b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        int32_t capacity = (totalLength + 3) & ~3;  // round up to a multiple of 4 ints
2011b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        ownedCodes = (int32_t *)uprv_malloc(capacity * 4 + 256);
2021b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        if(ownedCodes == NULL) {
2031b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            resetReordering();
2041b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            errorCode = U_MEMORY_ALLOCATION_ERROR;
2051b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            return;
2061b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        }
2071b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        if(reorderCodesCapacity != 0) {
2081b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            uprv_free(const_cast<int32_t *>(reorderCodes));
2091b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        }
2101b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        reorderCodes = ownedCodes;
2111b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        reorderCodesCapacity = capacity;
2121b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
2131b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    uprv_memcpy(ownedCodes + reorderCodesCapacity, table, 256);
2141b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    uprv_memcpy(ownedCodes, codes, codesLength * 4);
2151b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    uprv_memcpy(ownedCodes + codesLength, ranges, rangesLength * 4);
2161b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    reorderTable = reinterpret_cast<const uint8_t *>(reorderCodes + reorderCodesCapacity);
2171b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    reorderCodesLength = codesLength;
2181b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    reorderRanges = reinterpret_cast<uint32_t *>(ownedCodes) + codesLength;
2191b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    reorderRangesLength = rangesLength;
2201b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert}
2211b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert
2221b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubertvoid
2231b7d32f919554dda9c193b32188251337bc756f1Fredrik RoubertCollationSettings::copyReorderingFrom(const CollationSettings &other, UErrorCode &errorCode) {
2241b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(U_FAILURE(errorCode)) { return; }
2251b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(!other.hasReordering()) {
2261b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        resetReordering();
2271b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        return;
2281b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
2291b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    minHighNoReorder = other.minHighNoReorder;
2301b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(other.reorderCodesCapacity == 0) {
2311b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        // The reorder arrays are aliased to memory-mapped data.
2321b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        reorderTable = other.reorderTable;
2331b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        reorderRanges = other.reorderRanges;
2341b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        reorderRangesLength = other.reorderRangesLength;
2351b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        reorderCodes = other.reorderCodes;
2361b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        reorderCodesLength = other.reorderCodesLength;
2371b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    } else {
2381b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        setReorderArrays(other.reorderCodes, other.reorderCodesLength,
2391b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                         other.reorderRanges, other.reorderRangesLength,
2401b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                         other.reorderTable, errorCode);
2411b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
2421b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert}
2431b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert
2441b7d32f919554dda9c193b32188251337bc756f1Fredrik RoubertUBool
2451b7d32f919554dda9c193b32188251337bc756f1Fredrik RoubertCollationSettings::reorderTableHasSplitBytes(const uint8_t table[256]) {
2461b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    U_ASSERT(table[0] == 0);
2471b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    for(int32_t i = 1; i < 256; ++i) {
2481b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        if(table[i] == 0) {
2491b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            return TRUE;
2501b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        }
2511b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
2521b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    return FALSE;
2531b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert}
2541b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert
2551b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubertuint32_t
2561b7d32f919554dda9c193b32188251337bc756f1Fredrik RoubertCollationSettings::reorderEx(uint32_t p) const {
2571b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if(p >= minHighNoReorder) { return p; }
2581b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // Round up p so that its lower 16 bits are >= any offset bits.
2591b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    // Then compare q directly with (limit, offset) pairs.
2601b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    uint32_t q = p | 0xffff;
2611b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    uint32_t r;
2621b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    const uint32_t *ranges = reorderRanges;
2631b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    while(q >= (r = *ranges)) { ++ranges; }
2641b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    return p + (r << 24);
265fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
266fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
267fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
268fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::setStrength(int32_t value, int32_t defaultOptions, UErrorCode &errorCode) {
269fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
270fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t noStrength = options & ~STRENGTH_MASK;
271fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    switch(value) {
272fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_PRIMARY:
273fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_SECONDARY:
274fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_TERTIARY:
275fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_QUATERNARY:
276fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_IDENTICAL:
277fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noStrength | (value << STRENGTH_SHIFT);
278fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
279fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_DEFAULT:
280fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noStrength | (defaultOptions & STRENGTH_MASK);
281fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
282fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    default:
283fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
284fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
285fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
286fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
287fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
288fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
289fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::setFlag(int32_t bit, UColAttributeValue value,
290fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                           int32_t defaultOptions, UErrorCode &errorCode) {
291fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
292fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    switch(value) {
293fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_ON:
294fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options |= bit;
295fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
296fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_OFF:
297fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options &= ~bit;
298fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
299fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_DEFAULT:
300fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = (options & ~bit) | (defaultOptions & bit);
301fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
302fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    default:
303fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
304fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
305fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
306fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
307fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
308fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
309fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::setCaseFirst(UColAttributeValue value,
310fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                int32_t defaultOptions, UErrorCode &errorCode) {
311fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
312fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t noCaseFirst = options & ~CASE_FIRST_AND_UPPER_MASK;
313fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    switch(value) {
314fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_OFF:
315fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noCaseFirst;
316fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
317fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_LOWER_FIRST:
318fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noCaseFirst | CASE_FIRST;
319fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
320fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_UPPER_FIRST:
321fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noCaseFirst | CASE_FIRST_AND_UPPER_MASK;
322fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
323fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_DEFAULT:
324fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noCaseFirst | (defaultOptions & CASE_FIRST_AND_UPPER_MASK);
325fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
326fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    default:
327fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
328fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
329fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
330fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
331fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
332fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
333fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::setAlternateHandling(UColAttributeValue value,
334fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                        int32_t defaultOptions, UErrorCode &errorCode) {
335fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
336fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t noAlternate = options & ~ALTERNATE_MASK;
337fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    switch(value) {
338fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_NON_IGNORABLE:
339fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noAlternate;
340fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
341fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_SHIFTED:
342fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noAlternate | SHIFTED;
343fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
344fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_DEFAULT:
345fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noAlternate | (defaultOptions & ALTERNATE_MASK);
346fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
347fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    default:
348fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
349fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
350fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
351fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
352fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
353fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
354fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationSettings::setMaxVariable(int32_t value, int32_t defaultOptions, UErrorCode &errorCode) {
355fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
356fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t noMax = options & ~MAX_VARIABLE_MASK;
357fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    switch(value) {
358fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case MAX_VAR_SPACE:
359fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case MAX_VAR_PUNCT:
360fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case MAX_VAR_SYMBOL:
361fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case MAX_VAR_CURRENCY:
362fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noMax | (value << MAX_VARIABLE_SHIFT);
363fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
364fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    case UCOL_DEFAULT:
365fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        options = noMax | (defaultOptions & MAX_VARIABLE_MASK);
366fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
367fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    default:
368fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
369fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        break;
370fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
371fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
372fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
373fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_END
374fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
375fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#endif  // !UCONFIG_NO_COLLATION
376