new

my $blob = Clownfish::Blob->new($byte_string);

Create a Blob containing the passed-in bytes. END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( pod => $constructor );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish     PACKAGE = Clownfish::Blob

SV* new(either_sv, sv) SV *either_sv; SV *sv; CODE: { STRLEN size; char *ptr = SvPV(sv, size); cfish_Blob *self = (cfish_Blob*)XSBind_new_blank_obj(aTHX_ either_sv); cfish_Blob_init(self, ptr, size); RETVAL = CFISH_OBJ_TO_SV_NOINC(self); } OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Blob",
);
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);
$binding->exclude_constructor;

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_boolean { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; use Clownfish::Boolean qw( $true_singleton $false_singleton );

my $bool = Clownfish::Boolean->singleton($truth_value);
my $truth_value = $bool->get_value;

if ($bool->equals($true_singleton)) {
    print "true\n";
}
END_SYNOPSIS
my $description = <<'END_DESCRIPTION';
There are only two singleton instances of this class: C<$true_singleton> and
C<$false_singleton> which are exported on demand.
END_DESCRIPTION
my $constructor = <<'END_CONSTRUCTOR';
=head2 singleton

my $bool = Clownfish::Boolean->singleton($truth_value);

Return either $true_singleton or $false_singleton depending on the supplied value. END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->set_description($description); $pod_spec->add_constructor( pod => $constructor );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish   PACKAGE = Clownfish::Boolean

SV* singleton(either_sv, value) SV *either_sv; bool value; CODE: { RETVAL = CFISH_OBJ_TO_SV_INC(cfish_Bool_singleton(value)); } OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Boolean",
);
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_bytebuf { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; my $buf = Clownfish::ByteBuf->new($byte_string); my $byte_string = $buf->to_perl; END_SYNOPSIS my $constructor = <<'END_CONSTRUCTOR'; =head2 new

my $buf = Clownfish::ByteBuf->new($byte_string);

Create a ByteBuf containing the passed-in bytes. END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( pod => $constructor );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish     PACKAGE = Clownfish::ByteBuf

SV* new(either_sv, sv) SV *either_sv; SV *sv; CODE: { STRLEN size; char *ptr = SvPV(sv, size); cfish_ByteBuf *self = (cfish_ByteBuf*)XSBind_new_blank_obj(aTHX_ either_sv); cfish_BB_init_bytes(self, ptr, size); RETVAL = CFISH_OBJ_TO_SV_NOINC(self); } OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::ByteBuf",
);
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);
$binding->exclude_constructor;

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_charbuf { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; my $buf = Clownfish::CharBuf->new; $buf->cat('abc'); $buf->cat_char(ord("\n")); print $buf->to_string; END_SYNOPSIS my $constructor = <<'END_CONSTRUCTOR'; my $buf = Clownfish::CharBuf->new( capacity => 256 ); END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( sample => $constructor );

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::CharBuf",
);
$binding->set_pod_spec($pod_spec);

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_string { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; my $string = Clownfish::String->new('abc'); print $string->to_perl, "\n"; END_SYNOPSIS my $constructor = <<'END_CONSTRUCTOR'; =head2 new

my $string = Clownfish::String->new($perl_string);

Return a String containing the passed-in Perl string. END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( pod => $constructor );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish     PACKAGE = Clownfish::String

SV* new(either_sv, sv) SV *either_sv; SV *sv; CODE: { STRLEN size; char *ptr = SvPVutf8(sv, size); cfish_String *self = (cfish_String*)XSBind_new_blank_obj(aTHX_ either_sv); cfish_Str_init_from_trusted_utf8(self, ptr, size); RETVAL = CFISH_OBJ_TO_SV_NOINC(self); } OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::String",
);
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);
$binding->exclude_constructor;

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_stringiterator { my @hand_rolled = qw( Next Prev );

my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new;
my $synopsis = <<'END_SYNOPSIS';
my $iter = $string->top;
while (my $code_point = $iter->next) {
    ...
}
END_SYNOPSIS
my $next_pod = <<'END_POD';
=head2 next

my $code_point = $iter->next;

Return the code point after the current position and advance the iterator. Returns undef at the end of the string. Returns zero but true for U+0000. END_POD my $prev_pod = <<'END_POD'; =head2 prev

my $code_point = $iter->prev;

Return the code point before the current position and go one step back. Returns undef at the start of the string. Returns zero but true for U+0000. END_POD $pod_spec->set_synopsis($synopsis); $pod_spec->add_method( method => 'Next', alias => 'next', pod => $next_pod, ); $pod_spec->add_method( method => 'Prev', alias => 'prev', pod => $prev_pod, );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish   PACKAGE = Clownfish::StringIterator

SV* next(self) cfish_StringIterator *self; CODE: { int32_t cp = CFISH_StrIter_Next(self);

if (cp == CFISH_STR_OOB) {
    RETVAL = &PL_sv_undef;
}
else if (cp == 0) {
    /* Zero but true. */
    RETVAL = newSVpvn("0e0", 3);
}
else {
    RETVAL = newSViv(cp);
}
}
OUTPUT: RETVAL

SV* prev(self) cfish_StringIterator *self; CODE: { int32_t cp = CFISH_StrIter_Prev(self);

if (cp == CFISH_STR_OOB) {
    RETVAL = &PL_sv_undef;
}
else if (cp == 0) {
    /* Zero but true. */
    RETVAL = newSVpvn("0e0", 3);
}
else {
    RETVAL = newSViv(cp);
}
}
OUTPUT: RETVAL
END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::StringIterator",
);
$binding->set_pod_spec($pod_spec);
$binding->exclude_method($_) for @hand_rolled;
$binding->append_xs($xs_code);

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_err { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; package MyErr; use base qw( Clownfish::Err );

...

package main;
use Scalar::Util qw( blessed );
while (1) {
    eval {
        do_stuff() or MyErr->throw("retry");
    };
    if ( blessed($@) and $@->isa("MyErr") ) {
        warn "Retrying...\n";
    }
    else {
        # Re-throw.
        die "do_stuff() died: $@";
    }
}
END_SYNOPSIS
$pod_spec->set_synopsis($synopsis);

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish    PACKAGE = Clownfish::Err

SV* trap(routine_sv, context_sv) SV *routine_sv; SV *context_sv; CODE: cfish_Err *error = XSBind_trap(routine_sv, context_sv); RETVAL = CFISH_OBJ_TO_SV_NOINC(error); OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Err",
);
$binding->bind_constructor( alias => '_new' );
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_hash { my @hand_rolled = qw( Store );

my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new;
my $synopsis = <<'END_SYNOPSIS';
my $hash = Clownfish::Hash->new;
$hash->store($key, $value);
my $value = $hash->fetch($key);
END_SYNOPSIS
my $constructor = <<'END_CONSTRUCTOR';
my $hash = Clownfish::Hash->new( capacity => 256 );
END_CONSTRUCTOR
my $store_pod = <<'END_POD';
=head2 store

$hash->store($key, $value);

Store a key-value pair. END_POD $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( sample => $constructor ); $pod_spec->add_method( method => 'Store', alias => 'store', pod => $store_pod, );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish    PACKAGE = Clownfish::Hash
SV*
fetch_raw(self, key)
cfish_Hash *self;
cfish_String *key;
CODE:
RETVAL = CFISH_OBJ_TO_SV_INC(CFISH_Hash_Fetch_IMP(self, key));
OUTPUT: RETVAL

void store(self, key, value_sv); cfish_Hash *self; cfish_String *key; SV *value_sv; PPCODE: { cfish_Obj *value = (cfish_Obj*)XSBind_perl_to_cfish_nullable(aTHX_ value_sv, CFISH_OBJ); CFISH_Hash_Store_IMP(self, key, value); } END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Hash",
);
$binding->set_pod_spec($pod_spec);
$binding->exclude_method($_) for @hand_rolled;
$binding->append_xs($xs_code);

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_hashiterator { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; my $iter = Clownfish::HashIterator->new($hash); while ($iter->next) { my $key = $iter->get_key; my $value = $iter->get_value; } END_SYNOPSIS my $constructor = <<'END_CONSTRUCTOR'; my $iter = Clownfish::HashIterator->new($hash); END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( sample => $constructor );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish   PACKAGE = Clownfish::HashIterator

SV* new(either_sv, hash) SV *either_sv; cfish_Hash *hash; CODE: { cfish_HashIterator *self = (cfish_HashIterator*)XSBind_new_blank_obj(aTHX_ either_sv); cfish_HashIter_init(self, hash); RETVAL = CFISH_OBJ_TO_SV_NOINC(self); } OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::HashIterator",
);
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);
$binding->exclude_constructor;

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_float { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; my $float = Clownfish::Float->new(2.5); my $value = $float->get_value; END_SYNOPSIS my $constructor = <<'END_CONSTRUCTOR'; my $float = Clownfish::Float->new($value); END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( sample => $constructor );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish   PACKAGE = Clownfish::Float

SV* new(either_sv, value) SV *either_sv; double value; CODE: { cfish_Float *self = (cfish_Float*)XSBind_new_blank_obj(aTHX_ either_sv); cfish_Float_init(self, value); RETVAL = CFISH_OBJ_TO_SV_NOINC(self); } OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Float",
);
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);
$binding->exclude_constructor;

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_integer { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; my $integer = Clownfish::Integer->new(7); my $value = $integer->get_value; END_SYNOPSIS my $constructor = <<'END_CONSTRUCTOR'; my $integer = Clownfish::Integer->new($value); END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( sample => $constructor );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish   PACKAGE = Clownfish::Integer

SV* new(either_sv, value) SV *either_sv; int64_t value; CODE: { cfish_Integer *self = (cfish_Integer*)XSBind_new_blank_obj(aTHX_ either_sv); cfish_Int_init(self, value); RETVAL = CFISH_OBJ_TO_SV_NOINC(self); } OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Integer",
);
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);
$binding->exclude_constructor;

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_obj { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; package MyObj; use base qw( Clownfish::Obj );

# Inside-out member var.
my %foo;

sub new {
    my ( $class, %args ) = @_;
    my $foo = delete $args{foo};
    my $self = $class->SUPER::new(%args);
    $foo{$$self} = $foo;
    return $self;
}

sub get_foo {
    my $self = shift;
    return $foo{$$self};
}

sub DESTROY {
    my $self = shift;
    delete $foo{$$self};
    $self->SUPER::DESTROY;
}
END_SYNOPSIS
my $description = <<'END_DESCRIPTION';
Clownfish::Obj is the base class of the Clownfish object hierarchy.

From the standpoint of a Perl programmer, all classes are implemented as blessed scalar references, with the scalar storing a pointer to a C struct.

Subclassing

The recommended way to subclass Clownfish::Obj and its descendants is to use the inside-out design pattern. (See Class::InsideOut for an introduction to inside-out techniques.)

Since the blessed scalar stores a C pointer value which is unique per-object, $$self can be used as an inside-out ID.

# Accessor for 'foo' member variable.
sub get_foo {
    my $self = shift;
    return $foo{$$self};
}

Caveats:

  • Inside-out aficionados will have noted that the "cached scalar id" stratagem recommended above isn't compatible with ithreads.

  • Overridden methods must not return undef unless the API specifies that returning undef is permissible. (Failure to adhere to this rule currently results in a segfault rather than an exception.)

CONSTRUCTOR

new

my $self = $class->SUPER::new;

Abstract constructor -- must be invoked via a subclass. Attempting to instantiate objects of class "Clownfish::Obj" directly causes an error.

Takes no arguments; if any are supplied, an error will be reported. END_DESCRIPTION my $to_perl_pod = <<'END_POD'; =head2 to_perl

my $native = $obj->to_perl;

Tries to convert the object to its native Perl representation. END_POD my $destroy_pod = <<'END_POD'; =head2 DESTROY

All Clownfish classes implement a DESTROY method; if you override it in a subclass, you must call $self->SUPER::DESTROY to avoid leaking memory. END_POD $pod_spec->set_synopsis($synopsis); $pod_spec->set_description($description); $pod_spec->add_method( method => 'To_Host', alias => 'to_perl', pod => $to_perl_pod, ); $pod_spec->add_method( method => 'Destroy', alias => 'DESTROY', pod => $destroy_pod, );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish     PACKAGE = Clownfish::Obj

SV* get_class(self) cfish_Obj *self CODE: cfish_Class *klass = cfish_Obj_get_class(self); RETVAL = (SV*)CFISH_Class_To_Host(klass); OUTPUT: RETVAL

SV* get_class_name(self) cfish_Obj *self CODE: cfish_String *class_name = cfish_Obj_get_class_name(self); RETVAL = (SV*)CFISH_Str_To_Host(class_name); OUTPUT: RETVAL

bool is_a(self, class_name) cfish_Obj *self; cfish_String *class_name; CODE: { cfish_Class *target = cfish_Class_fetch_class(class_name); RETVAL = cfish_Obj_is_a(self, target); } OUTPUT: RETVAL

SV* clone_raw(self) cfish_Obj *self; CODE: RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_Obj_Clone(self)); OUTPUT: RETVAL

SV* to_perl(self) cfish_Obj *self; CODE: RETVAL = (SV*)CFISH_Obj_To_Host(self); OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Obj",
);
$binding->bind_method(
    alias  => 'DESTROY',
    method => 'Destroy',
);
$binding->append_xs($xs_code);
$binding->set_pod_spec($pod_spec);

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_vector { my @hand_rolled = qw( Store );

my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new;
my $synopsis = <<'END_SYNOPSIS';
my $vector = Clownfish::Vector->new;
$vector->store($tick, $value);
my $value = $vector->fetch($tick);
END_SYNOPSIS
my $constructor = <<'END_CONSTRUCTOR';
my $vector = Clownfish::Vector->new( capacity => 256 );
END_CONSTRUCTOR
my $store_pod = <<'END_POD';
=head2 store

$vector->store($tick, $elem)

Store an element at index tick, possibly displacing an existing element. END_POD $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( sample => $constructor ); $pod_spec->add_method( method => 'Store', alias => 'store', pod => $store_pod, );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish   PACKAGE = Clownfish::Vector

SV* pop_raw(self) cfish_Vector *self; CODE: RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_Vec_Pop(self)); OUTPUT: RETVAL

SV* delete_raw(self, tick) cfish_Vector *self; uint32_t tick; CODE: RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_Vec_Delete(self, tick)); OUTPUT: RETVAL

void store(self, tick, value); cfish_Vector *self; uint32_t tick; cfish_Obj *value; PPCODE: { if (value) { CFISH_INCREF(value); } CFISH_Vec_Store_IMP(self, tick, value); }

SV* fetch_raw(self, tick) cfish_Vector *self; uint32_t tick; CODE: RETVAL = CFISH_OBJ_TO_SV_INC(CFISH_Vec_Fetch(self, tick)); OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Vector",
);
$binding->set_pod_spec($pod_spec);
$binding->exclude_method($_) for @hand_rolled;
$binding->append_xs($xs_code);

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_class { my $pod_spec = Clownfish::CFC::Binding::Perl::Pod->new; my $synopsis = <<'END_SYNOPSIS'; my $class = Clownfish::Class->fetch_class('Foo::Bar'); my $subclass = Clownfish::Class->singleton('Foo::Bar::Jr', $class); END_SYNOPSIS my $fetch_class_sample = <<'END_CONSTRUCTOR'; my $class = Clownfish::Class->fetch_class($class_name); END_CONSTRUCTOR my $singleton_sample = <<'END_CONSTRUCTOR'; my $class = Clownfish::Class->singleton( class_name => $class_name, parent => $parent, ); END_CONSTRUCTOR $pod_spec->set_synopsis($synopsis); $pod_spec->add_constructor( alias => 'fetch_class', sample => $fetch_class_sample, ); $pod_spec->add_constructor( alias => 'singleton', sample => $singleton_sample, );

my $xs_code = <<'END_XS_CODE';
MODULE = Clownfish   PACKAGE = Clownfish::Class

SV* fetch_class(unused_sv, class_name) SV *unused_sv; cfish_String *class_name; CODE: { cfish_Class *klass = cfish_Class_fetch_class(class_name); CFISH_UNUSED_VAR(unused_sv); RETVAL = klass ? (SV*)CFISH_Class_To_Host(klass) : &PL_sv_undef; } OUTPUT: RETVAL

SV* singleton(unused_sv, ...) SV *unused_sv; CODE: { static const XSBind_ParamSpec param_specs[2] = { XSBIND_PARAM("class_name", true), XSBIND_PARAM("parent", false), }; int32_t locations[2]; cfish_String *class_name = NULL; cfish_Class *parent = NULL; cfish_Class *singleton = NULL; CFISH_UNUSED_VAR(unused_sv); XSBind_locate_args(aTHX_ &(ST(0)), 1, items, param_specs, locations, 2); class_name = (cfish_String*)XSBind_arg_to_cfish( aTHX_ ST(locations[0]), "class_name", CFISH_STRING, CFISH_ALLOCA_OBJ(CFISH_STRING)); if (locations[1] < items) { parent = (cfish_Class*)XSBind_arg_to_cfish_nullable( aTHX_ ST(locations[1]), "parent", CFISH_CLASS, NULL); } singleton = cfish_Class_singleton(class_name, parent); RETVAL = (SV*)CFISH_Class_To_Host(singleton); } OUTPUT: RETVAL END_XS_CODE

my $binding = Clownfish::CFC::Binding::Perl::Class->new(
    parcel     => "Clownfish",
    class_name => "Clownfish::Class",
);
$binding->set_pod_spec($pod_spec);
$binding->append_xs($xs_code);

Clownfish::CFC::Binding::Perl::Class->register($binding);
}

sub bind_stringhelper { my $xs_code = <<'END_XS_CODE'; MODULE = Clownfish PACKAGE = Clownfish::Util::StringHelper

Turn an SV's UTF8 flag on. Equivalent to Encode::_utf8_on, but we don't have to load Encode.

Turn an SV's UTF8 flag off.

Upgrade a SV to UTF8, converting Latin1 if necessary. Equivalent to utf::upgrade().

Concatenate one scalar onto the end of the other, ignoring UTF-8 status of the second scalar. This is necessary because $not_utf8 . $utf8 results in a scalar which has been infected by the UTF-8 flag of the second argument.