Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

add Intro to XS/C++ presentation

  • Loading branch information...
commit e55389e4a971d75d2da68ec16cfcd28da9c49de7 1 parent 2a63516
Doug Bell authored
655 Perl/Intro-XS-CXX.html
... ... @@ -0,0 +1,655 @@
  1 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  2 +<html xmlns="http://www.w3.org/1999/xhtml">
  3 +
  4 +<head>
  5 +<title>Intro to XS/C++</title>
  6 +<!-- metadata -->
  7 +<meta name="generator" content="S5" />
  8 +<meta name="version" content="S5 1.2a2" />
  9 +<meta name="author" content="Doug Bell" />
  10 +<meta name="company" content="Double Cluepon Software Corp." />
  11 +<meta name="license" content="CC-BY-SA 3.0" />
  12 +<!-- configuration parameters -->
  13 +<meta name="defaultView" content="slideshow" />
  14 +<meta name="controlVis" content="hidden" />
  15 +<!-- style sheet links -->
  16 +<link rel="stylesheet" href="../s5/ui/default/slides.css" type="text/css" media="projection" id="slideProj" />
  17 +<link rel="stylesheet" href="../s5/ui/default/outline.css" type="text/css" media="screen" id="outlineStyle" />
  18 +<link rel="stylesheet" href="../s5/ui/default/print.css" type="text/css" media="print" id="slidePrint" />
  19 +<link rel="stylesheet" href="../s5/ui/default/opera.css" type="text/css" media="projection" id="operaFix" />
  20 +<!-- embedded styles -->
  21 +<style type="text/css" media="all">
  22 +</style>
  23 +<!-- S5 JS -->
  24 +<script src="../s5/ui/default/slides.js" type="text/javascript"></script>
  25 +<!-- SHJS -->
  26 +<script type="text/javascript" src="../shjs/sh_main.min.js"></script>
  27 +<script type="text/javascript" src="../shjs/lang/sh_perl.min.js"></script>
  28 +<script type="text/javascript" src="../shjs/lang/sh_c.min.js"></script>
  29 +<script type="text/javascript" src="../shjs/lang/sh_cpp.min.js"></script>
  30 +<link rel="stylesheet" href="../shjs/css/sh_ide-eclipse.min.css" type="text/css" />
  31 +</head>
  32 +<body>
  33 +
  34 +<div class="layout">
  35 +<div id="controls"><!-- DO NOT EDIT --></div>
  36 +<div id="currentSlide"><!-- DO NOT EDIT --></div>
  37 +<div id="header"></div>
  38 +<div id="footer">
  39 +<h1>Intro to XS/C++</h1>
  40 +<h2>Chicago.PM -- 2012-03-22</h2>
  41 +</div>
  42 +</div>
  43 +
  44 +<ol class="xoxo presentation">
  45 +<!-- Begin presentation -->
  46 +
  47 +<li class="slide">
  48 +<h1>Intro to XS/C++</h1>
  49 +<h3>Doug Bell</h3>
  50 +<h4><a href="http://www.doublecluepon.com">Double Cluepon Software Corp.</a></h4>
  51 +<div class="handout"></div>
  52 +</li>
  53 +
  54 +<!-- li class="slide" -->
  55 +<!-- pre class="sh_perl" -->
  56 +
  57 +<li class="slide">
  58 +<h1>Don't Panic</h1>
  59 +<ul>
  60 +<li>XS has a reputation for being obtuse
  61 +<ul>
  62 +<li>Compared to Perl?</li>
  63 +<li>Lower-level</li>
  64 +</ul></li>
  65 +<li>Try it again for the first time</li>
  66 +</ul>
  67 +</li>
  68 +
  69 +<li class="slide">
  70 +<h1>Just the Basics</h1>
  71 +<ul>
  72 +<li>XS provides a way to call native libraries from Perl</li>
  73 +<li>Probably C or C++</li>
  74 +<li>XS for C is well-documented
  75 +<ul>
  76 +<li><a href="http://perldoc.perl.org/index-internals.html">http://perldoc.perl.org/index-internals.html</a></li>
  77 +<li><a href="http://world.std.com/~swmcd/steven/perl/pm/xs/intro/">http://world.std.com/~swmcd/steven/perl/pm/xs/intro/</a></li>
  78 +</ul></li>
  79 +<li>XS for C++ less-so
  80 +<ul>
  81 +<li>Some mention in `perldoc perlxs`</li>
  82 +<li><a href="http://www.johnkeiser.com/perl-xs-c++.html">http://www.johnkeiser.com/perl-xs-c++.html</a></li>
  83 +<li>C++ is a wonderful language for XS</li>
  84 +</ul></li>
  85 +</li>
  86 +</ul>
  87 +</li>
  88 +
  89 +<li class="slide">
  90 +<h1>Start with h2xs</h1>
  91 +<ul>
  92 +<li>Build a bare XS module called MyModule
  93 +<ul><li><code>h2xs -A --skip-exporter -nMyModule</code>
  94 +<ul><li><code>-A</code> -- no AUTOLOAD</li>
  95 +<li><code>--skip-exporter</code> -- no use Exporter</li>
  96 +<li><code>-nMyModule</code> -- name MyModule</li>
  97 +</ul></li>
  98 +</ul></li>
  99 +<li>Set appropriate Makefile.PL parameters
  100 +<ul><li><code>h2xs -L/opt/local/lib -lmylib</code></li>
  101 +<li>Much like the arguments to gcc/g++</li>
  102 +</ul></li>
  103 +</ul></li>
  104 +
  105 +<li class="slide">
  106 +<h1>What we have</h1>
  107 +<div style="float: left; width: 50%"><ul>
  108 +<li>MyModule/</li>
  109 +<li>README</li>
  110 +<li>Changes</li>
  111 +<li>MANIFEST</li>
  112 +<li>ppport.h</li>
  113 +<li>lib/MyModule.pm</li>
  114 +</ul></div>
  115 +<div style="float: left"><ul>
  116 +<li>t/MyModule.t</li>
  117 +<li>MyModule.xs</li>
  118 +<li>Makefile.PL</li>
  119 +<li>Missing: typemap</li>
  120 +<li>Missing: perlobject.map</li>
  121 +</ul></div>
  122 +</li>
  123 +
  124 +<li class="slide">
  125 +<h1>lib/MyModule.pm</h1>
  126 +<pre class="sh_perl">
  127 +package MyModule;
  128 +
  129 +use 5.014001;
  130 +use strict;
  131 +use warnings;
  132 +
  133 +our @ISA = qw();
  134 +
  135 +our $VERSION = '0.01';
  136 +
  137 +require XSLoader;
  138 +XSLoader::load('MyModule', $VERSION);
  139 +
  140 +# Preloaded methods go here.
  141 +
  142 +1;
  143 +</pre>
  144 +</li>
  145 +
  146 +<li class="slide">
  147 +<h1>MyModule.xs</h1>
  148 +
  149 +<pre class="sh_cpp">
  150 +#include "EXTERN.h"
  151 +#include "perl.h"
  152 +#include "XSUB.h"
  153 +
  154 +#include "ppport.h"
  155 +
  156 +MODULE = MyModule PACKAGE = MyModule
  157 +</pre>
  158 +<ul>
  159 +<li>Before "MODULE" -- C/C++</li>
  160 +<li>After "MODULE" -- XS</li>
  161 +<li>.xs files processed by xsubpp into C/C++</li>
  162 +<li>XS covered later, some administrative details first...</li>
  163 +</ul>
  164 +</li>
  165 +
  166 +<li class="slide">
  167 +<h1>C++ Edits to MyModule.xs</h1>
  168 +<ul>
  169 +<li>Add 'extern "C"' around C headers</li>
  170 +</ul>
  171 +<pre class="sh_cpp">
  172 +#ifdef __cplusplus
  173 +extern "C" {
  174 +#endif
  175 +#include "EXTERN.h"
  176 +#include "perl.h"
  177 +#include "XSUB.h"
  178 +#ifdef __cplusplus
  179 +}
  180 +#endif
  181 +</pre>
  182 +<ul>
  183 +<li>This prevents name-mangling</li>
  184 +</ul>
  185 +</li>
  186 +
  187 +<li class="slide">
  188 +<h1>C++ typemap file</h1>
  189 +<ul>
  190 +<li><a href="http://www.cpan.org/authors/id/DMR/">http://www.cpan.org/authors/id/DMR/</a></li>
  191 +<li>perlobject.map</li>
  192 +<li>We'll add it to Makefile.PL later</li>
  193 +</ul>
  194 +</li>
  195 +
  196 +<li class="slide">
  197 +<h1>typemap file</h1>
  198 +<ul>
  199 +<li>typemap maps C/C++ types to/from Perl SV</li>
  200 +</ul>
  201 +<pre class="sh_perl">
  202 +# typemap
  203 +MyClass * O_OBJECT
  204 +</pre>
  205 +<ul>
  206 +<li>O_OBJECT defined in perlobject.map</li>
  207 +</ul>
  208 +</li>
  209 +<li class="slide">
  210 +<h1>typemap file</h1>
  211 +<pre class="sh_perl" style="font-size: smaller">
  212 +MyClass * O_MYCLASS
  213 +
  214 +OUTPUT
  215 +O_MYCLASS
  216 + sv_setref_pv( $arg, CLASS, (void*)$var );
  217 +
  218 +INPUT
  219 +O_MYCLASS
  220 + if ( sv_isobject($arg) &amp;&amp; (SvTYPE(SvRV($arg)) == SVt_PVMG) ) {
  221 + $var = ($type)SvIV((SV*)SvRV( $arg ));
  222 + }
  223 + else {
  224 + warn( \"${Package}::$func_name() -- \
  225 + $var not a blessed SV reference\" );
  226 + XSRETURN_UNDEF;
  227 + }
  228 +</pre>
  229 +<div style="float: left; width: 50%"><ul style="font-size: smaller">
  230 +<li>Acts much like macro definitions</li>
  231 +<li><code>CLASS</code> created by XS new()</li>
  232 +</ul></div>
  233 +<div style="float: left"><ul style="font-size: smaller">
  234 +<li><code>$arg</code> replaced by Perl SV</li>
  235 +<li><code>$var</code> replaced by C/C++ variable</li>
  236 +</ul></div>
  237 +</li>
  238 +
  239 +</li>
  240 +<li class="slide">
  241 +<h1>Makefile.PL</h1>
  242 +<pre class="sh_perl" style="font-size: smaller">
  243 +use 5.014001;
  244 +use ExtUtils::MakeMaker;
  245 +WriteMakefile(
  246 + NAME =&gt; 'MyModule',
  247 + VERSION_FROM =&gt; 'lib/MyModule.pm', # finds $VERSION
  248 + PREREQ_PM =&gt; {}, # e.g., Module::Name =&gt; 1.1
  249 + ($] &gt;= 5.005 ? ## Add these new keywords supported since 5.005
  250 + (ABSTRACT_FROM =&gt; 'lib/MyModule.pm', # retrieve abstract from module
  251 + AUTHOR =&gt; 'Doug &lt;madcityzen@gmail.com&gt;') : ()),
  252 + LIBS =&gt; [''], # e.g., '-lm'
  253 + DEFINE =&gt; '', # e.g., '-DHAVE_SOMETHING'
  254 + INC =&gt; '-I.', # e.g., '-I. -I/usr/include/other'
  255 + # Un-comment this if you add C files to link with later:
  256 + # OBJECT =&gt; '$(O_FILES)', # link all the C files too
  257 + ### Add these for C++ support
  258 + CC =&gt; 'g++', # Override from Config
  259 + LD =&gt; 'g++', # Override from Config
  260 + XSOPT =&gt; '-C++',
  261 + TYPEMAPS =&gt; ['perlobject.map'],
  262 +);
  263 +</pre>
  264 +
  265 +</li>
  266 +<li class="slide">
  267 +<h1>Interface a C++ Class</h1>
  268 +
  269 +<pre class="sh_cpp">
  270 +#ifdef __cplusplus
  271 +extern "C" {
  272 +#endif
  273 +#include "EXTERN.h"
  274 +#include "perl.h"
  275 +#include "XSUB.h"
  276 +#ifdef __cplusplus
  277 +}
  278 +#endif
  279 +</pre>
  280 +</li>
  281 +
  282 +</li>
  283 +<li class="slide">
  284 +<h1>Interface a C++ Class</h1>
  285 +<pre class="sh_cpp" style="font-size: smaller">
  286 +class Card {
  287 + int value_;
  288 + enum t_suit { SPADES, CLUBS, HEARTS, DIAMONDS } suit_;
  289 + public:
  290 + Card( int value, t_suit suit ) {
  291 + value_ = value;
  292 + suit_ = suit;
  293 + }
  294 + ~Card() { }
  295 + int value() { return value_; }
  296 + int suit() { return suit_; }
  297 + void set_value( int value ) {
  298 + value_ = value;
  299 + }
  300 + void set_suit( t_suit suit ) {
  301 + suit_ = t_suit;
  302 + }
  303 +};
  304 +</pre>
  305 +
  306 +</li>
  307 +<li class="slide">
  308 +<h1>Interface a C++ Class</h1>
  309 +<pre class="sh_cpp" style="font-size:smaller">
  310 +MODULE = Card PACKAGE = Card
  311 +
  312 +Card *
  313 +Card::new( int suit, int value )
  314 +
  315 +void
  316 +Card::DESTROY()
  317 +
  318 +int
  319 +Card::value()
  320 +
  321 +int
  322 +Card::suit()
  323 +
  324 +void
  325 +Card::set_value( int value )
  326 +
  327 +void
  328 +Card::set_suit( int suit )
  329 +</pre>
  330 +</li>
  331 +
  332 +</li>
  333 +<li class="slide">
  334 +<h1>typemap</h1>
  335 +<pre class="sh_perl">
  336 +Card * O_OBJECT
  337 +</pre>
  338 +<ul>
  339 +<li><code>Card::new()</code> gives us CLASS automatically</li>
  340 +<li>Other <code>Card::*</code> knows it gets a Card * and calls it <code>THIS</code></li>
  341 +<li>All this comes from <code>XSOPTS =&gt; '-C++',</code></li>
  342 +</ul>
  343 +
  344 +</li>
  345 +<li class="slide">
  346 +<h1>Build and test</h1>
  347 +
  348 +<pre>
  349 +$ perl Makefile.PL &amp;&amp; make test
  350 +</pre>
  351 +
  352 +<ul><li>And you're done</li></ul>
  353 +
  354 +<div style="position: fixed; bottom: 150px; width: 85%; color: grey; font-size: smaller; font-family: monospace; font-style: italic; text-align: center;">
  355 +This space accidentally left blank
  356 +</div>
  357 +</li>
  358 +<li class="slide">
  359 +<h1>More Difficult Interfaces</h1>
  360 +
  361 +<pre class="sh_cpp">
  362 +#include &lt;vector&gt;
  363 +class Deck {
  364 + std::vector&lt;Card&gt; cards_;
  365 + public:
  366 + Deck() { }
  367 + ~Deck() { }
  368 + void add_card( Card card ) {
  369 + cards_.push_back( card );
  370 + }
  371 + std::vector cards() {
  372 + return cards_;
  373 + }
  374 +};
  375 +</pre>
  376 +</li>
  377 +<li class="slide">
  378 +<h1>More Difficult Interfaces</h1>
  379 +
  380 +<pre class="sh_cpp">
  381 +MODULE = Card PACKAGE = Deck
  382 +
  383 +Deck *
  384 +Deck::new()
  385 +
  386 +void
  387 +Deck::DESTROY()
  388 +</pre>
  389 +<ul>
  390 +<li>Standard boilerplate</li>
  391 +<li>Module turns into Card.so</li>
  392 +<li>Package turns into <code>package Deck;</code></li>
  393 +<li>Include in Card.xs</li>
  394 +</ul>
  395 +
  396 +</li>
  397 +<li class="slide">
  398 +<h1>Custom CODE:</h1>
  399 +
  400 +<pre class="sh_perl">
  401 +void
  402 +Deck::add_card( suit, value )
  403 + int suit
  404 + int value
  405 + CODE:
  406 + Card card( suit, value );
  407 + THIS-&gt;add_card( card );
  408 +</pre>
  409 +<ul>
  410 +<li>Change the interface of Deck</li>
  411 +<li>CODE: is C/C++ code</li>
  412 +</ul>
  413 +
  414 +</li>
  415 +<li class="slide">
  416 +<h1>Returning Arrays</h1>
  417 +
  418 +<pre class="sh_cpp" style="font-size: smaller">
  419 +AV *
  420 +Deck::cards()
  421 + CODE:
  422 + std::vector&lt;Card&gt; cards( THIS-&gt;cards() );
  423 + std::vector&lt;Card&gt;::iterator iter( cards.begin() );
  424 + RETVAL = newAV(); // create an array
  425 + sv_2mortal( (SV*)RETVAL ); // "mortalize"
  426 + for ( ; iter != cards.end(); iter++ ) {
  427 + SV* card_sv( newSV(0) ); // create a scalar
  428 + sv_setref_pv( card_sv, "Card", (void*)&amp;*iter ); // bless
  429 + av_push( RETVAL, card_sv );
  430 + }
  431 + OUTPUT:
  432 + RETVAL
  433 +</pre>
  434 +<div style="float: left; width: 49%">
  435 +<ul style="font-size: smaller">
  436 +<li>AV - Array Value; SV - Scalar Value</li>
  437 +<li>Mortal - delayed refcount decrement
  438 +<ul><li>If not used, will be GCed</li>
  439 +<li><code>my @cards = $deck-&gt;cards;</code></li>
  440 +</ul></li>
  441 +<li>RETVAL - Created automatically with type</li>
  442 +</ul></div>
  443 +<div style="float: left; width: 49%">
  444 +<ul style="font-size: smaller">
  445 +<li><code>sv_setref_pv</code> - Set SV to be Reference to Pointer Value<ul>
  446 +<li>Bless into a package too</li>
  447 +</ul></li>
  448 +<li>CODE: requires OUTPUT:</li>
  449 +</ul>
  450 +</div>
  451 +
  452 +</li>
  453 +<li class="slide">
  454 +<h1>Thems The Basics</h1>
  455 +<ul>
  456 +<li>Questions</li>
  457 +<li>Comments</li>
  458 +<li>Concerns</li>
  459 +<li>Scathing Criticisms</li>
  460 +<li>Bombastic Praise</li>
  461 +<li>Moving on...</li>
  462 +</ul>
  463 +</li>
  464 +
  465 +<li class="slide">
  466 +<h1>Memory Management with SVs</h1>
  467 +<ul>
  468 +<li>Perl SVs are reference counted</li>
  469 +<li>C++11 std::shared_ptr is reference counted</li>
  470 +<li>Same techniques can be used to track SVs through C++
  471 +<ul><li>Good for C++ callbacks</li>
  472 +<li>POSIX-threaded applications</li>
  473 +<li>Avoid memory leaks</li>
  474 +<li>Type-safety with templates</li>
  475 +<li>Pointer can be used after we're done with it (ownership)</li>
  476 +</ul></li>
  477 +</ul>
  478 +
  479 +</li>
  480 +<li class="slide">
  481 +<h1>Building shared_sv</h1>
  482 +<ul>
  483 +<li>The Required 4 methods for STL containers<ul>
  484 +<li>Default (empty) Constructor</li>
  485 +<li>Copy constructor</li>
  486 +<li>Assignment operator</li>
  487 +<li>Destructor</li>
  488 +</ul></li>
  489 +<li>Mostly C++ code</li>
  490 +</ul>
  491 +
  492 +</li>
  493 +<li class="slide">
  494 +<h1>Constructor(s)</h1>
  495 +
  496 +<ul>
  497 +<li>One for STL containers to create empty objects</li>
  498 +<li>One for users to create new SVs</li>
  499 +</ul>
  500 +<pre class="sh_cpp">
  501 +/** Default constructor needed for STL containers */
  502 +shared_sv() : p_(0), sv_(0) {};
  503 +
  504 +/** Useful constructor */
  505 +shared_sv( void* p, std::string package )
  506 + : p_(p), sv_( newSV(0) ) // Created with refcnt 1
  507 +{
  508 + if ( sv_ == 0 ) return;
  509 + sv_ = sv_setref_pv( sv_, package.c_str(), p_ );
  510 +}
  511 +</pre>
  512 +
  513 +</li>
  514 +<li class="slide">
  515 +<h1>Copy constructor</h1>
  516 +<pre class="sh_cpp">
  517 +shared_sv( const shared_sv&amp; that )
  518 + : p_(that.p_), sv_(that.sv_)
  519 +{
  520 + if ( sv_ == 0 ) return; // Don't do empty SVs
  521 + // We can increment the refcount faster if we
  522 + // don't care about return value (void)
  523 + SvREFCNT_inc_void( sv_ );
  524 +}
  525 +</pre>
  526 +<ul>
  527 +<li>Copying increments ref count</li>
  528 +<li>Happens a lot inside STL containers</li>
  529 +<li>Happens during method calls</li>
  530 +</ul>
  531 +
  532 +</li>
  533 +<li class="slide">
  534 +<h1>Assignment operator</h1>
  535 +<pre class="sh_cpp">
  536 +shared_sv&amp; operator=( const shared_sv&amp; that ) {
  537 + if ( this == &amp;that ) return *this; // Mandatory
  538 + p_ = that.p_;
  539 + if ( sv_ != 0 )
  540 + SvREFCNT_dec( sv_ ); // Lose our SV
  541 + sv_ = that.sv();
  542 + if ( sv_ == 0 ) return *this;
  543 + SvREFCNT_inc_void( sv_ ); // Gain their SV
  544 + return *this;
  545 +}
  546 +</pre>
  547 +<ul>
  548 +<li>Assign into STL containers
  549 +<ul>
  550 +<li><code>vector[i] = new shared_sv(...);</code></li>
  551 +</ul></li>
  552 +<li>Also happens a lot during STL container internals</li>
  553 +</ul>
  554 +</li>
  555 +
  556 +</li>
  557 +<li class="slide">
  558 +<h1>Destructor</h1>
  559 +<pre class="sh_perl">
  560 +~shared_sv() {
  561 + if ( sv_ == 0 ) return;
  562 + SvREFCNT_dec( sv_ );
  563 +}
  564 +</pre>
  565 +<ul>
  566 +<li>We're done, decrement our refcount</li>
  567 +<li>When refcount is zero, the DESTROY() XS method is called</li>
  568 +<li>Default DESTROY for XS/C++ is <code>delete THIS</code></li>
  569 +</ul>
  570 +
  571 +</li>
  572 +<li class="slide">
  573 +<h1>Usage</h1>
  574 +<ul>
  575 +<li>In routines</li>
  576 +</ul>
  577 +<pre class="sh_perl">
  578 +shared_sv make_card( ) {
  579 + // Card* card = new Card(); &lt;- bad
  580 + shared_sv ssv( new Card(), "Card" ); // &lt;- good
  581 + // We return a copy
  582 + return ssv;
  583 + // Copy means refcount incremented
  584 +}
  585 +</pre>
  586 +<ul><li>In containers</li></ul>
  587 +<pre class="sh_cpp">
  588 +std::vector&lt;shared_sv&gt; cxx_array();
  589 +// Card* card = new Card(); &lt;- bad
  590 +shared_sv ssv( new Card(), "Card" ); // &lt;- good
  591 +cxx_array.push_back( ssv );
  592 +// cxx_array keeps a copy, refcount incremented
  593 +</pre>
  594 +
  595 +</li>
  596 +<li class="slide">
  597 +<h1>Helpful tips</h1>
  598 +<ul>
  599 +<li>Keep little C/C++ inside .xs file
  600 +<ul><li>Sharing functions between .xs files is hairy</li>
  601 +<li>Make a static lib to link against</li>
  602 +</ul>
  603 +<li>Build a Perly interface in the XS if possible
  604 +<ul><li>C-style interfaces are not Perly</li></ul>
  605 +</li>
  606 +<li>Do most things in Perl
  607 +<ul><li>More stuff done in Perl, more flexibility you have</li>
  608 +<li>Pull routines out into Perl as long as interface remains Perly</li>
  609 +</ul></li>
  610 +<li>One directory for each XS package
  611 +<ul><li>Subdirectories of main XS package</li>
  612 +<li>Helps share code when in Perl</li>
  613 +</ul>
  614 +</ul></li>
  615 +
  616 +</li>
  617 +<li class="slide">
  618 +<h1>Docs for C++</h1>
  619 +<ul>
  620 +<li><a href="http://www.cplusplus.com/reference/">http://www.cplusplus.com/reference/</a></li>
  621 +<li><a href="http://www.parashift.com/c++-faq-lite/">http://www.parashift.com/c++-faq-lite/</a></li>
  622 +<li><em>Effective C++</em>, <em>Effective STL</em>, <em>More Effective C++</em> by Scott Meyers</li>
  623 +<li><em>C++ Coding Standards</em> by Andrei Alexandrescu and Herb Sutter
  624 +<ul><li>Perl Best Practices for C++</li></ul></li>
  625 +</ul>
  626 +
  627 +</li>
  628 +<li class="slide">
  629 +<h1>The End!</h1>
  630 +<ul>
  631 + <li>
  632 + Slides: <a href="http://preaction.github.com/Perl/Intro-XS-CXX.html">
  633 + http://preaction.github.com/Perl/Intro-XS-CXX.html
  634 + </a>
  635 + </li>
  636 + <li>Code:<ul>
  637 + <li><a href="http://preaction.github.com/Perl/Intro-XS-CXX/shared_sv.hpp">shared_sv.hpp</a></li>
  638 + </ul></li>
  639 +</ul>
  640 +<p>Slides are licensed under a <a
  641 + href="http://creativecommons.org/licenses/by-sa/3.0/us/">CC-BY-SA
  642 + 3.0 license</a>.</p>
  643 +<p>Code is licensed under the <a href="http://dev.perl.org/licenses/artistic.html">
  644 +Artistic License</a> or <a
  645 + href="http://www.gnu.org/licenses/gpl-1.0.txt">GNU GPL v1.0</a> or
  646 +later (the same terms as Perl itself).</p>
  647 +</li>
  648 +
  649 +<!-- Done with presentation -->
  650 +</ol> <!-- class="xoxo presentation" -->
  651 +
  652 +<script type="text/javascript">sh_highlightDocument();</script>
  653 +</body>
  654 +</html>
  655 +
182 Perl/Intro-XS-CXX/shared_sv.hpp
... ... @@ -0,0 +1,182 @@
  1 +#ifndef SHARED_SV_INCLUDE
  2 +#define SHARED_SV_INCLUDE
  3 +
  4 +/**
  5 + * A dumb pointer that also contains a Perl SV* that wraps the pointer,
  6 + * creating a smart pointer.
  7 + *
  8 + * This class is useful when you need to have the SV in C++ later, for a
  9 + * callback in a threaded application, for example. This class is meant to
  10 + * be held inside of an STL container or another object to help avoid
  11 + * memory leaks that are caused by improper use of dumb pointers.
  12 + *
  13 + * The Perl SV* is considered the owner of the pointer, so this class will
  14 + * never free the data pointed to, it will only decrement the SV* reference
  15 + * count so that Perl can free the data if it wants to. This allows the Perl
  16 + * programmer to use the SV* even after the shared_sv instance goes away.
  17 + *
  18 + * If you need to keep a SV* inside C++ code (to perform callbacks, for
  19 + * example), you should create a shared_sv inside XS and return a new SV by
  20 + * calling ref() instead. Don't return a weak_ref() from an XSUB with an SV*
  21 + * return type.
  22 + *
  23 + * Ex:
  24 + *
  25 + * std::vector<shared_sv<MyClass> > instances;
  26 + *
  27 + * SV*
  28 + * new( CLASS )
  29 + * char* CLASS
  30 + * CODE:
  31 + * shared_sv<MyClass> ssv( new MyClass(), CLASS );
  32 + * instances.push_back( ssv ); // We need the SV in C++ later...
  33 + * RETVAL = ssv.ref();
  34 + * // XS calls sv_2mortal on XSUBs that return SV*
  35 + */
  36 +
  37 +#include <iostream>
  38 +#include "perl.h"
  39 +
  40 +template< typename T >
  41 +class shared_sv {
  42 + /**
  43 + * The pointer our SV contains. This is here for convenience, it is also possible to
  44 + * get this exact pointer out of the sv_.
  45 + *
  46 + * This is a dumb pointer managed by Perl's SV ref counting. This class encapsulates
  47 + * this reference counting for C++'s use-cases.
  48 + */
  49 + T* p_;
  50 + /**
  51 + * A reference to the SV containing our pointer. This SV holds all the
  52 + * responsibility for the p_ pointer. There must be a DESTROY() XSUB that
  53 + * properly frees the pointer inside or you will leak
  54 + */
  55 + SV* sv_;
  56 + public:
  57 + /**
  58 + * Create a new, blank shared_sv. No Perl SV is created. This is required for
  59 + * STL container classes.
  60 + */
  61 + shared_sv()
  62 + : p_(0), sv_(0)
  63 + {};
  64 +
  65 + /**
  66 + * Create a new SV with the given pointer. The SV is blessed into the given
  67 + * class.
  68 + */
  69 + shared_sv( T* p, std::string package )
  70 + : p_(p), sv_( newSV(0) ) // SV created with refcnt 1
  71 + {
  72 + if ( sv_ == 0 ) return;
  73 + sv_ = sv_setref_pv( sv_, package.c_str(), p_ );
  74 + // std::cout << "SharedSV with pointer " << p_ << " SV: " << sv_ << " REF: " << SvREFCNT( sv_ )
  75 + // << std::endl;
  76 + }
  77 +
  78 + /**
  79 + * Copy constructor. Increments refcount.
  80 + */
  81 + shared_sv( const shared_sv<T>& that )
  82 + : p_(that.p_), sv_(that.sv_)
  83 + {
  84 + // We can inc the refcount faster if we don't care about return value (void)
  85 + if ( sv_ == 0 ) return;
  86 + SvREFCNT_inc_void( sv_ );
  87 + // std::cout << "SV " << sv_ << " ++ " << SvREFCNT( sv_ ) << std::endl;
  88 + }
  89 +
  90 + /**
  91 + * A casting copy constructor, increments refcount. Uses a static_cast
  92 + * on the pointer
  93 + */
  94 + template< typename Y > shared_sv( const shared_sv<Y>& that )
  95 + : p_(static_cast<T*>(that.get())), sv_(that.sv())
  96 + {
  97 + if ( sv_ == 0 ) return;
  98 + SvREFCNT_inc_void( sv_ );
  99 + // std::cout << "SV " << sv_ << " ++ " << SvREFCNT( sv_ ) <<
  100 + // std::endl;
  101 + }
  102 +
  103 + /**
  104 + * Assignment operator will decrement old refcount and increment new refcount
  105 + */
  106 + shared_sv<T>& operator=( const shared_sv<T>& that )
  107 + {
  108 + if ( this == &that ) return *this;
  109 + p_ = static_cast<T*>(that.get());
  110 + if ( sv_ != 0 ) {
  111 + // std::cout << "SV " << sv_ << " -- " << SvREFCNT( sv_ ) << std::endl;
  112 + SvREFCNT_dec( sv_ );
  113 + }
  114 + sv_ = that.sv();
  115 + if ( sv_ == 0 ) return *this;
  116 + SvREFCNT_inc_void( sv_ );
  117 + // std::cout << "SV " << sv_ << " ++ " << SvREFCNT( sv_ ) << std::endl;
  118 + return *this;
  119 + }
  120 +
  121 + /**
  122 + * Destructor should dec our SV*. Perl will free our pointer
  123 + * by calling the SV's DESTROY() XS function if the SV* ref count is 0.
  124 + *
  125 + * We do not do any delete here in case someone in the Perl side has a
  126 + * reference. We want them to be able to use that reference.
  127 + */
  128 + ~shared_sv() {
  129 + if ( sv_ == 0 ) return;
  130 + SvREFCNT_dec( sv_ );
  131 + // std::cout << "SV " << sv_ << " -- " << SvREFCNT( sv_ ) << std::endl;
  132 + }
  133 +
  134 + /**
  135 + * Get the SV. If you plan on giving the SV back to Perl, use ref() or
  136 + * weak_ref() instead.
  137 + */
  138 + SV* sv() const {
  139 + return sv_;
  140 + }
  141 +
  142 + /**
  143 + * Get the object pointer.
  144 + */
  145 + T* get() const {
  146 + return p_;
  147 + }
  148 +
  149 + /**
  150 + * Get the object pointer
  151 + */
  152 + T* operator->() const {
  153 + return get();
  154 + }
  155 +
  156 + /**
  157 + * Create a new reference to the underlying SV and return it,
  158 + * incrementing this SV's ref count. The SV returned has a ref count of
  159 + * 1.
  160 + */
  161 + SV* ref() const {
  162 + return newRV( SvRV(sv_) );
  163 + }
  164 +
  165 + /**
  166 + * Create a new reference to the underlying SV and return it without
  167 + * incrementing the SV's ref count.
  168 + *
  169 + * This is good for when you still want the SV stored here to be
  170 + * cleaned up even if this object (or the reference returned from
  171 + * weak_ref()) is still around.
  172 + *
  173 + * Do not use this if returning the SV from an XSUB with a return type
  174 + * of SV*. Perl automatically calls sv_2mortal on RETVAL for you, and
  175 + * you will get a warning: "Attempt to free unreferenced scalar".
  176 + */
  177 + SV* weak_ref() const {
  178 + return newRV_noinc( SvRV(sv_) );
  179 + }
  180 +};
  181 +#endif
  182 +
8 index.html 100644 → 100755
@@ -4,6 +4,7 @@
4 4 <h2>Perl</h2>
5 5 <ul>
6 6 <li><a href="/Perl/PSGI-Testing.html">Testing with PSGI</a></li>
  7 + <li><a href="/Perl/Intro-XS-CXX.html">Introduction to XS in C++</a></li>
7 8 </ul>
8 9 <h2>WebGUI</h2>
9 10 <ul>
@@ -13,8 +14,9 @@
13 14 <p>All presentations here are licensed under a <a
14 15 href="http://creativecommons.org/licenses/by-sa/3.0/us/">CC-BY-SA
15 16 3.0 license</a>.</p>
16   - <p>All code here is licensed under the <a
17   - href="http://www.gnu.org/licenses/gpl-3.0.txt">GNU GPL v3.0</a> or
18   - later.</p>
  17 + <p>All code here is licensed under the
  18 + <a href="http://dev.perl.org/licenses/artistic.html">Artistic License</a>
  19 + or <a href="http://www.gnu.org/licenses/gpl-1.0.txt">GNU GPL v1.0</a> or
  20 + later, at your discretion (the same terms as Perl 5 itself).</p>
19 21 </body>
20 22 </html>

0 comments on commit e55389e

Please sign in to comment.
Something went wrong with that request. Please try again.