coordf_t T_NV

std::string                     T_STD_STRING
local_encoded_string     		T_STD_STRING_LOCAL_ENCODING
t_config_option_key             T_STD_STRING
t_model_material_id             T_STD_STRING

std::vector<std::string>	    T_STD_VECTOR_STD_STRING

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

std::vector<unsigned int>	    T_STD_VECTOR_UINT

std::vector<double>	            T_STD_VECTOR_DOUBLE

t_layer_height_ranges           T_LAYER_HEIGHT_RANGES


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

BoundingBoxf*              O_OBJECT_SLIC3R
Ref<BoundingBoxf>          O_OBJECT_SLIC3R_T
Clone<BoundingBoxf>        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
Clone<DynamicPrintConfig>  O_OBJECT_SLIC3R_T

StaticPrintConfig*         O_OBJECT_SLIC3R
Ref<StaticPrintConfig>     O_OBJECT_SLIC3R_T

PrintObjectConfig*         O_OBJECT_SLIC3R
Ref<PrintObjectConfig>     O_OBJECT_SLIC3R_T

PrintRegionConfig*         O_OBJECT_SLIC3R
Ref<PrintRegionConfig>     O_OBJECT_SLIC3R_T

GCodeConfig*               O_OBJECT_SLIC3R
Ref<GCodeConfig>           O_OBJECT_SLIC3R_T

PrintConfig*               O_OBJECT_SLIC3R
Ref<PrintConfig>           O_OBJECT_SLIC3R_T

FullPrintConfig*           O_OBJECT_SLIC3R
Ref<FullPrintConfig>       O_OBJECT_SLIC3R_T

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

Point3*                    O_OBJECT_SLIC3R
Ref<Point3>                O_OBJECT_SLIC3R_T
Clone<Point3>              O_OBJECT_SLIC3R_T

Vec2d*                     O_OBJECT_SLIC3R
Ref<Vec2d>                 O_OBJECT_SLIC3R_T
Clone<Vec2d>               O_OBJECT_SLIC3R_T

Vec3d*                     O_OBJECT_SLIC3R
Ref<Vec3d>                 O_OBJECT_SLIC3R_T
Clone<Vec3d>               O_OBJECT_SLIC3R_T

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

Linef3*                    O_OBJECT_SLIC3R
Ref<Linef3>                O_OBJECT_SLIC3R_T
Clone<Linef3>              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

ExtrusionMultiPath*        O_OBJECT_SLIC3R
Ref<ExtrusionMultiPath>    O_OBJECT_SLIC3R_T
Clone<ExtrusionMultiPath>  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

ExtrusionSimulator*        O_OBJECT_SLIC3R
Ref<ExtrusionSimulator>    O_OBJECT_SLIC3R_T
Clone<ExtrusionSimulator>  O_OBJECT_SLIC3R_T

Filler*                    O_OBJECT_SLIC3R
Ref<Filler>                O_OBJECT_SLIC3R_T
Clone<Filler>              O_OBJECT_SLIC3R_T

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

PrintState*                O_OBJECT_SLIC3R
Ref<PrintState>            O_OBJECT_SLIC3R_T

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

SurfaceCollection*         O_OBJECT_SLIC3R
Ref<SurfaceCollection>     O_OBJECT_SLIC3R_T

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

PrintRegion*               O_OBJECT_SLIC3R
Ref<PrintRegion>           O_OBJECT_SLIC3R_T

PrintObject*               O_OBJECT_SLIC3R
Ref<PrintObject>           O_OBJECT_SLIC3R_T

Print*                     O_OBJECT_SLIC3R
Ref<Print>                 O_OBJECT_SLIC3R_T
Clone<Print>               O_OBJECT_SLIC3R_T

LayerRegion*               O_OBJECT_SLIC3R
Ref<LayerRegion>           O_OBJECT_SLIC3R_T

Layer*                     O_OBJECT_SLIC3R
Ref<Layer>                 O_OBJECT_SLIC3R_T

SupportLayer*              O_OBJECT_SLIC3R
Ref<SupportLayer>          O_OBJECT_SLIC3R_T

PlaceholderParser*         O_OBJECT_SLIC3R
Ref<PlaceholderParser>     O_OBJECT_SLIC3R_T
Clone<PlaceholderParser>   O_OBJECT_SLIC3R_T

CoolingBuffer*             O_OBJECT_SLIC3R
Ref<CoolingBuffer>         O_OBJECT_SLIC3R_T
Clone<CoolingBuffer>       O_OBJECT_SLIC3R_T

GCode*                      O_OBJECT_SLIC3R
Ref<GCode>                  O_OBJECT_SLIC3R_T
Clone<GCode>                O_OBJECT_SLIC3R_T

GCodePreviewData*			O_OBJECT_SLIC3R
Ref<GCodePreviewData>		O_OBJECT_SLIC3R_T
Clone<GCodePreviewData>		O_OBJECT_SLIC3R_T

MotionPlanner*             O_OBJECT_SLIC3R
Ref<MotionPlanner>         O_OBJECT_SLIC3R_T
Clone<MotionPlanner>       O_OBJECT_SLIC3R_T

GCodeSender*               O_OBJECT_SLIC3R
Ref<GCodeSender>           O_OBJECT_SLIC3R_T
Clone<GCodeSender>         O_OBJECT_SLIC3R_T

BridgeDetector*            O_OBJECT_SLIC3R
Ref<BridgeDetector>        O_OBJECT_SLIC3R_T
Clone<BridgeDetector>      O_OBJECT_SLIC3R_T

PerimeterGenerator*         O_OBJECT_SLIC3R
Ref<PerimeterGenerator>     O_OBJECT_SLIC3R_T
Clone<PerimeterGenerator>   O_OBJECT_SLIC3R_T

PrintObjectSupportMaterial*       O_OBJECT_SLIC3R
Ref<PrintObjectSupportMaterial>   O_OBJECT_SLIC3R_T
Clone<PrintObjectSupportMaterial> O_OBJECT_SLIC3R_T

Axis                  T_UV
ExtrusionLoopRole     T_UV
ExtrusionRole     T_UV
ExtrusionSimulationType T_UV
FlowRole     T_UV
PrintStep     T_UV
PrintObjectStep     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
PrintRegionPtrs*    T_PTR_ARRAYREF_PTR
PrintObjectPtrs*    T_PTR_ARRAYREF_PTR
LayerPtrs*          T_PTR_ARRAYREF_PTR
SupportLayerPtrs*   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

T_STD_STRING
    {
      size_t len;
      // const char * c = SvPV($arg, len);
      // Always convert strings to UTF-8 before passing them to XS
      const char * c = SvPVutf8($arg, len);
      $var = std::string(c, len);
    }

INPUT
T_STD_STRING_LOCAL_ENCODING
    {
      size_t len;
      const char * c = SvPV($arg, len);
      $var = std::string(c, len);
    }

T_STD_VECTOR_STD_STRING
	if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) {
	  AV* av = (AV*)SvRV($arg);
	  const unsigned int alen = av_len(av)+1;
	  $var = std::vector<std::string>(alen);
	  STRLEN len;
	  char* tmp;
	  SV** elem;
	  for (unsigned int i = 0; i < alen; i++) {
	    elem = av_fetch(av, i, 0);
	    if (elem != NULL) {
	    tmp = SvPV(*elem, len);
	      ${var}[i] = std::string(tmp, len);
	    }
	    else
	      ${var}[i] = std::string(\"\");
	  }
	}
	else
	  Perl_croak(aTHX_ \"%s: %s is not an array reference\",
	             ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]},
	             \"$var\");

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

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

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

O_OBJECT_SLIC3R
    if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) {
        if ( sv_isa($arg, Slic3r::perl_class_name($var) ) ||  sv_isa($arg, Slic3r::perl_class_name_ref($var) )) {
              $var = ($type)SvIV((SV*)SvRV( $arg ));
        } else {
              croak(\"$var is not of type %s (got %s)\", Slic3r::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;
        $var.resize(len);
        for (unsigned int i = 0; i < len; i++) {
            SV** elem = av_fetch(av, i, 0);
            from_SV_check(*elem, &$var\[i]);
        }
    } 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 (!looks_like_number(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

T_STD_STRING
    $arg = newSVpvn_utf8( $var.c_str(), $var.length(), true );

T_STD_STRING_LOCAL_ENCODING
    $arg = newSVpvn( $var.c_str(), $var.length() );

T_STD_VECTOR_STD_STRING
	AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	const unsigned int len = $var.size();
        if (len)
          av_extend(av, len-1);
	for (unsigned int i = 0; i < len; i++) {
	  const std::string& str = ${var}[i];
	  STRLEN len = str.length();
	  av_store(av, i, newSVpvn_utf8(str.c_str(), len, true));
	}

T_STD_VECTOR_INT
	AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	const unsigned int len = $var.size();
        if (len)
          av_extend(av, len-1);
	for (unsigned int i = 0; i < len; i++) {
	  av_store(av, i, newSViv(${var}[i]));
	}

T_STD_VECTOR_UINT
	AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	const unsigned int len = $var.size();
        if (len)
          av_extend(av, len-1);
	for (unsigned int i = 0; i < len; i++) {
	  av_store(av, i, newSVuv(${var}[i]));
	}

T_STD_VECTOR_DOUBLE
	AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	const unsigned int len = $var.size();
        if (len)
          av_extend(av, len-1);
	for (unsigned int i = 0; i < len; i++) {
	  av_store(av, i, newSVnv(${var}[i]));
	}

# return object from pointer
O_OBJECT_SLIC3R
        if ($var == NULL)
            XSRETURN_UNDEF;
        sv_setref_pv( $arg, Slic3r::perl_class_name($var), (void*)$var );

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


T_ARRAYREF
	AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	const unsigned int len = $var.size();
	if (len > 0) av_extend(av, len-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));
	}

T_ARRAYREF_PTR
    AV* av = newAV();
	$arg = newRV_noinc((SV*)av);
	sv_2mortal($arg);
	const unsigned int len = $var->size();
	if (len > 0) av_extend(av, len-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);
	const unsigned int len = $var->size();
	if (len > 0) av_extend(av, len-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);
	const unsigned int len = $var.size();
	if (len > 0) av_extend(av, len-1);
	int i = 0;
    for (${type}::iterator it = $var.begin(); it != $var.end(); ++it) {
        av_store(av, i++, to_SV(*it));
	}

T_LAYER_HEIGHT_RANGES
    AV* av = newAV();
    $arg = newRV_noinc((SV*)av);
    sv_2mortal($arg);
	const unsigned int len = $var.size();
	if (len > 0) av_extend(av, len-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();
        av_extend(rangeAV, 2);
        for (int j = 0; j < 3; ++j) {
            av_store(rangeAV, j, newSVnv(range_values[j]));
        }

        av_store(av, i++, (SV*)newRV_noinc((SV*)rangeAV));
    }
