Als Referenz ist in C/C++ der entsprechende Operator (sizeof
) Kompilierzeit und kann mit Template-Programmierung (Generics) verwendet werden.Ist MemoryLayout <T> .size/stride/Ausrichtung kompilieren Zeit?
Ich war auf der Suche durch Swift Algorithmen Verein für Implementierungen von gemeinsamen Datenstrukturen und kam über ihre Durchführung eines Bit Set:
public struct BitSet {
private(set) public var size: Int
private let N = 64
public typealias Word = UInt64
fileprivate(set) public var words: [Word]
public init(size: Int) {
precondition(size > 0)
self.size = size
// Round up the count to the next multiple of 64.
let n = (size + (N-1))/N
words = [Word](repeating: 0, count: n)
}
<clipped>
In einer Sprache, wo sizeof als Kompilierung konstanten Operator vorhanden ist, würde ich Set N
zu sizeof(Word) * 8
oder besser MemoryLayout<UInt64>.size * 8
anstatt die "magische Zahl" 64. Ich gebe zu, es ist nicht sehr Magie hier, aber der Punkt steht, wenn nur nur um es semantisch klar zu machen, was los ist.
Weiter notierte ich die Familie der Funktionen, für die die gleichen Fragen gelten (ref).
static func size(ofValue value: T) -> Int
static func stride(ofValue value: T) -> Int
static func alignment(ofValue value: T) -> Int
Bearbeiten: Hinzufügen von etwas Demontage von generischen/nicht generische Version von Funktionen.
Non-generic swift:
func getSizeOfInt() -> Int {
return MemoryLayout<UInt64>.size
}
Erzeugt diese Demontage:
(lldb) disassemble --frame
MemoryLayout`getSizeOfInt() -> Int:
0x1000013c0 <+0>: pushq %rbp
0x1000013c1 <+1>: movq %rsp, %rbp
0x1000013c4 <+4>: movl $0x8, %eax
-> 0x1000013c9 <+9>: popq %rbp
0x1000013ca <+10>: retq
auf der 0x8 konstant Basierend, das sieht aus wie ein Kompilierung Konstante basierend auf @Charles Srstka Antwort.
Wie wäre es mit der generischen schnellen Implementierung?
func getSizeOf<T>(_ t:T) -> Int {
return MemoryLayout<T>.size
}
diese Demontage Produziert:
(lldb) disassemble --frame
MemoryLayout`getSizeOf<A> (A) -> Int:
0x100001390 <+0>: pushq %rbp
0x100001391 <+1>: movq %rsp, %rbp
0x100001394 <+4>: subq $0x20, %rsp
0x100001398 <+8>: movq %rsi, -0x8(%rbp)
0x10000139c <+12>: movq %rdi, -0x10(%rbp)
-> 0x1000013a0 <+16>: movq -0x8(%rsi), %rax
0x1000013a4 <+20>: movq 0x88(%rax), %rcx
0x1000013ab <+27>: movq %rcx, -0x18(%rbp)
0x1000013af <+31>: callq *0x20(%rax)
0x1000013b2 <+34>: movq -0x18(%rbp), %rax
0x1000013b6 <+38>: addq $0x20, %rsp
0x1000013ba <+42>: popq %rbp
0x1000013bb <+43>: retq
0x1000013bc <+44>: nopl (%rax)
Die oben sieht nicht Zeit kompilieren ...? Ich bin noch nicht vertraut mit Assembler auf Mac/lldb.
Hey danke. Mein Assembler ist im Allgemeinen rostig und ich habe überhaupt nicht mit lldb gespielt. In der "generischen" Version dieses Codes, die ich zu meiner Antwort hinzugefügt habe, ist mir jedoch viel mehr Arbeit aufgefallen. – Josh
Btw, die obige generische Impl Demontage ist die gleiche mit -O0 vs -O3. Ich sehe deinen neuen Zusatz - was du sagst, macht Sinn und ist interessant. In C++ werden sogar templatisierte Versionen von sizeof zur Kompilierzeit berechnet, weil sie * zur Kompilierzeit bekannt ist. Das ist der Punkt einer Vorlagenfunktion in C++, Sie spezialisieren sich für Typ T und behalten Typsicherheit bei. Ich werde mehr darüber nachdenken, warum diese Register in diesem Fall verwendet werden, und Ihre Antwort richtig markieren. – Josh
Bearbeitete die Antwort, um Ihre bearbeitete Frage zu beantworten. –