XS::Framework::Manual::SVAPI::Sv - XS::Framework Sv C++ class reference
The Perl SV* is variadic type, which actually can be Hash (HV*), Array(AV*) etc.
SV*
The Sv object may own the underlying Perl <SV*> or may not, i.e. the held SV* is NULL. That way some methods are NULL-safe, i.e. they can be invoked when SV* is NULL; the other methods are NULL-unsafe, and inoking them leads to undefined behaviour, most likely the program will crash.
NULL
Sv class tried to follow DWIM-principle whenever it is possible and zero- or minimal costs. For example:
Sv
SV* arg; // arg may be NULL or may be not Sv1 sv1(arg) Sv2 sv2 = sv1;
If the arg wasn't NULL, then it's refcounter will be increased twice (on sv1 and sv2 construction), and decreased twice (on sv1 and sv2 destruction). if arg was NULL, then both variables sv1 and sv2 will held NULL SV*. The code above is NULL-safe. However, the following code is NULL-unsafe, i.e. may lead to crashes:
arg
sv1
sv2
SV* arg; // arg may be NULL or may be not Sv1 sv1(arg) sv1.payload_attach(&some_payload, &some_marker);
The non-null existance of arg have to checked i.e.
if (sv1) { sv1.payload_attach(&some_payload, &some_marker); }
Now this piece of code is safe from crashes at runtime.
When the empty constructor is invoked the Sv variable will be empty, i.e. hold no any perl SV*:
Sv item;
To let it hold new Perl variable (empty string), it should be constructed via static method create, i.e.:
create
auto item = Sv::create();
It is quite common to just wrap underlying Perl C type, the overloaded constructor can be invoked
Sv (SV* sv, bool policy = INCREMENT) Sv (AV* sv, bool policy = INCREMENT) Sv (HV* sv, bool policy = INCREMENT) Sv (CV* sv, bool policy = INCREMENT) Sv (GV* sv, bool policy = INCREMENT) AV* av = ...; Sv my(av);
The ref-couning policy defines, whether the underlying SV* should be incremented upon Sv object construction; it is true by default. When the Sv goes out of scope, it's destructor will be invoked and the refcounter of the underlying SV* will always be dec-remented.
policy
true
dec
The construtor does never throws, as all valid SV* values are accepted.
The rule of thumb is following: if Sv wrapper is intended to share ownership with the SV*, it should use INCREMENT policy (this is default, and mostly used case); if the wrapper should own the variable, then the policy should be NONE.
INCREMENT
NONE
There are convenient static methods to create an Sv wrapper without incrementing the refcounter:
static Sv noinc (SV* val) static Sv noinc (AV* val) static Sv noinc (HV* val) static Sv noinc (CV* val) static Sv noinc (GV* val) AV* av = ...; auto my = Sv::noinc(av);
The copy and move constructors are provided; the refcounter is not touched:
Sv (const Sv& oth) Sv (Sv&& oth)
There are a few Sv-constants, which represent common values, e.g. :
static const Sv undef; static const Sv yes; static const Sv no;
Sv& operator= (SV* val) Sv& operator= (AV* val) Sv& operator= (HV* val) Sv& operator= (CV* val) Sv& operator= (GV* val) Sv& operator= (const Sv& oth)
The assignment operators are complementaty to the constructors above. As the possible underlying SV* will be thrown away after assignemnt, it's refcounter is dec-remented and the ref-counter of the new value is incremented.
Sv& operator= (Sv&& oth)
Move-assignment operator is implemented simply by swapping underlying SV* without touching ref-counter.
All assignment operators are NULL-safe
The get the underlying SV* it is possible either to use related coersion operator or dereference operator:
operator SV* () const SV* operator-> () const
Please note, the result might be nullptr if the underlyging SV* was nullptr.
nullptr
It is possible to unwrap the underlying SV* either via operator coercion; it is safe and somewhat slower, as in the case of coercion failure the nullptr is returned:
operator AV* () const operator HV* () const operator CV* () const operator GV* () const
Or it is possible to do zero-cost typecasting, but without any warranty on type safety or non-nullity:
template <typename T = SV> one_of_t<T,SV,AV,HV,CV,GV>* get ()
For example:
AV* av_src = ...; Sv sv(av_src); AV* av_src = sv; if (!av_src) { // do something! } AV* av_src_unsafe = sv.get<AV*>();
To resolve ambiguities in using Sv with Perl macros it the void* coercion operator is supplied:
void*
operator void* () const
explicit operator bool () const
Returns true if the Sv wraps any Perl SV*. It is convenient to use in XS-adapters to check whether any value has been supplied in Perl script, e.g.
void MyClass::my_method(SV* optional1 = nullptr, Sv opt2 = Sv{}) { Sv opt1(optional1); if (opt1) { ... } // a bit more convenient, right? if (opt2) { ... } }
Please note, that undef is valid perl SV* and it returns true for the operator.
undef
bool defined() const
Null-safe method which returns true the object holds any SV* and later is defined.
bool is_true () const
Checks whether the object holds Perl value which evaluates to true. This is NULL-safe method.
bool is_scalar () const bool is_ref () const bool is_simple () const bool is_string () const bool is_like_number () const bool is_array () const bool is_array_ref () const bool is_hash () const bool is_hash_ref () const bool is_sub () const bool is_sub_ref () const bool is_glob () const bool is_object () const bool is_object_ref () const bool is_stash () const
All the methods above try to guess corresponding SV* type and return true upon successful guess. All the methods are NULL-safe.
svtype type () const
This is NULL-unsafe type extraction from from SV*.
bool readonly () const void readonly (bool val)
This NULL-unsafe methods examine Perl SV* for read-only flag or set/unset it.
U32 use_count () const
Returns refcounter value. If SV* is NULL, then 0 is returned.
0
void upgrade (svtype type)
Tries to upgrade SV* into the specified type. Exception is thrown if the variable is already marked as readonly or upon attempt to upgrade defined scalar (non-undef) into more than SVt_PVMG.
SVt_PVMG
This is NULL-unsafe method.
void dump () const
Dumps the underlyign SV* to stderr.
stderr
void reset ()
Decrements refcounter in the undrerlying SV* and sets it to NULL.
This is NULL-safe method.
SV* detach ()
Releases ownership on the underlying SV* (which might be NULL) and returns it. The refcounter is not touched.
This method is useful when manually returning SV* on perl stack in xs-adapter, e.g.
void MyClass::method() { ... Sv mysv = somefunc(); mXPUSHs(mysv.detach()); // mXPUSHs will make it mortal ... }
note that you *MUST* use perl API macros with mortalizing or you will get a memory leak
SV* detach_mortal ()
Same as detach() + sv_2mortal()
detach()
sv_2mortal()
This method is useful when manually returning SV* on perl stack in xs-adapter without using perl mortalizing macros, e.g.
void MyClass::method() { ... Sv mysv = somefunc(); EXTEND(SP, 1); ST(0) = mysv.detach_mortal(); XSRETURN(1); }
note that you *MUST NOT* use perl API macros with mortalizing or you will get a double free error.
double free
operator== (const Sv& lh, const Sv& rh) operator!= (const Sv& lh, const Sv& rh) operator== (const Sv& lh, SV* rh) operator!= (const Sv& lh, SV* rh) operator== (SV* lh, const Sv& rh) operator!= (SV* lh, const Sv& rh) operator== (const Sv& lh, AV* rh) operator!= (const Sv& lh, AV* rh) operator== (AV* lh, const Sv& rh) operator!= (AV* lh, const Sv& rh) operator== (const Sv& lh, HV* rh) operator!= (const Sv& lh, HV* rh) operator== (HV* lh, const Sv& rh) operator!= (HV* lh, const Sv& rh) operator== (const Sv& lh, CV* rh) operator!= (const Sv& lh, CV* rh) operator== (CV* lh, const Sv& rh) operator!= (CV* lh, const Sv& rh) operator== (const Sv& lh, GV* rh) operator!= (const Sv& lh, GV* rh) operator== (GV* lh, const Sv& rh) operator!= (GV* lh, const Sv& rh)
This is group of identity checks operators, i.e. determine whether the underlyging SV* points to the same address as the other argument. As only addresses are compared, all the operations are NULL-safe.
Perl gives possibility to attach arbitrary data to SV* via magic slots. The XS::Framework exposes that facility too. To distinguish between different payloads, it is required to supply the per-type unique marker. XS::Framework assumes that it is enough to have just unique address to identiy unique marker. The easiest way to accomplish that is to have:
static xs::Sv::payload_marker_t my_payload_marker{};
To attach payload the following NULL-unsafe methods can be used:
MAGIC* payload_attach (void* ptr, Sv obj, const payload_marker_t* marker) MAGIC* payload_attach (void* ptr, const payload_marker_t* marker) MAGIC* payload_attach (Sv obj, const payload_marker_t* marker)
The result is perl MAGIC* pointer, which can be safely ignored. To remove magic payload from <SV*> the payload_detach method can be used:
MAGIC*
payload_detach
int payload_detach (payload_marker_t* marker)
To check payload existance via it's market the payload_exists can be used:
payload_exists
bool payload_exists (const payload_marker_t* marker)
Finally, to get the payload the payload method should be used:
payload
Payload payload (const payload_marker_t* marker) const struct Payload { void* ptr; SV* obj; };
In the returned Payload struct you should access the ptr or obj, depending on what kind of payload was attached. Both ptr and obj can be used, if both of them were set.
Payload
ptr
obj
A few words should be told about payload cleanup. If the attached payload type was SV*, then underlying refcounter will be increased, and once magic payload goes of of live, the refcounter will be decremented. However, if arbitrary data was attached as void*, then user-supplied cleanup function will invoked, once it was attached ot the payload marker. The usual place to initialize that custom payload function is BOOT XS-adapter section, for example:
BOOT
static xs::Sv::payload_marker_t my_payload_marker{}; static int my_payload_marker_free(pTHX_ SV*, MAGIC* mg) { void* payload = (void*)mg->mg_ptr; // place custom clean-up code here. return 0; } BOOT { my_payload_marker.svt_free = my_payload_marker_free; }
All methods, which work with magic are NULL-unsafe.
Swaps underlying SV* between lh and rh
lh
rh
XS::Framework
XS::Framework::Manual::SVAPI
XS::Framework::Manual::SVAPI::Sub
XS::Framework::Manual::SVAPI::Array
XS::Framework::Manual::SVAPI::Glob
XS::Framework::Manual::SVAPI::Hash
XS::Framework::Manual::SVAPI::List
XS::Framework::Manual::SVAPI::Object
XS::Framework::Manual::SVAPI::Ref
XS::Framework::Manual::SVAPI::Scalar
XS::Framework::Manual::SVAPI::Simple
XS::Framework::Manual::SVAPI::Stash
To install XS::Framework, copy and paste the appropriate command in to your terminal.
cpanm
cpanm XS::Framework
CPAN shell
perl -MCPAN -e shell install XS::Framework
For more information on module installation, please visit the detailed CPAN module installation guide.