SortFlavor HashCollection::preSort(const AccessorT& acc, bool checkTypes) { assert(m_size > 0); if (!checkTypes && !hasTombstones()) { // No need to loop over the elements, we're done return GenericSort; } auto* start = data(); auto* end = data() + posLimit(); bool allInts UNUSED = true; bool allStrs UNUSED = true; for (;;) { if (checkTypes) { while (!isTombstone(start)) { allInts = (allInts && acc.isInt(*start)); allStrs = (allStrs && acc.isStr(*start)); ++start; if (start == end) { goto done; } } } else { while (!isTombstone(start)) { ++start; if (start == end) { goto done; } } } --end; if (start == end) { goto done; } while (isTombstone(end)) { --end; if (start == end) { goto done; } } copyElm(*end, *start); } done: setPosLimit(start - data()); // The logic above possibly moved elements and tombstones around // within the buffer, so we make sure m_pos is not pointing at // garbage by resetting it. The logic above ensures that the first // slot is not a tombstone, so it's safe to set m_pos to 0. arrayData()->m_pos = 0; assert(!hasTombstones()); if (checkTypes) { return allStrs ? StringSort : allInts ? IntegerSort : GenericSort; } else { return GenericSort; } }
HphpArray::SortFlavor HphpArray::preSort(const AccessorT& acc, bool checkTypes) { assert(m_size > 0); if (isPacked()) { // todo t2607563: this is pessimistic. packedToMixed(); } if (!checkTypes && m_size == m_used) { // No need to loop over the elements, we're done return GenericSort; } Elm* start = data(); Elm* end = data() + m_used; bool allInts UNUSED = true; bool allStrs UNUSED = true; for (;;) { if (checkTypes) { while (!isTombstone(start->data.m_type)) { allInts = (allInts && acc.isInt(*start)); allStrs = (allStrs && acc.isStr(*start)); ++start; if (start == end) { goto done; } } } else { while (!isTombstone(start->data.m_type)) { ++start; if (start == end) { goto done; } } } --end; if (start == end) { goto done; } while (isTombstone(end->data.m_type)) { --end; if (start == end) { goto done; } } memcpy(start, end, sizeof(Elm)); } done: m_used = start - data(); assert(m_size == m_used); if (checkTypes) { return allStrs ? StringSort : allInts ? IntegerSort : GenericSort; } else { return GenericSort; } }
HphpArray::SortFlavor HphpArray::preSort(const AccessorT& acc, bool checkTypes) { ASSERT(m_size > 0); if (!checkTypes && ssize_t(m_size) == ssize_t(m_lastE + 1)) { // No need to loop over the elements, we're done return GenericSort; } Elm* start = m_data; Elm* end = m_data + m_lastE + 1; bool allInts UNUSED = true; bool allStrs UNUSED = true; for (;;) { if (checkTypes) { while (start->data.m_type != KindOfTombstone) { allInts = (allInts && acc.isInt(*start)); allStrs = (allStrs && acc.isStr(*start)); ++start; if (start == end) { goto done; } } } else { while (start->data.m_type != KindOfTombstone) { ++start; if (start == end) { goto done; } } } --end; if (start == end) { goto done; } while (end->data.m_type == KindOfTombstone) { --end; if (start == end) { goto done; } } memcpy(start, end, sizeof(Elm)); } done: m_lastE = (start - m_data) - 1; ASSERT(ssize_t(m_size) == ssize_t(m_lastE + 1)); if (checkTypes) { return allStrs ? StringSort : allInts ? IntegerSort : GenericSort; } else { return GenericSort; } }
ZendArray::SortFlavor ZendArray::preSort(Bucket** buffer, const AccessorT& acc, bool checkTypes) { assert(m_size > 0); bool allInts UNUSED = true; bool allStrs UNUSED = true; uint i = 0; // Build up an auxillary array of Bucket pointers. We will // sort this auxillary array, and then we will rebuild the // linked list based on the result. if (checkTypes) { for (Bucket *p = m_pListHead; p; ++i, p = p->pListNext) { allInts = (allInts && acc.isInt(p)); allStrs = (allStrs && acc.isStr(p)); buffer[i] = p; } return allStrs ? StringSort : allInts ? IntegerSort : GenericSort; } else { for (Bucket *p = m_pListHead; p; ++i, p = p->pListNext) { buffer[i] = p; } return GenericSort; } }