Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/js/src/builtin/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 9 kB image not shown  

Quelle  Sorting-inl.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef builtin_Sorting_inl_h
#define builtin_Sorting_inl_h

#include "builtin/Sorting.h"

#include "js/Conversions.h"
#include "vm/JSContext.h"
#include "vm/JSFunction.h"
#include "vm/JSObject.h"

namespace js {

void ArraySortData::init(JSObject* obj, JSObject* comparator, ValueVector&& vec,
                         uint32_t length, uint32_t denseLen) {
  MOZ_ASSERT(!vec.empty(), "must have items to sort");
  MOZ_ASSERT(denseLen <= length);

  obj_ = obj;
  comparator_ = comparator;

  this->length = length;
  this->denseLen = denseLen;
  this->vec = std::move(vec);

  auto getComparatorKind = [](JSContext* cx, JSObject* comparator) {
    if (!comparator->is<JSFunction>()) {
      return ComparatorKind::Unoptimized;
    }
    JSFunction* fun = &comparator->as<JSFunction>();
    if (!fun->hasJitEntry() || fun->isClassConstructor()) {
      return ComparatorKind::Unoptimized;
    }
    if (fun->realm() == cx->realm() && fun->nargs() <= ComparatorActualArgs) {
      return ComparatorKind::JSSameRealmNoRectifier;
    }
    return ComparatorKind::JS;
  };
  comparatorKind_ = getComparatorKind(cx(), comparator);
}

ArraySortData::ArraySortData(JSContext* cx) : cx_(cx) {
#ifdef DEBUG
  cx_->liveArraySortDataInstances++;
#endif
}

void ArraySortData::freeMallocData() {
  vec.clearAndFree();
#ifdef DEBUG
  MOZ_ASSERT(cx_->liveArraySortDataInstances > 0);
  cx_->liveArraySortDataInstances--;
#endif
}

template <ArraySortKind Kind>
static MOZ_ALWAYS_INLINE ArraySortResult
MaybeYieldToComparator(ArraySortData* d, const Value& x, const Value& y) {
  if constexpr (Kind == ArraySortKind::Array) {
    // https://tc39.es/ecma262/#sec-comparearrayelements
    // 23.1.3.30.2 CompareArrayElements ( x, y, comparefn )

    // Steps 1-2.
    if (x.isUndefined()) {
      d->setComparatorReturnValue(Int32Value(y.isUndefined() ? 0 : 1));
      return ArraySortResult::Done;
    }

    // Step 3.
    if (y.isUndefined()) {
      d->setComparatorReturnValue(Int32Value(-1));
      return ArraySortResult::Done;
    }
  } else {
    // https://tc39.es/ecma262/#sec-comparetypedarrayelements
    // 23.2.4.7 CompareTypedArrayElements ( x, y, comparefn )

    // Step 1.
    MOZ_ASSERT((x.isNumber() && y.isNumber()) ||
               (x.isBigInt() && y.isBigInt()));
  }

  // Yield to the JIT trampoline (or js::array_sort) if the comparator is a JS
  // function we can call more efficiently from JIT code.
  auto kind = d->comparatorKind();
  if (MOZ_LIKELY(kind != ArraySortData::ComparatorKind::Unoptimized)) {
    d->setComparatorArgs(x, y);
    return (kind == ArraySortData::ComparatorKind::JSSameRealmNoRectifier)
               ? ArraySortResult::CallJSSameRealmNoRectifier
               : ArraySortResult::CallJS;
  }
  return CallComparatorSlow(d, x, y);
}

static MOZ_ALWAYS_INLINE bool RvalIsLessOrEqual(ArraySortData* data,
                                                bool* lessOrEqual) {
  // https://tc39.es/ecma262/#sec-comparearrayelements
  // 23.1.3.30.2 CompareArrayElements ( x, y, comparefn )
  //
  // https://tc39.es/ecma262/#sec-comparetypedarrayelements
  // 23.2.4.7 CompareTypedArrayElements ( x, y, comparefn )
  //
  // Note: CompareTypedArrayElements step 2 is identical to CompareArrayElements
  // step 4.

  // Fast path for int32 return values.
  Value rval = data->comparatorReturnValue();
  if (MOZ_LIKELY(rval.isInt32())) {
    *lessOrEqual = rval.toInt32() <= 0;
    return true;
  }

  // Step 4.a.
  Rooted<Value> rvalRoot(data->cx(), rval);
  double d;
  if (MOZ_UNLIKELY(!ToNumber(data->cx(), rvalRoot, &d))) {
    return false;
  }

  // Step 4.b-c.
  *lessOrEqual = std::isnan(d) ? true : (d <= 0);
  return true;
}

static MOZ_ALWAYS_INLINE void CopyValues(Value* out, const Value* list,
                                         uint32_t start, uint32_t end) {
  for (uint32_t i = start; i <= end; i++) {
    out[i] = list[i];
  }
}

// static
template <ArraySortKind Kind>
ArraySortResult ArraySortData::sortWithComparatorShared(ArraySortData* d) {
  auto& vec = d->vec;

  // This function is like a generator that is called repeatedly from the JIT
  // trampoline or js::array_sort. Resume the sorting algorithm where we left
  // off before calling the comparator.
  switch (d->state) {
    case State::Initial:
      break;
    case State::InsertionSortCall1:
      goto insertion_sort_call1;
    case State::InsertionSortCall2:
      goto insertion_sort_call2;
    case State::MergeSortCall1:
      goto merge_sort_call1;
    case State::MergeSortCall2:
      goto merge_sort_call2;
  }

  d->list = vec.begin();

  // Use insertion sort for small arrays.
  if (d->denseLen <= InsertionSortMaxLength) {
    for (d->i = 1; d->i < d->denseLen; d->i++) {
      d->item = vec[d->i];
      d->j = d->i - 1;
      do {
        {
          ArraySortResult res =
              MaybeYieldToComparator<Kind>(d, vec[d->j], d->item);
          if (res != ArraySortResult::Done) {
            d->state = State::InsertionSortCall1;
            return res;
          }
        }
      insertion_sort_call1:
        bool lessOrEqual;
        if (!RvalIsLessOrEqual(d, &lessOrEqual)) {
          return ArraySortResult::Failure;
        }
        if (lessOrEqual) {
          break;
        }
        vec[d->j + 1] = vec[d->j];
      } while (d->j-- > 0);
      vec[d->j + 1] = d->item;
    }
  } else {
    static constexpr size_t InitialWindowSize = 4;

    // Use insertion sort for initial ranges.
    for (d->start = 0; d->start < d->denseLen - 1;
         d->start += InitialWindowSize) {
      d->end =
          std::min<uint32_t>(d->start + InitialWindowSize - 1, d->denseLen - 1);
      for (d->i = d->start + 1; d->i <= d->end; d->i++) {
        d->item = vec[d->i];
        d->j = d->i - 1;
        do {
          {
            ArraySortResult res =
                MaybeYieldToComparator<Kind>(d, vec[d->j], d->item);
            if (res != ArraySortResult::Done) {
              d->state = State::InsertionSortCall2;
              return res;
            }
          }
        insertion_sort_call2:
          bool lessOrEqual;
          if (!RvalIsLessOrEqual(d, &lessOrEqual)) {
            return ArraySortResult::Failure;
          }
          if (lessOrEqual) {
            break;
          }
          vec[d->j + 1] = vec[d->j];
        } while (d->j-- > d->start);
        vec[d->j + 1] = d->item;
      }
    }

    // Merge sort. Set d->out to scratch space initially.
    d->out = vec.begin() + d->denseLen;
    for (d->windowSize = InitialWindowSize; d->windowSize < d->denseLen;
         d->windowSize *= 2) {
      for (d->start = 0; d->start < d->denseLen;
           d->start += 2 * d->windowSize) {
        // The midpoint between the two subarrays.
        d->mid = d->start + d->windowSize - 1;

        // To keep from going over the edge.
        d->end = std::min<uint32_t>(d->start + 2 * d->windowSize - 1,
                                    d->denseLen - 1);

        // Merge comparator-sorted slices list[start..<=mid] and
        // list[mid+1..<=end], storing the merged sequence in out[start..<=end].

        // Skip lopsided runs to avoid doing useless work.
        if (d->mid >= d->end) {
          CopyValues(d->out, d->list, d->start, d->end);
          continue;
        }

        // Skip calling the comparator if the sub-list is already sorted.
        {
          ArraySortResult res = MaybeYieldToComparator<Kind>(
              d, d->list[d->mid], d->list[d->mid + 1]);
          if (res != ArraySortResult::Done) {
            d->state = State::MergeSortCall1;
            return res;
          }
        }
      merge_sort_call1:
        bool lessOrEqual;
        if (!RvalIsLessOrEqual(d, &lessOrEqual)) {
          return ArraySortResult::Failure;
        }
        if (lessOrEqual) {
          CopyValues(d->out, d->list, d->start, d->end);
          continue;
        }

        d->i = d->start;
        d->j = d->mid + 1;
        d->k = d->start;

        while (d->i <= d->mid && d->j <= d->end) {
          {
            ArraySortResult res =
                MaybeYieldToComparator<Kind>(d, d->list[d->i], d->list[d->j]);
            if (res != ArraySortResult::Done) {
              d->state = State::MergeSortCall2;
              return res;
            }
          }
        merge_sort_call2:
          bool lessOrEqual;
          if (!RvalIsLessOrEqual(d, &lessOrEqual)) {
            return ArraySortResult::Failure;
          }
          d->out[d->k++] = lessOrEqual ? d->list[d->i++] : d->list[d->j++];
        }

        // Empty out any remaining elements. Use local variables to let the
        // compiler generate more efficient code.
        Value* out = d->out;
        Value* list = d->list;
        uint32_t k = d->k;
        uint32_t mid = d->mid;
        uint32_t end = d->end;
        for (uint32_t i = d->i; i <= mid; i++) {
          out[k++] = list[i];
        }
        for (uint32_t j = d->j; j <= end; j++) {
          out[k++] = list[j];
        }
      }

      // Swap both lists.
      std::swap(d->list, d->out);
    }
  }

  return ArraySortResult::Done;
}

}  // namespace js

#endif /* builtin_Sorting_inl_h */

Messung V0.5
C=88 H=66 G=77

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.