Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duff's device in Swift

We know that a Duff's device makes use of interlacing the structures of a fallthrough switch and a loop like:

send(to, from, count)
register short *to, *from;
register count;
{
    register n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
            } while (--n > 0);
    }
}

Now, in Swif 2.1, switch-case control flows do not implicitly have fallthrough as we read in Swift docs:

No Implicit Fallthrough

In contrast with switch statements in C and Objective-C, switch statements in Swift do not fall through the bottom of each case and into the next one by default. Instead, the entire switch statement finishes its execution as soon as the first matching switch case is completed, without requiring an explicit break statement. This makes the switch statement safer and easier to use than in C, and avoids executing more than one switch case by mistake.

Now, given that there's a fallthrough clause to have explicitly a fallthrough side effect in Swift:

Fallthrough

Switch statements in Swift do not fall through the bottom of each case and into the next one. Instead, the entire switch statement completes its execution as soon as the first matching case is completed. By contrast, C requires you to insert an explicit break statement at the end of every switch case to prevent fallthrough. Avoiding default fallthrough means that Swift switch statements are much more concise and predictable than their counterparts in C, and thus they avoid executing multiple switch cases by mistake.

that is pretty much like:

let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += " a prime number, and also"
    fallthrough
default:
    description += " an integer."
}
print(description)
// prints "The number 5 is a prime number, and also an integer."

considering that as Wikipedia reminds to us, the devices comes out from the issue

A straightforward code to copy items from an array to a memory-mapped output register might look like this:
do {                          /* count > 0 assumed */
    *to = *from++;            /* "to" pointer is NOT incremented, see explanation below */
} while(--count > 0);

Which would be the exact implementation of a Duff's device in Swift?

This is just a language & coding question, it is not intended to be applied in real Swift applications.

like image 815
loretoparisi Avatar asked Jan 25 '16 15:01

loretoparisi


People also ask

How does Duff’s device work?

- GeeksforGeeks How does Duff’s Device work? Duff’s device is a trick to express loop unrolling directly in C or C++ without extra code to treat the leftover partial loop.The trick is to use a switch statement where all but one of the cases labels are in the middle of a while loop. Further, all cases fall through to the end of the while loop.

How does Duffs device differ from this standard loop unrolling?

2: How does Duffs device differ from this standard loop unrolling? Duffs device is just a clever way of dealing with the remainder loop cycles when N % n != 0. The whole do / while executes N / n number of times as per standard loop unrolling (because the case 0 applies).

Is Duff’s device legal C code?

Despite the impression, it makes Duff’s device is legal C and C++ code (however, it is not valid in Java). How is it useful? Take a step-up from those "Hello World" programs.

How does Duff handle the remainder of a block?

Most algorithms that copy blocks of bytes at a time will handle the remainder bytes at the end, but Duff's device handles them at the beginning. The function calculates count % 8 for the switch statement to figure what the remainder will be, jumps to the case label for that many bytes, and copies them.


Video Answer


2 Answers

Duffs device is about more than optimisation. If you look at https://research.swtch.com/duff it is a discussion of implementing co-routines using this mechanism (see paragraph 8 for a comment from Mr. Duff).

If you try to write a portable co-routine package without this ability. You will end up in assembly or re-writing jmpbuf entries [ neither is portable ].

Modern languages like go and swift have more restrictive memory models than C, so this sort of mechanism (I imagine) would cause all sorts of tracking problems. Even the lambda-like block structure in clang,gcc end up intertwined with thread local storage, and can cause all sorts of havoc unless you stick to trivial applications.

like image 125
mevets Avatar answered Oct 01 '22 22:10

mevets


You express your intent in the highest level code possible, and trust the Swift compiler to optimize it for you, instead of trying to optimize it yourself. Swift is a high level language. You don't do low level loop unrolling in a high level language.

And in Swift, especially, you don't need to worry about copying arrays (the original application of Duff's Device) because Swift pretends to copy an array whenever you assign it, using "copy on write." This means that it will use the same array for two variables as long as you are just reading from them, but as soon as you modify one of them, it will create a duplicate in the background.

For example, from https://developer.apple.com/documentation/swift/array Modifying Copies of Arrays

Each array has an independent value that includes the values of all
of its elements. For simple types such as integers and other structures,
this means that when you change a value in one array, the value of that
element does not change in any copies of the array. For example:

var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers
numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[1, 2, 3, 4, 5]"
like image 25
Andru Luvisi Avatar answered Oct 01 '22 20:10

Andru Luvisi