Skip to content

Commit

Permalink
Add and utilise intermediate domNode role
Browse files Browse the repository at this point in the history
It saves having to nativecast in some cases, e.g. getElementsByTagName()
runs about 25% faster.
  • Loading branch information
dwarring committed Feb 18, 2023
1 parent 85afeed commit e48ba34
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 21 deletions.
2 changes: 2 additions & 0 deletions lib/LibXML/Item.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ also does LibXML::Types::Itemish;
also does LibXML::Types::XPathish;
also does LibXML::_Configurable;

method raw { itemNode }

sub box-class($_) is export(:box-class) {
::?CLASS.box-class($_)
}
Expand Down
10 changes: 6 additions & 4 deletions lib/LibXML/Node/Set.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,20 @@ has LibXML::Item $.of;
has Bool $.deref;
has xmlNodeSet $.raw;
has $!hstore;
has CArray $!nodeTab;

submethod TWEAK {
$!raw //= xmlNodeSet.new;
$!raw //= xmlNodeSet.new;
.Reference given $!raw;
$!nodeTab = nativecast(CArray[$!of.raw], $!raw.nodeTab);
}
submethod DESTROY {
.Unreference with $!raw;
}

method elems is also<size Numeric> { $!raw.nodeNr }
method Seq returns Seq handles<Array list values map grep> {
my CArray $tab := $!raw.nodeTab;
(^$!raw.nodeNr).map: { $!of.box: $tab[$_], :$.config };
(^$!raw.nodeNr).map: { $!of.box: $!nodeTab[$_], :$.config };
}

method Hash handles <AT-KEY keys pairs> {
Expand All @@ -49,14 +50,15 @@ method Hash handles <AT-KEY keys pairs> {
method AT-POS(UInt:D $pos) {
$pos >= $!raw.nodeNr
?? $!of
!! $!of.box($!raw.nodeTab[$pos], :$.config);
!! $!of.box($!nodeTab[$pos], :$.config);
}
method add(LibXML::Item:D $node) is also<push> {
constant Ref = 1;
fail "node has wrong type {$node.WHAT.raku} for node-set of type: {$!of.WHAT}"
unless $node ~~ $!of;
$!hstore= Nil;
$!raw.push($node.raw.ItemNode, Ref);
$!nodeTab = nativecast(CArray[$!of.raw], $!raw.nodeTab);
$node;
}
method pop {
Expand Down
39 changes: 29 additions & 10 deletions lib/LibXML/Raw.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -1023,10 +1023,20 @@ class xmlNode is anyNode {
method domSetNamespaceDeclPrefix(xmlCharP $prefix, xmlCharP $ns-prefix --> int32) is native($BIND-XML2) {*}
}

role domNode[$class, UInt:D $type] is export {
@ClassMap[$type] = $class;
method delegate {
fail "expected node of type $type, got {self.type}"
unless self.type == $type;
self
}
}


#| xmlNode of type: XML_ELEMENT_NODE
class xmlElem is xmlNode is export does LibXML::Raw::DOM::Element {
BEGIN @ClassMap[XML_ELEMENT_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_ELEMENT_NODE];

method NewNs(xmlCharP $href, xmlCharP $prefix --> xmlNs) is native($XML2) is symbol('xmlNewNs') {*};
method SetProp(Str, Str --> xmlAttr) is native($XML2) is symbol('xmlSetProp') {*}
method domGetAttributeNode(xmlCharP $qname --> xmlAttr) is native($BIND-XML2) {*}
Expand Down Expand Up @@ -1060,7 +1070,8 @@ class xmlElem is xmlNode is export does LibXML::Raw::DOM::Element {

#| xmlNode of type: XML_TEXT_NODE
class xmlTextNode is xmlNode is repr('CStruct') is export {
BEGIN @ClassMap[XML_TEXT_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_TEXT_NODE];

our sub New(Str $content --> xmlTextNode) is native($XML2) is symbol('xmlNewText') {*}
method new(Str :$content!, xmlDoc :$doc) {
given New($content) -> xmlTextNode:D $node {
Expand All @@ -1073,7 +1084,8 @@ class xmlTextNode is xmlNode is repr('CStruct') is export {

#| xmlNode of type: XML_COMMENT_NODE
class xmlCommentNode is xmlNode is repr('CStruct') is export {
BEGIN @ClassMap[XML_COMMENT_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_COMMENT_NODE];

our sub New(Str $content --> xmlCommentNode) is native($XML2) is symbol('xmlNewComment') {*}
method new(Str :$content!, xmlDoc :$doc) {
given New($content) -> xmlCommentNode:D $node {
Expand All @@ -1085,7 +1097,8 @@ class xmlCommentNode is xmlNode is repr('CStruct') is export {

#| xmlNode of type: XML_CDATA_SECTION_NODE
class xmlCDataNode is xmlNode is repr('CStruct') is export {
BEGIN @ClassMap[XML_CDATA_SECTION_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_CDATA_SECTION_NODE];

our sub New(xmlDoc, Blob $content, int32 $len --> xmlCDataNode) is native($XML2) is symbol('xmlNewCDataBlock') {*}
multi method new(Str :content($string)!, xmlDoc :$doc --> xmlCDataNode:D) {
my Blob $content = $string.encode;
Expand All @@ -1099,7 +1112,8 @@ class xmlCDataNode is xmlNode is repr('CStruct') is export {

#| xmlNode of type: XML_PI_NODE
class xmlPINode is xmlNode is repr('CStruct') is export {
BEGIN @ClassMap[XML_PI_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_PI_NODE];

our sub New(xmlCharP $name, xmlCharP $content) is native($XML2) is symbol('xmlNewPI') {*}
multi method new(xmlDoc:D :$doc!, Str:D :$name!, Str :$content) {
$doc.new-pi(:$name, :$content);
Expand All @@ -1111,15 +1125,17 @@ class xmlPINode is xmlNode is repr('CStruct') is export {

#| xmlNode of type: XML_ENTITY_REF_NODE
class xmlEntityRefNode is xmlNode is repr('CStruct') is export {
BEGIN @ClassMap[XML_ENTITY_REF_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_ENTITY_REF_NODE];

multi method new(xmlDoc:D :$doc!, Str:D :$name!) {
$doc.new-ent-ref(:$name);
}
}

#| An attribute on an XML node (type: XML_ATTRIBUTE_NODE)
class xmlAttr is anyNode does LibXML::Raw::DOM::Attr is export {
BEGIN @ClassMap[XML_ATTRIBUTE_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_ATTRIBUTE_NODE];

has xmlNs $.ns; # the associated namespace
has int32 $.atype; # the attribute type if validating
has Pointer $.psvi; # for type/PSVI information
Expand All @@ -1135,7 +1151,8 @@ class xmlAttr is anyNode does LibXML::Raw::DOM::Attr is export {

#| An XML document (type: XML_DOCUMENT_NODE)
class xmlDoc is anyNode does LibXML::Raw::DOM::Document is export {
BEGIN @ClassMap[XML_DOCUMENT_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_DOCUMENT_NODE];

has int32 $.compression; # level of zlib compression
has int32 $.standalone is rw; # standalone document (no external refs)
# 1 if standalone="yes"
Expand Down Expand Up @@ -1227,7 +1244,8 @@ class xmlDoc is anyNode does LibXML::Raw::DOM::Document is export {

#| xmlDoc of type: XML_HTML_DOCUMENT_NODE
class htmlDoc is xmlDoc is repr('CStruct') is export {
BEGIN @ClassMap[XML_HTML_DOCUMENT_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_HTML_DOCUMENT_NODE];

method DumpFormat(AllocedStr $ is rw, int32 $ is rw, int32 ) is symbol('htmlDocDumpMemoryFormat') is native($XML2) {*}
our sub New(xmlCharP $URI, xmlCharP $external-id --> htmlDoc) is native($XML2) is symbol('htmlNewDoc') {*}
method new(Str :$URI, Str :$external-id) {
Expand All @@ -1245,7 +1263,8 @@ class htmlDoc is xmlDoc is repr('CStruct') is export {

#| xmlNode of type: XML_DOCUMENT_FRAG_NODE
class xmlDocFrag is xmlNode is export {
BEGIN @ClassMap[XML_DOCUMENT_FRAG_NODE] = $?CLASS;
also does domNode[$?CLASS, XML_DOCUMENT_FRAG_NODE];

our sub New(xmlDoc $doc --> xmlDocFrag) is native($XML2) is symbol('xmlNewDocFragment') {*}
method new(xmlDoc :$doc, xmlNode :$nodes) {
my xmlDocFrag:D $frag = New($doc);
Expand Down
11 changes: 6 additions & 5 deletions lib/LibXML/_ParentNode.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ unit role LibXML::_ParentNode;

use LibXML::Node;
use LibXML::Config;
use LibXML::Enums;
use LibXML::Types :QName, :NameVal;

method iterate-set(|) {...}

method getElementsByTagName(Str:D $name) {
self.iterate-set(LibXML::Node, $.raw.getElementsByTagName($name));
method getElementsByTagName(Str:D $name) is raw {
self.iterate-set(self.box-class(XML_ELEMENT_NODE), $.raw.getElementsByTagName($name));
}
method getElementsByLocalName(Str:D $name) {
self.iterate-set(LibXML::Node, $.raw.getElementsByLocalName($name));
self.iterate-set(self.box-class(XML_ELEMENT_NODE), $.raw.getElementsByLocalName($name));
}
method getElementsByTagNameNS(Str $uri, Str $name) {
self.iterate-set(LibXML::Node, $.raw.getElementsByTagNameNS($uri, $name));
self.iterate-set(self.box-class(XML_ELEMENT_NODE), $.raw.getElementsByTagNameNS($uri, $name));
}
method getChildrenByLocalName(Str:D $name) {
self.iterate-set(LibXML::Node, $.raw.getChildrenByLocalName($name));
Expand All @@ -26,7 +27,7 @@ method getChildrenByTagNameNS(Str:D $uri, Str:D $name) {
self.iterate-set(LibXML::Node, $.raw.getChildrenByTagNameNS($uri, $name));
}
method elements {
self.iterate-set(LibXML::Node, $.raw.getChildrenByLocalName('*'));
self.iterate-set(self.box-class(XML_ELEMENT_NODE), $.raw.getChildrenByLocalName('*'));
}

#| adds a child element with tag $name and text content $value
Expand Down
4 changes: 2 additions & 2 deletions t/08findnodes.t
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ subtest 'dom interaction', {
my $root= $doc.createElement( "A" );
$doc.setDocumentElement($root);

my $b= $doc.createElement( "B" );
my $b = $doc.createElement( "B" );
$root.appendChild( $b );

my @list = $doc.findnodes( '//A' );
Expand All @@ -201,7 +201,7 @@ subtest 'dom interaction', {
ok( @list[0].isSameNode( $b ), ' TODO : Add test name' );
}

subtest 'findnode/unbindNoode', {
subtest 'findnode/unbindNode', {
# test potential unbinding-segfault-problem
my $doc = LibXML.createDocument();
my $root= $doc.createElement( "A" );
Expand Down

0 comments on commit e48ba34

Please sign in to comment.