/* * Copyright (C) 2014-2019 Muhammad Tayyab Akram * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "BidiChain.h" #include "SBAssert.h" #include "SBBase.h" #include "BracketQueue.h" static void BracketQueueFinalizePairs(BracketQueueRef queue, BracketQueueListRef list, SBInteger top) { do { SBInteger limit = (list == queue->_rearList ? queue->_rearTop : BracketQueueList_MaxIndex); while (++top <= limit) { if (list->openingLink[top] != BidiLinkNone && list->closingLink[top] == BidiLinkNone) { list->openingLink[top] = BidiLinkNone; } } list = list->next; top = 0; } while (list); } SB_INTERNAL void BracketQueueInitialize(BracketQueueRef queue) { queue->_firstList.previous = NULL; queue->_firstList.next = NULL; queue->_frontList = NULL; queue->_rearList = NULL; queue->count = 0; queue->shouldDequeue = SBFalse; } SB_INTERNAL void BracketQueueReset(BracketQueueRef queue, SBBidiType direction) { queue->_frontList = &queue->_firstList; queue->_rearList = &queue->_firstList; queue->_frontTop = 0; queue->_rearTop = -1; queue->count = 0; queue->shouldDequeue = SBFalse; queue->_direction = direction; } SB_INTERNAL void BracketQueueEnqueue(BracketQueueRef queue, BidiLink priorStrongLink, BidiLink openingLink, SBCodepoint bracket) { BracketQueueListRef list; SBInteger top; /* The queue can only take a maximum of 63 elements. */ SBAssert(queue->count < BracketQueueGetMaxCapacity()); if (queue->_rearTop != BracketQueueList_MaxIndex) { list = queue->_rearList; top = ++queue->_rearTop; } else { BracketQueueListRef rearList; rearList = queue->_rearList; list = rearList->next; if (!list) { list = malloc(sizeof(BracketQueueList)); list->previous = rearList; list->next = NULL; rearList->next = list; } queue->_rearList = list; queue->_rearTop = top = 0; } queue->count += 1; list->priorStrongLink[top] = priorStrongLink; list->openingLink[top] = openingLink; list->closingLink[top] = BidiLinkNone; list->bracket[top] = bracket; list->strongType[top] = SBBidiTypeNil; } SB_INTERNAL void BracketQueueDequeue(BracketQueueRef queue) { /* The queue must NOT be empty. */ SBAssert(queue->count != 0); if (queue->_frontTop != BracketQueueList_MaxIndex) { queue->_frontTop += 1; } else { BracketQueueListRef frontList = queue->_frontList; if (frontList == queue->_rearList) { queue->_rearTop = -1; } else { queue->_frontList = frontList->next; } queue->_frontTop = 0; } queue->count -= 1; } SB_INTERNAL void BracketQueueSetStrongType(BracketQueueRef queue, SBBidiType strongType) { BracketQueueListRef list = queue->_rearList; SBInteger top = queue->_rearTop; while (1) { SBInteger limit = (list == queue->_frontList ? queue->_frontTop : 0); do { if (list->closingLink[top] == BidiLinkNone && list->strongType[top] != queue->_direction) { list->strongType[top] = strongType; } } while (top-- > limit); if (list == queue->_frontList) { break; } list = list->previous; top = BracketQueueList_MaxIndex; } } SB_INTERNAL void BracketQueueClosePair(BracketQueueRef queue, BidiLink closingLink, SBCodepoint bracket) { BracketQueueListRef list = queue->_rearList; SBInteger top = queue->_rearTop; SBCodepoint canonical; switch (bracket) { case 0x232A: canonical = 0x3009; break; case 0x3009: canonical = 0x232A; break; default: canonical = bracket; break; } while (1) { SBBoolean isFrontList = (list == queue->_frontList); SBInteger limit = (isFrontList ? queue->_frontTop : 0); do { if (list->openingLink[top] != BidiLinkNone && list->closingLink[top] == BidiLinkNone && (list->bracket[top] == bracket || list->bracket[top] == canonical)) { list->closingLink[top] = closingLink; BracketQueueFinalizePairs(queue, list, top); if (isFrontList && top == queue->_frontTop) { queue->shouldDequeue = SBTrue; } return; } } while (top-- > limit); if (isFrontList) { break; } list = list->previous; top = BracketQueueList_MaxIndex; } } SB_INTERNAL SBBoolean BracketQueueShouldDequeue(BracketQueueRef queue) { return queue->shouldDequeue; } SB_INTERNAL BidiLink BracketQueueGetPriorStrongLink(BracketQueueRef queue) { return queue->_frontList->priorStrongLink[queue->_frontTop]; } SB_INTERNAL BidiLink BracketQueueGetOpeningLink(BracketQueueRef queue) { return queue->_frontList->openingLink[queue->_frontTop]; } SB_INTERNAL BidiLink BracketQueueGetClosingLink(BracketQueueRef queue) { return queue->_frontList->closingLink[queue->_frontTop]; } SB_INTERNAL SBBidiType BracketQueueGetStrongType(BracketQueueRef queue) { return queue->_frontList->strongType[queue->_frontTop]; } SB_INTERNAL void BracketQueueFinalize(BracketQueueRef queue) { BracketQueueListRef list = queue->_firstList.next; while (list) { BracketQueueListRef next = list->next; free(list); list = next; } }