EnglischFranzösischSpanisch

OnWorks-Favicon

PDL::PPp – Online in der Cloud

Führen Sie PDL::PPp im kostenlosen Hosting-Anbieter OnWorks über Ubuntu Online, Fedora Online, den Windows-Online-Emulator oder den MAC OS-Online-Emulator aus

Dies ist der Befehl PDL::PPp, der beim kostenlosen Hosting-Anbieter OnWorks mit einer unserer zahlreichen kostenlosen Online-Workstations wie Ubuntu Online, Fedora Online, dem Windows-Online-Emulator oder dem MAC OS-Online-Emulator ausgeführt werden kann

PROGRAMM:

NAME/FUNKTION


PDL::PP – Generieren Sie PDL-Routinen aus prägnanten Beschreibungen

ZUSAMMENFASSUNG


z.B

pp_def(
'sumover',
Pars => 'a(n); [o]b();',
Code => q{
double tmp=0;
Schleife(n) %{
tmp += $a();
%}
$b() = tmp;
},
);

pp_done();

FUNKTIONEN


Hier ist eine kurze Referenzliste der von PDL::PP bereitgestellten Funktionen.

pp_add_boot
Fügen Sie Code zum BOOT-Abschnitt der generierten XS-Datei hinzu

pp_add_exported
Fügen Sie Funktionen zur Liste der exportierten Funktionen hinzu

pp_add_isa
Fügen Sie Einträge zur @ISA-Liste hinzu

pp_addbegin
Legt den Code fest, der oben in der generierten .pm-Datei hinzugefügt werden soll

pp_addhdr
Fügen Sie Code und Includes zum C-Abschnitt der generierten XS-Datei hinzu

pp_addpm
Fügen Sie Code zur generierten .pm-Datei hinzu

pp_addxs
Fügen Sie der generierten XS-Datei zusätzlichen XS-Code hinzu

pp_beginwrap
Fügen Sie dem Code für die generierte .pm-Datei einen BEGIN-Block-Umbruch hinzu

pp_bless
Legt das Paket fest, zu dem der XS-Code hinzugefügt wird (Standard ist PDL).

pp_boundscheck
Kontrollstatus der PDL-Grenzüberprüfungsaktivität

pp_core_importList
Geben Sie an, was aus PDL::Core importiert wird

pp_def
Definieren Sie eine neue PDL-Funktion

pp_deprecate_module
Fügen Sie Laufzeit- und POD-Warnungen zu einem veralteten Modul hinzu

pp_done
Markieren Sie das Ende der PDL::PP-Definitionen in der Datei

pp_export_nothing
Löschen Sie die Exportliste für Ihr generiertes Modul

pp_line_numbers
Fügen Sie Informationen zur Zeilennummer hinzu, um das Debuggen von PDL::PP-Code zu vereinfachen

pp_setversion
Legen Sie die Version für .pm- und .xs-Dateien fest

Überblick


Warum brauchen wir PP? Mehrere Gründe: Erstens möchten wir in der Lage sein, Unterprogramme zu generieren
Code für jeden der PDL-Datentypen (PDL_Byte, PDL_Short usw.). AUTOMATISCH. Zweitens,
wenn man sich auf Slices von PDL-Arrays in Perl bezieht (z. B. „$a->slice('0:10:2,:')“ oder andere
Dinge wie Transponierungen) ist es schön, dies transparent machen zu können und zu können
um dies „vor Ort“ zu tun, also keine Speicherkopie des Abschnitts erstellen zu müssen. PP-Griffe
alle notwendigen Element- und Offset-Arithmetik für Sie. Es gibt auch die Vorstellungen von
Threading (wiederholter Aufruf derselben Routine für mehrere Slices, siehe PDL::Indexing)
und Datenfluss (siehe PDL::Dataflow), der die Verwendung von PP ermöglicht.

Im Folgenden gehen wir davon aus, dass der Leser mit den Konzepten von vertraut ist
implizites und explizites Threading und Indexmanipulationen innerhalb der PDL. Falls Sie es noch nicht getan haben
Wenn Sie von diesen Konzepten gehört haben oder mit ihnen nicht sehr vertraut sind, ist es an der Zeit, dies zu überprüfen
PDL::Indizierung.

Wie der Name schon vermuten lässt, handelt es sich bei PDL::PP um einen Vorprozessor, das heißt, er erweitert den Code um
Ersetzungen, um echten C-Code zu erstellen. Technisch gesehen ist die Ausgabe XS-Code (siehe perlxs) aber
das kommt C sehr nahe.

Wie verwendet man PP? Nun, zum größten Teil schreibt man einfach gewöhnlichen C-Code, außer
spezielle PP-Konstrukte, die folgende Form annehmen:

$something(etwas anderes)

oder:

PPFunktion %{

%}

Das wichtigste PP-Konstrukt ist die Form „$array()“. Betrachten Sie das sehr einfache PP
Funktion zum Summieren der Elemente eines 1D-Vektors (tatsächlich ist dies der tatsächlichen sehr ähnlich).
von 'sumover' verwendeter Code):

pp_def('sumit',
Pars => 'a(n); [o]b();',
Code => q{
doppeltes tmp;
tmp = 0;
Schleife(n) %{
tmp += $a();
%}
$b() = tmp;
}
);

Was ist los? Die Zeile „Pars =>“ ist für PP sehr wichtig – sie spezifiziert alle
Argumente und ihre Dimensionalität. Wir nennen das das Stempel, Unterschrift der PP-Funktion (vgl
siehe auch die Erläuterungen in PDL::Indexing). In diesem Fall übernimmt die Routine eine 1-D-Funktion als
Eingabe und gibt einen 0-D-Skalar als Ausgabe zurück. Für den Zugriff wird das PP-Konstrukt „$a()“ verwendet
Elemente des Arrays a(n) für Sie - PP füllt den gesamten erforderlichen C-Code aus.

Sie werden feststellen, dass wir den Operator „q{}“ in einfachen Anführungszeichen verwenden. Dies ist kein
Unfall. Im Allgemeinen möchten Sie einfache Anführungszeichen verwenden, um Ihre PP-Code-Abschnitte zu kennzeichnen. PDL::PP
verwendet „$var()“ zum Parsen und wenn Sie keine einfachen Anführungszeichen verwenden, wird Perl dies versuchen
interpoliere „$var()“. Auch die Verwendung des einfachen Anführungszeichens „q“ mit geschweiften Klammern macht es möglich
Es sieht so aus, als würden Sie einen Codeblock erstellen, was Sie meinen. (Perl ist schlau genug, um
Suchen Sie nach verschachtelten geschweiften Klammern und schließen Sie das Zitat erst, wenn die passende geschweifte Klammer gefunden wird
geschweiften Klammern, sodass es sicher ist, verschachtelte Blöcke zu haben.) Unter anderen Umständen, z. B. wenn Sie
Das Zusammenfügen eines Codeblocks mithilfe von Zeichenfolgenverkettungen ist häufig am einfachsten
echte einfache Anführungszeichen als

Code => 'something'.$interpolatable.'somethingelse;'

Im einfachen Fall hier, bei dem auf alle Elemente zugegriffen wird, wird das PP-Konstrukt „loop(n) %{ ...“ verwendet.
%}“ wird verwendet, um alle Elemente in der Dimension „n“ zu durchlaufen. Beachten Sie diese Funktion von PP: ALL
ABMESSUNGEN SIND NACH NAMEN ANGEGEBEN.

Dies wird deutlicher, wenn wir das PP vermeiden loop () Konstruieren und schreiben Sie die Schleife explizit
mit herkömmlichem C:

pp_def('sumit',
Pars => 'a(n); [o]b();',
Code => q{
int i,n_size;
doppeltes tmp;
n_size = $SIZE(n);
tmp = 0;
for(i=0; i
tmp += $a(n=>i);
}
$b() = tmp;
},
);

Das macht das Gleiche wie zuvor, ist aber langatmiger. Sie können sehen, dass Sie das Element „i“ erhalten
a() sagen wir „$a(n=>i)“ – wir geben die Dimension mit dem Namen „n“ an. In 2D könnten wir sagen:

Pars=>'a(m,n);',
...
tmp += $a(m=>i,n=>j);
...

Die Syntax „m=>i“ lehnt sich an Perl-Hashes an, die tatsächlich in der Implementierung verwendet werden
von PP. Man könnte auch „$a(n=>j,m=>i)“ sagen, da die Reihenfolge nicht wichtig ist.

Sie können im obigen Beispiel auch die Verwendung eines anderen PP-Konstrukts sehen – $SIZE(n) to get
die Länge der Dimension „n“.

Es sollte jedoch beachtet werden, dass Sie, wenn möglich, keine explizite C-Schleife schreiben sollten
habe das PP-„Schleifen“-Konstrukt verwendet, da PDL::PP automatisch die Schleifengrenzen für prüft
Sie, die Verwendung von „loop“ macht den Code prägnanter usw. Aber es gibt sicherlich Situationen
wo Sie eine explizite Steuerung der Schleife benötigen und jetzt wissen, wie das geht ;).

Um noch einmal auf „Warum PP?“ einzugehen. - der obige Code für sumit() wird für jeden Datentyp generiert. Es
wird mit Slices von Arrays „in-place“ arbeiten. Es wird automatisch eingefädelt – z. B. wenn ein 2D
Wenn das Array angegeben ist, wird es für jede 1D-Zeile wiederholt aufgerufen (überprüfen Sie erneut PDL::Indexing).
Einzelheiten zum Einfädeln). Und dann ist b() ein 1D-Array mit den Summen jeder Zeile. Wir konnten
Rufen Sie es stattdessen mit $a->xchg(0,1) auf, um die Spalten zu summieren. Und Datenflussverfolgung usw. wird es sein
erhältlich.

Wie Sie sehen, erspart PP dem Programmierer das Schreiben einer Menge sich unnötig wiederholendem C-Code –
Unserer Meinung nach ist dies eine der besten Funktionen von PDL, die das Schreiben neuer C-Unterroutinen erleichtert
für PDL eine erstaunlich prägnante Übung. Ein zweiter Grund ist die Fähigkeit, PP expandieren zu lassen
Konvertieren Sie Ihre prägnanten Codedefinitionen je nach den Anforderungen des Computers in unterschiedlichen C-Code
Architektur in Frage. Stellen Sie sich zum Beispiel vor, Sie hätten das Glück, einen Supercomputer zu haben
deine Hände; In diesem Fall möchten Sie, dass PDL::PP Code generiert, der die Vorteile nutzt
der Vektorisierungs-/Parallel-Computing-Funktionen Ihrer Maschine (dies ist ein Projekt für die
Zukunft). Das Endergebnis ist in jedem Fall, dass Ihr unveränderter Code weiterhin erweitert werden sollte
Funktionierender XS-Code, auch wenn sich die Interna von PDL geändert haben.

Da Sie den Code außerdem in einem echten Perl-Skript generieren, macht es viel Spaß
Dinge, die Sie tun können. Nehmen wir an, Sie müssen sowohl sumit (wie oben) als auch multit schreiben.
Mit ein bisschen Kreativität schaffen wir das

for({Name => 'sumit', Init => '0', Op => '+='},
{Name => 'multit', Init => '1', Op => '*='}) {
pp_def($_->{Name},
Pars => 'a(n); [o]b();',
Code => '
doppeltes tmp;
tmp = '.$_->{Init}.';
Schleife(n) %{
tmp '.$_->{Op}.' $a();
%}
$b() = tmp;
');
}

wodurch beide Funktionen leicht definiert werden. Wenn Sie nun später die Signatur ändern müssen oder
Dimensionalität oder was auch immer, Sie müssen nur eine Stelle in Ihrem Code ändern. Ja sicher,
Ihr Editor verfügt zwar über „Ausschneiden und Einfügen“ und „Suchen und Ersetzen“, aber es sind immer noch weniger
lästig und definitiv schwieriger, nur einen Ort zu vergessen und seltsame Käfer zu haben
Einschleichen. Auch das spätere Hinzufügen von „orit“ (bitweises Oder) ist ein Einzeiler.

Und denken Sie daran, Sie verfügen wirklich über die vollen Fähigkeiten von Perl – Sie können es ganz einfach lesen
jede Eingabedatei und erstellen Sie Routinen aus den Informationen in dieser Datei. Für einfache Fälle wie
Im oben genannten Fall bevorzugt der Autor (Tjl) derzeit die Hash-Syntax wie oben – das ist jedoch nicht der Fall
viel mehr Zeichen als die entsprechende Array-Syntax, aber viel einfacher zu verstehen und
zu navigieren.

Erwähnenswert ist hier auch die Möglichkeit, den Zeiger auf den Anfang der Daten zu setzen
Speicher – eine Voraussetzung für die Anbindung von PDL an einige Bibliotheken. Dies wird mit dem gehandhabt
„$P(var)“-Direktive, siehe unten.

Wenn Sie mit der Arbeit an einer neuen pp_def'ined-Funktion beginnen, werden Sie normalerweise einen Fehler machen
Finden Sie einen Stapel Compilerfehler, die Zeilennummern in der generierten XS-Datei angeben. Wenn du
Wenn Sie wissen, wie man XS-Dateien liest (oder wenn Sie es auf die harte Tour lernen möchten), können Sie die öffnen
Erstellen Sie die generierte XS-Datei und suchen Sie nach der Zeilennummer mit dem Fehler. Allerdings eine aktuelle
Die Ergänzung zu PDL::PP hilft dabei, die korrekte Zeilennummer Ihrer Fehler zu melden:
„pp_line_numbers“. Arbeiten Sie mit dem ursprünglichen Gipfelbeispiel, falls Sie eine falsche Schreibweise hatten
tmp in Ihrem Code, könnten Sie den (fehlerhaften) Code in etwas wie diesen und den ändern
Der Compiler würde Ihnen viel mehr nützliche Informationen liefern:

pp_def('sumit',
Pars => 'a(n); [o]b();',
Code => pp_line_numbers(__LINE__, q{
doppeltes tmp;
tmp = 0;
Schleife(n) %{
tmp += $a();
%}
$b() = rmp;
})
);

Für die obige Situation sagt mir mein Compiler:

...
test.pd:15: Fehler: 'rmp' nicht deklariert (erste Verwendung in dieser Funktion)
...

In meinem Beispielskript (test.pd genannt) ist Zeile 15 genau die Zeile, in der ich meine erstellt habe
Tippfehler: „rmp“ statt „tmp“.

Nach diesem kurzen Überblick über die allgemeine Vorgehensweise bei der Programmierung von PDL-Routinen
PDL::PP fassen wir zusammen, unter welchen Umständen Sie dies tatsächlich verwenden sollten
Präprozessor/Precompiler. Sie sollten PDL::PP verwenden, wenn Sie möchten

· Schnittstelle von PDL zu einer externen Bibliothek

· Schreiben Sie einen Algorithmus, der langsam wäre, wenn er in Perl codiert wäre (das passiert nicht so oft wie Sie).
denken; Werfen Sie zunächst einen Blick auf Threading und Datenfluss.

· Seien Sie ein PDL-Entwickler (und selbst dann ist es nicht obligatorisch)

WARNUNG


Aufgrund seiner Architektur kann PDL::PP einerseits flexibel und einfach zu bedienen sein,
und gleichzeitig überaus kompliziert. Derzeit ist ein Teil des Problems dieser Fehler
Nachrichten sind nicht sehr informativ und wenn etwas schief geht, sollten Sie besser wissen, was Sie tun
tun und in der Lage sein, sich durch die Interna zu hacken (oder es herauszufinden).
Versuch und Irrtum, was mit deinen Argumenten für „pp_def“ nicht stimmt). Obwohl daran gearbeitet wird
Wenn Sie bessere Warnungen erstellen möchten, scheuen Sie sich nicht, Ihre Fragen an die Mailingliste zu senden
Du gerätst in Schwierigkeiten.

BESCHREIBUNG


Nachdem Sie nun eine Vorstellung davon haben, wie Sie „pp_def“ zum Definieren neuer PDL-Funktionen verwenden können, ist es an der Zeit, dies zu tun
Erklären Sie die allgemeine Syntax von „pp_def“. „pp_def“ verwendet als Argumente zunächst den Namen des
Funktion, die Sie definieren, und dann eine Hash-Liste, die verschiedene Schlüssel enthalten kann.

Basierend auf diesen Schlüsseln generiert PP XS-Code und eine .pm-Datei. Die Funktion „pp_done“ (siehe
Beispiel in der SYNOPSIS) wird verwendet, um PDL::PP mitzuteilen, dass keine weiteren Definitionen vorhanden sind
Diese Datei und es ist Zeit, die .xs- und zu generieren
.pm-Datei.

Infolgedessen kann es mehrere geben pp_def() Aufrufe innerhalb einer Datei (nach Konvention files
mit PP-Code haben die Endung .pd oder .pp), aber im Allgemeinen nur eine pp_done().

Es gibt zwei Hauptarten der Verwendung von pp_def(), die „Datenoperation“ und „Slice“.
„Operation“-Prototypen.

Die „Datenoperation“ wird verwendet, um einige Daten zu übernehmen, sie zu verstümmeln und einige andere Daten auszugeben; Das
Dazu gehören beispielsweise die Operation „+“, die Matrixinverse, Summierung usw. sowie alle Beispiele
über die wir bisher in diesem Dokument gesprochen haben. Implizites und explizites Threading und das
Die Erstellung des Ergebnisses erfolgt bei diesen Vorgängen automatisch. Du kannst sogar
Führen Sie einen Datenfluss mit „sumit“, „sumover“ usw. durch (seien Sie nicht bestürzt, wenn Sie das nicht verstehen
Konzept des Datenflusses in PDL noch sehr gut; es ist noch sehr experimentell).

Die „Slice-Operation“ ist eine andere Art von Operation: Bei einer Slice-Operation sind Sie es nicht
Wenn Sie Daten ändern, definieren Sie Korrespondenzen zwischen verschiedenen Elementen von zwei
piddles (Beispiele umfassen die Indexmanipulations-/Slicing-Funktionsdefinitionen in der Datei
scheiben.pd das ist Teil der PDL-Distribution; Aber Vorsicht, dies ist kein Einführungsniveau
Sachen).

Wenn PDL mit Unterstützung für ungültige Werte kompiliert wurde (z. B. „WITH_BADVAL => 1“), dann zusätzlich
Für „pp_def“ sind Schlüssel erforderlich, wie unten erläutert.

Wenn Sie nur daran interessiert sind, mit einer externen Bibliothek zu kommunizieren (zum Beispiel mit einigen
lineare Algebra/Matrix-Bibliothek), Sie benötigen normalerweise die „Datenoperation“, also machen wir weiter
das erst mal besprechen.

Daten-Management Betrieb


A einfach Beispiel
Bei der Datenoperation müssen Sie wissen, welche Datendimensionen Sie benötigen. Zunächst ein Beispiel
mit Skalaren:

pp_def('hinzufügen',
Pars => 'a(); B(); [o]c();',
Code => '$c() = $a() + $b();'
);

Das sieht etwas seltsam aus, aber lassen Sie es uns genauer untersuchen. Die erste Zeile ist einfach: Wir definieren a
Routine mit dem Namen 'add'. Die zweite Zeile deklariert einfach unsere Parameter und die
Klammern bedeuten, dass es sich um Skalare handelt. Wir nennen die Zeichenfolge, die unsere Parameter definiert und
ihre Dimensionalität die Stempel, Unterschrift dieser Funktion. Für seine Relevanz im Hinblick auf
Informationen zu Threading und Indexmanipulationen finden Sie in der Manpage PDL::Indexing.

Die dritte Zeile ist die eigentliche Operation. Sie müssen die Dollarzeichen und Klammern verwenden
um sich auf Ihre Parameter zu beziehen (dies wird sich wahrscheinlich irgendwann in der Zukunft ändern, einmal a
gute Syntax gefunden wird).

Diese Zeilen sind alles, was nötig ist, um die Funktion für PDL tatsächlich zu definieren (naja,
eigentlich ist es das nicht; Sie müssen zusätzlich eine Makefile.PL schreiben (siehe unten) und diese erstellen
Modul (so etwas wie „perl Makefile.PL; make“); aber lassen Sie uns das für den Moment ignorieren).
Also kannst du jetzt tun

benutze MyModule;
$a = pdl 2,3,4;
$b = pdl 5;

$c = add($a,$b);
# oder
add($a,$b,($c=null)); # Alternative Form, nützlich, wenn $c vorhanden war
# auf etwas Großes voreingestellt, hier nicht sinnvoll.

und dass das Threading ordnungsgemäß funktioniert (das Ergebnis ist $c == [7 8 9]).

Der Pars Abschnitt: Stempel, Unterschrift of a PP Funktion
Wenn Sie den obigen Beispielcode sehen, werden Sie sich höchstwahrscheinlich fragen: Was ist das für ein seltsames „$c=null“?
Syntax im zweiten Aufruf unserer neuen „Add“-Funktion? Wenn Sie sich das noch einmal ansehen
Definition von „add“ werden Sie feststellen, dass das dritte Argument „c“ mit dem gekennzeichnet ist
Qualifizierer „[o]“, der PDL::PP mitteilt, dass es sich um ein Ausgabeargument handelt. Also der obige Aufruf an
add bedeutet „ein neues $c mit den richtigen Abmessungen von Grund auf erstellen“ – „null“ ist etwas Besonderes
Token für „leeres Piddle“ (Sie fragen sich vielleicht, warum wir nicht den Wert „undef“ verwendet haben, um dies zu kennzeichnen
anstelle des PDL-spezifischen „null“; wir denken gerade darüber nach ;).

[Dies sollte auch in einem anderen Abschnitt des Handbuchs erklärt werden!!] Der Grund dafür
Wenn Sie diese Syntax als Alternative haben, können Sie dies tun, wenn Sie wirklich große Rätsel haben

$c = PDL->null;
for(eine lange Schleife) {
# munge a,b
add($a,$b,$c);
# munge c, lege etwas zurück zu a,b
}

und vermeiden Sie es, $c jedes Mal zuzuweisen und wieder freizugeben. Es wird zunächst einmal vergeben
hinzufügen() und danach bleibt der Speicher bestehen, bis $c zerstört wird.

Wenn du es nur sagst

$c = add($a,$b);

Der von PP generierte Code füllt automatisch „$c=null“ aus und gibt das Ergebnis zurück. Wenn
Sie möchten mehr über die Gründe erfahren, warum PDL::PP diesen Ausgabestil unterstützt
Argumente werden als letzte Argumente angegeben. Überprüfen Sie die Manpage PDL::Indexing.

„[o]“ ist nicht das einzige Qualifikationsmerkmal, das ein pdl-Argument in der Signatur haben kann. Ein anderer
Ein wichtiges Qualifikationsmerkmal ist die Option „[t]“, die eine PDL als temporär kennzeichnet. Was macht das
bedeuten? Sie teilen PDL::PP mit, dass dieses PDL im Verlauf nur für temporäre Ergebnisse verwendet wird
Sie haben die Berechnung beendet und sind nach Abschluss der Berechnung nicht mehr an ihrem Wert interessiert
vollendet. Aber warum sollte PDL::PP das überhaupt wissen wollen? Der Grund
ist eng mit den Konzepten der automatischen PDL-Erstellung verbunden (Sie haben oben davon gehört) und
implizites Threading. Wenn Sie implizites Threading verwenden, ändert sich die Dimensionalität automatisch
Die erstellten pdls sind tatsächlich größer als in der Signatur angegeben. Mit „[o]“ gekennzeichnet
PDLs werden so erstellt, dass sie die zusätzlichen Abmessungen haben, die für die Anzahl erforderlich sind
von impliziten Gewindeabmessungen. Beim Erstellen eines temporären PDL wird dies jedoch immer nur der Fall sein
groß genug gemacht werden, damit das Ergebnis für eine Iteration in einer Thread-Schleife gespeichert werden kann, d. h
so groß, wie es die Signatur erfordert. So wird weniger Speicher verschwendet, wenn Sie ein PDL als kennzeichnen
vorübergehend. Zweitens können Sie die automatische Ausgabeerstellung mit temporären PDLs verwenden, selbst wenn Sie
verwenden explizites Threading, das für normale Ausgabe-PDLs, die mit „[o]“ gekennzeichnet sind, verboten ist.
(siehe PDL::Indexing).

Hier ist ein Beispiel, in dem wir das Qualifikationsmerkmal [t] verwenden. Wir definieren die Funktion „callf“.
ruft eine C-Routine „f“ auf, die ein temporäres Array derselben Größe und desselben Typs wie das Array benötigt
„a“ (Entschuldigung für die Vorwärtsreferenz für $P; es ist ein Zeigerzugriff, siehe unten):

pp_def('callf',
Pars => 'a(n); [t] tmp(n); [o] b()',
Code => 'int ns = $SIZE(n);
f($P(a),$P(b),$P(tmp),ns);
'
);

Argument Größe und dem Stempel, Unterschrift
Jetzt haben wir gerade über die Abmessungen von PDLs und die Signatur gesprochen. Wie hängen sie zusammen?
Nehmen wir an, wir möchten einem Vektor einen Skalar + die Indexzahl hinzufügen:

pp_def('add2',
Pars => 'a(n); B(); [o]c(n);',
Code => 'loop(n) %{
$c() = $a() + $b() + n;
%}'
);

Hier sind mehrere Punkte zu beachten: Erstens enthält das Argument „Pars“ jetzt das n
Argumente, um zu zeigen, dass wir eine einzige Dimension haben a und dem c. Es ist wichtig zu beachten
dass es sich bei Dimensionen um tatsächliche Entitäten handelt, auf die über den Namen zugegriffen wird, so dass dies erklärt wird a und dem c zu
haben die gleich erste Dimensionen. In den meisten PP-Definitionen wird die Größe der benannten Dimensionen angegeben
aus den jeweiligen Dimensionen von Nicht-Ausgabe-PDLs (solche ohne „[o]“-Flag) festgelegt werden, aber
Manchmal möchten Sie möglicherweise die Größe einer benannten Dimension explizit über eine festlegen
ganzzahliger Parameter. Sehen Sie unten in der Beschreibung des Abschnitts „OtherPars“, wie das funktioniert.

Konstant Argument Größe in Stempel, Unterschrift
Angenommen, Sie möchten, dass automatisch eine Ausgabedatei erstellt wird, und Sie wissen das bei jedem
Rufen Sie an, dass seine Dimension die gleiche Größe hat (z. B. 9), unabhängig von den Abmessungen des
Eingaberätsel. In diesem Fall verwenden Sie zur Angabe die folgende Syntax im Pars-Abschnitt
die Größe der Dimension:

' [o] y(n=9); '

Wie erwartet werden bei Bedarf zusätzliche Abmessungen erstellt, die durch das Gewindeschneiden erforderlich sind. Wenn du
Sie müssen eine benannte Dimension gemäß einer komplizierteren Formel (als einer Konstante) zuweisen.
Sie müssen den unten beschriebenen Schlüssel „RedoDimsCode“ verwenden.

Typ Konvertierungen und dem Stempel, Unterschrift
Die Signatur bestimmt auch die Typkonvertierungen, die bei einem PP durchgeführt werden
Funktion aufgerufen wird. Was passiert also, wenn wir eines unserer zuvor definierten aufrufen?
Funktionen mit PDLs unterschiedlichen Typs, z

add2($a,$b,($ret=null));

wobei $a vom Typ „PDL_Float“ und $b vom Typ „PDL_Short“ ist? Mit der Signatur wie abgebildet
Die Definition von „add2“ über dem Datentyp der Operation (wie zur Laufzeit bestimmt) lautet
die des PDL mit dem „höchsten“ Typ (Sequenz ist Byte < short < ushort < long < float
< doppelt). Im add2-Beispiel ist der Datentyp der Operation float ($a hat das
Datentyp). Alle pdl-Argumente werden dann typkonvertiert in diesen Datentyp (das ist nicht der Fall).
Inplace konvertiert, aber eine Kopie mit dem richtigen Typ wird erstellt, wenn ein pdl-Argument nicht vorhanden ist
die Art der Operation). Null-PDLs tragen keinen Typ zur Bestimmung bei
Art der Operation. Sie werden jedoch mit dem Datentyp der Operation erstellt;
hier wird $ret beispielsweise vom Typ float sein. Sie sollten sich dieser Regeln bewusst sein, wenn
Aufrufen von PP-Funktionen mit PDLs verschiedener Typen, um den zusätzlichen Speicher zu beanspruchen und
Laufzeitanforderungen berücksichtigen.

Diese Typkonvertierungen sind für die meisten Funktionen korrekt, die Sie normalerweise mit „pp_def“ definieren.
Es gibt jedoch bestimmte Fälle, in denen das Typkonvertierungsverhalten leicht verändert ist
gewünscht. In diesen Fällen können zusätzliche Qualifizierer in der Signatur verwendet werden, um das anzugeben
gewünschte Eigenschaften im Hinblick auf die Typkonvertierung. Diese Qualifikationen können mit kombiniert werden
diejenigen, denen wir bereits begegnet sind (die Schaffung Qualifikanten „[o]“ und „[t]“). Lass uns gehen
durch die Liste der Qualifizierer, die das Typkonvertierungsverhalten ändern.

Das wichtigste ist das Qualifikationsmerkmal „int“, das bei einem pdl-Argument nützlich ist
stellt Indizes in ein anderes PDL dar. Schauen wir uns ein Beispiel aus „PDL::Ufunc“ an:

pp_def('maximum_ind',
Pars => 'a(n); int [o] b()',
Code => '$GENERIC() cur;
int curin;
Schleife(n) %{
if (!n || $a() > cur) {cur = $a(); curind = n;}
%}
$b() = curind;',
);

Die Funktion „maximum_ind“ ermittelt den Index des größten Elements eines Vektors. Wenn du schaust
An der Signatur erkennen Sie, dass das Ausgabeargument „b“ mit deklariert wurde
zusätzliches „int“-Qualifikationsmerkmal. Für Typkonvertierungen hat dies folgende Konsequenzen:
Unabhängig vom Typ des Eingabe-PDL „a“ ist das Ausgabe-PDL „b“ vom Typ „PDL_Long“.
was Sinn macht, da „b“ einen Index in „a“ darstellt. Darüber hinaus, wenn Sie anrufen
Funktion mit einem vorhandenen Ausgabe-PDL „b“, dessen Typ keinen Einfluss auf den Datentyp der Funktion hat
Betrieb (siehe oben). Selbst wenn „a“ von einem kleineren Typ als „b“ ist, ist dies nicht der Fall
konvertiert, um dem Typ „b“ zu entsprechen, bleibt jedoch unberührt, was Speicher und CPU-Zyklen spart
und ist die richtige Vorgehensweise, wenn „b“ Indizes darstellt. Beachten Sie auch, dass Sie das verwenden können
'int'-Qualifizierer zusammen mit anderen Qualifizierern (den „[o]“- und „[t]“-Qualifizierern). Ordnung ist
signifikant – Typqualifizierer stehen vor Erstellungsqualifizierern („[o]“ und „[t]“).

Das obige Beispiel zeigt auch die typische Verwendung des Makros „$GENERIC()“. Es dehnt sich aus
zum aktuellen Typ in einer sogenannten generischen Schleife. Was ist eine generische Schleife? Wie du schon
Ich habe gehört, dass eine PP-Funktion einen Laufzeitdatentyp hat, der durch den Typ der PDL-Argumente bestimmt wird
es wurde mit aufgerufen. Der von PP generierte XS-Code für diese Funktion enthält daher a
Schalter wie „switch (type) {case PDL_Byte: ... case PDL_Double: ...}“, der einen Fall auswählt
basierend auf dem Laufzeitdatentyp der Funktion (es wird als Typ „Schleife“ bezeichnet, weil dort
ist eine Schleife im PP-Code, die die Fälle generiert). In jedem Fall wird Ihr Code einmalig eingefügt
für jeden PDL-Typ in diese Switch-Anweisung ein. Das Makro „$GENERIC()“ wird einfach auf erweitert
Geben Sie in jeder Kopie Ihres geparsten Codes in dieser „switch“-Anweisung den entsprechenden Typ ein, z. B. in der
„case PDL_Byte“ Abschnitt „cur“ wird zu „PDL_Byte“ erweitert und so weiter für den anderen Fall
Aussagen. Ich denke, Sie wissen, dass dies in einigen Fällen ein nützliches Makro ist, um Werte von pdls zu speichern
Code.

Es gibt einige andere Qualifizierer mit ähnlichen Auswirkungen wie „int“. Für dein
Der Einfachheit halber gibt es die Qualifikationsmerkmale „float“ und „double“ mit analogen Konsequenzen
Typkonvertierungen als „int“. Nehmen wir an, Sie haben eine sehr großes Array, für das Sie möchten
Berechnen Sie Zeilen- und Spaltensummen mit einem Äquivalent der Funktion „sumover“. Allerdings mit
Bei der normalen Definition von „sumover“ könnten Probleme auftreten, wenn Ihre Daten z. B. von sind
Geben Sie kurz ein. Ein Anruf wie

sumover($large_pdl,($sums = null));

führt dazu, dass $sums vom Typ short sind und daher anfällig für Überlauffehler sind, wenn
$large_pdl ist ein sehr großes Array. Auf der anderen Seite anrufen

@dims = $large_pdl->dims; Shift @dims;
sumover($large_pdl,($sums = zeroes(double,@dims)));

ist auch keine gute Alternative. Jetzt haben wir keine Überlaufprobleme bei $sums, sondern bei
Der Aufwand für eine Typkonvertierung von $large_pdl in double ist etwas Schlimmes, wenn das wirklich so ist
eine große pdl. Hier bietet sich „double“ an:

pp_def('sumoverd',
Pars => 'a(n); double [o] b()',
Code => 'double tmp=0;
Schleife(n) %{ tmp += a(); %}
$b() = tmp;',
);

Dies umgeht die Typkonvertierungs- und Überlaufprobleme. Wieder analog zum
Der „int“-Qualifizierer „double“ führt dazu, dass „b“ unabhängig vom Typ immer vom Typ „double“ ist
von „a“, ohne als Nebeneffekt zu einer Typkonvertierung von „a“ zu führen.

Schließlich gibt es noch die „type+“-Qualifizierer, bei denen der Typ entweder „int“ oder „float“ ist. Was
soll das heißen. Lassen Sie uns das Qualifikationsmerkmal „int+“ mit der tatsächlichen Definition von veranschaulichen
Zusammenfassung:

pp_def('sumover',
Pars => 'a(n); int+ [o] b()',
Code => '$GENERIC(b) tmp=0;
Schleife(n) %{ tmp += a(); %}
$b() = tmp;',
);

Wie wir bereits für die Qualifizierer „int“, „float“ und „double“ gesehen haben, ist ein mit a markiertes pdl
Das Qualifikationsmerkmal „type+“ hat keinen Einfluss auf den Datentyp der PDL-Operation. Seine Bedeutung ist
„Machen Sie dieses PDL mindestens vom Typ „type“ oder höher, je nach Typ des
Operation". Im Summover-Beispiel bedeutet dies, dass, wenn Sie die Funktion mit einem „a“ aufrufen,
vom Typ PDL_Short wird das Ausgabe-PDL vom Typ PDL_Long sein (genau wie es der Fall gewesen wäre).
Fall mit dem Qualifizierer „int“. Dies wiederum versucht, Überlaufprobleme bei der Verwendung zu vermeiden
kleine Datentypen (z. B. Byte-Bilder). Allerdings, wenn der Datentyp der Operation höher ist
als der im „type+“-Qualifizierer „b“ angegebene Typ, wird mit dem Datentyp erstellt
die Operation, z. B. wenn „a“ vom Typ double ist, dann ist auch „b“ double. Wir hoffen
Sie stimmen zu, dass dies ein sinnvolles Verhalten für „sumover“ ist. Es sollte offensichtlich sein, wie die
Der Qualifizierer „float+“ funktioniert analog. Es kann erforderlich sein, einen Satz angeben zu können
von alternativen Typen für die Parameter. Dies wird jedoch voraussichtlich nicht umgesetzt
bis jemand eine sinnvolle Verwendung dafür findet.

Beachten Sie, dass wir jetzt das $GENERIC-Makro mit dem Namen des PDL angeben mussten, um das abzuleiten
Typ aus diesem Argument. Warum das? Wenn Sie unsere Erklärungen sorgfältig befolgt haben, werden Sie dies tun
haben erkannt, dass „b“ in manchen Fällen einen anderen Typ haben wird als der Typ von
Betrieb. Der Aufruf des Makros „$GENERIC“ mit „b“ als Argument stellt sicher, dass der Typ
wird immer das gleiche sein wie das von „b“ in diesem Teil der generischen Schleife.

Das ist so ziemlich alles, was es über den Abschnitt „Pars“ in einem „pp_def“-Aufruf zu sagen gibt. Du solltest
Denken Sie daran, dass dieser Abschnitt die definiert Stempel, Unterschrift einer PP-definierten Funktion, die Sie verwenden können
mehrere Optionen, um bestimmte Argumente als Ausgabe- und temporäre Argumente und so weiter zu qualifizieren
Dimensionen, auf die Sie später im Abschnitt „Code“ verweisen können, werden über ihren Namen definiert.

Es ist wichtig, dass Sie die Bedeutung der Signatur seit der neuesten PDL verstehen
Versionen können Sie es verwenden, um Thread-Funktionen innerhalb von Perl zu definieren, also das, was wir nennen
Perl Grad des einfädeln. Weitere Informationen finden Sie unter PDL::Indexing.

Der Code Abschnitt
Der Abschnitt „Code“ enthält den eigentlichen XS-Code, der sich im innersten Teil von a befindet
Thread-Schleife (Wenn Sie nicht wissen, was eine Thread-Schleife ist, haben Sie es immer noch nicht gelesen
PDL::Indizierung; Mach es jetzt ;) nachdem alle PP-Makros (wie $GENERIC) und PP-Funktionen ausgeführt wurden
erweitert (wie die „Loop“-Funktion, die wir als nächstes erklären werden).

Lassen Sie uns kurz das „Summover“-Beispiel wiederholen:

pp_def('sumover',
Pars => 'a(n); int+ [o] b()',
Code => '$GENERIC(b) tmp=0;
Schleife(n) %{ tmp += a(); %}
$b() = tmp;',
);

Das „Schleifen“-Konstrukt im Abschnitt „Code“ bezieht sich auch auf den Dimensionsnamen, sodass Sie dies nicht tun
Sie müssen etwaige Grenzen angeben: Die Schleife hat die richtige Größe und alles wird für Sie erledigt.
erneut.

Als nächstes gibt es die überraschende Tatsache, dass „$a()“ und „$b()“ dies tun nicht enthalten den Index. Das
ist nicht notwendig, da wir uns in einer Schleife befinden n und beide Variablen wissen welche Dimensionen
Das haben sie, sodass sie automatisch wissen, dass sie überholt werden.

Diese Funktion ist an vielen Stellen sehr praktisch und sorgt für viel kürzeren Code. Von
Natürlich gibt es Zeiten, in denen Sie dies umgehen möchten. Hier ist eine Funktion, die a erstellt
Matrixsymmetrisch und dient als Beispiel für die Codierung expliziter Schleifen:

pp_def('symm',
Pars => 'a(n,n); [o]c(n,n);',
Code => 'loop(n) %{
int n2;
for(n2=n; n2<$SIZE(n); n2++) {
$c(n0 => n, n1 => n2) =
$c(n0 => n2, n1 => n) =
$a(n0 => n, n1 => n2);
}
%}
'
);

Lassen Sie uns analysieren, was passiert. Erstens: Was soll diese Funktion tun? Von seinem
Signatur sehen Sie, dass es eine 2D-Matrix mit der gleichen Anzahl von Spalten und Zeilen benötigt und
gibt eine Matrix gleicher Größe aus. Aus einer gegebenen Eingabematrix $a wird eine Symmetrie berechnet
Ausgabematrix $c (symmetrisch im Matrixsinne, dass A^T = A, wobei ^T Matrix bedeutet
transponieren, oder im PDL-Sprachgebrauch $c == $c->xchg(0,1)). Dies geschieht, indem nur die Werte verwendet werden
auf und unter der Diagonale von $a. In der Ausgabematrix $c alle Werte auf und unter dem
Diagonale sind die gleichen wie die in $a, während die über der Diagonale ein Spiegelbild von sind
diejenigen unterhalb der Diagonale (oben und unten) werden hier so interpretiert, wie PDL druckt
2D-PDLs). Wenn diese Erklärung immer noch etwas seltsam klingt, machen Sie einfach weiter und erstellen Sie eine kleine Datei
in die Sie diese Definition schreiben, erstellen Sie die neue PDL-Erweiterung (siehe Abschnitt über
Makefiles für PP-Code) und probieren Sie es anhand einiger Beispiele aus.

Nachdem wir erklärt haben, was die Funktion bewirken soll, sind einige Punkte wichtig
notieren aus syntaktischer Sicht. Zuerst ermitteln wir die Größe der genannten Dimension
erneut „n“, indem Sie das $SIZE-Makro verwenden. Zweitens gibt es plötzlich diese lustigen „n0“ und „n1“
Indexnamen im Code, obwohl die Signatur nur die Dimension „n“ definiert. Warum das? Der
Der Grund wird deutlich, wenn man bedenkt, dass sowohl die erste als auch die zweite Dimension von $a und $b
werden in der Signatur von „symm“ mit „n“ bezeichnet. Dies teilt PDL::PP mit, dass der erste und der zweite
Die Dimension dieser Argumente sollte die gleiche Größe haben. Ansonsten die generierte Funktion
wird einen Laufzeitfehler auslösen. Bei einem Zugriff auf $a und $c kann PDL::PP jedoch nicht berücksichtigt werden
Auf welchen Index „n“ sich bezieht, lässt sich schon allein aus dem Indexnamen ablesen. deshalb, die
Indizes mit gleichen Dimensionsnamen werden von links nach rechts beginnend bei 0 nummeriert, z. B. in
Im obigen Beispiel bezieht sich „n0“ auf die erste Dimension von $a und $c, „n1“ auf die zweite und
so weiter.

In allen bisherigen Beispielen haben wir nur die „Pars“- und „Code“-Mitglieder des Hash verwendet
wurde an „pp_def“ übergeben. Es gibt sicherlich noch andere Schlüssel, die von PDL::PP und erkannt werden
Von einigen davon werden wir im Laufe dieses Dokuments erfahren. Finden Sie eine (nicht erschöpfende)
Liste der Schlüssel in Anhang A. Eine Liste von Makros und PP-Funktionen (die uns nur begegnet sind
einige davon in den obigen Beispielen), die um Werte des Hash-Arguments erweitert werden
zu „pp_def“ ist in Anhang B zusammengefasst.

An dieser Stelle könnte es angebracht sein zu erwähnen, dass PDL::PP kein vollständig statisches, sondern
gut gestaltete Reihe von Routinen (wie Tuomas es ausdrückt: „Hören Sie auf, PP als eine Reihe von zu betrachten
in Stein gemeißelte Routinen"), sondern eher eine Sammlung von Dingen, die der PDL::PP-Autor erstellt hat
(Tuomas J. Lukka) war der Meinung, dass er häufig in seine PDL-Erweiterungsroutinen schreiben müsste.
PP versucht, erweiterbar zu sein, damit in Zukunft neuer gemeinsamer Code entstehen kann, wenn neue Anforderungen entstehen
wieder hinein abstrahiert werden. Wenn Sie mehr darüber erfahren möchten, warum Sie möglicherweise etwas ändern möchten
PDL::PP und wie man es macht, lesen Sie im Abschnitt über PDL::PP-Interna.

Handling Badewanne Werte
Wenn Sie keine Unterstützung für schlechte Werte in PDL kompiliert haben, können Sie diesen Abschnitt und die ignorieren
Zugehörige Schlüssel: „BadCode“, „HandleBad“, ... (versuchen Sie, den Wert von auszudrucken
$PDL::Bad::Status – wenn es gleich 0 ist, fahren Sie direkt fort.

Beim Schreiben von Code werden mehrere Schlüssel und Makros verwendet, um fehlerhafte Werte zu verarbeiten. Der erste
Einer davon ist der „HandleBad“-Schlüssel:

HandleBad => 0
Dies markiert eine PP-Routine als NICHT Umgang mit schlechten Werten. Wenn diese Routine gesendet wird, werden Rätsel gelöst
Wenn ihr „badflag“ gesetzt ist, wird eine Warnmeldung an STDOUT und die Piddles ausgegeben
werden so verarbeitet, als ob der zur Darstellung fehlerhafter Werte verwendete Wert eine gültige Zahl wäre. Der
Der Wert „badflag“ wird nicht an die Ausgabe-Piddles weitergegeben.

Ein Beispiel hierfür sind FFT-Routinen, die im Allgemeinen keine Möglichkeit haben
einen Teil der Daten zu ignorieren.

HandleBad => 1
Dies führt dazu, dass PDL::PP zusätzlichen Code schreibt, der sicherstellt, dass der Abschnitt „BadCode“ verwendet wird
dass das Makro „$ISBAD()“ (und seine Brüder) funktionieren.

HandleBad ist nicht angegeben
Wenn bei einem der Eingabe-Piddles das „Badflag“ gesetzt ist, gilt dies auch für die Ausgabe-Piddles
Ihr „Badflag“ ist gesetzt, aber jeder bereitgestellte BadCode wird ignoriert.

Der Wert von „HandleBad“ wird verwendet, um den Inhalt des „BadDoc“-Schlüssels zu definieren, falls dies nicht der Fall ist
gegeben.

Um mit fehlerhaften Werten umzugehen, muss der Code etwas anders geschrieben werden. zum Beispiel,

$c() = $a() + $b();

wird so etwas wie

if ( $a() != BADVAL && $b() != BADVAL ) {
$c() = $a() + $b();
} Else {
$c() = BADVAL;
}

Allerdings möchten wir die zweite Version nur, wenn in den Eingabefeldern fehlerhafte Werte vorhanden sind
(und diese Unterstützung für schlechte Werte ist erwünscht!) – andernfalls möchten wir tatsächlich den Originalcode.
Hier kommt der Schlüssel „BadCode“ ins Spiel; Sie verwenden es, um den Code anzugeben, der ausgeführt werden soll, wenn er fehlerhaft ist
Es können Werte vorhanden sein, und PP verwendet diese und den Abschnitt „Code“, um etwas zu erstellen
mögen:

if (bad_values_are_present) {
fancy_threadloop_stuff {
BadCode
}
} Else {
fancy_threadloop_stuff {
Code
}
}

Dieser Ansatz bedeutet, dass es praktisch keinen Overhead gibt, wenn keine schlechten Werte vorhanden sind
(dh die Badflag-Routine gibt 0 zurück).

Der Abschnitt „BadCode“ kann dieselben Makros und Schleifenkonstrukte wie der Abschnitt „Code“ verwenden.
Allerdings wäre es ohne die folgenden zusätzlichen Makros wenig sinnvoll:

$ISBAD(var)
Um zu überprüfen, ob der Wert eines Piddles schlecht ist, verwenden Sie das Makro $ISBAD:

if ( $ISBAD(a()) ) { printf("a() ist fehlerhaft\n"); }

Sie können auch auf bestimmte Elemente eines Piddles zugreifen:

if ( $ISBAD(a(n=>l)) ) { printf("Element %d von a() ist fehlerhaft\n", l); }

$ISGOOD(var)
Dies ist das Gegenteil des $ISBAD-Makros.

$SETBAD(var)
Für den Fall, dass Sie ein Element eines Piddles schlecht festlegen möchten.

$ISBADVAR(c_var,pdl)
Wenn Sie den Wert eines Piddles „$a()“ in einer C-Variablen („foo“ sagen wir) zwischengespeichert haben, dann zu
Überprüfen Sie, ob es fehlerhaft ist, verwenden Sie „$ISBADVAR(foo,a)“.

$ISGOODVAR(c_var,pdl)
Wie oben, aber diesmal wird überprüft, ob der zwischengespeicherte Wert nicht fehlerhaft ist.

$SETBADVAR(c_var,pdl)
Um den fehlerhaften Wert für ein Piddle in eine AC-Variable zu kopieren, verwenden Sie „$SETBADVAR(foo,a)“.

MACHEN: Erwähnen Sie „$PPISBAD()“ usw. Makros.

Mit diesen Makros könnte der obige Code wie folgt angegeben werden:

Code => '$c() = $a() + $b();',
BadCode => '
if ( $ISBAD(a()) || $ISBAD(b()) ) {
$SETBAD(c());
} Else {
$c() = $a() + $b();
}',

Da dies Perl ist, TMTOWTDI, könnten Sie auch schreiben:

BadCode => '
if ( $ISGOOD(a()) && $ISGOOD(b()) ) {
$c() = $a() + $b();
} Else {
$SETBAD(c());
}',

Wenn Sie Zugriff auf den Wert des Badflags für ein bestimmtes Piddle haben möchten, können Sie das verwenden
„$PDLSTATExxxx()“ Makros:

$PDLSTATEISBAD(pdl)
$PDLSTATEISGOOD(pdl)
$PDLSTATESETBAD(pdl)
$PDLSTATESETGOOD(pdl)

MACHEN: Erwähnen Sie auch die Optionen „FindBadStatusCode“ und „CopyBadStatusCode“ für „pp_def“.
als „BadDoc“-Schlüssel.

Anschluss deine eigene/Bibliothek Funktionen Verwendung von PP
Bedenken Sie nun Folgendes: Sie haben Ihre eigene C-Funktion (die möglicherweise tatsächlich Teil davon ist).
eine Bibliothek, die Sie mit PDL verbinden möchten), die als Argumente zwei Zeiger auf verwendet
Vektoren von Double:

void myfunc(int n,double *v1,double *v2);

Die richtige Art, die PDL-Funktion zu definieren, ist

pp_def('myfunc',
Pars => 'a(n); [o]b(n);',
GenericTypes => ['D'],
Code => 'myfunc($SIZE(n),$P(a),$P(b));'
);

Das „$P(“vonDie Syntax „)“ gibt einen Zeiger auf das erste Element und die anderen Elemente zurück
wird danach garantiert lügen.

Beachten Sie, dass hier viele Fehler passieren können. Zunächst muss $SIZE(n) verwendet werden
statt „n“. Zweitens sollten Sie in diesem Code keine Schleifen einfügen. Drittens stoßen wir hier auf
ein neuer Hash-Schlüssel, der von PDL::PP erkannt wird: Die „GenericTypes“-Deklaration weist PDL::PP an
GENERIEREN SIE DEN TYPELOOP NUR FÜR DIE LISTE DER ANGEGEBENEN TYPEN. In diesem Fall „doppelt“. Das
hat zwei Vorteile. Erstens wird die Größe des kompilierten Codes erheblich reduziert, zweitens wenn
Nicht-Double-Argumente werden an „myfunc()“ übergeben. PDL konvertiert sie automatisch in
double vor der Übergabe an die externe C-Routine und konvertieren Sie sie anschließend wieder zurück.

Man kann „Pars“ auch verwenden, um die Typen einzelner Argumente zu qualifizieren. So könnte man auch
schreibe das als:

pp_def('myfunc',
Pars => 'double a(n); double [o]b(n);',
Code => 'myfunc($SIZE(n),$P(a),$P(b));'
);

Die Typspezifikation in „Pars“ schließt das Argument von der Variation in der Typschleife aus –
Vielmehr wird es auch automatisch vom angegebenen Typ konvertiert. Das ist offensichtlich
nützlich in einem allgemeineren Beispiel, z. B.:

void myfunc(int n,float *v1,long *v2);

pp_def('myfunc',
Pars => 'float a(n); long [o]b(n);',
GenericTypes => ['F'],
Code => 'myfunc($SIZE(n),$P(a),$P(b));'
);

Beachten Sie, dass wir immer noch „GenericTypes“ verwenden, um die Größe der Typschleife zu reduzieren, was PP natürlich tun könnte
Im Prinzip erkennen Sie dies und führen es automatisch aus, obwohl der Code dies noch nicht erreichen muss
Grad an Raffinesse!

Beachten Sie abschließend, dass bei der automatischen Konvertierung von Typen das Qualifikationsmerkmal „[o]“ verwendet werden MUSS
Ausgabevariablen oder hartnäckige Änderungen werden von PP wegoptimiert!

Wenn Sie eine Schnittstelle zu einer großen Bibliothek herstellen, können Sie die Schnittstelle noch weiter automatisieren. Perl kann
Ich helfe Ihnen noch einmal(!), dies zu tun. In vielen Bibliotheken gibt es bestimmte Aufrufkonventionen.
Dies kann ausgenutzt werden. Kurz gesagt, Sie können einen kleinen Parser schreiben (was wirklich nicht der Fall ist).
schwierig in Perl), der dann die Aufrufe von „pp_def“ aus geparsten Beschreibungen von generiert
die Funktionen in dieser Bibliothek. Ein Beispiel finden Sie hier Slatec Schnittstelle im
„Lib“-Baum der PDL-Distribution. Wenn Sie (während des Debuggens) überprüfen möchten, welche Aufrufe erfolgen
PP-Funktionen Ihr Perl-Code generiert ein kleines Hilfspaket, das nützlich ist
ersetzt die PP-Funktionen durch gleichnamige Funktionen, die ihre Argumente an stdout ausgeben.

Sag nur

perl -MPDL::PP::Dump myfile.pd

um die Aufrufe an „pp_def“ und Freunde zu sehen. Versuchen Sie es mit ops.pd und dem Slatec.pd. Wenn du bist
Wenn Sie interessiert sind (oder es erweitern möchten), befindet sich die Quelle in Basic/Gen/PP/Dump.pm

Andere Makros und dem Funktionen in Code Abschnitt
Makros: Bisher sind uns die Makros $SIZE, $GENERIC und $P begegnet. Jetzt werden wir es tun
Erklären Sie schnell die anderen Makros, die im Abschnitt „Code“ von PDL::PP erweitert werden
mit Anwendungsbeispielen.

$T Das Makro $T wird für Typwechsel verwendet. Dies ist sehr nützlich, wenn Sie es verwenden müssen
verschiedene externe (z. B. Bibliotheks-)Funktionen abhängig vom Eingabetyp der Argumente.
Die allgemeine Syntax lautet

$Ttypeletters(type_alternatives)

wobei „typeletters“ eine Permutation einer Teilmenge der vorhandenen Buchstaben „BSULFD“ ist
für Byte, Short, Ushort usw. und „type_alternatives“ sind die Erweiterungen beim Typ
des PP-Vorgangs mit dem im jeweiligen Buchstaben angegebenen Wert übereinstimmt. Lasst uns
Veranschaulichen Sie diese unverständliche Beschreibung anhand eines Beispiels. Vorausgesetzt, Sie haben zwei C
Funktionen mit Prototypen

void float_func(float *in, float *out);
void double_func(double *in, double *out);

die im Grunde das Gleiche tun, aber einer akzeptiert Float- und der andere Doppelzeiger.
Sie könnten sie mit PDL verbinden, indem Sie eine generische Funktion „foofunc“ definieren (die Folgendes tut).
Rufen Sie je nach Art der Transformation die richtige Funktion auf):

pp_def('foofunc',
Pars => ' a(n); [o] b();',
Code => ' $TFD(float_func,double_func) ($P(a),$P(b));'
GenericTypes => [qw(FD)],
);

Bitte beachten Sie, dass Sie es nicht sagen können

Code => ' $TFD(float,double)_func ($P(a),$P(b));'

da das $T-Makro analog zu C-Präprozessormakros mit nachgestellten Leerzeichen erweitert wird.
Die oben abgebildete etwas längere Form ist korrekt. Wenn Sie es wirklich kurz halten möchten, dann
kann man natürlich machen

'$TBSULFD('.(join ',',map {"long_identifier_name_$_"}
qw/byt short unseigned lounge flotte dubble/).');'

$PP
Das $PP-Makro wird für ein sogenanntes verwendet physikalisch Zeiger Zugangdem „Vermischten Geschmack“. Seine physikalisch bezieht sich auf
einige interne Optimierungen von PDL (für diejenigen, die mit dem PDL-Kern vertraut sind).
Apropos Vaffine-Optimierungen). Dieses Makro ist hauptsächlich für den internen Gebrauch und für Sie bestimmt
Sie sollten es in keinem Ihrer normalen Codes verwenden müssen.

$COMP (und der Abschnitt „OtherPars“)
Das $COMP-Makro wird verwendet, um auf Nicht-PDL-Werte im Codeabschnitt zuzugreifen. Sein Name ist
abgeleitet aus der Implementierung von Transformationen in PDL. Die Variablen, auf die Sie verweisen können
zur Verwendung von $COMP sind Mitglieder der „compiled“-Struktur, die die PDL darstellt
Die betreffende Transformation enthält jedoch noch keine Informationen zu den Dimensionen
(Weitere Details finden Sie unter PDL::Internals.) Sie können $COMP jedoch genauso behandeln
Black Box, ohne etwas über die Implementierung von Transformationen in PDL zu wissen.
Wann würden Sie dieses Makro verwenden? Seine Hauptverwendung besteht darin, auf Werte von Argumenten zuzugreifen
werden im Abschnitt „OtherPars“ einer „pp_def“-Definition deklariert. Aber dann hast du es nicht getan
Schon von dem „OtherPars“-Schlüssel gehört?! Lassen Sie uns ein weiteres Beispiel zur Veranschaulichung haben
Typische Verwendung beider neuer Funktionen:

pp_def('pnmout',
Pars => 'a(M)',
OtherPars => "char* fd",
GenericTypes => [qw(BUSL)],
Code => 'PerlIO *fp;
IO *io;

io = GvIO(gv_fetchpv($COMP(fd),FALSE,SVt_PVIO));
if (!io || !(fp = IoIFP(io)))
croak("Kann FP nicht herausfinden");

if (PerlIO_write(fp,$P(a),len) != len)
croak("Fehler beim Schreiben der PNM-Datei");
');

Mit dieser Funktion werden Daten aus einem PDL in eine Datei geschrieben. Der Dateideskriptor wird übergeben
als String in diese Funktion ein. Dieser Parameter geht nicht in den Abschnitt „Pars“.
da es nicht sinnvoll wie ein PDL behandelt werden kann, sondern eher in den treffend benannten
Abschnitt „AnderePars“. Die Parameter im Abschnitt „OtherPars“ folgen denen im Abschnitt „Pars“.
Abschnitt beim Aufrufen der Funktion, d. h

open FILE,“>out.dat“ oder „out.dat konnte nicht geöffnet werden“;
pnmout($pdl,'DATEI');

Wenn Sie innerhalb des Codeabschnitts auf diesen Parameter zugreifen möchten, müssen Sie PP mitteilen
mit dem $COMP-Makro, d. h. Sie schreiben „$COMP(fd)“ wie im Beispiel. Ansonsten PP
Ich wüsste nicht, dass das „fd“, auf das Sie sich beziehen, das gleiche ist wie das in der angegebene
Abschnitt „AnderePars“.

Eine weitere Verwendung des Abschnitts „OtherPars“ besteht darin, eine benannte Dimension in der Signatur festzulegen.
Sehen wir uns ein Beispiel an, wie das gemacht wird:

pp_def('setdim',
Pars => '[o] a(n)',
OtherPars => 'int ns => n',
Code => 'loop(n) %{ $a() = n; %}',
);

Dies besagt, dass die benannte Dimension „n“ aus dem Wert von initialisiert wird mehr
Parameter „ns“, das vom Typ „Integer“ ist (ich nehme an, Sie haben erkannt, dass wir das verwenden
„CType From => benannter_dim“-Syntax). Jetzt können Sie diese Funktion wie gewohnt aufrufen:

setdim(($a=null),5);
drucke $a;
[ 0 1 2 3 4 ]

Zugegebenermaßen ist diese Funktion nicht sehr nützlich, aber sie zeigt, wie sie funktioniert. Wenn du
Rufen Sie die Funktion mit einem vorhandenen pdl auf und Sie müssen das nicht explizit angeben
Größe von „n“, da PDL::PP sie aus den Dimensionen des Nicht-Null-PDL ermitteln kann. In
In diesem Fall geben Sie einfach den Dimensionsparameter als „-1“ an:

$a = hist($b);
setdim($a,-1);

Das sollte es tun.

Die einzige PP-Funktion, die wir bisher in den Beispielen verwendet haben, ist „loop“. Zusätzlich,
Derzeit gibt es zwei weitere Funktionen, die im Abschnitt „Code“ erkannt werden:

Threadloop
Wie wir oben gehört haben, definiert die Signatur einer PP-definierten Funktion die Dimensionen aller
die in a involvierten pdl-Argumente Primitive Betrieb. Allerdings ruft man oft an
Funktionen, die Sie mit PP definiert haben, mit PDLs, die mehr Dimensionen als diese haben
in der Signatur angegeben. In diesem Fall wird die primitive Operation für alle durchgeführt
Unterscheiben geeigneter Dimensionalität in dem, was man a nennt Faden Schleife (Siehe auch
Übersicht oben und PDL::Indexing). Vorausgesetzt, Sie haben eine gewisse Vorstellung von diesem Konzept
Ich werde wahrscheinlich zu schätzen wissen, dass die im Codeabschnitt angegebene Operation so sein sollte
optimiert, da dies die engste Schleife innerhalb einer Fadenschleife ist. Wenn Sie jedoch noch einmal vorbeischauen
Anhand des Beispiels, in dem wir die Funktion „pnmout“ definieren, werden Sie das schnell erkennen
Das Hochladen des Dateideskriptors „IO“ in der inneren Thread-Schleife ist beim Schreiben nicht sehr effizient
ein PDL mit vielen Zeilen. Ein besserer Ansatz wäre, den „IO“-Deskriptor einmal nachzuschlagen
außerhalb der Thread-Schleife und verwenden Sie ihren Wert dann innerhalb der engsten Thread-Schleife. Das ist
Genau da kommt die „Threadloop“-Funktion zum Einsatz. Hier ist eine verbesserte Definition
von „pnmout“, das diese Funktion verwendet:

pp_def('pnmout',
Pars => 'a(M)',
OtherPars => "char* fd",
GenericTypes => [qw(BUSL)],
Code => 'PerlIO *fp;
IO *io;
int len;

io = GvIO(gv_fetchpv($COMP(fd),FALSE,SVt_PVIO));
if (!io || !(fp = IoIFP(io)))
croak("Kann FP nicht herausfinden");

Länge = $GRÖßE(m) * sizeof($GENERIC());

Threadloop %{
if (PerlIO_write(fp,$P(a),len) != len)
croak("Fehler beim Schreiben der PNM-Datei");
%}
');

Dies funktioniert wie folgt. Normalerweise wird der C-Code, den Sie schreiben, im Abschnitt „Code“ platziert
innerhalb einer Thread-Schleife (d. h. PP generiert den entsprechenden umgebenden XS-Code).
Wenn Sie jedoch explizit die Funktion „threadloop“ verwenden, erkennt PDL::PP dies und
umschließt Ihren Code nicht mit einer zusätzlichen Thread-Schleife. Dies hat zur Folge, dass Sie codieren
Das Schreiben außerhalb der Thread-Schleife wird nur einmal pro Transformation und nur des Codes ausgeführt
mit im umgebenden „%{ ... %}“-Paar wird innerhalb der engsten Thread-Schleife platziert. Das
ist auch praktisch, wenn Sie eine Entscheidung (oder insbesondere einen anderen Code) ausführen möchten
CPU-intensiver Code) nur einmal pro Thread, d. h

pp_addhdr('
#define RAW 0
#define ASCII 1
');
pp_def('do_raworascii',
Pars => 'a(); B(); [o]c()',
OtherPars => 'int mode',
Code => ' Schalter ($COMP(Modus)) {
Fall RAW:
Threadloop %{
/* rohe Sachen machen */
%}
break;
Fall ASCII:
Threadloop %{
/* ASCII-Sachen machen */
%}
break;
Standard:
croak("unbekannter Modus");
}'
);

Typen
Die Funktion „Typen“ funktioniert ähnlich wie das Makro „$T“. Allerdings mit der Funktion „Typen“.
Der Code im folgenden Block (wie üblich durch „%{“ und „%}“ getrennt) wird für alle ausgeführt
die Fälle, in denen der Datentyp der Operation ist jedem of die Typen, die dargestellt werden durch
die Buchstaben im Argument zum „Typ“, z

Code => '...

Typen(BSUL) %{
/* Ganzzahlige Operation ausführen */
%}
Typen(FD) %{
/* Gleitkommaoperation ausführen */
%}
... '

Der RedoDimsCode Abschnitt
Der Schlüssel „RedoDimsCode“ ist ein optionaler Schlüssel, der zum Berechnen der Abmessungen von Piddles verwendet wird
Laufzeit, falls die Standardregeln für die Berechnung von Dimensionen aus der Signatur nicht gelten
ausreichend. Der Inhalt des Eintrags „RedoDimsCode“ wird auf die gleiche Weise interpretiert
Der Codeabschnitt wird interpretiert-- dh, PP-Makros werden erweitert und das Ergebnis ist
als C-Code interpretiert. Der Zweck des Codes besteht darin, die Größe einiger Dimensionen festzulegen
erscheinen in der Signatur. Speicherzuweisung und Threadloops usw. werden als eingerichtet
wenn das berechnete Maß in der Signatur enthalten wäre. In Ihrem Code berechnen Sie zunächst
Wählen Sie dann die gewünschte Größe einer benannten Dimension in der Signatur entsprechend Ihren Anforderungen aus
Weisen Sie ihm diesen Wert über das $ zuGRÖSSE() Makro.

Betrachten Sie als Beispiel die folgende Situation. Sie stellen eine Schnittstelle zu einer externen Bibliothek her
Routine, die die Übergabe eines temporären Arrays für den Arbeitsbereich als Argument erfordert. Zwei
Eingabedaten-Arrays, die übergeben werden, sind p(m) und x(n). Das Ausgabedatenarray ist y(n). Der
Für die Routine ist ein Arbeitsbereich-Array mit einer Länge von n+m*m erforderlich, und Sie benötigen den Speicher
wird automatisch erstellt, genau wie es für jedes mit [t] oder [o] gekennzeichnete Piddle der Fall wäre. Was
Sie möchten etwas sagen wie

pp_def( "myexternalfunc",
Pars => " p(M); x(n); [o] y; [t] Arbeit(n+m*m); ", ...

aber das wird nicht funktionieren, weil PP keine Ausdrücke mit Arithmetik interpretieren kann
Unterschrift. Stattdessen schreibst du

pp_def( "myexternalfunc",
Pars => " p(M); x(n); [o] y; [t] Arbeit(wn); ",
RedoDimsCode => "
int im = $PDL(p)->dims[0];
int in = $PDL(x)->dims[0];
int min = in + im * im;
int inw = $PDL(work)->dims[0];
$SIZE(wn) = inw >= min ? inw: min; ",
Code => "
externalfunc($P(p),$P(x),$GRÖßE(m),$SIZE(n),$P(work));
";)

Dieser Code funktioniert wie folgt: Das Makro $PDL(p) wird zu einem Zeiger auf die pdl-Struktur für erweitert
das Piddle p. In diesem Fall benötigen Sie keinen Zeiger auf die Daten (z. B. $P), weil Sie
Ich möchte auf die Methoden für das Piddle auf der C-Ebene zugreifen. Sie erhalten die erste Dimension von
jedes der Rätsel und speichere sie in ganzen Zahlen. Dann berechnen Sie die Mindestlänge
Arbeitsarray sein kann. Wenn der Benutzer ein Piddle „Arbeit“ mit ausreichend Speicherplatz gesendet hat, dann belassen Sie es
allein. Wenn der Benutzer beispielsweise eine Null-PDL oder überhaupt keine PDL gesendet hat, beträgt die Größe von wn
Null und Sie setzen ihn auf den Minimalwert zurück. Bevor der Code im Abschnitt Code steht
Das ausgeführte PP erstellt den richtigen Speicher für „Arbeit“, falls dieser nicht vorhanden ist. Beachten Sie, dass Sie
Hat nur die erste Dimension von „p“ und „x“ angenommen, da der Benutzer möglicherweise Rätsel mit gesendet hat
zusätzliche Einfädelmaße. Natürlich funktioniert das temporäre Piddle (beachten Sie die [t]-Flagge)
sollten ohnehin keine Gewindemaße angegeben werden.

Sie können „RedoDimsCode“ auch verwenden, um die Dimension eines Piddles festzulegen, das mit [o] gekennzeichnet ist. In diesem
Falls Sie die Dimensionen für die benannte Dimension in der Signatur mit $ festlegenGRÖSSE() wie in
das vorangehende Beispiel. Da das Piddle jedoch mit [o] anstelle von [t] gekennzeichnet ist,
Gewindebemaßungen werden bei Bedarf hinzugefügt, genauso wie die Größe der Bemaßung
wird nach den üblichen Regeln aus der Signatur berechnet. Hier ist ein Beispiel von
PDL::Math

pp_def("polyroots",
Pars => 'cr(n); ci(n); [Ö]rr(M); [Ö]ri(M);',
RedoDimsCode => 'int sn = $PDL(cr)->dims[0]; $GRÖßE(m) = sn-1;',

Die Eingabefelder sind der Real- und Imaginärteil komplexer Koeffizienten von a
Polynom. Die ausgegebenen Rätsel sind reale und imaginäre Teile der Wurzeln. Es gibt „n“
Wurzeln auf ein Polynom „n“-ter Ordnung und ein solches Polynom hat „n+1“ Koeffizienten (die
zeoreth bis zum „n“ten). In diesem Beispiel funktioniert das Einfädeln korrekt. Das heißt, die
erste Abmessung des Ausgangszapfens mit angepasster Abmessung, aber anderes Gewinde
Dimensionen werden so zugewiesen, als ob kein „RedoDimsCode“ vorhanden wäre.

Typkarte Umgang in „AnderePars“ Abschnitt
Der oben besprochene Abschnitt „OtherPars“ ist sehr oft von entscheidender Bedeutung, wenn Sie
Schnittstelle zu externen Bibliotheken mit PDL. In vielen Fällen jedoch auch die externen Bibliotheken
Verwenden Sie abgeleitete Typen oder Zeiger verschiedener Typen.

Die Standardmethode, dies in Perl zu handhaben, ist die Verwendung einer „Typemap“-Datei. Dies wird in besprochen
einige Details zu Perlxs in der Standard-Perl-Dokumentation. Bei PP ist die Funktionalität sehr
ähnlich, sodass Sie eine „Typemap“-Datei in dem Verzeichnis erstellen können, in dem sich Ihre PP-Datei befindet
und wenn es erstellt wird, wird es automatisch eingelesen, um die entsprechende Übersetzung zu ermitteln
zwischen dem C-Typ und dem in Perl integrierten Typ.

Allerdings gibt es einige wichtige Unterschiede zur allgemeinen Handhabung von Typen
in XS. Das erste und wahrscheinlich wichtigste ist, dass es sich derzeit um Zeiger auf Typen handelt
im Abschnitt „OtherPars“ nicht zulässig. Um diese Einschränkung zu umgehen, müssen Sie die verwenden
Typ „IV“ (Danke an Judd Taylor für den Hinweis, dass dies für die Portabilität notwendig ist).

Es ist wahrscheinlich am besten, dies mit ein paar Codeausschnitten zu veranschaulichen:

Die Funktion „gsl_spline_init“ hat beispielsweise die folgende C-Deklaration:

int gsl_spline_init(gsl_spline * spline,
const double xa[], const double ya[], size_t size);

Offensichtlich sind die Arrays „xa“ und „ya“ Kandidaten für die Übergabe als Piddles und das
Das Argument „Größe“ ist nur die Länge dieser Piddles, die von verarbeitet werden können
Makro „$SIZE()“ in PP. Das Problem ist der Zeiger auf den Typ „gsl_spline“. Das Natürliche
Die Lösung wäre, eine „OtherPars“-Deklaration des Formulars zu schreiben

OtherPars => 'gsl_spline *spl'

und schreiben Sie eine kurze „Typemap“-Datei, die diesen Typ verarbeitet. Dies funktioniert derzeit nicht
Jedoch! Was Sie also tun müssen, ist, das Problem ein wenig (und in gewisser Weise) zu umgehen
das ist auch einfacher!):

Die Lösung besteht darin, „spline“ im Abschnitt „OtherPars“ mit einem „Integer Value“ zu deklarieren.
„IV“. Dies verbirgt die Natur der Variablen vor PP und Sie müssen dies (nun ja) vermeiden
(Zumindest Compiler-Warnungen!) Führen Sie eine Typumwandlung durch, wenn Sie die Variable in Ihrem Code verwenden.
Somit sollte „OtherPars“ die Form annehmen:

OtherPars => 'IV spl'

und wenn Sie es im Code verwenden, werden Sie schreiben

INT2PTR(gsl_spline *, $COMP(spl))

Dabei wurde das Perl-API-Makro „INT2PTR“ verwendet, um die zu vermeidende Zeigerumwandlung zu handhaben
Compilerwarnungen und Probleme für Maschinen mit gemischtem 32-Bit- und 64-Bit-Perl
Konfigurationen. Dies zusammensetzen, wie Andres Jordan es getan hat (mit der Modifikation
unter Verwendung von „IV“ von Judd Taylor) in „gsl_interp.pd“ in der Distributionsquelle erhalten Sie:

pp_def('init_meat',
Pars => 'double x(n); double y(n);',
OtherPars => 'IV spl',
Code =>'
gsl_spline_init,( INT2PTR(gsl_spline *, $COMP(spl)), $P(x),$P(y),$SIZE(n)));'
);

wo ich einen Makro-Wrapper-Aufruf entfernt habe, aber das würde die Diskussion verschleiern.

Der andere kleine Unterschied im Vergleich zur standardmäßigen Typemap-Verarbeitung in Perl besteht darin
Der Benutzer kann mit dem keine nicht standardmäßigen Typemap-Speicherorte oder Typemap-Dateinamen angeben
Option „TYPEMAPS“ in MakeMaker... Daher können Sie nur eine Datei namens „typemap“ und/oder verwenden
„IV“-Trick oben.

Andere nützlich PP Tasten in die Datenerfassung Betrieb Definitionen
Sie haben bereits von der Taste „OtherPars“ gehört. Derzeit gibt es nicht viele andere Schlüssel
für eine Datenoperation, die bei der normalen PP-Programmierung (was auch immer das ist) nützlich sein wird. In
Tatsächlich wäre es interessant, von einem Fall zu hören, in dem Sie denken, dass Sie mehr brauchen als das, was Sie brauchen
ist im Moment vorgesehen. Bitte melden Sie sich auf einer der PDL-Mailinglisten. Die meisten anderen
Von „pp_def“ erkannte Schlüssel sind nur für das, was wir aufrufen, wirklich nützlich Scheibe Geschäftstätigkeit (sehen
auch oben).

Eine Sache, die stark geplant ist, ist die variable Anzahl von Argumenten, die a sein werden
etwas knifflig.

Eine unvollständige Liste der verfügbaren Schlüssel:

An Ort und Stelle
Durch das Setzen dieses Schlüssels wird die Routine als In-Place-Arbeitsroutine markiert, d. h. als Ein- und Ausgabe
Rätsel sind die gleichen. Ein Beispiel ist „$a->inplace->sqrt()“ (oder „sqrt(inplace($a))“).

Inplace => 1
Verwenden Sie diese Option, wenn die Routine eine unäre Funktion ist, z. B. „sqrt“.

Inplace => ['a']
Wenn es mehr als ein Eingabepuzzle gibt, geben Sie den Namen des möglichen an
an Ort und Stelle mithilfe einer Array-Referenz geändert.

Inplace => ['a','b']
Wenn mehr als ein Ausgabe-Piddle vorhanden ist, geben Sie den Namen des Eingabe-Piddles an und
Ausgabe piddle in einer 2-Element-Array-Referenz. Dies wird wahrscheinlich nicht benötigt, bleibt aber bestehen
Der Vollständigkeit halber hier.

Wenn schlechte Werte verwendet werden, muss darauf geachtet werden, dass die Ausbreitung sichergestellt wird
Badflag, wenn Inplace verwendet wird; Betrachten Sie diesen Auszug aus Einfach/Schlecht/schlecht.pd:

pp_def('replacebad',HandleBad => 1,
Pars => 'a(); [o]b();',
OtherPars => 'double newval',
Inplace => 1,
CopyBadStatusCode =>
'/* Badflag propagieren, wenn es vorhanden ist UND es sich geändert hat */
if ( a == b && $ISPDLSTATEBAD(a) )
PDL->propogate_badflag( b, 0 );

/* Stellen Sie immer sicher, dass die Ausgabe „gut“ ist */
$SETPDLSTATEGOOD(b);
',
...

Da diese Routine alle fehlerhaften Werte entfernt, hatte das Ausgabe-Piddle sein fehlerhaftes Flag
gelöscht. Wenn es direkt ausgeführt wird (also „a == b“), müssen wir allen Kindern von „a“ mitteilen, dass
dass die fehlerhafte Flagge gelöscht wurde (um Zeit zu sparen, stellen wir sicher, dass wir anrufen
„PDL->propogate_badgflag“ nur, wenn für das Eingabe-Piddle das Bad-Flag gesetzt war.

HINWEIS: Eine Idee besteht darin, dass die Dokumentation für die Routine automatisch erfolgen könnte
markiert, um anzuzeigen, dass es inplace ausgeführt werden kann, also etwas Ähnliches wie „how“.
„HandleBad“ legt „BadDoc“ fest, wenn es nicht angegeben wird (dies ist keine ideale Lösung).

Andere PDL::PP Funktionen zu Support prägnant Paket Definition
Bisher haben wir die Funktionen „pp_def“ und „pp_done“ beschrieben. PDL::PP exportiert einige
weitere Funktionen, die Ihnen beim Schreiben prägnanter PDL-Erweiterungspaketdefinitionen helfen.

pp_addhdr

Wenn Sie wie im obigen Beispiel eine Schnittstelle zu Bibliotheksfunktionen herstellen, müssen Sie diese häufig einschließen
zusätzliche C-Include-Dateien. Da die XS-Datei von PP generiert wird, benötigen wir dazu einige Mittel
Lassen Sie PP die entsprechenden Include-Direktiven an der richtigen Stelle in das generierte XS einfügen
Datei. Hierzu gibt es die Funktion „pp_addhdr“. Dies ist auch die zu verwendende Funktion
wenn Sie einige C-Funktionen für die interne Verwendung durch einige der XS-Funktionen definieren möchten
(meistens handelt es sich um durch „pp_def“ definierte Funktionen). Durch die Einbeziehung dieser Funktionen hier können Sie
Stellen Sie sicher, dass PDL::PP Ihren Code vor der Stelle einfügt, an der sich das eigentliche XS-Modul befindet
Abschnitt beginnt und wird daher von xsubpp unberührt gelassen (vgl. perlxs und dem perlxstut
Manpages).

Ein typischer Anruf wäre

pp_addhdr('
#enthalten /* wir brauchen Defs von XXXX */
#include "libprotos.h" /* Prototypen von Bibliotheksfunktionen */
#include "mylocaldecs.h" /* Lokale Decs */

static void do_the real_work(PDL_Byte * in, PDL_Byte * out, int n)
{
/* einige Berechnungen mit den Daten durchführen */
}
');

Dadurch wird sichergestellt, dass alle benötigten Konstanten und Prototypen ordnungsgemäß enthalten sind
dass Sie die hier definierten internen Funktionen in den „pp_def“s verwenden können, z.B.:

pp_def('barfoo',
Pars => ' a(n); [o] b(n)',
GenericTypes => ['B'],
Code => ' int ns = $SIZE(n);
do_the_real_work($P(a),$P(b),ns);
',
);

pp_addpm

In vielen Fällen ist der eigentliche PP-Code (d. h. die Argumente für „pp_def“-Aufrufe) nur ein Teil davon
das Paket, das Sie gerade implementieren. Oft gibt es zusätzlichen Perl-Code und XS
Code, den Sie normalerweise in die PM- und XS-Dateien geschrieben hätten, werden jetzt automatisch erstellt
generiert durch PP. Wie bekommt man dieses Zeug also in diese dynamisch generierten Dateien?
Glücklicherweise gibt es ein paar Funktionen, die allgemein als „pp_addXXX“ bezeichnet werden und die Ihnen dabei helfen
dabei.

Nehmen wir an, Sie haben zusätzlichen Perl-Code, der in den generierten Code eingefügt werden soll pm-Datei. Das
lässt sich ganz einfach mit dem Befehl „pp_addpm“ erreichen:

pp_addpm(<<'EOD');

=head1 NAME

PDL::Lib::Mylib – eine PDL-Schnittstelle zur Mylib-Bibliothek

=head1 BESCHREIBUNG

Dieses Paket implementiert eine Schnittstelle zum Mylib-Paket mit full
Threading- und Indexierungsunterstützung (siehe L ).

= schneiden

benutze PGPLOT;

=head2 use_myfunc
Diese Funktion wendet die myfunc-Operation auf alle an
Elemente der Eingabe-PDL unabhängig von den Abmessungen
und gibt die Summe des Ergebnisses zurück
= schneiden

sub use_myfunc {
mein $pdl = Shift;

myfunc($pdl->clump(-1),($res=null));

return $res->sum;
}

ODL

pp_add_exported

Sie haben wahrscheinlich schon die Idee. In manchen Fällen möchten Sie auch Ihre zusätzlichen Daten exportieren
Funktionen. Um Probleme mit PP zu vermeiden, die auch mit @EXPORT herumspielen
Arrays weisen Sie PP einfach an, Ihre Funktionen zur Liste der exportierten Funktionen hinzuzufügen:

pp_add_exported('use_myfunc gethynx');

pp_add_isa

Der Befehl „pp_add_isa“ funktioniert wie die Funktion „pp_add_exported“. Die Argumente dazu
„pp_add_isa“ werden der @ISA-Liste hinzugefügt, z

pp_add_isa(' Some::Other::Class ');

pp_bless

Wenn Ihre pp_def-Routinen als Objektmethoden verwendet werden sollen, verwenden Sie „pp_bless“, um die anzugeben
Paket (d. h. Klasse), zu dem Sie gehören pp_defEd-Methoden werden hinzugefügt. Zum Beispiel,
"pp_bless('PDL::MyClass')". Der Standardwert ist „PDL“, wenn dies weggelassen wird.

pp_addxs

Manchmal möchten Sie zusätzlichen eigenen XS-Code hinzufügen (was im Allgemeinen nicht der Fall ist).
Alle Threading-/Indizierungsprobleme werden behoben, es werden jedoch andere Funktionen bereitgestellt, auf die Sie zugreifen möchten
von der Perl-Seite) in die generierte XS-Datei übertragen

pp_addxs('','

# Bestimmen Sie die Endianness der Maschine

int
isbigendian()
CODE:
unsigniertes kurzes i;
PDL_Byte *b;

ich = 42; b = (PDL_Byte*) (void*) &i;

wenn (*b == 42)
RETVAL = 0;
sonst wenn (*(b+1) == 42)
RETVAL = 1;
sonst
croak("Unmöglich - Maschine ist weder Big noch Little Endian!!\n");
AUSGABE:
WIEDERHOLUNG
');

Insbesondere „pp_add_exported“ und „pp_addxs“ sollten mit Vorsicht verwendet werden. PP verwendet
PDL::Exporter. Wenn Sie also PP Ihre Funktion exportieren lassen, bedeutet dies, dass sie dem hinzugefügt werden
Standardliste der standardmäßig exportierten Funktionen (die durch das Export-Tag definierte Liste).
„:Func“). Wenn Sie „pp_addxs“ verwenden, sollten Sie nicht versuchen, etwas zu tun, das Threading beinhaltet
oder direkt indizieren. PP ist viel besser darin, den entsprechenden Code aus Ihrem zu generieren
Definitionen.

pp_add_boot

Schließlich möchten Sie möglicherweise etwas Code zum BOOT-Abschnitt der XS-Datei hinzufügen (falls Sie dies nicht tun).
Weißt du, was das ist? perlxs). Dies geht ganz einfach mit dem Befehl „pp_add_boot“:

pp_add_boot(<
descrip = mylib_initialize(KEEP_OPEN);

if (descrip == NULL)
croak("Bibliothek kann nicht initialisiert werden");

GlobalStruc->descrip = descrip;
GlobalStruc->maxfiles = 200;
EOB

pp_export_nothing

Standardmäßig fügt PP.pm alle mit der pp_def-Funktion definierten Subs in die Ausgabe-.pm ein
der EXPORT-Liste der Datei. Dies kann zu Problemen führen, wenn Sie ein untergeordnetes Objekt erstellen
Sie möchten nicht, dass Methoden exportiert werden. (d. h. die Methoden werden nur mit aufgerufen
$object->Methodensyntax).

In diesen Fällen können Sie anrufen pp_export_nothing() um die Exportliste zu löschen. Beispiel (At
das Ende der .pd-Datei):

pp_export_nothing();
pp_done();

pp_core_importList

Standardmäßig setzt PP.pm die Option „use Core;“ Zeile in die .pm-Ausgabedatei. Dies importiert Cores
Exportierte Namen in den aktuellen Namespace, was zu Problemen führen kann, wenn Sie zu viele Namen haben.
Reiten einer der Core-Methoden in der aktuellen Datei. Am Ende erhalten Sie Nachrichten wie
„Warnung: sub sumover in Datei subclass.pm neu definiert“ beim Ausführen des Programms.

In diesen Fällen kann die pp_core_importList verwendet werden, um zu ändern, wovon importiert wird
Core.pm. Zum Beispiel:

pp_core_importList('()')

Dies würde zur Folge haben

Verwenden Sie Core();

wird in der .pm-Ausgabedatei generiert. Dies würde dazu führen, dass keine Namen importiert werden
Core.pm. Ebenso anrufen

pp_core_importList(' qw/ barf /')

würde dazu führen

benutze Core qw/ barf/;

wird in der .pm-Ausgabedatei generiert. Dies würde dazu führen, dass nur „Kotz“ importiert würde
von Core.pm.

pp_setversion

Ich bin mir ziemlich sicher, dass Sie dadurch gleichzeitig die .pm- und .xs-Dateien festlegen können.
Versionen, wodurch unnötige Versionsunterschiede zwischen den beiden vermieden werden. Um dies zu nutzen, müssen Sie es einfach haben
die folgende Zeile irgendwann in Ihrer .pd-Datei:

pp_setversion('0.0.3');

Verwenden Sie dies jedoch nicht, wenn Sie Module::Build::PDL verwenden. Weitere Informationen finden Sie in der Dokumentation dieses Moduls
Details.

pp_deprecate_module

Wenn ein bestimmtes Modul als veraltet gilt, kann diese Funktion verwendet werden, um es als veraltet zu markieren
veraltet. Dies hat zur Folge, dass eine Warnung ausgegeben wird, wenn ein Benutzer versucht, das zu „verwenden“.
Modul. Der generierte POD für dieses Modul enthält auch einen Verfallshinweis. Der
Das Ersatzmodul kann wie folgt als Argument übergeben werden:

pp_deprecate_module( infavor => "PDL::NewNonDeprecatedModule" );

Beachten Sie, dass die Funktion Auswirkungen hat einzige die Laufzeitwarnung und den POD.

Making deine PP Funktion "Privat"


Nehmen wir an, Sie haben in Ihrem Modul eine Funktion namens PDL::foo, die das PP verwendet
Funktion „bar_pp“, um die schwere Arbeit zu erledigen. Aber Sie möchten nicht für „bar_pp“ werben.
existiert. Dazu müssen Sie dann Ihre PP-Funktion an den Anfang Ihrer Moduldatei verschieben
rufen Sie uns an!

pp_export_nothing()

um die „EXPORT“-Liste zu löschen. Um sicherzustellen, dass keine Dokumentation (auch nicht die Standard-PP-Dokumente) vorhanden ist
generiert, gesetzt

Doc => undef

und um zu verhindern, dass die Funktion zur Symboltabelle hinzugefügt wird, setzen Sie

PMFunc => ''

in Ihrer pp_def-Deklaration (siehe Image2D.pd für ein Beispiel). Dies wird effektiv funktionieren
Ihre PP-Funktion „privat“. Wie auch immer es ist immer zugänglich über PDL::bar_pp aufgrund von Perl
Moduldesign. Wenn Sie es jedoch privat machen, wird der Benutzer sich sehr weit von seiner Privatsphäre entfernen
Art, es zu nutzen, sodass er oder sie die Konsequenzen tragen muss!

Slice Betrieb


Der Abschnitt zur Slice-Operation in diesem Handbuch basiert auf Datenfluss und verzögerter Auswertung:
Wenn Sie es brauchen, bitten Sie Tjl, es zu schreiben. eine Lieferung innerhalb einer Woche nach Erhalt der E-Mail
ist zu 95 % wahrscheinlich und eine Lieferung in zwei Wochen ist zu 99 % wahrscheinlich.

Und überhaupt erfordern die Slice-Operationen eine viel tiefergehende Kenntnis der PDL-Interna
als die Datenoperationen. Darüber hinaus ist die Komplexität der damit verbundenen Probleme
deutlich höher als im durchschnittlichen Datenbetrieb. Wenn Sie überzeugen möchten
Werfen Sie einen Blick auf diese Tatsache Basic/Slices/slices.pd Datei im PDL
Verteilung :-). Dennoch sind Funktionen, die mit den Slice-Operationen generiert wurden, am
Herzstück der Indexmanipulations- und Datenflussfunktionen von PDL.

Außerdem gibt es viele schmutzige Probleme mit virtuellen Piddles und Vaffines, auf die wir noch eingehen werden
hier komplett überspringen.

Scheiben und dem Badewanne Werte
Slice-Operationen müssen in der Lage sein, fehlerhafte Werte zu verarbeiten (sofern die Unterstützung in PDL kompiliert ist).
Am einfachsten ist es anzuschauen Basic/Slices/slices.pd um zu sehen, wie das funktioniert.

Neben „BadCode“ gibt es auch die Schlüssel „BadBackCode“ und „BadRedoDimsCode“.
„pp_def“. Allerdings sollte jeder „EquivCPOffsCode“ nicht müssen geändert werden, da Änderungen möglich sind
in die Definition des Makros „$EQUIVCPOFFS()“ aufgenommen (d. h. behandelt).
automatisch durch PDL::PP>.

A wenige merkt an on Schreiben a Aufschneiden Routine...
In den folgenden Absätzen wird das Schreiben einer neuen Slicing-Routine („Bereich“) beschrieben. beliebig
Fehler sind CEDs. (--CED 26)

Handling of "warnen" und dem "Kotzen" in PP Code


Zum Drucken von Warnmeldungen oder zum Abbrechen/Sterben können Sie von PP aus „warn“ oder „barf“ aufrufen
Code. Sie sollten sich jedoch darüber im Klaren sein, dass diese Aufrufe mithilfe von C neu definiert wurden
Präprozessormakros zu „PDL->barf“ und „PDL->warn“. Diese Neudefinitionen sind vorhanden
verhindern, dass Sie versehentlich Perls „warn“ oder „barf“ direkt aufrufen, was zu Problemen führen kann
Segfaults beim Pthreading (z. B. Prozessor-Multithreading).

PDLs eigene Versionen von „barf“ und „warn“ stellen Warn- oder Barf-Nachrichten in die Warteschlange bis danach
Das Pthreading ist abgeschlossen und dann werden die Perl-Versionen dieser Routinen aufgerufen.

Weitere Informationen zum P-Threading finden Sie unter PDL::ParallelCPU.

SINNVOLL ROUTINEN


Die PDL-„Kern“-Struktur, definiert in Basic/Core/pdlcore.h.PL, enthält Zeiger auf a
Anzahl der Routinen, die für Sie nützlich sein können. Die meisten dieser Routinen befassen sich mit
Manipulation von Rätseln, aber einige sind allgemeiner:

PDL->qsort_B( PDL_Byte *xx, int a, int b )
Sortieren Sie das Array „xx“ zwischen den Indizes „a“ und „b“. Es gibt auch Versionen für
andere PDL-Datentypen mit den Postfixen „_S“, „_U“, „_L“, „_F“ und „_D“. Jedes Modul, das verwendet
Dies muss sicherstellen, dass „PDL::Ufunc“ geladen wird.

PDL->qsort_ind_B( PDL_Byte *xx, int *ix, int a, int b )
Wie bei „PDL->qsort_B“, aber dieses Mal werden die Indizes und nicht die Daten sortiert.

Die Routine „med2d“ in Lib/Image2D/image2d.pd zeigt, wie solche Routinen verwendet werden.

MAKEFILES FÜR PP DATEIEN


Wenn Sie ein Paket aus Ihrer PP-Datei generieren möchten (typische Dateierweiterungen sind
„.pd“ oder „.pp“ für Dateien mit PP-Code) ist es am einfachsten und sichersten, sie zu belassen
Generierung der entsprechenden Befehle für das Makefile. Im Folgenden skizzieren wir
das typische Format eines Perl-Makefiles, aus dem Ihr Paket automatisch erstellt und installiert wird
eine Beschreibung in einer PP-Datei. Die meisten Regeln zum Erstellen der XS-, PM- und anderen erforderlichen Dateien
aus der PP-Datei sind bereits im PDL::Core::Dev-Paket vordefiniert. Wir müssen es einfach tun
Weisen Sie MakeMaker an, es zu verwenden.

In den meisten Fällen können Sie Ihr Makefile wie folgt definieren

# Makefile.PL für ein durch PP-Code definiertes Paket.

benutze PDL::Core::Dev; # Holen Sie sich Entwicklungsdienstprogramme
verwenden Sie ExtUtils::MakeMaker;

$package = ["mylib.pd",Mylib,PDL::Lib::Mylib];
%hash = pdlpp_stdargs($package);
$hash{OBJECT} .= ' zusätzlicher_Ccode$(OBJ_EXT) ';
$hash{clean}->{FILES} .= ' todelete_Ccode$(OBJ_EXT) ';
$hash{'VERSION_FROM'} = 'mylib.pd';
WriteMakefile(%hash);

sub MY::postamble { pdlpp_postamble($package); }

Hier ist die Liste in $package: zuerst: Name der PP-Quelldatei, dann das Präfix für
erzeugte Dateien und schließlich den gesamten Paketnamen. Sie können den Hash beliebig ändern
wie Sie möchten, aber es wäre vernünftig, innerhalb einiger Grenzen zu bleiben, damit Ihr Paket
wird weiterhin mit späteren Versionen von PDL funktionieren.

Wenn Sie keine vorgefertigten Argumente verwenden möchten, finden Sie hier ein generisches Argument Makefile.PL dass du kannst
Passen Sie es an Ihre eigenen Bedürfnisse an:

# Makefile.PL für ein durch PP-Code definiertes Paket.

benutze PDL::Core::Dev; # Holen Sie sich Entwicklungsdienstprogramme
verwenden Sie ExtUtils::MakeMaker;

WriteMakefile(
'NAME' => 'PDL::Lib::Mylib',
'VERSION_FROM' => 'mylib.pd',
'TYPEMAPS' => [&PDL_TYPEMAP()],
'OBJECT' => 'mylib$(OBJ_EXT) zusätzlicher_Ccode$(OBJ_EXT)',
'PM' => { 'Mylib.pm' => '$(INST_LIBDIR)/Mylib.pm'},
'INC' => &PDL_INCLUDE(), # Include-Verzeichnisse hinzufügen, wie von Ihrer Bibliothek benötigt
'LIBS' => [''], # Link-Anweisungen nach Bedarf hinzufügen
'clean' => {'FILES' =>
'Mylib.pm Mylib.xs Mylib$(OBJ_EXT)
zusätzlicher_Ccode$(OBJ_EXT)'},
);

# Genpp-Regel hinzufügen; Dadurch wird PDL::PP für unsere PP-Datei aufgerufen
# Das Argument ist eine Array-Referenz, wobei das Array drei String-Elemente enthält:
# arg1: Name der Quelldatei, die den PP-Code enthält
# arg2: Basisname der zu generierenden xs- und pm-Dateien
# arg3: Name des Pakets, das generiert werden soll
sub MY::postamble { pdlpp_postamble(["mylib.pd",Mylib,PDL::Lib::Mylib]); }

Um das Leben noch einfacher zu machen, definiert PDL::Core::Dev die Funktion „pdlpp_stdargs“, die zurückgibt
ein Hash mit Standardwerten, der übergeben werden kann (entweder direkt oder nach entsprechender
Änderung) zu einem Aufruf von WriteMakefile. Derzeit gibt „pdlpp_stdargs“ einen Hash zurück, wo
Die Schlüssel werden wie folgt ausgefüllt:

(
'NAME' => $mod,
'TYPEMAPS' => [&PDL_TYPEMAP()],
'OBJECT' => "$pref\$(OBJ_EXT)",
PM => {"$pref.pm" => "\$(INST_LIBDIR)/$pref.pm"},
MAN3PODS => {"$src" => "\$(INST_MAN3DIR)/$mod.\$(MAN3EXT)"},
'INC' => &PDL_INCLUDE(),
'LIBS' => [''],
'clean' => {'FILES' => "$pref.xs $pref.pm $pref\$(OBJ_EXT)"},
)

Dabei ist $src der Name der Quelldatei mit PP-Code, $pref das Präfix für den generierten
.pm- und .xs-Dateien und $mod der Name des zu generierenden Erweiterungsmoduls.

INTERN


Die Interna der aktuellen Version bestehen aus einer großen Tabelle, die die Regeln enthält
nach denen Dinge übersetzt werden und die Subs, die diese Regeln umsetzen.

Später wäre es sinnvoll, die Tabelle vom Benutzer modifizieren zu lassen, damit sie anders ist
Dinge können ausprobiert werden.

[Meta-Kommentar: Hier wird es hoffentlich in Zukunft mehr geben; Derzeit ist Ihre beste Wahl
um den Quellcode zu lesen :-( oder fragen Sie in der Liste nach (versuchen Sie zuerst Letzteres) ]

Anhang A: Manche Tasten anerkannte by PDL::PP


Sofern nicht anders angegeben, handelt es sich bei den Argumenten um Zeichenfolgen. Mit (schlecht) gekennzeichnete Schlüssel sind nur
Wird verwendet, wenn die Unterstützung für schlechte Werte in PDL kompiliert wird.

Pars
Definieren Sie die Signatur Ihrer Funktion

AnderePars
Argumente, die keine PDLs sind. Standard: nichts. Dies ist eine durch Semikolons getrennte Liste von
Argumente, z. B. „OtherPars=>'int k; double value; char* fd'“. Siehe $COMP(x) und auch
derselbe Eintrag in Anhang B.

Code
der eigentliche Code, der die Funktionalität implementiert; mehrere PP-Makros und PP-Funktionen
werden im Stringwert erkannt

HandleBad (schlecht)
Wenn der Wert auf 1 gesetzt ist, wird davon ausgegangen, dass die Routine fehlerhafte Werte und den Code im BadCode unterstützt
Schlüssel wird verwendet, wenn fehlerhafte Werte vorhanden sind; Es richtet auch die Dinge so ein, dass „$ISBAD()“
usw. Makros können verwendet werden. Wenn der Wert auf 0 gesetzt ist, wird die Routine veranlasst, eine Warnung auszudrucken, falls einer der folgenden Punkte vorliegt
Die Eingabe-Piddles haben ihr Bad-Flag gesetzt.

BadCode (schlecht)
Geben Sie den Code an, der verwendet werden soll, wenn in den Eingabefeldern fehlerhafte Werte vorhanden sein könnten. Nur verwendet
wenn „HandleBad => 1“.

GenericTypes
Eine Array-Referenz. Das Array kann eine beliebige Teilmenge der einstelligen Zeichenfolgen „B“ enthalten.
„S“, „U“, „L“, „Q“, „F“ und „D“, die angeben, welche Typen Ihr Betrieb akzeptiert.
Die Bedeutung jedes Typs ist:

B – vorzeichenbehaftetes Byte (d. h. vorzeichenbehaftetes Zeichen)
S – vorzeichenbehaftet kurz (Zwei-Byte-Ganzzahl)
U – Kurzschluss ohne Vorzeichen
L – vorzeichenbehaftet lang (Vier-Byte-Ganzzahl, int auf 32-Bit-Systemen)
Q – vorzeichenbehaftet lang lang (acht Byte Ganzzahl)
F – schweben
D - doppelt

Dies ist sehr nützlich (und wichtig!) bei der Anbindung einer externen Bibliothek. Standard:
[qw/BSULQFD/]

An Ort und Stelle
Markieren Sie eine Funktion als arbeitsfähig.

Inplace => 1 if Pars => 'a(); [o]b();'
Inplace => ['a'] if Pars => 'a(); B(); [o]c();'
Inplace => ['a','b'] if Pars => 'a(); B(); [o]c(); [o]d();'

Wenn schlechte Werte verwendet werden, muss darauf geachtet werden, dass die Ausbreitung sichergestellt wird
Badflag, wenn Inplace verwendet wird; Siehe zum Beispiel den Code für „replacebad“ in
Einfach/Schlecht/schlecht.pd.

Doc Wird verwendet, um eine Dokumentationszeichenfolge im Pod-Format anzugeben. Weitere Informationen finden Sie unter PDL::Doc
PDL-Dokumentationskonventionen. Hinweis: Im Sonderfall handelt es sich um die PP-Zeichenfolge „Doc“.
eine Zeile, die implizit für die Kurzreferenz UND die Dokumentation verwendet wird!

Wenn das Feld „Doc“ weggelassen wird, generiert PP eine Standarddokumentation (nach allem, was es weiß).
über die Signatur).

Wenn Sie wirklich möchten, dass die Funktion an dieser Stelle NICHT in irgendeiner Weise dokumentiert wird (z
für eine interne Routine oder weil Sie es an anderer Stelle im Code tun) explizit
Geben Sie „Doc=>undef“ an.

BadDoc (schlecht)
Enthält den vom Befehl „badinfo“ (in „perldl“) oder dem Schalter „-b“ zurückgegebenen Text
zum Shell-Skript „pdldoc“. In vielen Fällen müssen Sie dies nicht angeben, da
Die Informationen können automatisch von PDL::PP erstellt werden. Allerdings, wie es sich für Computer gehört,
generierter Text, er ist eher gestelzt; Vielleicht ist es viel besser, es selbst zu machen!

NoPthread
Optionales Flag, um anzugeben, dass die PDL-Funktion ausgeführt werden soll nicht Verwenden Sie Prozessor-Threads (d. h
pthreads oder POSIX-Threads), um die Arbeit auf mehrere CPU-Kerne aufzuteilen. Diese Option ist
Wird normalerweise auf 1 gesetzt, wenn die zugrunde liegende PDL-Funktion nicht threadsicher ist. Wenn diese Option
nicht vorhanden ist, wird davon ausgegangen, dass die Funktion threadsicher ist. Diese Option gilt nur
wenn PDL mit aktivierten POSIX-Threads kompiliert wurde.

PMCode
Mit PDL-Funktionen können Sie ein Piddle übergeben, in dem die Ausgabe gespeichert werden soll. Das
ist praktisch, weil Sie ein Ausgabe-Piddle einmal zuweisen und es viele Male wiederverwenden können; Die
Eine Alternative wäre, dass PDL jedes Mal ein neues Piddle erstellt, was möglicherweise Rechenleistung verschwendet
Zyklen oder, wahrscheinlicher, RAM. Diese zusätzliche Flexibilität geht mit höheren Kosten einher
Komplexität: PDL::PP muss Funktionen schreiben, die intelligent genug sind, um die zu zählen
übergebene Argumente und erstellen im Handumdrehen neue Rätsel, aber nur, wenn Sie sie möchten.

PDL::PP ist intelligent genug, dies zu tun, es gibt jedoch Einschränkungen hinsichtlich der Argumentreihenfolge und
dergleichen. Wenn Sie eine flexiblere Funktion wünschen, können Sie Ihre eigene Perl-Seite schreiben
Wrapper und geben Sie ihn im PMCode-Schlüssel an. Die von Ihnen angegebene Zeichenfolge muss (sollte)
Definieren Sie eine Perl-Funktion mit einem Namen, der dem entspricht, den Sie pp_def im ersten Schritt gegeben haben
Ort. Wenn Sie die PP-generierte Funktion schließlich aufrufen möchten, müssen Sie dies tun
Geben Sie alle Piddles in der genauen Reihenfolge an, die in der Signatur angegeben ist: Ausgabepiddles sind
nicht optional, und die PP-generierte Funktion gibt nichts zurück. Das Verschleierte
Der Name, den Sie anrufen werden, ist _ _int.

Ich glaube, dass diese Dokumentation weiterer Klärung bedarf, aber das muss genügen.
:-(

PMFunc
Wenn pp_def Funktionen generiert, definiert es diese normalerweise im PDL-Paket. Dann,
In der .pm-Datei, die für Ihr Modul generiert wird, wird normalerweise eine Zeile hinzugefügt
Kopiert diese Funktion im Wesentlichen mit Code in die Symboltabelle Ihres aktuellen Pakets
das sieht so aus:

*func_name = \&PDL::func_name;

Es ist ein bisschen schlauer (es weiß, wann man so etwas in ein Paket packen muss).
BEGIN-Block zum Beispiel, und wenn Sie für pp_bless etwas anderes angegeben haben), aber
Das ist der Kern davon. Wenn Sie die Funktion nicht in Ihr aktuelles importieren möchten
Sie können die Symboltabelle des Pakets angeben

PMFunc => '',

PMFunc hat keine weiteren Nebenwirkungen, sodass Sie damit beliebigen Perl-Code einfügen können
in Ihr Modul integrieren, wenn Sie möchten. Sie sollten jedoch pp_addpm verwenden, wenn Sie Perl hinzufügen möchten
Code zu Ihrem Modul hinzufügen.

Anhang B: PP Makros und dem Funktionen


Makros
Mit (bad) gekennzeichnete Makros werden nur verwendet, wenn die Unterstützung für schlechte Werte in PDL kompiliert ist.

$Variablenname_von_sig()
Greifen Sie auf ein PDL (anhand seines Namens) zu, das in der Signatur angegeben wurde

$COMP(x)
Greifen Sie auf einen Wert in der privaten Datenstruktur dieser Transformation zu (wird hauptsächlich dazu verwendet).
Verwenden Sie ein Argument, das im Abschnitt „OtherPars“ angegeben ist)

$SIZE(n)
zur Laufzeit durch die tatsächliche Größe von a ersetzt namens Maß (wie in der angegeben).
Stempel, Unterschrift)

$GENERISCH()
durch den C-Typ ersetzt, der dem Laufzeittyp der Operation entspricht

$P(a) ein Zeigerzugriff auf die PDL mit dem Namen „a“ in der Signatur. Nützlich für die Anbindung an C
Funktionen

$PP(a) ein physischer Zeigerzugriff auf pdl „a“; hauptsächlich für den internen Gebrauch

$TXXX(Alternative,Alternative)
Erweiterungsalternativen entsprechend der Laufzeitart der Operation, wobei XXX für einige steht
Zeichenfolge, die mit „/[BSULFD+]/“ übereinstimmt.

$PDL(a)
einen Zeiger auf die pdl-Datenstruktur (pdl *) von piddle „a“ zurückgeben

$ISBAD(a()) (schlecht)
gibt true zurück, wenn der in „a()“ gespeicherte Wert dem ungültigen Wert für dieses Piddle entspricht.
Erfordert die Einstellung von „HandleBad“ auf 1.

$ISGOOD(a()) (schlecht)
gibt true zurück, wenn der in „a()“ gespeicherte Wert nicht dem fehlerhaften Wert dafür entspricht
pinkeln. Erfordert die Einstellung von „HandleBad“ auf 1.

$SETBAD(a()) (schlecht)
Setzt „a()“ auf den schlechten Wert für dieses Rätsel. Erfordert die Einstellung von „HandleBad“.
um 1.

Funktionen
„loop(DIMS) %{ ... %}“
Schleife über benannte Dimensionen; Limits werden von PP automatisch generiert

„Threadloop %{ ... %}“
Schließen Sie den folgenden Code in eine Thread-Schleife ein

„types(TYPES) ​​%{ ... %}“
Führen Sie den folgenden Code aus, wenn der Operationstyp einer von „TYPES“ ist.

Anhang C: Funktionen importiert by PDL::PP


Eine Reihe von Funktionen werden importiert, wenn Sie „PDL::PP verwenden“. Dazu gehören Funktionen, die
Steuern Sie den generierten C- oder XS-Code, Funktionen, die den generierten Perl-Code steuern, und
Funktionen, die die Pakete und Symboltabellen manipulieren, in denen der Code erstellt wird.

Erzeugen von C und dem XS Code
Der Hauptzweck von PDL::PP besteht darin, es Ihnen leicht zu machen, die Threading-Engine um Sie herum zu wickeln
eigenen C-Code, aber Sie können auch einige andere Dinge tun.

pp_def
Wird verwendet, um die Threading-Engine um Ihren C-Code zu wickeln. Praktisch das gesamte Dokument
diskutiert die Verwendung von pp_def.

pp_done
Zeigt an, dass Sie mit PDL::PP fertig sind und dass die .xs- und .pm-Dateien generiert werden sollen
basierend auf den anderen pp_*-Funktionen, die Sie aufgerufen haben. Diese Funktion benötigt keine
Argumente.

pp_addxs
Auf diese Weise können Sie XS-Code zu Ihrer .xs-Datei hinzufügen. Dies ist nützlich, wenn Sie Perl-Dateien erstellen möchten.
zugängliche Funktionen, die C-Code aufrufen, aber das Threading nicht aufrufen können oder sollten
Motor. XS ist die Standardmethode, mit der Sie perl-zugänglichen C-Code umschließen. Du kannst
Erfahren Sie mehr bei perlxs.

pp_add_boot
Diese Funktion fügt die Zeichenfolge hinzu, die Sie an den XS BOOT-Abschnitt übergeben. Der BOOT-Bereich
ist C-Code, der von Perl aufgerufen wird, wenn Ihr Modul geladen wird und nützlich ist für
automatische Initialisierung. Mehr über XS und den BOOT-Bereich erfahren Sie bei perlxs.

pp_addhdr
Fügt Ihrer XS-Datei reinen C-Code hinzu. XS-Dateien sind so strukturiert, dass reiner C-Code erforderlich ist
kommen vor XS-Spezifikationen. Dadurch können Sie einen solchen C-Code angeben.

pp_boundscheck
PDL überprüft normalerweise die Grenzen Ihrer Zugriffe, bevor sie diese durchführen. Das kannst du umdrehen
zur Laufzeit ein- oder ausschalten, indem Sie MyPackage::set_boundscheck festlegen. Mit dieser Funktion können Sie
um diese Laufzeitflexibilität zu entfernen und niemals Überprüfen Sie die Grenzen. Es gibt auch die zurück
aktueller Grenzüberprüfungsstatus, wenn ohne Argumente aufgerufen.

HINWEIS: Ich habe in anderen Dokumentationen nichts über die Überprüfung von Grenzen gefunden. Das
muss angesprochen werden.

Erzeugen von Perl Code
Viele Funktionen, die bei Verwendung von PDL::PP importiert werden, ermöglichen es Ihnen, den Inhalt von zu ändern
generierte .pm-Datei. Zusätzlich zu pp_def und pp_done spielen diese Funktionen folgende Rolle:
hauptsächlich, um Code zu verschiedenen Teilen Ihrer generierten .pm-Datei hinzuzufügen.

pp_addpm
Fügt Perl-Code zur generierten .pm-Datei hinzu. PDL::PP verfolgt tatsächlich drei
verschiedene Abschnitte des generierten Codes: oben, in der Mitte und unten. Du kannst hinzufügen
Perl-Code in den mittleren Abschnitt unter Verwendung der Ein-Argument-Form, wobei das Argument das ist
Perl-Code, den Sie bereitstellen möchten. In der Form mit zwei Argumenten ist das erste Argument ein
anonymer Hash mit nur einem Schlüssel, der angibt, wo das zweite Argument abgelegt werden soll,
Dies ist die Zeichenfolge, die Sie der .pm-Datei hinzufügen möchten. Der Hash ist einer davon
Drei:

{At => 'Top'}
{At => 'Mitte'}
{At => 'Bot'}

Beispielsweise:

pp_addpm({At => 'Bot'}, <

=head1 Etwas Dokumentation

Ich weiß, dass ich das mitten in meine Datei schreibe, aber es geht weiter
der untere.

= schneiden

POD

Warnung: Wenn Sie in der Mitte Ihrer .pd-Datei die dafür bestimmte Dokumentation einfügen
Unten in Ihrem Pod werden Sie CPAN gründlich verwirren. Wenn andererseits in der
In der Mitte Ihrer .pd-Datei fügen Sie etwas Perl-Code hinzu, der für den unteren oder oberen Rand Ihrer Datei bestimmt ist
.pm-Datei, Sie müssen sich nur selbst verwirren. :-)

pp_beginwrap
Fügt den BEGIN-Blockumbruch hinzu. Bestimmte Deklarationen können jedoch in BEGIN-Blöcke eingeschlossen werden
Das Standardverhalten besteht darin, keinen solchen Umbruch zu haben.

pp_addbegin
Legt den Code fest, der am Anfang Ihrer .pm-Datei hinzugefügt wird, auch über dem von Ihnen angegebenen Code
mit „pp_addpm({At => ‚Top‘}, ...)“. Im Gegensatz zu pp_addpm überschreibt der Aufruf alles
war schon mal da. Im Allgemeinen sollten Sie es wahrscheinlich nicht verwenden.

Tracking Line Zahlen
Wenn Sie Kompilierungsfehler erhalten, entweder von Ihrem C-ähnlichen Code oder Ihrem Perl-Code, kann dies hilfreich sein
um diese Fehler auf die Zeilennummern in der Quelldatei zurückzuführen, bei denen der Fehler aufgetreten ist
auftrat.

pp_line_numbers
Benötigt eine Zeilennummer und eine (normalerweise lange) Codezeichenfolge. Die Zeilennummer sollte
Geben Sie die Zeile an, in der das Zitat beginnt. Dies ist normalerweise Perls „__LINE__“
Literal, es sei denn, Sie verwenden Heredocs. In diesem Fall ist es „__LINE__ + 1“. Der
Die zurückgegebene Zeichenfolge enthält dazwischenliegende #line-Direktiven, um dem Compiler bei der Fehlermeldung zu helfen
auf der richtigen Linie.

Ändern Symbol Tisch und dem Exportieren Verhalten
PDL::PP exportiert normalerweise alle mit pp_def generierten Funktionen und installiert sie normalerweise
in die PDL-Symboltabelle eingefügt. Sie können dieses Verhalten jedoch mit diesen Funktionen ändern.

pp_bless
Legt das Paket (Symboltabelle) fest, zu dem der XS-Code hinzugefügt wird. Der Standardwert ist PDL.
Das ist im Allgemeinen das, was Sie wollen. Wenn Sie den Standardsegen verwenden und einen erstellen
Funktion myfunc, dann können Sie Folgendes tun:

$piddle->myfunc( );
PDL::myfunc($piddle, );

Wenn Sie Ihre Funktionen hingegen in ein anderes Paket übertragen, können Sie sie nicht aufrufen
sie als PDL-Methoden und müssen sie wie folgt aufrufen:

MyPackage::myfunc($piddle, );

Natürlich können Sie jederzeit die PMFunc-Taste verwenden, um Ihre Funktion zum PDL-Symbol hinzuzufügen
Tisch, aber warum?

pp_add_isa
Fügt der Liste der Module hinzu, aus denen Sie stammen Modulen erbt. Die Standardliste ist

qw(PDL::Exporter DynaLoader)

pp_core_importlist
Am Anfang Ihrer generierten .pm-Datei befindet sich eine Zeile, die wie folgt aussieht:

benutze PDL::Core;

Sie können dies ändern, indem Sie eine Zeichenfolge für pp_core_importlist angeben. Zum Beispiel,

pp_core_importlist('::Blarg');

wird darin enden, dass

benutze PDL::Core::Blarg;

Sie können dies beispielsweise verwenden, um eine Liste von Symbolen hinzuzufügen, die aus PDL::Core importiert werden sollen. Für
Beispiel:

pp_core_importlist(" ':Internal'");

führt zu der folgenden Verwendungsanweisung:

use PDL::Core ':Internal';

pp_setversion
Legt die Version Ihres Moduls fest. Die Version muss zwischen .xs und .pm konsistent sein
Datei und wird verwendet, um sicherzustellen, dass Ihre Perl-Bibliotheken nicht unter der Version leiden
verzerren.

pp_add_exported
Fügt alle von Ihnen vergebenen Namen zur Exportliste hinzu. Mit pp_def erstellte Funktionen
werden automatisch zur Liste hinzugefügt. Diese Funktion ist nützlich, wenn Sie Perl definieren
Funktionen mit pp_addpm oder pp_addxs, die Sie ebenfalls exportieren möchten.

pp_export_nothing
Dadurch wird die Liste der exportierten Symbole auf nichts zurückgesetzt. Das nennt man wahrscheinlich besser
„pp_export_clear“, da Sie exportierte Symbole nach dem Aufruf hinzufügen können
„pp_export_nothing“. Wenn es kurz vor dem Aufruf von pp_done aufgerufen wird, stellt dies sicher, dass Ihr
Das Modul exportiert nichts, wenn Sie beispielsweise möchten, dass Programmierer nur Ihr Modul verwenden
Funktionen als Methoden.

Verwenden Sie PDL::PPp online über die Dienste von onworks.net


Kostenlose Server & Workstations

Laden Sie Windows- und Linux-Apps herunter

Linux-Befehle

Ad