164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// Copyright (C) 2016 and later: Unicode, Inc. and others.
264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html
3fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/*
4fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*******************************************************************************
51b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert* Copyright (C) 2012-2015, International Business Machines
6fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* Corporation and others.  All Rights Reserved.
7fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*******************************************************************************
8fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* collationkeys.cpp
9fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*
10fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* created on: 2012sep02
11fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius* created by: Markus W. Scherer
12fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius*/
13fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
14fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/utypes.h"
15fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
16fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#if !UCONFIG_NO_COLLATION
17fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
18fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "unicode/bytestream.h"
19fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collation.h"
20fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationiterator.h"
21fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationkeys.h"
22fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "collationsettings.h"
23fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#include "uassert.h"
24fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
25fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_BEGIN
26fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
27fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusSortKeyByteSink::~SortKeyByteSink() {}
28fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
29fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
30fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusSortKeyByteSink::Append(const char *bytes, int32_t n) {
31fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (n <= 0 || bytes == NULL) {
32fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;
33fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
34fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (ignore_ > 0) {
35fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int32_t ignoreRest = ignore_ - n;
36fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if (ignoreRest >= 0) {
37fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ignore_ = ignoreRest;
38fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            return;
39fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
40fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            bytes += ignore_;
41fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            n = -ignoreRest;
42fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            ignore_ = 0;
43fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
44fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
45fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t length = appended_;
46fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    appended_ += n;
47fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if ((buffer_ + length) == bytes) {
48fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return;  // the caller used GetAppendBuffer() and wrote the bytes already
49fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
50fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t available = capacity_ - length;
51fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (n <= available) {
52fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uprv_memcpy(buffer_ + length, bytes, n);
53fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
54fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        AppendBeyondCapacity(bytes, n, length);
55fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
56fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
57fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
58fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliuschar *
59fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusSortKeyByteSink::GetAppendBuffer(int32_t min_capacity,
60fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                 int32_t desired_capacity_hint,
61fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                 char *scratch,
62fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                 int32_t scratch_capacity,
63fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                 int32_t *result_capacity) {
64fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (min_capacity < 1 || scratch_capacity < min_capacity) {
65fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        *result_capacity = 0;
66fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return NULL;
67fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
68fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (ignore_ > 0) {
69fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Do not write ignored bytes right at the end of the buffer.
70fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        *result_capacity = scratch_capacity;
71fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return scratch;
72fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
73fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t available = capacity_ - appended_;
74fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (available >= min_capacity) {
75fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        *result_capacity = available;
76fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return buffer_ + appended_;
77fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else if (Resize(desired_capacity_hint, appended_)) {
78fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        *result_capacity = capacity_ - appended_;
79fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return buffer_ + appended_;
80fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
81fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        *result_capacity = scratch_capacity;
82fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return scratch;
83fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
84fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
85fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
86fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusnamespace {
87fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
88fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/**
89fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius * uint8_t byte buffer, similar to CharString but simpler.
90fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius */
91fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusclass SortKeyLevel : public UMemory {
92fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliuspublic:
93fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SortKeyLevel() : len(0), ok(TRUE) {}
94fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    ~SortKeyLevel() {}
95fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
96fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    /** @return FALSE if memory allocation failed */
97fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UBool isOk() const { return ok; }
98fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UBool isEmpty() const { return len == 0; }
99fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t length() const { return len; }
100fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    const uint8_t *data() const { return buffer.getAlias(); }
101fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint8_t operator[](int32_t index) const { return buffer[index]; }
102fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
103fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint8_t *data() { return buffer.getAlias(); }
104fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
105fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    void appendByte(uint32_t b);
106fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    void appendWeight16(uint32_t w);
107fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    void appendWeight32(uint32_t w);
108fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    void appendReverseWeight16(uint32_t w);
109fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
110fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    /** Appends all but the last byte to the sink. The last byte should be the 01 terminator. */
111fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    void appendTo(ByteSink &sink) const {
112fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        U_ASSERT(len > 0 && buffer[len - 1] == 1);
113fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        sink.Append(reinterpret_cast<const char *>(buffer.getAlias()), len - 1);
114fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
115fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
116fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusprivate:
117fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    MaybeStackArray<uint8_t, 40> buffer;
118fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t len;
119fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UBool ok;
120fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
121fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UBool ensureCapacity(int32_t appendCapacity);
122fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
123fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SortKeyLevel(const SortKeyLevel &other); // forbid copying of this class
124fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SortKeyLevel &operator=(const SortKeyLevel &other); // forbid copying of this class
125fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius};
126fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
127fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid SortKeyLevel::appendByte(uint32_t b) {
128fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(len < buffer.getCapacity() || ensureCapacity(1)) {
129fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        buffer[len++] = (uint8_t)b;
130fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
131fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
132fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
133fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
134fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusSortKeyLevel::appendWeight16(uint32_t w) {
135fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    U_ASSERT((w & 0xffff) != 0);
136fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint8_t b0 = (uint8_t)(w >> 8);
137fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint8_t b1 = (uint8_t)w;
138fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t appendLength = (b1 == 0) ? 1 : 2;
139fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((len + appendLength) <= buffer.getCapacity() || ensureCapacity(appendLength)) {
140fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        buffer[len++] = b0;
141fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(b1 != 0) {
142fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            buffer[len++] = b1;
143fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
144fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
145fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
146fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
147fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
148fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusSortKeyLevel::appendWeight32(uint32_t w) {
149fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    U_ASSERT(w != 0);
150fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint8_t bytes[4] = { (uint8_t)(w >> 24), (uint8_t)(w >> 16), (uint8_t)(w >> 8), (uint8_t)w };
151fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t appendLength = (bytes[1] == 0) ? 1 : (bytes[2] == 0) ? 2 : (bytes[3] == 0) ? 3 : 4;
152fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((len + appendLength) <= buffer.getCapacity() || ensureCapacity(appendLength)) {
153fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        buffer[len++] = bytes[0];
154fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(bytes[1] != 0) {
155fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            buffer[len++] = bytes[1];
156fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(bytes[2] != 0) {
157fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                buffer[len++] = bytes[2];
158fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(bytes[3] != 0) {
159fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    buffer[len++] = bytes[3];
160fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
161fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
162fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
163fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
164fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
165fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
166fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
167fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusSortKeyLevel::appendReverseWeight16(uint32_t w) {
168fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    U_ASSERT((w & 0xffff) != 0);
169fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint8_t b0 = (uint8_t)(w >> 8);
170fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint8_t b1 = (uint8_t)w;
171fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t appendLength = (b1 == 0) ? 1 : 2;
172fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((len + appendLength) <= buffer.getCapacity() || ensureCapacity(appendLength)) {
173fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(b1 == 0) {
174fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            buffer[len++] = b0;
175fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        } else {
176fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            buffer[len] = b1;
177fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            buffer[len + 1] = b0;
178fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            len += 2;
179fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
180fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
181fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
182fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
183fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUBool SortKeyLevel::ensureCapacity(int32_t appendCapacity) {
184fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(!ok) {
185fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return FALSE;
186fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
187fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t newCapacity = 2 * buffer.getCapacity();
188fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t altCapacity = len + 2 * appendCapacity;
189fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (newCapacity < altCapacity) {
190fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        newCapacity = altCapacity;
191fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
192fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if (newCapacity < 200) {
193fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        newCapacity = 200;
194fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
195fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(buffer.resize(newCapacity, len)==NULL) {
196fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        return ok = FALSE;
197fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
198fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    return TRUE;
199fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
200fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
201fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}  // namespace
202fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
203fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationKeys::LevelCallback::~LevelCallback() {}
204fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
205fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusUBool
206fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationKeys::LevelCallback::needToWrite(Collation::Level /*level*/) { return TRUE; }
207fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
208fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius/**
209fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius * Map from collation strength (UColAttributeValue)
210fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius * to a mask of Collation::Level bits up to that strength,
211fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius * excluding the CASE_LEVEL which is independent of the strength,
212fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius * and excluding IDENTICAL_LEVEL which this function does not write.
213fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius */
214fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusstatic const uint32_t levelMasks[UCOL_STRENGTH_LIMIT] = {
215fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    2,          // UCOL_PRIMARY -> PRIMARY_LEVEL
216fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    6,          // UCOL_SECONDARY -> up to SECONDARY_LEVEL
217fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    0x16,       // UCOL_TERTIARY -> up to TERTIARY_LEVEL
218fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    0x36,       // UCOL_QUATERNARY -> up to QUATERNARY_LEVEL
219fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    0, 0, 0, 0,
220fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    0, 0, 0, 0,
221fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    0, 0, 0,
222fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    0x36        // UCOL_IDENTICAL -> up to QUATERNARY_LEVEL
223fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius};
224fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
225fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusvoid
226fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusCollationKeys::writeSortKeyUpToQuaternary(CollationIterator &iter,
227fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                          const UBool *compressibleBytes,
228fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                          const CollationSettings &settings,
229fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                          SortKeyByteSink &sink,
230fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                          Collation::Level minLevel, LevelCallback &callback,
231fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                          UBool preflight, UErrorCode &errorCode) {
232fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
233fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
234fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t options = settings.options;
235fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Set of levels to process and write.
236fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint32_t levels = levelMasks[CollationSettings::getStrength(options)];
237fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((options & CollationSettings::CASE_LEVEL) != 0) {
238fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        levels |= Collation::CASE_LEVEL_FLAG;
239fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
240fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Minus the levels below minLevel.
241fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    levels &= ~(((uint32_t)1 << minLevel) - 1);
242fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(levels == 0) { return; }
243fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
244fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint32_t variableTop;
245fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((options & CollationSettings::ALTERNATE_MASK) == 0) {
246fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        variableTop = 0;
247fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    } else {
248fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // +1 so that we can use "<" and primary ignorables test out early.
249fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        variableTop = settings.variableTop + 1;
250fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
251fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
252fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint32_t tertiaryMask = CollationSettings::getTertiaryMask(options);
253fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
254fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SortKeyLevel cases;
255fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SortKeyLevel secondaries;
256fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SortKeyLevel tertiaries;
257fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    SortKeyLevel quaternaries;
258fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
2591b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    uint32_t prevReorderedPrimary = 0;  // 0==no compression
260fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t commonCases = 0;
261fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t commonSecondaries = 0;
262fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t commonTertiaries = 0;
263fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    int32_t commonQuaternaries = 0;
264fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
265fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    uint32_t prevSecondary = 0;
2661b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    int32_t secSegmentStart = 0;
267fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
268fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    for(;;) {
269fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // No need to keep all CEs in the buffer when we write a sort key.
270fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        iter.clearCEsIfNoneRemaining();
271fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int64_t ce = iter.nextCE(errorCode);
272fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uint32_t p = (uint32_t)(ce >> 32);
273fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(p < variableTop && p > Collation::MERGE_SEPARATOR_PRIMARY) {
274fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // Variable CE, shift it to quaternary level.
275fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // Ignore all following primary ignorables, and shift further variable CEs.
276fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(commonQuaternaries != 0) {
277fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                --commonQuaternaries;
278fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                while(commonQuaternaries >= QUAT_COMMON_MAX_COUNT) {
279fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    quaternaries.appendByte(QUAT_COMMON_MIDDLE);
280fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    commonQuaternaries -= QUAT_COMMON_MAX_COUNT;
281fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
282fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Shifted primary weights are lower than the common weight.
283fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                quaternaries.appendByte(QUAT_COMMON_LOW + commonQuaternaries);
284fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                commonQuaternaries = 0;
285fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
286fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            do {
287fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if((levels & Collation::QUATERNARY_LEVEL_FLAG) != 0) {
2881b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    if(settings.hasReordering()) {
2891b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        p = settings.reorder(p);
2901b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    }
2911b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    if((p >> 24) >= QUAT_SHIFTED_LIMIT_BYTE) {
292fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        // Prevent shifted primary lead bytes from
293fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        // overlapping with the common compression range.
294fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        quaternaries.appendByte(QUAT_SHIFTED_LIMIT_BYTE);
295fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
2961b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    quaternaries.appendWeight32(p);
297fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
298fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                do {
299fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    ce = iter.nextCE(errorCode);
300fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    p = (uint32_t)(ce >> 32);
301fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                } while(p == 0);
302fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } while(p < variableTop && p > Collation::MERGE_SEPARATOR_PRIMARY);
303fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
304fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // ce could be primary ignorable, or NO_CE, or the merge separator,
305fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // or a regular primary CE, but it is not variable.
306fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // If ce==NO_CE, then write nothing for the primary level but
307fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // terminate compression on all levels and then exit the loop.
308fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(p > Collation::NO_CE_PRIMARY && (levels & Collation::PRIMARY_LEVEL_FLAG) != 0) {
3091b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            // Test the un-reordered primary for compressibility.
3101b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            UBool isCompressible = compressibleBytes[p >> 24];
3111b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            if(settings.hasReordering()) {
3121b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                p = settings.reorder(p);
3131b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            }
314fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uint32_t p1 = p >> 24;
3151b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            if(!isCompressible || p1 != (prevReorderedPrimary >> 24)) {
3161b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                if(prevReorderedPrimary != 0) {
3171b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    if(p < prevReorderedPrimary) {
318fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        // No primary compression terminator
319fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        // at the end of the level or merged segment.
320fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        if(p1 > Collation::MERGE_SEPARATOR_BYTE) {
321fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            sink.Append(Collation::PRIMARY_COMPRESSION_LOW_BYTE);
322fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        }
323fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    } else {
324fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        sink.Append(Collation::PRIMARY_COMPRESSION_HIGH_BYTE);
325fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
326fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
327fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                sink.Append(p1);
3281b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                if(isCompressible) {
3291b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    prevReorderedPrimary = p;
330fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                } else {
3311b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    prevReorderedPrimary = 0;
332fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
333fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
334fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            char p2 = (char)(p >> 16);
335fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(p2 != 0) {
336fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                char buffer[3] = { p2, (char)(p >> 8), (char)p };
337fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                sink.Append(buffer, (buffer[1] == 0) ? 1 : (buffer[2] == 0) ? 2 : 3);
338fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
339fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // Optimization for internalNextSortKeyPart():
340fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // When the primary level overflows we can stop because we need not
341fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            // calculate (preflight) the whole sort key length.
342fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(!preflight && sink.Overflowed()) {
343fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(U_SUCCESS(errorCode) && !sink.IsOk()) {
344fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    errorCode = U_MEMORY_ALLOCATION_ERROR;
345fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
346fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                return;
347fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
348fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
349fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
350fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uint32_t lower32 = (uint32_t)ce;
351fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(lower32 == 0) { continue; }  // completely ignorable, no secondary/case/tertiary/quaternary
352fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
353fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if((levels & Collation::SECONDARY_LEVEL_FLAG) != 0) {
354fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uint32_t s = lower32 >> 16;
355fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(s == 0) {
356fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // secondary ignorable
3571b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            } else if(s == Collation::COMMON_WEIGHT16 &&
3581b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    ((options & CollationSettings::BACKWARD_SECONDARY) == 0 ||
3591b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        p != Collation::MERGE_SEPARATOR_PRIMARY)) {
3601b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                // s is a common secondary weight, and
3611b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                // backwards-secondary is off or the ce is not the merge separator.
362fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                ++commonSecondaries;
363fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else if((options & CollationSettings::BACKWARD_SECONDARY) == 0) {
364fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(commonSecondaries != 0) {
365fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    --commonSecondaries;
366fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    while(commonSecondaries >= SEC_COMMON_MAX_COUNT) {
367fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        secondaries.appendByte(SEC_COMMON_MIDDLE);
368fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        commonSecondaries -= SEC_COMMON_MAX_COUNT;
369fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
370fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    uint32_t b;
371fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    if(s < Collation::COMMON_WEIGHT16) {
372fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = SEC_COMMON_LOW + commonSecondaries;
373fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    } else {
374fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = SEC_COMMON_HIGH - commonSecondaries;
375fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
376fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    secondaries.appendByte(b);
377fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    commonSecondaries = 0;
378fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
379fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                secondaries.appendWeight16(s);
380fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else {
381fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(commonSecondaries != 0) {
382fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    --commonSecondaries;
383fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    // Append reverse weights. The level will be re-reversed later.
384fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    int32_t remainder = commonSecondaries % SEC_COMMON_MAX_COUNT;
385fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    uint32_t b;
386fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    if(prevSecondary < Collation::COMMON_WEIGHT16) {
387fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = SEC_COMMON_LOW + remainder;
388fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    } else {
389fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = SEC_COMMON_HIGH - remainder;
390fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
391fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    secondaries.appendByte(b);
392fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    commonSecondaries -= remainder;
393fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    // commonSecondaries is now a multiple of SEC_COMMON_MAX_COUNT.
394fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    while(commonSecondaries > 0) {  // same as >= SEC_COMMON_MAX_COUNT
395fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        secondaries.appendByte(SEC_COMMON_MIDDLE);
396fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        commonSecondaries -= SEC_COMMON_MAX_COUNT;
397fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
398fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    // commonSecondaries == 0
399fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
4001b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                if(0 < p && p <= Collation::MERGE_SEPARATOR_PRIMARY) {
4011b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    // The backwards secondary level compares secondary weights backwards
4021b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    // within segments separated by the merge separator (U+FFFE).
4031b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    uint8_t *secs = secondaries.data();
4041b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    int32_t last = secondaries.length() - 1;
4051b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    if(secSegmentStart < last) {
4061b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        uint8_t *p = secs + secSegmentStart;
4071b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        uint8_t *q = secs + last;
4081b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        do {
4091b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                            uint8_t b = *p;
4101b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                            *p++ = *q;
4111b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                            *q-- = b;
4121b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        } while(p < q);
413fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
4141b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    secondaries.appendByte(p == Collation::NO_CE_PRIMARY ?
4151b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        Collation::LEVEL_SEPARATOR_BYTE : Collation::MERGE_SEPARATOR_BYTE);
4161b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    prevSecondary = 0;
4171b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    secSegmentStart = secondaries.length();
418fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                } else {
419fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    secondaries.appendReverseWeight16(s);
4201b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    prevSecondary = s;
421fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
422fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
423fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
424fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
425fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if((levels & Collation::CASE_LEVEL_FLAG) != 0) {
426fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if((CollationSettings::getStrength(options) == UCOL_PRIMARY) ?
427fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    p == 0 : lower32 <= 0xffff) {
428fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Primary+caseLevel: Ignore case level weights of primary ignorables.
429fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Otherwise: Ignore case level weights of secondary ignorables.
430fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // For details see the comments in the CollationCompare class.
431fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else {
432fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                uint32_t c = (lower32 >> 8) & 0xff;  // case bits & tertiary lead byte
433fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                U_ASSERT((c & 0xc0) != 0xc0);
4341b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                if((c & 0xc0) == 0 && c > Collation::LEVEL_SEPARATOR_BYTE) {
435fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    ++commonCases;
436fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                } else {
437fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    if((options & CollationSettings::UPPER_FIRST) == 0) {
438fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        // lowerFirst: Compress common weights to nibbles 1..7..13, mixed=14, upper=15.
4391b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        // If there are only common (=lowest) weights in the whole level,
4401b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        // then we need not write anything.
4411b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        // Level length differences are handled already on the next-higher level.
4421b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        if(commonCases != 0 &&
4431b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                                (c > Collation::LEVEL_SEPARATOR_BYTE || !cases.isEmpty())) {
444fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            --commonCases;
445fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            while(commonCases >= CASE_LOWER_FIRST_COMMON_MAX_COUNT) {
446fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                cases.appendByte(CASE_LOWER_FIRST_COMMON_MIDDLE << 4);
447fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                commonCases -= CASE_LOWER_FIRST_COMMON_MAX_COUNT;
448fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            }
449fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            uint32_t b;
4501b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                            if(c <= Collation::LEVEL_SEPARATOR_BYTE) {
451fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                b = CASE_LOWER_FIRST_COMMON_LOW + commonCases;
452fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            } else {
453fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                b = CASE_LOWER_FIRST_COMMON_HIGH - commonCases;
454fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            }
455fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            cases.appendByte(b << 4);
456fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            commonCases = 0;
457fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        }
4581b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        if(c > Collation::LEVEL_SEPARATOR_BYTE) {
459fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            c = (CASE_LOWER_FIRST_COMMON_HIGH + (c >> 6)) << 4;  // 14 or 15
460fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        }
461fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    } else {
462fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        // upperFirst: Compress common weights to nibbles 3..15, mixed=2, upper=1.
463fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        // The compressed common case weights only go up from the "low" value
464fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        // because with upperFirst the common weight is the highest one.
465fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        if(commonCases != 0) {
466fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            --commonCases;
467fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            while(commonCases >= CASE_UPPER_FIRST_COMMON_MAX_COUNT) {
468fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                cases.appendByte(CASE_UPPER_FIRST_COMMON_LOW << 4);
469fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                                commonCases -= CASE_UPPER_FIRST_COMMON_MAX_COUNT;
470fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            }
471fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            cases.appendByte((CASE_UPPER_FIRST_COMMON_LOW + commonCases) << 4);
472fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            commonCases = 0;
473fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        }
4741b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                        if(c > Collation::LEVEL_SEPARATOR_BYTE) {
475fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                            c = (CASE_UPPER_FIRST_COMMON_LOW - (c >> 6)) << 4;  // 2 or 1
476fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        }
477fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
4781b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    // c is a separator byte 01,
479fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    // or a left-shifted nibble 0x10, 0x20, ... 0xf0.
480fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    cases.appendByte(c);
481fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
482fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
483fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
484fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
485fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if((levels & Collation::TERTIARY_LEVEL_FLAG) != 0) {
486fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uint32_t t = lower32 & tertiaryMask;
487fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            U_ASSERT((lower32 & 0xc000) != 0xc000);
488fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            if(t == Collation::COMMON_WEIGHT16) {
489fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                ++commonTertiaries;
490fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else if((tertiaryMask & 0x8000) == 0) {
491fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Tertiary weights without case bits.
492fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Move lead bytes 06..3F to C6..FF for a large common-weight range.
493fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(commonTertiaries != 0) {
494fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    --commonTertiaries;
495fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    while(commonTertiaries >= TER_ONLY_COMMON_MAX_COUNT) {
496fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        tertiaries.appendByte(TER_ONLY_COMMON_MIDDLE);
497fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        commonTertiaries -= TER_ONLY_COMMON_MAX_COUNT;
498fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
499fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    uint32_t b;
500fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    if(t < Collation::COMMON_WEIGHT16) {
501fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = TER_ONLY_COMMON_LOW + commonTertiaries;
502fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    } else {
503fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = TER_ONLY_COMMON_HIGH - commonTertiaries;
504fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
505fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    tertiaries.appendByte(b);
506fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    commonTertiaries = 0;
507fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
508fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(t > Collation::COMMON_WEIGHT16) { t += 0xc000; }
509fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                tertiaries.appendWeight16(t);
510fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else if((options & CollationSettings::UPPER_FIRST) == 0) {
511fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Tertiary weights with caseFirst=lowerFirst.
512fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Move lead bytes 06..BF to 46..FF for the common-weight range.
513fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(commonTertiaries != 0) {
514fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    --commonTertiaries;
515fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    while(commonTertiaries >= TER_LOWER_FIRST_COMMON_MAX_COUNT) {
516fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        tertiaries.appendByte(TER_LOWER_FIRST_COMMON_MIDDLE);
517fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        commonTertiaries -= TER_LOWER_FIRST_COMMON_MAX_COUNT;
518fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
519fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    uint32_t b;
520fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    if(t < Collation::COMMON_WEIGHT16) {
521fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = TER_LOWER_FIRST_COMMON_LOW + commonTertiaries;
522fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    } else {
523fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = TER_LOWER_FIRST_COMMON_HIGH - commonTertiaries;
524fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
525fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    tertiaries.appendByte(b);
526fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    commonTertiaries = 0;
527fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
528fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(t > Collation::COMMON_WEIGHT16) { t += 0x4000; }
529fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                tertiaries.appendWeight16(t);
530fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else {
531fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Tertiary weights with caseFirst=upperFirst.
532fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Do not change the artificial uppercase weight of a tertiary CE (0.0.ut),
533fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // to keep tertiary CEs well-formed.
534fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Their case+tertiary weights must be greater than those of
535fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // primary and secondary CEs.
536fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                //
5371b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                // Separator         01 -> 01      (unchanged)
5381b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                // Lowercase     02..04 -> 82..84  (includes uncased)
539fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Common weight     05 -> 85..C5  (common-weight compression range)
540fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Lowercase     06..3F -> C6..FF
5411b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                // Mixed case    42..7F -> 42..7F
5421b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                // Uppercase     82..BF -> 02..3F
543fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Tertiary CE   86..BF -> C6..FF
5441b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                if(t <= Collation::NO_CE_WEIGHT16) {
545fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    // Keep separators unchanged.
546fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                } else if(lower32 > 0xffff) {
547fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    // Invert case bits of primary & secondary CEs.
548fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    t ^= 0xc000;
549fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    if(t < (TER_UPPER_FIRST_COMMON_HIGH << 8)) {
550fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        t -= 0x4000;
551fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
552fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                } else {
553fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    // Keep uppercase bits of tertiary CEs.
554fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    U_ASSERT(0x8600 <= t && t <= 0xbfff);
555fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    t += 0x4000;
556fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
557fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(commonTertiaries != 0) {
558fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    --commonTertiaries;
559fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    while(commonTertiaries >= TER_UPPER_FIRST_COMMON_MAX_COUNT) {
560fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        tertiaries.appendByte(TER_UPPER_FIRST_COMMON_MIDDLE);
561fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        commonTertiaries -= TER_UPPER_FIRST_COMMON_MAX_COUNT;
562fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
563fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    uint32_t b;
564fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    if(t < (TER_UPPER_FIRST_COMMON_LOW << 8)) {
565fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = TER_UPPER_FIRST_COMMON_LOW + commonTertiaries;
566fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    } else {
567fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = TER_UPPER_FIRST_COMMON_HIGH - commonTertiaries;
568fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
569fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    tertiaries.appendByte(b);
570fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    commonTertiaries = 0;
571fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
572fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                tertiaries.appendWeight16(t);
573fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
574fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
575fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
576fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if((levels & Collation::QUATERNARY_LEVEL_FLAG) != 0) {
577fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uint32_t q = lower32 & 0xffff;
5781b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            if((q & 0xc0) == 0 && q > Collation::NO_CE_WEIGHT16) {
579fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                ++commonQuaternaries;
5801b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            } else if(q == Collation::NO_CE_WEIGHT16 &&
581fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    (options & CollationSettings::ALTERNATE_MASK) == 0 &&
5821b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    quaternaries.isEmpty()) {
5831b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                // If alternate=non-ignorable and there are only common quaternary weights,
5841b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                // then we need not write anything.
585fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // The only weights greater than the merge separator and less than the common weight
586fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // are shifted primary weights, which are not generated for alternate=non-ignorable.
587fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // There are also exactly as many quaternary weights as tertiary weights,
588fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // so level length differences are handled already on tertiary level.
589fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                // Any above-common quaternary weight will compare greater regardless.
5901b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                quaternaries.appendByte(Collation::LEVEL_SEPARATOR_BYTE);
591fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else {
5921b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                if(q == Collation::NO_CE_WEIGHT16) {
5931b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                    q = Collation::LEVEL_SEPARATOR_BYTE;
594fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                } else {
595fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    q = 0xfc + ((q >> 6) & 3);
596fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
597fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                if(commonQuaternaries != 0) {
598fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    --commonQuaternaries;
599fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    while(commonQuaternaries >= QUAT_COMMON_MAX_COUNT) {
600fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        quaternaries.appendByte(QUAT_COMMON_MIDDLE);
601fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        commonQuaternaries -= QUAT_COMMON_MAX_COUNT;
602fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
603fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    uint32_t b;
604fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    if(q < QUAT_COMMON_LOW) {
605fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = QUAT_COMMON_LOW + commonQuaternaries;
606fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    } else {
607fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                        b = QUAT_COMMON_HIGH - commonQuaternaries;
608fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    }
609fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    quaternaries.appendByte(b);
610fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                    commonQuaternaries = 0;
611fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                }
612fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius                quaternaries.appendByte(q);
613fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
614fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
615fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
616fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if((lower32 >> 24) == Collation::LEVEL_SEPARATOR_BYTE) { break; }  // ce == NO_CE
617fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
618fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
619fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(U_FAILURE(errorCode)) { return; }
620fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
621fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    // Append the beyond-primary levels.
622fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    UBool ok = TRUE;
623fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((levels & Collation::SECONDARY_LEVEL_FLAG) != 0) {
624fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(!callback.needToWrite(Collation::SECONDARY_LEVEL)) { return; }
625fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        ok &= secondaries.isOk();
626fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        sink.Append(Collation::LEVEL_SEPARATOR_BYTE);
6271b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        secondaries.appendTo(sink);
628fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
629fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
630fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((levels & Collation::CASE_LEVEL_FLAG) != 0) {
631fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(!callback.needToWrite(Collation::CASE_LEVEL)) { return; }
632fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        ok &= cases.isOk();
633fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        sink.Append(Collation::LEVEL_SEPARATOR_BYTE);
634fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        // Write pairs of nibbles as bytes, except separator bytes as themselves.
635fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        int32_t length = cases.length() - 1;  // Ignore the trailing NO_CE.
636fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        uint8_t b = 0;
637fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        for(int32_t i = 0; i < length; ++i) {
638fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            uint8_t c = (uint8_t)cases[i];
6391b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            U_ASSERT((c & 0xf) == 0 && c != 0);
6401b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert            if(b == 0) {
6411b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                b = c;
642fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            } else {
6431b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                sink.Append(b | (c >> 4));
6441b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert                b = 0;
645fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            }
646fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
647fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(b != 0) {
648fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius            sink.Append(b);
649fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        }
650fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
651fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
652fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((levels & Collation::TERTIARY_LEVEL_FLAG) != 0) {
653fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(!callback.needToWrite(Collation::TERTIARY_LEVEL)) { return; }
654fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        ok &= tertiaries.isOk();
655fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        sink.Append(Collation::LEVEL_SEPARATOR_BYTE);
656fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        tertiaries.appendTo(sink);
657fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
658fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
659fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if((levels & Collation::QUATERNARY_LEVEL_FLAG) != 0) {
660fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        if(!callback.needToWrite(Collation::QUATERNARY_LEVEL)) { return; }
661fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        ok &= quaternaries.isOk();
662fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        sink.Append(Collation::LEVEL_SEPARATOR_BYTE);
663fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        quaternaries.appendTo(sink);
664fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
665fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
666fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    if(!ok || !sink.IsOk()) {
667fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius        errorCode = U_MEMORY_ALLOCATION_ERROR;
668fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius    }
669fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius}
670fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
671fceb39872958b9fa2505e63f8b8699a9e0f882f4ccorneliusU_NAMESPACE_END
672fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius
673fceb39872958b9fa2505e63f8b8699a9e0f882f4ccornelius#endif  // !UCONFIG_NO_COLLATION
674