=head1 NAME XS::Framework::Manual::SVAPI::Sv - XS::Framework Sv C++ class reference =head1 Sv =head2 Overview The Perl C is variadic type, which actually can be Hash (HV*), Array(AV*) etc. The Sv object I own the underlying Perl or I, i.e. the held SV* is C. That way some methods are NULL-safe, i.e. they can be invoked when C is C; the other methods are NULL-unsafe, and inoking them leads to B, most likely the program will crash. C class tried to follow I whenever it is possible and zero- or minimal costs. For example: SV* arg; // arg may be NULL or may be not Sv1 sv1(arg) Sv2 sv2 = sv1; If the C wasn't NULL, then it's refcounter will be increased twice (on C and C construction), and decreased twice (on C and C destruction). if C was NULL, then both variables C and C will held NULL C. The code above is NULL-safe. However, the following code is NULL-unsafe, i.e. may lead to crashes: 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 C 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. =head2 Construction When the empty constructor is invoked the C variable will be empty, i.e. hold no any perl C: Sv item; To let it hold new Perl variable (empty string), it should be constructed via static method C, i.e.: auto item = Sv::create(); It is quite common to just I 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 C defines, whether the underlying C should be incremented upon Sv object construction; it is C by default. When the Sv goes out of scope, it's destructor will be invoked and the refcounter of the underlying C will always be C-remented. The construtor does never throws, as all valid C values are accepted. The rule of thumb is following: if Sv wrapper is intended to B ownership with the C, it should use C policy (this is default, and mostly used case); if the wrapper should own the variable, then the policy should be C. There are convenient static methods to create an C 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) =head2 undef, yes, no There are a few Sv-constants, which represent common values, e.g. : static const Sv undef; static const Sv yes; static const Sv no; =head2 assignment operators 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 C will be thrown away after assignemnt, it's refcounter is C-remented and the ref-counter of the new value is incremented. Sv& operator= (Sv&& oth) Move-assignment operator is implemented simply by swapping underlying C without touching ref-counter. All assignment operators are NULL-safe =head2 getters The get the underlying C it is possible either to use related coersion operator or dereference operator: operator SV* () const SV* operator-> () const Please note, the result might be C if the underlyging C was C. It is possible to unwrap the underlying C either via operator coercion; it is B, as in the case of coercion failure the C 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 one_of_t* 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(); To resolve ambiguities in using C with Perl macros it the C coercion operator is supplied: operator void* () const =head2 bool operator() explicit operator bool () const Returns true if the C wraps any Perl C. 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 C is valid perl C and it returns C for the operator. =head2 defined() bool defined() const Null-safe method which returns C the object holds any C and later is defined. =head2 is_true() bool is_true () const Checks whether the object holds Perl value which evaluates to C. This is NULL-safe method. =head2 type-inspecting methods 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 C type and return C upon successful guess. All the methods are NULL-safe. svtype type () const This is NULL-unsafe type extraction from from C. =head2 readonly() =head2 readonly(bool val) bool readonly () const void readonly (bool val) This NULL-unsafe methods examine Perl C for read-only flag or set/unset it. =head2 use_count() U32 use_count () const Returns refcounter value. If C is NULL, then C<0> is returned. =head2 upgrade (svtype type) void upgrade (svtype type) Tries to upgrade C 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 C. This is NULL-unsafe method. =head2 dump () void dump () const Dumps the underlyign C to C. =head2 reset () void reset () Decrements refcounter in the undrerlying C and sets it to C. This is NULL-safe method. =head2 detach() SV* detach () Releases ownership on the underlying C (which might be C) and returns it. The refcounter is not touched. This is NULL-safe method. 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 =head2 detach_mortal() SV* detach_mortal () Same as C + C This is NULL-safe method. 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 C error. =head2 operators ==() and !=() 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 C points to the same address as the other argument. As only addresses are compared, all the operations are NULL-safe. =head2 magic payload Perl gives possibility to attach arbitrary data to C via magic slots. The L exposes that facility too. To distinguish between different payloads, it is required to supply the per-type unique marker. L assumes that it is enough to have just I 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 C pointer, which can be safely ignored. To remove magic payload from the C method can be used: int payload_detach (payload_marker_t* marker) To check payload existance via it's market the C can be used: bool payload_exists (const payload_marker_t* marker) Finally, to get the payload the C method should be used: Payload payload (const payload_marker_t* marker) const struct Payload { void* ptr; SV* obj; }; In the returned C struct you should access the C or C, depending on what kind of payload was attached. Both C and C can be used, if both of them were set. A few words should be told about payload cleanup. If the attached payload type was C, 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 C, 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 C XS-adapter section, for example: 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. =head2 void swap (Sv& lh, Sv& rh) Swaps underlying SV* between C and C =head1 SEE ALSO L L L L L L L L L L L L =cut