| //===------------- Array.cpp - Swift Array Operations Support -------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Implementations of the array runtime functions. |
| // |
| // arrayInitWithCopy(T *dest, T *src, size_t count, M* self) |
| // arrayInitWithTake(NoAlias|FrontToBack|BackToFront)(T *dest, T *src, |
| // size_t count, M* self) |
| // arrayAssignWithCopy(NoAlias|FrontToBack|BackToFront)(T *dest, T *src, |
| // size_t count, M* self) |
| // arrayAssignWithTake(T *dest, T *src, size_t count, M* self) |
| // arrayDestroy(T *dst, size_t count, M* self) |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/Runtime/Config.h" |
| #include "swift/Runtime/HeapObject.h" |
| #include "swift/Runtime/Metadata.h" |
| |
| using namespace swift; |
| |
| namespace { |
| enum class ArrayCopy : unsigned { |
| NoAlias = 0, |
| FrontToBack = 1, |
| BackToFront = 2 |
| }; |
| |
| enum class ArraySource { |
| Copy, |
| Take |
| }; |
| |
| enum class ArrayDest { |
| Init, |
| Assign |
| }; |
| } // end anonymous namespace. |
| |
| static void array_pod_copy(ArrayCopy copyKind, OpaqueValue *dest, |
| OpaqueValue *src, size_t stride, size_t count) { |
| if (copyKind == ArrayCopy::NoAlias) { |
| memcpy(dest, src, stride * count); |
| return; |
| } |
| |
| assert(copyKind == ArrayCopy::FrontToBack || |
| copyKind == ArrayCopy::BackToFront); |
| memmove(dest, src, stride * count); |
| } |
| |
| namespace { |
| typedef OpaqueValue *(*const WitnessFunction)(OpaqueValue *, OpaqueValue *, |
| const Metadata *); |
| } |
| |
| template <ArrayDest destOp, ArraySource srcOp> |
| static WitnessFunction get_witness_function(const ValueWitnessTable *wtable) { |
| if (destOp == ArrayDest::Init) { |
| if (srcOp == ArraySource::Copy) |
| return wtable->initializeWithCopy; |
| else { |
| assert(srcOp == ArraySource::Take); |
| return wtable->initializeWithTake; |
| } |
| } else { |
| assert(destOp == ArrayDest::Assign); |
| if (srcOp == ArraySource::Copy) { |
| return wtable->assignWithCopy; |
| } else { |
| assert(srcOp == ArraySource::Take); |
| return wtable->assignWithTake; |
| } |
| } |
| } |
| template <ArrayDest destOp, ArraySource srcOp, ArrayCopy copyKind> |
| static void array_copy_operation(OpaqueValue *dest, OpaqueValue *src, |
| size_t count, const Metadata *self) { |
| if (count == 0) |
| return; |
| |
| auto wtable = self->getValueWitnesses(); |
| auto stride = wtable->getStride(); |
| |
| // If we are doing a copy we need PODness for a memcpy. |
| if (srcOp == ArraySource::Copy) { |
| auto isPOD = wtable->isPOD(); |
| if (isPOD) { |
| array_pod_copy(copyKind, dest, src, stride, count); |
| return; |
| } |
| } else { |
| // Otherwise, we are doing a take and need bitwise takability for a copy. |
| assert(srcOp == ArraySource::Take); |
| auto isBitwiseTakable = wtable->isBitwiseTakable(); |
| if (isBitwiseTakable && (destOp == ArrayDest::Init || wtable->isPOD())) { |
| array_pod_copy(copyKind, dest, src, stride, count); |
| return; |
| } |
| } |
| |
| // Call the witness to do the copy. |
| if (copyKind == ArrayCopy::NoAlias || copyKind == ArrayCopy::FrontToBack) { |
| auto copy = get_witness_function<destOp, srcOp>(wtable); |
| for (size_t i = 0; i < count; ++i) { |
| auto offset = i * stride; |
| auto *from = reinterpret_cast<OpaqueValue *>((char *)src + offset); |
| auto *to = reinterpret_cast<OpaqueValue *>((char *)dest + offset); |
| copy(to, from, self); |
| } |
| return; |
| } |
| |
| // Back-to-front copy. |
| assert(copyKind == ArrayCopy::BackToFront); |
| assert(count != 0); |
| |
| auto copy = get_witness_function<destOp, srcOp>(wtable); |
| size_t i = count; |
| do { |
| auto offset = --i * stride; |
| auto *from = reinterpret_cast<OpaqueValue *>((char *)src + offset); |
| auto *to = reinterpret_cast<OpaqueValue *>((char *)dest + offset); |
| copy(to, from, self); |
| } while (i != 0); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayInitWithCopy(OpaqueValue *dest, OpaqueValue *src, size_t count, |
| const Metadata *self) { |
| array_copy_operation<ArrayDest::Init, ArraySource::Copy, ArrayCopy::NoAlias>( |
| dest, src, count, self); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayInitWithTakeNoAlias(OpaqueValue *dest, OpaqueValue *src, |
| size_t count, const Metadata *self) { |
| array_copy_operation<ArrayDest::Init, ArraySource::Take, ArrayCopy::NoAlias>( |
| dest, src, count, self); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayInitWithTakeFrontToBack(OpaqueValue *dest, OpaqueValue *src, |
| size_t count, const Metadata *self) { |
| array_copy_operation<ArrayDest::Init, ArraySource::Take, |
| ArrayCopy::FrontToBack>(dest, src, count, self); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayInitWithTakeBackToFront(OpaqueValue *dest, OpaqueValue *src, |
| size_t count, const Metadata *self) { |
| array_copy_operation<ArrayDest::Init, ArraySource::Take, |
| ArrayCopy::BackToFront>(dest, src, count, self); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayAssignWithCopyNoAlias(OpaqueValue *dest, OpaqueValue *src, |
| size_t count, const Metadata *self) { |
| array_copy_operation<ArrayDest::Assign, ArraySource::Copy, |
| ArrayCopy::NoAlias>(dest, src, count, self); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayAssignWithCopyFrontToBack(OpaqueValue *dest, OpaqueValue *src, |
| size_t count, const Metadata *self) { |
| array_copy_operation<ArrayDest::Assign, ArraySource::Copy, |
| ArrayCopy::FrontToBack>(dest, src, count, self); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayAssignWithCopyBackToFront(OpaqueValue *dest, OpaqueValue *src, |
| size_t count, const Metadata *self) { |
| array_copy_operation<ArrayDest::Assign, ArraySource::Copy, |
| ArrayCopy::BackToFront>(dest, src, count, self); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayAssignWithTake(OpaqueValue *dest, OpaqueValue *src, |
| size_t count, const Metadata *self) { |
| array_copy_operation<ArrayDest::Assign, ArraySource::Take, |
| ArrayCopy::NoAlias>(dest, src, count, self); |
| } |
| |
| SWIFT_CC(c) |
| SWIFT_RUNTIME_EXPORT |
| void swift_arrayDestroy(OpaqueValue *begin, size_t count, const Metadata *self) { |
| if (count == 0) |
| return; |
| |
| auto wtable = self->getValueWitnesses(); |
| |
| // Nothing to do if the type is POD. |
| if (wtable->isPOD()) |
| return; |
| |
| auto stride = wtable->getStride(); |
| for (size_t i = 0; i < count; ++i) { |
| auto offset = i * stride; |
| auto *obj = reinterpret_cast<OpaqueValue *>((char *)begin + offset); |
| wtable->destroy(obj, self); |
| } |
| } |