12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci/*
42e5b6d6dSopenharmony_ci*******************************************************************************
52e5b6d6dSopenharmony_ci* Copyright (C) 2013-2014, International Business Machines
62e5b6d6dSopenharmony_ci* Corporation and others.  All Rights Reserved.
72e5b6d6dSopenharmony_ci*******************************************************************************
82e5b6d6dSopenharmony_ci* collationrootelements.cpp
92e5b6d6dSopenharmony_ci*
102e5b6d6dSopenharmony_ci* created on: 2013mar05
112e5b6d6dSopenharmony_ci* created by: Markus W. Scherer
122e5b6d6dSopenharmony_ci*/
132e5b6d6dSopenharmony_ci
142e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
152e5b6d6dSopenharmony_ci
162e5b6d6dSopenharmony_ci#if !UCONFIG_NO_COLLATION
172e5b6d6dSopenharmony_ci
182e5b6d6dSopenharmony_ci#include "collation.h"
192e5b6d6dSopenharmony_ci#include "collationrootelements.h"
202e5b6d6dSopenharmony_ci#include "uassert.h"
212e5b6d6dSopenharmony_ci
222e5b6d6dSopenharmony_ciU_NAMESPACE_BEGIN
232e5b6d6dSopenharmony_ci
242e5b6d6dSopenharmony_ciint64_t
252e5b6d6dSopenharmony_ciCollationRootElements::lastCEWithPrimaryBefore(uint32_t p) const {
262e5b6d6dSopenharmony_ci    if(p == 0) { return 0; }
272e5b6d6dSopenharmony_ci    U_ASSERT(p > elements[elements[IX_FIRST_PRIMARY_INDEX]]);
282e5b6d6dSopenharmony_ci    int32_t index = findP(p);
292e5b6d6dSopenharmony_ci    uint32_t q = elements[index];
302e5b6d6dSopenharmony_ci    uint32_t secTer;
312e5b6d6dSopenharmony_ci    if(p == (q & 0xffffff00)) {
322e5b6d6dSopenharmony_ci        // p == elements[index] is a root primary. Find the CE before it.
332e5b6d6dSopenharmony_ci        // We must not be in a primary range.
342e5b6d6dSopenharmony_ci        U_ASSERT((q & PRIMARY_STEP_MASK) == 0);
352e5b6d6dSopenharmony_ci        secTer = elements[index - 1];
362e5b6d6dSopenharmony_ci        if((secTer & SEC_TER_DELTA_FLAG) == 0) {
372e5b6d6dSopenharmony_ci            // Primary CE just before p.
382e5b6d6dSopenharmony_ci            p = secTer & 0xffffff00;
392e5b6d6dSopenharmony_ci            secTer = Collation::COMMON_SEC_AND_TER_CE;
402e5b6d6dSopenharmony_ci        } else {
412e5b6d6dSopenharmony_ci            // secTer = last secondary & tertiary for the previous primary
422e5b6d6dSopenharmony_ci            index -= 2;
432e5b6d6dSopenharmony_ci            for(;;) {
442e5b6d6dSopenharmony_ci                p = elements[index];
452e5b6d6dSopenharmony_ci                if((p & SEC_TER_DELTA_FLAG) == 0) {
462e5b6d6dSopenharmony_ci                    p &= 0xffffff00;
472e5b6d6dSopenharmony_ci                    break;
482e5b6d6dSopenharmony_ci                }
492e5b6d6dSopenharmony_ci                --index;
502e5b6d6dSopenharmony_ci            }
512e5b6d6dSopenharmony_ci        }
522e5b6d6dSopenharmony_ci    } else {
532e5b6d6dSopenharmony_ci        // p > elements[index] which is the previous primary.
542e5b6d6dSopenharmony_ci        // Find the last secondary & tertiary weights for it.
552e5b6d6dSopenharmony_ci        p = q & 0xffffff00;
562e5b6d6dSopenharmony_ci        secTer = Collation::COMMON_SEC_AND_TER_CE;
572e5b6d6dSopenharmony_ci        for(;;) {
582e5b6d6dSopenharmony_ci            q = elements[++index];
592e5b6d6dSopenharmony_ci            if((q & SEC_TER_DELTA_FLAG) == 0) {
602e5b6d6dSopenharmony_ci                // We must not be in a primary range.
612e5b6d6dSopenharmony_ci                U_ASSERT((q & PRIMARY_STEP_MASK) == 0);
622e5b6d6dSopenharmony_ci                break;
632e5b6d6dSopenharmony_ci            }
642e5b6d6dSopenharmony_ci            secTer = q;
652e5b6d6dSopenharmony_ci        }
662e5b6d6dSopenharmony_ci    }
672e5b6d6dSopenharmony_ci    return ((int64_t)p << 32) | (secTer & ~SEC_TER_DELTA_FLAG);
682e5b6d6dSopenharmony_ci}
692e5b6d6dSopenharmony_ci
702e5b6d6dSopenharmony_ciint64_t
712e5b6d6dSopenharmony_ciCollationRootElements::firstCEWithPrimaryAtLeast(uint32_t p) const {
722e5b6d6dSopenharmony_ci    if(p == 0) { return 0; }
732e5b6d6dSopenharmony_ci    int32_t index = findP(p);
742e5b6d6dSopenharmony_ci    if(p != (elements[index] & 0xffffff00)) {
752e5b6d6dSopenharmony_ci        for(;;) {
762e5b6d6dSopenharmony_ci            p = elements[++index];
772e5b6d6dSopenharmony_ci            if((p & SEC_TER_DELTA_FLAG) == 0) {
782e5b6d6dSopenharmony_ci                // First primary after p. We must not be in a primary range.
792e5b6d6dSopenharmony_ci                U_ASSERT((p & PRIMARY_STEP_MASK) == 0);
802e5b6d6dSopenharmony_ci                break;
812e5b6d6dSopenharmony_ci            }
822e5b6d6dSopenharmony_ci        }
832e5b6d6dSopenharmony_ci    }
842e5b6d6dSopenharmony_ci    // The code above guarantees that p has at most 3 bytes: (p & 0xff) == 0.
852e5b6d6dSopenharmony_ci    return ((int64_t)p << 32) | Collation::COMMON_SEC_AND_TER_CE;
862e5b6d6dSopenharmony_ci}
872e5b6d6dSopenharmony_ci
882e5b6d6dSopenharmony_ciuint32_t
892e5b6d6dSopenharmony_ciCollationRootElements::getPrimaryBefore(uint32_t p, UBool isCompressible) const {
902e5b6d6dSopenharmony_ci    int32_t index = findPrimary(p);
912e5b6d6dSopenharmony_ci    int32_t step;
922e5b6d6dSopenharmony_ci    uint32_t q = elements[index];
932e5b6d6dSopenharmony_ci    if(p == (q & 0xffffff00)) {
942e5b6d6dSopenharmony_ci        // Found p itself. Return the previous primary.
952e5b6d6dSopenharmony_ci        // See if p is at the end of a previous range.
962e5b6d6dSopenharmony_ci        step = (int32_t)q & PRIMARY_STEP_MASK;
972e5b6d6dSopenharmony_ci        if(step == 0) {
982e5b6d6dSopenharmony_ci            // p is not at the end of a range. Look for the previous primary.
992e5b6d6dSopenharmony_ci            do {
1002e5b6d6dSopenharmony_ci                p = elements[--index];
1012e5b6d6dSopenharmony_ci            } while((p & SEC_TER_DELTA_FLAG) != 0);
1022e5b6d6dSopenharmony_ci            return p & 0xffffff00;
1032e5b6d6dSopenharmony_ci        }
1042e5b6d6dSopenharmony_ci    } else {
1052e5b6d6dSopenharmony_ci        // p is in a range, and not at the start.
1062e5b6d6dSopenharmony_ci        uint32_t nextElement = elements[index + 1];
1072e5b6d6dSopenharmony_ci        U_ASSERT(isEndOfPrimaryRange(nextElement));
1082e5b6d6dSopenharmony_ci        step = (int32_t)nextElement & PRIMARY_STEP_MASK;
1092e5b6d6dSopenharmony_ci    }
1102e5b6d6dSopenharmony_ci    // Return the previous range primary.
1112e5b6d6dSopenharmony_ci    if((p & 0xffff) == 0) {
1122e5b6d6dSopenharmony_ci        return Collation::decTwoBytePrimaryByOneStep(p, isCompressible, step);
1132e5b6d6dSopenharmony_ci    } else {
1142e5b6d6dSopenharmony_ci        return Collation::decThreeBytePrimaryByOneStep(p, isCompressible, step);
1152e5b6d6dSopenharmony_ci    }
1162e5b6d6dSopenharmony_ci}
1172e5b6d6dSopenharmony_ci
1182e5b6d6dSopenharmony_ciuint32_t
1192e5b6d6dSopenharmony_ciCollationRootElements::getSecondaryBefore(uint32_t p, uint32_t s) const {
1202e5b6d6dSopenharmony_ci    int32_t index;
1212e5b6d6dSopenharmony_ci    uint32_t previousSec, sec;
1222e5b6d6dSopenharmony_ci    if(p == 0) {
1232e5b6d6dSopenharmony_ci        index = (int32_t)elements[IX_FIRST_SECONDARY_INDEX];
1242e5b6d6dSopenharmony_ci        // Gap at the beginning of the secondary CE range.
1252e5b6d6dSopenharmony_ci        previousSec = 0;
1262e5b6d6dSopenharmony_ci        sec = elements[index] >> 16;
1272e5b6d6dSopenharmony_ci    } else {
1282e5b6d6dSopenharmony_ci        index = findPrimary(p) + 1;
1292e5b6d6dSopenharmony_ci        previousSec = Collation::BEFORE_WEIGHT16;
1302e5b6d6dSopenharmony_ci        sec = getFirstSecTerForPrimary(index) >> 16;
1312e5b6d6dSopenharmony_ci    }
1322e5b6d6dSopenharmony_ci    U_ASSERT(s >= sec);
1332e5b6d6dSopenharmony_ci    while(s > sec) {
1342e5b6d6dSopenharmony_ci        previousSec = sec;
1352e5b6d6dSopenharmony_ci        U_ASSERT((elements[index] & SEC_TER_DELTA_FLAG) != 0);
1362e5b6d6dSopenharmony_ci        sec = elements[index++] >> 16;
1372e5b6d6dSopenharmony_ci    }
1382e5b6d6dSopenharmony_ci    U_ASSERT(sec == s);
1392e5b6d6dSopenharmony_ci    return previousSec;
1402e5b6d6dSopenharmony_ci}
1412e5b6d6dSopenharmony_ci
1422e5b6d6dSopenharmony_ciuint32_t
1432e5b6d6dSopenharmony_ciCollationRootElements::getTertiaryBefore(uint32_t p, uint32_t s, uint32_t t) const {
1442e5b6d6dSopenharmony_ci    U_ASSERT((t & ~Collation::ONLY_TERTIARY_MASK) == 0);
1452e5b6d6dSopenharmony_ci    int32_t index;
1462e5b6d6dSopenharmony_ci    uint32_t previousTer, secTer;
1472e5b6d6dSopenharmony_ci    if(p == 0) {
1482e5b6d6dSopenharmony_ci        if(s == 0) {
1492e5b6d6dSopenharmony_ci            index = (int32_t)elements[IX_FIRST_TERTIARY_INDEX];
1502e5b6d6dSopenharmony_ci            // Gap at the beginning of the tertiary CE range.
1512e5b6d6dSopenharmony_ci            previousTer = 0;
1522e5b6d6dSopenharmony_ci        } else {
1532e5b6d6dSopenharmony_ci            index = (int32_t)elements[IX_FIRST_SECONDARY_INDEX];
1542e5b6d6dSopenharmony_ci            previousTer = Collation::BEFORE_WEIGHT16;
1552e5b6d6dSopenharmony_ci        }
1562e5b6d6dSopenharmony_ci        secTer = elements[index] & ~SEC_TER_DELTA_FLAG;
1572e5b6d6dSopenharmony_ci    } else {
1582e5b6d6dSopenharmony_ci        index = findPrimary(p) + 1;
1592e5b6d6dSopenharmony_ci        previousTer = Collation::BEFORE_WEIGHT16;
1602e5b6d6dSopenharmony_ci        secTer = getFirstSecTerForPrimary(index);
1612e5b6d6dSopenharmony_ci    }
1622e5b6d6dSopenharmony_ci    uint32_t st = (s << 16) | t;
1632e5b6d6dSopenharmony_ci    while(st > secTer) {
1642e5b6d6dSopenharmony_ci        if((secTer >> 16) == s) { previousTer = secTer; }
1652e5b6d6dSopenharmony_ci        U_ASSERT((elements[index] & SEC_TER_DELTA_FLAG) != 0);
1662e5b6d6dSopenharmony_ci        secTer = elements[index++] & ~SEC_TER_DELTA_FLAG;
1672e5b6d6dSopenharmony_ci    }
1682e5b6d6dSopenharmony_ci    U_ASSERT(secTer == st);
1692e5b6d6dSopenharmony_ci    return previousTer & 0xffff;
1702e5b6d6dSopenharmony_ci}
1712e5b6d6dSopenharmony_ci
1722e5b6d6dSopenharmony_ciuint32_t
1732e5b6d6dSopenharmony_ciCollationRootElements::getPrimaryAfter(uint32_t p, int32_t index, UBool isCompressible) const {
1742e5b6d6dSopenharmony_ci    U_ASSERT(p == (elements[index] & 0xffffff00) || isEndOfPrimaryRange(elements[index + 1]));
1752e5b6d6dSopenharmony_ci    uint32_t q = elements[++index];
1762e5b6d6dSopenharmony_ci    int32_t step;
1772e5b6d6dSopenharmony_ci    if((q & SEC_TER_DELTA_FLAG) == 0 && (step = (int32_t)q & PRIMARY_STEP_MASK) != 0) {
1782e5b6d6dSopenharmony_ci        // Return the next primary in this range.
1792e5b6d6dSopenharmony_ci        if((p & 0xffff) == 0) {
1802e5b6d6dSopenharmony_ci            return Collation::incTwoBytePrimaryByOffset(p, isCompressible, step);
1812e5b6d6dSopenharmony_ci        } else {
1822e5b6d6dSopenharmony_ci            return Collation::incThreeBytePrimaryByOffset(p, isCompressible, step);
1832e5b6d6dSopenharmony_ci        }
1842e5b6d6dSopenharmony_ci    } else {
1852e5b6d6dSopenharmony_ci        // Return the next primary in the list.
1862e5b6d6dSopenharmony_ci        while((q & SEC_TER_DELTA_FLAG) != 0) {
1872e5b6d6dSopenharmony_ci            q = elements[++index];
1882e5b6d6dSopenharmony_ci        }
1892e5b6d6dSopenharmony_ci        U_ASSERT((q & PRIMARY_STEP_MASK) == 0);
1902e5b6d6dSopenharmony_ci        return q;
1912e5b6d6dSopenharmony_ci    }
1922e5b6d6dSopenharmony_ci}
1932e5b6d6dSopenharmony_ci
1942e5b6d6dSopenharmony_ciuint32_t
1952e5b6d6dSopenharmony_ciCollationRootElements::getSecondaryAfter(int32_t index, uint32_t s) const {
1962e5b6d6dSopenharmony_ci    uint32_t secTer;
1972e5b6d6dSopenharmony_ci    uint32_t secLimit;
1982e5b6d6dSopenharmony_ci    if(index == 0) {
1992e5b6d6dSopenharmony_ci        // primary = 0
2002e5b6d6dSopenharmony_ci        U_ASSERT(s != 0);
2012e5b6d6dSopenharmony_ci        index = (int32_t)elements[IX_FIRST_SECONDARY_INDEX];
2022e5b6d6dSopenharmony_ci        secTer = elements[index];
2032e5b6d6dSopenharmony_ci        // Gap at the end of the secondary CE range.
2042e5b6d6dSopenharmony_ci        secLimit = 0x10000;
2052e5b6d6dSopenharmony_ci    } else {
2062e5b6d6dSopenharmony_ci        U_ASSERT(index >= (int32_t)elements[IX_FIRST_PRIMARY_INDEX]);
2072e5b6d6dSopenharmony_ci        secTer = getFirstSecTerForPrimary(index + 1);
2082e5b6d6dSopenharmony_ci        // If this is an explicit sec/ter unit, then it will be read once more.
2092e5b6d6dSopenharmony_ci        // Gap for secondaries of primary CEs.
2102e5b6d6dSopenharmony_ci        secLimit = getSecondaryBoundary();
2112e5b6d6dSopenharmony_ci    }
2122e5b6d6dSopenharmony_ci    for(;;) {
2132e5b6d6dSopenharmony_ci        uint32_t sec = secTer >> 16;
2142e5b6d6dSopenharmony_ci        if(sec > s) { return sec; }
2152e5b6d6dSopenharmony_ci        secTer = elements[++index];
2162e5b6d6dSopenharmony_ci        if((secTer & SEC_TER_DELTA_FLAG) == 0) { return secLimit; }
2172e5b6d6dSopenharmony_ci    }
2182e5b6d6dSopenharmony_ci}
2192e5b6d6dSopenharmony_ci
2202e5b6d6dSopenharmony_ciuint32_t
2212e5b6d6dSopenharmony_ciCollationRootElements::getTertiaryAfter(int32_t index, uint32_t s, uint32_t t) const {
2222e5b6d6dSopenharmony_ci    uint32_t secTer;
2232e5b6d6dSopenharmony_ci    uint32_t terLimit;
2242e5b6d6dSopenharmony_ci    if(index == 0) {
2252e5b6d6dSopenharmony_ci        // primary = 0
2262e5b6d6dSopenharmony_ci        if(s == 0) {
2272e5b6d6dSopenharmony_ci            U_ASSERT(t != 0);
2282e5b6d6dSopenharmony_ci            index = (int32_t)elements[IX_FIRST_TERTIARY_INDEX];
2292e5b6d6dSopenharmony_ci            // Gap at the end of the tertiary CE range.
2302e5b6d6dSopenharmony_ci            terLimit = 0x4000;
2312e5b6d6dSopenharmony_ci        } else {
2322e5b6d6dSopenharmony_ci            index = (int32_t)elements[IX_FIRST_SECONDARY_INDEX];
2332e5b6d6dSopenharmony_ci            // Gap for tertiaries of primary/secondary CEs.
2342e5b6d6dSopenharmony_ci            terLimit = getTertiaryBoundary();
2352e5b6d6dSopenharmony_ci        }
2362e5b6d6dSopenharmony_ci        secTer = elements[index] & ~SEC_TER_DELTA_FLAG;
2372e5b6d6dSopenharmony_ci    } else {
2382e5b6d6dSopenharmony_ci        U_ASSERT(index >= (int32_t)elements[IX_FIRST_PRIMARY_INDEX]);
2392e5b6d6dSopenharmony_ci        secTer = getFirstSecTerForPrimary(index + 1);
2402e5b6d6dSopenharmony_ci        // If this is an explicit sec/ter unit, then it will be read once more.
2412e5b6d6dSopenharmony_ci        terLimit = getTertiaryBoundary();
2422e5b6d6dSopenharmony_ci    }
2432e5b6d6dSopenharmony_ci    uint32_t st = (s << 16) | t;
2442e5b6d6dSopenharmony_ci    for(;;) {
2452e5b6d6dSopenharmony_ci        if(secTer > st) {
2462e5b6d6dSopenharmony_ci            U_ASSERT((secTer >> 16) == s);
2472e5b6d6dSopenharmony_ci            return secTer & 0xffff;
2482e5b6d6dSopenharmony_ci        }
2492e5b6d6dSopenharmony_ci        secTer = elements[++index];
2502e5b6d6dSopenharmony_ci        // No tertiary greater than t for this primary+secondary.
2512e5b6d6dSopenharmony_ci        if((secTer & SEC_TER_DELTA_FLAG) == 0 || (secTer >> 16) > s) { return terLimit; }
2522e5b6d6dSopenharmony_ci        secTer &= ~SEC_TER_DELTA_FLAG;
2532e5b6d6dSopenharmony_ci    }
2542e5b6d6dSopenharmony_ci}
2552e5b6d6dSopenharmony_ci
2562e5b6d6dSopenharmony_ciuint32_t
2572e5b6d6dSopenharmony_ciCollationRootElements::getFirstSecTerForPrimary(int32_t index) const {
2582e5b6d6dSopenharmony_ci    uint32_t secTer = elements[index];
2592e5b6d6dSopenharmony_ci    if((secTer & SEC_TER_DELTA_FLAG) == 0) {
2602e5b6d6dSopenharmony_ci        // No sec/ter delta.
2612e5b6d6dSopenharmony_ci        return Collation::COMMON_SEC_AND_TER_CE;
2622e5b6d6dSopenharmony_ci    }
2632e5b6d6dSopenharmony_ci    secTer &= ~SEC_TER_DELTA_FLAG;
2642e5b6d6dSopenharmony_ci    if(secTer > Collation::COMMON_SEC_AND_TER_CE) {
2652e5b6d6dSopenharmony_ci        // Implied sec/ter.
2662e5b6d6dSopenharmony_ci        return Collation::COMMON_SEC_AND_TER_CE;
2672e5b6d6dSopenharmony_ci    }
2682e5b6d6dSopenharmony_ci    // Explicit sec/ter below common/common.
2692e5b6d6dSopenharmony_ci    return secTer;
2702e5b6d6dSopenharmony_ci}
2712e5b6d6dSopenharmony_ci
2722e5b6d6dSopenharmony_ciint32_t
2732e5b6d6dSopenharmony_ciCollationRootElements::findPrimary(uint32_t p) const {
2742e5b6d6dSopenharmony_ci    // Requirement: p must occur as a root primary.
2752e5b6d6dSopenharmony_ci    U_ASSERT((p & 0xff) == 0);  // at most a 3-byte primary
2762e5b6d6dSopenharmony_ci    int32_t index = findP(p);
2772e5b6d6dSopenharmony_ci    // If p is in a range, then we just assume that p is an actual primary in this range.
2782e5b6d6dSopenharmony_ci    // (Too cumbersome/expensive to check.)
2792e5b6d6dSopenharmony_ci    // Otherwise, it must be an exact match.
2802e5b6d6dSopenharmony_ci    U_ASSERT(isEndOfPrimaryRange(elements[index + 1]) || p == (elements[index] & 0xffffff00));
2812e5b6d6dSopenharmony_ci    return index;
2822e5b6d6dSopenharmony_ci}
2832e5b6d6dSopenharmony_ci
2842e5b6d6dSopenharmony_ciint32_t
2852e5b6d6dSopenharmony_ciCollationRootElements::findP(uint32_t p) const {
2862e5b6d6dSopenharmony_ci    // p need not occur as a root primary.
2872e5b6d6dSopenharmony_ci    // For example, it might be a reordering group boundary.
2882e5b6d6dSopenharmony_ci    U_ASSERT((p >> 24) != Collation::UNASSIGNED_IMPLICIT_BYTE);
2892e5b6d6dSopenharmony_ci    // modified binary search
2902e5b6d6dSopenharmony_ci    int32_t start = (int32_t)elements[IX_FIRST_PRIMARY_INDEX];
2912e5b6d6dSopenharmony_ci    U_ASSERT(p >= elements[start]);
2922e5b6d6dSopenharmony_ci    int32_t limit = length - 1;
2932e5b6d6dSopenharmony_ci    U_ASSERT(elements[limit] >= PRIMARY_SENTINEL);
2942e5b6d6dSopenharmony_ci    U_ASSERT(p < elements[limit]);
2952e5b6d6dSopenharmony_ci    while((start + 1) < limit) {
2962e5b6d6dSopenharmony_ci        // Invariant: elements[start] and elements[limit] are primaries,
2972e5b6d6dSopenharmony_ci        // and elements[start]<=p<=elements[limit].
2982e5b6d6dSopenharmony_ci        int32_t i = (start + limit) / 2;
2992e5b6d6dSopenharmony_ci        uint32_t q = elements[i];
3002e5b6d6dSopenharmony_ci        if((q & SEC_TER_DELTA_FLAG) != 0) {
3012e5b6d6dSopenharmony_ci            // Find the next primary.
3022e5b6d6dSopenharmony_ci            int32_t j = i + 1;
3032e5b6d6dSopenharmony_ci            for(;;) {
3042e5b6d6dSopenharmony_ci                if(j == limit) { break; }
3052e5b6d6dSopenharmony_ci                q = elements[j];
3062e5b6d6dSopenharmony_ci                if((q & SEC_TER_DELTA_FLAG) == 0) {
3072e5b6d6dSopenharmony_ci                    i = j;
3082e5b6d6dSopenharmony_ci                    break;
3092e5b6d6dSopenharmony_ci                }
3102e5b6d6dSopenharmony_ci                ++j;
3112e5b6d6dSopenharmony_ci            }
3122e5b6d6dSopenharmony_ci            if((q & SEC_TER_DELTA_FLAG) != 0) {
3132e5b6d6dSopenharmony_ci                // Find the preceding primary.
3142e5b6d6dSopenharmony_ci                j = i - 1;
3152e5b6d6dSopenharmony_ci                for(;;) {
3162e5b6d6dSopenharmony_ci                    if(j == start) { break; }
3172e5b6d6dSopenharmony_ci                    q = elements[j];
3182e5b6d6dSopenharmony_ci                    if((q & SEC_TER_DELTA_FLAG) == 0) {
3192e5b6d6dSopenharmony_ci                        i = j;
3202e5b6d6dSopenharmony_ci                        break;
3212e5b6d6dSopenharmony_ci                    }
3222e5b6d6dSopenharmony_ci                    --j;
3232e5b6d6dSopenharmony_ci                }
3242e5b6d6dSopenharmony_ci                if((q & SEC_TER_DELTA_FLAG) != 0) {
3252e5b6d6dSopenharmony_ci                    // No primary between start and limit.
3262e5b6d6dSopenharmony_ci                    break;
3272e5b6d6dSopenharmony_ci                }
3282e5b6d6dSopenharmony_ci            }
3292e5b6d6dSopenharmony_ci        }
3302e5b6d6dSopenharmony_ci        if(p < (q & 0xffffff00)) {  // Reset the "step" bits of a range end primary.
3312e5b6d6dSopenharmony_ci            limit = i;
3322e5b6d6dSopenharmony_ci        } else {
3332e5b6d6dSopenharmony_ci            start = i;
3342e5b6d6dSopenharmony_ci        }
3352e5b6d6dSopenharmony_ci    }
3362e5b6d6dSopenharmony_ci    return start;
3372e5b6d6dSopenharmony_ci}
3382e5b6d6dSopenharmony_ci
3392e5b6d6dSopenharmony_ciU_NAMESPACE_END
3402e5b6d6dSopenharmony_ci
3412e5b6d6dSopenharmony_ci#endif  // !UCONFIG_NO_COLLATION
342