#pragma once
#include <xs/Sv.h>
#include <panda/string.h>
namespace xs {
using xs::my_perl;
namespace detail {
template <typename T> inline panda::enable_if_signed_integral_t<T> _getnum (SV* sv) { return SvIV(sv); }
template <typename T> inline panda::enable_if_unsigned_integral_t<T> _getnum (SV* sv) { return SvUV(sv); }
template <typename T> inline panda::enable_if_floatp_t<T> _getnum (SV* sv) { return SvNV(sv); }
struct AutoNumber {
AutoNumber(SV* sv) : sv(sv) {}
template <class T, typename = panda::enable_if_arithmetic_t<T>>
operator T () const { return sv ? _getnum<T>(sv) : T(); }
private:
SV* sv;
};
}
struct Scalar : Sv {
static const Scalar undef;
static const Scalar yes;
static const Scalar no;
static Scalar create () { return Scalar(newSV(0), NONE); }
static Scalar noinc (SV* val) { return Scalar(val, NONE); }
static Scalar noinc (GV* val) { return Scalar(val, NONE); }
Scalar (std::nullptr_t = nullptr) {}
Scalar (SV* sv, bool policy = INCREMENT) : Sv(sv, policy) { _validate(); }
Scalar (GV* sv, bool policy = INCREMENT) : Sv(sv, policy) {}
Scalar (const Scalar& oth) : Sv(oth) {}
Scalar (Scalar&& oth) : Sv(std::move(oth)) {}
Scalar (const Sv& oth) : Scalar(oth.get()) {}
Scalar (Sv&& oth) : Sv(std::move(oth)) { _validate(); }
Scalar (const Array&) = delete;
Scalar (const Hash&) = delete;
Scalar (const Sub&) = delete;
Scalar (const Io&) = delete;
Scalar& operator= (SV* val) {
Sv::operator=(val);
_validate();
return *this;
}
Scalar& operator= (GV* val) {
Sv::operator=(val);
return *this;
}
Scalar& operator= (const Scalar& oth) {
Sv::operator=(oth.sv);
return *this;
}
Scalar& operator= (Scalar&& oth) {
Sv::operator=(std::move(oth));
return *this;
}
Scalar& operator= (const Sv& oth) { return operator=(oth.get()); }
Scalar& operator= (Sv&& oth) {
Sv::operator=(std::move(oth));
_validate();
return *this;
}
Scalar& operator= (const Array&) = delete;
Scalar& operator= (const Hash&) = delete;
Scalar& operator= (const Sub&) = delete;
Scalar& operator= (const Io&) = delete;
void set (SV* val) { Sv::operator=(val); }
void set (GV* val) { Sv::operator=(val); }
operator AV* () const = delete;
operator HV* () const = delete;
operator CV* () const = delete;
operator IO* () const = delete;
template <class T = SV> panda::enable_if_one_of_t<T,SV,GV>* get () const { return (T*)sv; }
void upgrade (svtype type) {
if (type > SVt_PVMG && type != SVt_PVGV) throw std::logic_error("can't upgrade Scalar to something bigger than PVMG (and != PVGV)");
Sv::upgrade(type);
}
template <class T = panda::string>
T as_string () const {
if (!sv) return T();
STRLEN len;
const char* buf = SvPV_const(sv, len);
return T(buf, len);
}
template <class T = int> T as_number () const { return sv ? detail::_getnum<T>(sv) : T(); }
detail::AutoNumber number () const { return detail::AutoNumber(sv); }
static void __at_perl_destroy ();
private:
void _validate_rest();
void _validate () {
if (!sv || SvTYPE(sv) <= SVt_PVMG || SvTYPE(sv) == SVt_PVGV) return;
_validate_rest();
}
};
}