| /* |
| * Copyright (c) 2015 Cisco and/or its affiliates. |
| * 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. |
| */ |
| /* |
| * Imported into CLIB by Eliot Dresselhaus from: |
| * |
| * This file is part of |
| * MakeIndex - A formatter and format independent index processor |
| * |
| * This file is public domain software donated by |
| * Nelson Beebe (beebe@science.utah.edu). |
| * |
| * modifications copyright (c) 2003 Cisco Systems, Inc. |
| */ |
| |
| #include <vppinfra/clib.h> |
| |
| /* |
| * qsort.c: Our own version of the system qsort routine which is faster by an |
| * average of 25%, with lows and highs of 10% and 50%. The THRESHold below is |
| * the insertion sort threshold, and has been adjusted for records of size 48 |
| * bytes. The MTHREShold is where we stop finding a better median. |
| */ |
| |
| #define THRESH 4 /* threshold for insertion */ |
| #define MTHRESH 6 /* threshold for median */ |
| |
| typedef struct |
| { |
| word qsz; /* size of each record */ |
| word thresh; /* THRESHold in chars */ |
| word mthresh; /* MTHRESHold in chars */ |
| int (*qcmp) (const void *, const void *); /* the comparison routine */ |
| } qst_t; |
| |
| static void qst (qst_t * q, char *base, char *max); |
| |
| /* |
| * qqsort: First, set up some global parameters for qst to share. |
| * Then, quicksort with qst(), and then a cleanup insertion sort ourselves. |
| * Sound simple? It's not... |
| */ |
| |
| void |
| qsort (void *base, uword n, uword size, |
| int (*compar) (const void *, const void *)) |
| { |
| char *i; |
| char *j; |
| char *lo; |
| char *hi; |
| char *min; |
| char c; |
| char *max; |
| qst_t _q, *q = &_q; |
| |
| if (n <= 1) |
| return; |
| |
| q->qsz = size; |
| q->qcmp = compar; |
| q->thresh = q->qsz * THRESH; |
| q->mthresh = q->qsz * MTHRESH; |
| max = base + n * q->qsz; |
| if (n >= THRESH) |
| { |
| qst (q, base, max); |
| hi = base + q->thresh; |
| } |
| else |
| { |
| hi = max; |
| } |
| /* |
| * First put smallest element, which must be in the first THRESH, in the |
| * first position as a sentinel. This is done just by searching the |
| * first THRESH elements (or the first n if n < THRESH), finding the min, |
| * and swapping it into the first position. |
| */ |
| for (j = lo = base; (lo += q->qsz) < hi;) |
| { |
| if ((*compar) (j, lo) > 0) |
| j = lo; |
| } |
| if (j != base) |
| { /* swap j into place */ |
| for (i = base, hi = base + q->qsz; i < hi;) |
| { |
| c = *j; |
| *j++ = *i; |
| *i++ = c; |
| } |
| } |
| /* |
| * With our sentinel in place, we now run the following hyper-fast |
| * insertion sort. For each remaining element, min, from [1] to [n-1], |
| * set hi to the index of the element AFTER which this one goes. Then, do |
| * the standard insertion sort shift on a character at a time basis for |
| * each element in the frob. |
| */ |
| for (min = base; (hi = min += q->qsz) < max;) |
| { |
| while ((*q->qcmp) (hi -= q->qsz, min) > 0); |
| if ((hi += q->qsz) != min) |
| { |
| for (lo = min + q->qsz; --lo >= min;) |
| { |
| c = *lo; |
| for (i = j = lo; (j -= q->qsz) >= hi; i = j) |
| *i = *j; |
| *i = c; |
| } |
| } |
| } |
| } |
| |
| |
| |
| /* |
| * qst: Do a quicksort. First, find the median element, and put that one in |
| * the first place as the discriminator. (This "median" is just the median |
| * of the first, last and middle elements). (Using this median instead of |
| * the first element is a big win). Then, the usual partitioning/swapping, |
| * followed by moving the discriminator into the right place. Then, figure |
| * out the sizes of the two partions, do the smaller one recursively and the |
| * larger one via a repeat of this code. Stopping when there are less than |
| * THRESH elements in a partition and cleaning up with an insertion sort (in |
| * our caller) is a huge win. All data swaps are done in-line, which is |
| * space-losing but time-saving. (And there are only three places where this |
| * is done). |
| */ |
| |
| static void |
| qst (qst_t * q, char *base, char *max) |
| { |
| char *i; |
| char *j; |
| char *jj; |
| char *mid; |
| int ii; |
| char c; |
| char *tmp; |
| int lo; |
| int hi; |
| int qsz = q->qsz; |
| |
| lo = (int) (max - base); /* number of elements as chars */ |
| do |
| { |
| /* |
| * At the top here, lo is the number of characters of elements in the |
| * current partition. (Which should be max - base). Find the median |
| * of the first, last, and middle element and make that the middle |
| * element. Set j to largest of first and middle. If max is larger |
| * than that guy, then it's that guy, else compare max with loser of |
| * first and take larger. Things are set up to prefer the middle, |
| * then the first in case of ties. |
| */ |
| mid = i = base + qsz * ((unsigned) (lo / qsz) >> 1); |
| if (lo >= q->mthresh) |
| { |
| j = ((*q->qcmp) ((jj = base), i) > 0 ? jj : i); |
| if ((*q->qcmp) (j, (tmp = max - qsz)) > 0) |
| { |
| /* switch to first loser */ |
| j = (j == jj ? i : jj); |
| if ((*q->qcmp) (j, tmp) < 0) |
| j = tmp; |
| } |
| if (j != i) |
| { |
| ii = qsz; |
| do |
| { |
| c = *i; |
| *i++ = *j; |
| *j++ = c; |
| } |
| while (--ii); |
| } |
| } |
| /* Semi-standard quicksort partitioning/swapping */ |
| for (i = base, j = max - qsz;;) |
| { |
| while (i < mid && (*q->qcmp) (i, mid) <= 0) |
| i += qsz; |
| while (j > mid) |
| { |
| if ((*q->qcmp) (mid, j) <= 0) |
| { |
| j -= qsz; |
| continue; |
| } |
| tmp = i + qsz; /* value of i after swap */ |
| if (i == mid) |
| { /* j <-> mid, new mid is j */ |
| mid = jj = j; |
| } |
| else |
| { /* i <-> j */ |
| jj = j; |
| j -= qsz; |
| } |
| goto swap; |
| } |
| if (i == mid) |
| { |
| break; |
| } |
| else |
| { /* i <-> mid, new mid is i */ |
| jj = mid; |
| tmp = mid = i; /* value of i after swap */ |
| j -= qsz; |
| } |
| swap: |
| ii = qsz; |
| do |
| { |
| c = *i; |
| *i++ = *jj; |
| *jj++ = c; |
| } |
| while (--ii); |
| i = tmp; |
| } |
| /* |
| * Look at sizes of the two partitions, do the smaller one first by |
| * recursion, then do the larger one by making sure lo is its size, |
| * base and max are update correctly, and branching back. But only |
| * repeat (recursively or by branching) if the partition is of at |
| * least size THRESH. |
| */ |
| i = (j = mid) + qsz; |
| if ((lo = (int) (j - base)) <= (hi = (int) (max - i))) |
| { |
| if (lo >= q->thresh) |
| qst (q, base, j); |
| base = i; |
| lo = hi; |
| } |
| else |
| { |
| if (hi >= q->thresh) |
| qst (q, i, max); |
| max = j; |
| } |
| } |
| while (lo >= q->thresh); |
| } |
| |
| /* |
| * fd.io coding-style-patch-verification: ON |
| * |
| * Local Variables: |
| * eval: (c-set-style "gnu") |
| * End: |
| */ |