coordf_t T_NV

std::vector<Points::size_type>  T_STD_VECTOR_INT
std::vector<size_t>  T_STD_VECTOR_INT

t_config_option_key T_STD_STRING
t_model_material_id T_STD_STRING
t_layer_height_ranges   T_LAYER_HEIGHT_RANGES


BoundingBox*               O_OBJECT_SLIC3R
Ref<BoundingBox>           O_OBJECT_SLIC3R_T
Clone<BoundingBox>         O_OBJECT_SLIC3R_T

BoundingBoxf3*             O_OBJECT_SLIC3R
Ref<BoundingBoxf3>         O_OBJECT_SLIC3R_T
Clone<BoundingBoxf3>       O_OBJECT_SLIC3R_T

DynamicPrintConfig*        O_OBJECT_SLIC3R
Ref<DynamicPrintConfig>    O_OBJECT_SLIC3R_T
PrintObjectConfig*         O_OBJECT_SLIC3R
PrintRegionConfig*         O_OBJECT_SLIC3R
PrintConfig*               O_OBJECT_SLIC3R
FullPrintConfig*           O_OBJECT_SLIC3R
ZTable*                    O_OBJECT

TriangleMesh*              O_OBJECT_SLIC3R
Ref<TriangleMesh>          O_OBJECT_SLIC3R_T
Clone<TriangleMesh>        O_OBJECT_SLIC3R_T

Point*                     O_OBJECT_SLIC3R
Ref<Point>                 O_OBJECT_SLIC3R_T
Clone<Point>               O_OBJECT_SLIC3R_T

Pointf*                    O_OBJECT_SLIC3R
Ref<Pointf>                O_OBJECT_SLIC3R_T
Clone<Pointf>              O_OBJECT_SLIC3R_T

Pointf3*                   O_OBJECT_SLIC3R
Ref<Pointf3>               O_OBJECT_SLIC3R_T
Clone<Pointf3>             O_OBJECT_SLIC3R_T

Line*                      O_OBJECT_SLIC3R
Ref<Line>                  O_OBJECT_SLIC3R_T
Clone<Line>                O_OBJECT_SLIC3R_T

Polyline*                  O_OBJECT_SLIC3R
Ref<Polyline>              O_OBJECT_SLIC3R_T
Clone<Polyline>            O_OBJECT_SLIC3R_T

PolylineCollection*        O_OBJECT_SLIC3R
Ref<PolylineCollection>    O_OBJECT_SLIC3R_T
Clone<PolylineCollection>  O_OBJECT_SLIC3R_T

Polygon*                   O_OBJECT_SLIC3R
Ref<Polygon>               O_OBJECT_SLIC3R_T
Clone<Polygon>             O_OBJECT_SLIC3R_T

ExPolygon*                 O_OBJECT_SLIC3R
Ref<ExPolygon>             O_OBJECT_SLIC3R_T
Clone<ExPolygon>           O_OBJECT_SLIC3R_T

ExPolygonCollection*       O_OBJECT_SLIC3R
Ref<ExPolygonCollection>   O_OBJECT_SLIC3R_T
Clone<ExPolygonCollection> O_OBJECT_SLIC3R_T

ExtrusionEntityCollection*              O_OBJECT_SLIC3R
Ref<ExtrusionEntityCollection>          O_OBJECT_SLIC3R_T
Clone<ExtrusionEntityCollection>        O_OBJECT_SLIC3R_T

ExtrusionPath*             O_OBJECT_SLIC3R
Ref<ExtrusionPath>         O_OBJECT_SLIC3R_T
Clone<ExtrusionPath>       O_OBJECT_SLIC3R_T

ExtrusionLoop*             O_OBJECT_SLIC3R
Ref<ExtrusionLoop>         O_OBJECT_SLIC3R_T
Clone<ExtrusionLoop>       O_OBJECT_SLIC3R_T

Flow*                      O_OBJECT_SLIC3R
Ref<Flow>                  O_OBJECT_SLIC3R_T
Clone<Flow>                O_OBJECT_SLIC3R_T

PrintState*                O_OBJECT_SLIC3R

Surface*                   O_OBJECT_SLIC3R
Ref<Surface>               O_OBJECT_SLIC3R_T
Clone<Surface>             O_OBJECT_SLIC3R_T

SurfaceCollection*         O_OBJECT_SLIC3R

Extruder*                  O_OBJECT_SLIC3R

Model*                     O_OBJECT_SLIC3R
Ref<Model>                 O_OBJECT_SLIC3R_T
Clone<Model>               O_OBJECT_SLIC3R_T

ModelMaterial*             O_OBJECT_SLIC3R
Ref<ModelMaterial>         O_OBJECT_SLIC3R_T
Clone<ModelMaterial>       O_OBJECT_SLIC3R_T

ModelObject*               O_OBJECT_SLIC3R
Ref<ModelObject>           O_OBJECT_SLIC3R_T
Clone<ModelObject>         O_OBJECT_SLIC3R_T

ModelVolume*               O_OBJECT_SLIC3R
Ref<ModelVolume>           O_OBJECT_SLIC3R_T
Clone<ModelVolume>         O_OBJECT_SLIC3R_T

ModelInstance*             O_OBJECT_SLIC3R
Ref<ModelInstance>         O_OBJECT_SLIC3R_T
Clone<ModelInstance>       O_OBJECT_SLIC3R_T


ExtrusionLoopRole     T_UV
ExtrusionRole     T_UV
FlowRole     T_UV
PrintStep     T_UV
SurfaceType     T_UV
ClipperLib::JoinType		T_UV
ClipperLib::PolyFillType		T_UV

# we return these types whenever we want the items to be cloned
Points          T_ARRAYREF
Pointfs         T_ARRAYREF
Lines           T_ARRAYREF
Polygons        T_ARRAYREF
Polylines       T_ARRAYREF
ExPolygons      T_ARRAYREF
ExtrusionPaths  T_ARRAYREF
Surfaces        T_ARRAYREF

# we return these types whenever we want the items to be returned
# by reference and marked ::Ref because they're contained in another
# Perl object
Polygons*       T_ARRAYREF_PTR
ModelObjectPtrs* T_PTR_ARRAYREF_PTR
ModelVolumePtrs* T_PTR_ARRAYREF_PTR
ModelInstancePtrs*   T_PTR_ARRAYREF_PTR

# we return these types whenever we want the items to be returned
# by reference and not marked ::Ref because they're newly allocated
# and not referenced by any Perl object
TriangleMeshPtrs T_PTR_ARRAYREF


INPUT

O_OBJECT_SLIC3R
    if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) {
        if ( sv_isa($arg, perl_class_name($var) ) ||  sv_isa($arg, perl_class_name_ref($var) )) {
              $var = ($type)SvIV((SV*)SvRV( $arg ));
        } else {
              croak(\"$var is not of type %s (got %s)\", perl_class_name($var), HvNAME(SvSTASH(SvRV($arg))));
              XSRETURN_UNDEF;
        }
    } else {
        warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
        XSRETURN_UNDEF;
    }

T_ARRAYREF
    if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVAV) {
        AV* av = (AV*)SvRV($arg);
        const unsigned int len = av_len(av)+1;
        $type* tmp = new $type(len);
        for (unsigned int i = 0; i < len; i++) {
            SV** elem = av_fetch(av, i, 0);
            (*tmp)[i].from_SV_check(*elem);
        }
        $var = *tmp;
	    delete tmp;
    } else
        Perl_croak(aTHX_ \"%s: %s is not an array reference\",
	             ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]},
	             \"$var\");

T_LAYER_HEIGHT_RANGES
    {
        if (!SvROK($arg) || SvTYPE(SvRV($arg)) != SVt_PVAV) {
            Perl_croak(aTHX_ \"%s: %s is not an array reference\",
                     ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]},
                     \"$var\");
        }

        AV* av = (AV*)SvRV($arg);
        const unsigned int len = av_len(av)+1;
        t_layer_height_ranges tmp_ranges;
        for (unsigned int i = 0; i < len; i++) {
            SV* elem = *av_fetch(av, i, 0);
            if (!SvROK(elem) || SvTYPE(SvRV(elem)) != SVt_PVAV) {
                Perl_croak(
                    aTHX_ \"%s: %s contains something that is not an array reference\",
                        ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]},
                        \"$var\");
            }

            AV* elemAV = (AV*)SvRV(elem);
            if (av_len(elemAV) + 1 != 3) {
                Perl_croak(
                    aTHX_ \"%s: %s contains an array that isn't 3 elements long\",
                        ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]},
                        \"$var\");
            }

            coordf_t vals[3];
            for (unsigned int j = 0; j < 3; ++j) {
                SV *elem_elem = *av_fetch(elemAV, j, 0);
                if (!SvNOK(elem_elem)) {
                    Perl_croak(
                        aTHX_ \"%s: layer ranges and heights must be numbers\",
                            ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]});
                }

                vals[j] = SvNV(elem_elem);
            }

            tmp_ranges[t_layer_height_range(vals[0], vals[1])] = vals[2];
        }

        $var = tmp_ranges;
    }


OUTPUT
# return object from pointer
O_OBJECT_SLIC3R
        sv_setref_pv( $arg, perl_class_name($var), (void*)$var );

# return value handled by template class
O_OBJECT_SLIC3R_T
        sv_setref_pv( $arg, $type\::CLASS(), (void*)$var );


T_ARRAYREF
	AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	av_extend(av, $var.size()-1);
	int i = 0;
    for (${type}::const_iterator it = $var.begin(); it != $var.end(); ++it) {
        av_store(av, i++, perl_to_SV_clone_ref(*it));
	}
	$var.clear();

T_ARRAYREF_PTR
    AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	av_extend(av, $var->size()-1);
	int i = 0;
    for (${ my $t = $type; $t =~ s/\*$//; \$t }::iterator it = $var->begin(); it != $var->end(); ++it) {
        av_store(av, i++, perl_to_SV_ref(*it));
	}

T_PTR_ARRAYREF_PTR
    AV* av = newAV();
    $arg = newRV_noinc((SV*)av);
    sv_2mortal($arg);
    av_extend(av, $var->size()-1);
    int i = 0;
    for (${ my $t = $type; $t =~ s/\*$//; \$t }::iterator it = $var->begin(); it != $var->end(); ++it) {
        av_store(av, i++, perl_to_SV_ref(**it));
    }

T_PTR_ARRAYREF
    AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	av_extend(av, $var.size()-1);
	int i = 0;
    for (${type}::iterator it = $var.begin(); it != $var.end(); ++it) {
        av_store(av, i++, (*it)->to_SV());
	}

T_LAYER_HEIGHT_RANGES
    AV* av = newAV();
    $arg = newRV_noinc((SV*)av);
    sv_2mortal($arg);
    av_extend(av, $var.size() - 1);
    // map is sorted, so we can just copy it in order
    int i = 0;
    for (${type}::iterator it = $var.begin(); it != $var.end(); ++it) {
        const coordf_t range_values[] = {
                it->first.first,    // key's first = minz
                it->first.second,   // key's second = maxz
                it->second,         // value = height
            };

        AV *rangeAV = newAV();
        SV *rangeAV_ref = newRV_noinc((SV*)rangeAV);
        sv_2mortal(rangeAV_ref);
        av_extend(rangeAV, 2);
        for (int j = 0; j < 3; ++j) {
            SV *val = sv_newmortal();
            sv_setnv(val, range_values[j]);
            av_store(rangeAV, j, val);
        }

        av_store(av, i++, (SV*)rangeAV_ref);
    }
