using std::cout;  using std::cerr;  using std::endl;

#ifndef __CPP__INCLUDED__RPerl__DataStructure__Hash_cpp
#define __CPP__INCLUDED__RPerl__DataStructure__Hash_cpp 0.006_000

#include <RPerl/DataStructure/Hash.h>		// -> NULL (relies on <unordered_map> being included via Inline::CPP's AUTO_INCLUDE config option)

// [[[ TYPE-CHECKING ]]]
// [[[ TYPE-CHECKING ]]]
// [[[ TYPE-CHECKING ]]]

// DEV NOTE: for() loops are statements not expressions, so they can't be embedded in ternary operators, and thus this type-checking must be done with subroutines instead of macros
void integer_hashref_CHECK(SV* possible_integer_hashref)
{
	// DEV NOTE: the following two if() statements are functionally equivalent to the hashref_CHECK() macro, but with integer-specific error codes
    if ( not( SvOK(possible_integer_hashref) ) ) { croak( "\nERROR EIVHVRV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashref value expected but undefined/null value found,\ncroaking" ); }
    if ( not( SvHROKp(possible_integer_hashref) ) ) { croak( "\nERROR EIVHVRV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashref value expected but non-hashref value found,\ncroaking" ); }

    HV* possible_integer_hash;
    integer possible_integer_hash_num_keys;
    integer i;
    HE* possible_integer_hashentry;
    SV* possible_integer_hashentry_value;
    SV* possible_integer_hashentry_key;
    string possible_integer_hashentry_key_string;
    size_t possible_integer_hashentry_key_string_pos;

	possible_integer_hash = (HV*)SvRV(possible_integer_hashref);
	possible_integer_hash_num_keys = hv_iterinit(possible_integer_hash);

	for (i = 0;  i < possible_integer_hash_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		possible_integer_hashentry = hv_iternext(possible_integer_hash);

		// DEV NOTE: the following if() statement is functionally equivalent to the hashentry_CHECK() macro, but with integer-specific error code
		if (possible_integer_hashentry == NULL) { croak("\nERROR EIVHE00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashentry value expected but undefined/null value found,\ncroaking"); }
		possible_integer_hashentry_value = hv_iterval(possible_integer_hash, possible_integer_hashentry);

		// DEV NOTE: the following two if() statements are functionally equivalent to the integer_CHECK() macro & subroutine, but with hash-specific error codes
	    if (not(SvOK(possible_integer_hashentry_value)))
	    {
	    	possible_integer_hashentry_key = hv_iterkeysv(possible_integer_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_integer_hashentry_key_string = string(SvPV_nolen(possible_integer_hashentry_key));
			possible_integer_hashentry_key_string_pos = 0;
			while((possible_integer_hashentry_key_string_pos = possible_integer_hashentry_key_string.find("\\", possible_integer_hashentry_key_string_pos)) != string::npos)
			{
				possible_integer_hashentry_key_string.replace(possible_integer_hashentry_key_string_pos, 1, "\\\\");
				possible_integer_hashentry_key_string_pos += 2;
			}
			possible_integer_hashentry_key_string_pos = 0;
			while((possible_integer_hashentry_key_string_pos = possible_integer_hashentry_key_string.find("'", possible_integer_hashentry_key_string_pos)) != string::npos)
			{
				possible_integer_hashentry_key_string.replace(possible_integer_hashentry_key_string_pos, 1, "\\'");
				possible_integer_hashentry_key_string_pos += 2;
			}

	    	croak("\nERROR EIVHVRV02, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashref element value expected but undefined/null value found at key '%s',\ncroaking", possible_integer_hashentry_key_string.c_str());
	    }
		if (not(SvIOKp(possible_integer_hashentry_value)))
		{
	    	possible_integer_hashentry_key = hv_iterkeysv(possible_integer_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_integer_hashentry_key_string = string(SvPV_nolen(possible_integer_hashentry_key));
			possible_integer_hashentry_key_string_pos = 0;
			while((possible_integer_hashentry_key_string_pos = possible_integer_hashentry_key_string.find("\\", possible_integer_hashentry_key_string_pos)) != string::npos)
			{
				possible_integer_hashentry_key_string.replace(possible_integer_hashentry_key_string_pos, 1, "\\\\");
				possible_integer_hashentry_key_string_pos += 2;
			}
			possible_integer_hashentry_key_string_pos = 0;
			while((possible_integer_hashentry_key_string_pos = possible_integer_hashentry_key_string.find("'", possible_integer_hashentry_key_string_pos)) != string::npos)
			{
				possible_integer_hashentry_key_string.replace(possible_integer_hashentry_key_string_pos, 1, "\\'");
				possible_integer_hashentry_key_string_pos += 2;
			}

			croak("\nERROR EIVHVRV03, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashref element value expected but non-integer value found at key '%s',\ncroaking", possible_integer_hashentry_key_string.c_str());
		}
	}
}

void integer_hashref_CHECKTRACE(SV* possible_integer_hashref, const char* variable_name, const char* subroutine_name)
{
    if ( not( SvOK(possible_integer_hashref) ) ) { croak( "\nERROR EIVHVRV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashref value expected but undefined/null value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name ); }
    if ( not( SvHROKp(possible_integer_hashref) ) ) { croak( "\nERROR EIVHVRV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashref value expected but non-hashref value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name ); }

    HV* possible_integer_hash;
    integer possible_integer_hash_num_keys;
    integer i;
    HE* possible_integer_hashentry;
    SV* possible_integer_hashentry_value;
    SV* possible_integer_hashentry_key;
    string possible_integer_hashentry_key_string;
    size_t possible_integer_hashentry_key_string_pos;

	possible_integer_hash = (HV*)SvRV(possible_integer_hashref);
	possible_integer_hash_num_keys = hv_iterinit(possible_integer_hash);

	for (i = 0;  i < possible_integer_hash_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		possible_integer_hashentry = hv_iternext(possible_integer_hash);

		if (possible_integer_hashentry == NULL) { croak("\nERROR EIVHE00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashentry value expected but undefined/null value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name); }
		possible_integer_hashentry_value = hv_iterval(possible_integer_hash, possible_integer_hashentry);

	    if (not(SvOK(possible_integer_hashentry_value)))
	    {
	    	possible_integer_hashentry_key = hv_iterkeysv(possible_integer_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_integer_hashentry_key_string = string(SvPV_nolen(possible_integer_hashentry_key));
			possible_integer_hashentry_key_string_pos = 0;
			while((possible_integer_hashentry_key_string_pos = possible_integer_hashentry_key_string.find("\\", possible_integer_hashentry_key_string_pos)) != string::npos)
			{
				possible_integer_hashentry_key_string.replace(possible_integer_hashentry_key_string_pos, 1, "\\\\");
				possible_integer_hashentry_key_string_pos += 2;
			}
			possible_integer_hashentry_key_string_pos = 0;
			while((possible_integer_hashentry_key_string_pos = possible_integer_hashentry_key_string.find("'", possible_integer_hashentry_key_string_pos)) != string::npos)
			{
				possible_integer_hashentry_key_string.replace(possible_integer_hashentry_key_string_pos, 1, "\\'");
				possible_integer_hashentry_key_string_pos += 2;
			}

	    	croak("\nERROR EIVHVRV02, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashref element value expected but undefined/null value found at key '%s',\nin variable %s from subroutine %s,\ncroaking", possible_integer_hashentry_key_string.c_str(), variable_name, subroutine_name);
	    }
		if (not(SvIOKp(possible_integer_hashentry_value)))
		{
	    	possible_integer_hashentry_key = hv_iterkeysv(possible_integer_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_integer_hashentry_key_string = string(SvPV_nolen(possible_integer_hashentry_key));
			possible_integer_hashentry_key_string_pos = 0;
			while((possible_integer_hashentry_key_string_pos = possible_integer_hashentry_key_string.find("\\", possible_integer_hashentry_key_string_pos)) != string::npos)
			{
				possible_integer_hashentry_key_string.replace(possible_integer_hashentry_key_string_pos, 1, "\\\\");
				possible_integer_hashentry_key_string_pos += 2;
			}
			possible_integer_hashentry_key_string_pos = 0;
			while((possible_integer_hashentry_key_string_pos = possible_integer_hashentry_key_string.find("'", possible_integer_hashentry_key_string_pos)) != string::npos)
			{
				possible_integer_hashentry_key_string.replace(possible_integer_hashentry_key_string_pos, 1, "\\'");
				possible_integer_hashentry_key_string_pos += 2;
			}

			croak("\nERROR EIVHVRV03, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\ninteger_hashref element value expected but non-integer value found at key '%s',\nin variable %s from subroutine %s,\ncroaking", possible_integer_hashentry_key_string.c_str(), variable_name, subroutine_name);
		}
	}
}

void number_hashref_CHECK(SV* possible_number_hashref)
{
    if ( not( SvOK(possible_number_hashref) ) ) { croak( "\nERROR ENVHVRV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashref value expected but undefined/null value found,\ncroaking" ); }
    if ( not( SvHROKp(possible_number_hashref) ) ) { croak( "\nERROR ENVHVRV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashref value expected but non-hashref value found,\ncroaking" ); }

    HV* possible_number_hash;
    integer possible_number_hash_num_keys;
    integer i;
    HE* possible_number_hashentry;
    SV* possible_number_hashentry_value;
    SV* possible_number_hashentry_key;
    string possible_number_hashentry_key_string;
    size_t possible_number_hashentry_key_string_pos;

	possible_number_hash = (HV*)SvRV(possible_number_hashref);
	possible_number_hash_num_keys = hv_iterinit(possible_number_hash);

	for (i = 0;  i < possible_number_hash_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		possible_number_hashentry = hv_iternext(possible_number_hash);

		if (possible_number_hashentry == NULL) { croak("\nERROR ENVHE00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashentry value expected but undefined/null value found,\ncroaking"); }
		possible_number_hashentry_value = hv_iterval(possible_number_hash, possible_number_hashentry);

	    if (not(SvOK(possible_number_hashentry_value)))
	    {
	    	possible_number_hashentry_key = hv_iterkeysv(possible_number_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_number_hashentry_key_string = string(SvPV_nolen(possible_number_hashentry_key));
			possible_number_hashentry_key_string_pos = 0;
			while((possible_number_hashentry_key_string_pos = possible_number_hashentry_key_string.find("\\", possible_number_hashentry_key_string_pos)) != string::npos)
			{
				possible_number_hashentry_key_string.replace(possible_number_hashentry_key_string_pos, 1, "\\\\");
				possible_number_hashentry_key_string_pos += 2;
			}
			possible_number_hashentry_key_string_pos = 0;
			while((possible_number_hashentry_key_string_pos = possible_number_hashentry_key_string.find("'", possible_number_hashentry_key_string_pos)) != string::npos)
			{
				possible_number_hashentry_key_string.replace(possible_number_hashentry_key_string_pos, 1, "\\'");
				possible_number_hashentry_key_string_pos += 2;
			}

	    	croak("\nERROR ENVHVRV02, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashref element value expected but undefined/null value found at key '%s',\ncroaking", possible_number_hashentry_key_string.c_str());
	    }
		if (not(SvNOKp(possible_number_hashentry_value) || SvIOKp(possible_number_hashentry_value)))
		{
	    	possible_number_hashentry_key = hv_iterkeysv(possible_number_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_number_hashentry_key_string = string(SvPV_nolen(possible_number_hashentry_key));
			possible_number_hashentry_key_string_pos = 0;
			while((possible_number_hashentry_key_string_pos = possible_number_hashentry_key_string.find("\\", possible_number_hashentry_key_string_pos)) != string::npos)
			{
				possible_number_hashentry_key_string.replace(possible_number_hashentry_key_string_pos, 1, "\\\\");
				possible_number_hashentry_key_string_pos += 2;
			}
			possible_number_hashentry_key_string_pos = 0;
			while((possible_number_hashentry_key_string_pos = possible_number_hashentry_key_string.find("'", possible_number_hashentry_key_string_pos)) != string::npos)
			{
				possible_number_hashentry_key_string.replace(possible_number_hashentry_key_string_pos, 1, "\\'");
				possible_number_hashentry_key_string_pos += 2;
			}

			croak("\nERROR ENVHVRV03, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashref element value expected but non-number value found at key '%s',\ncroaking", possible_number_hashentry_key_string.c_str());
		}
	}
}

void number_hashref_CHECKTRACE(SV* possible_number_hashref, const char* variable_name, const char* subroutine_name)
{
    if ( not( SvOK(possible_number_hashref) ) ) { croak( "\nERROR ENVHVRV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashref value expected but undefined/null value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name ); }
    if ( not( SvHROKp(possible_number_hashref) ) ) { croak( "\nERROR ENVHVRV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashref value expected but non-hashref value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name ); }

    HV* possible_number_hash;
    integer possible_number_hash_num_keys;
    integer i;
    HE* possible_number_hashentry;
    SV* possible_number_hashentry_value;
    SV* possible_number_hashentry_key;
    string possible_number_hashentry_key_string;
    size_t possible_number_hashentry_key_string_pos;

	possible_number_hash = (HV*)SvRV(possible_number_hashref);
	possible_number_hash_num_keys = hv_iterinit(possible_number_hash);

	for (i = 0;  i < possible_number_hash_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		possible_number_hashentry = hv_iternext(possible_number_hash);

		if (possible_number_hashentry == NULL) { croak("\nERROR ENVHE00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashentry value expected but undefined/null value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name); }
		possible_number_hashentry_value = hv_iterval(possible_number_hash, possible_number_hashentry);

	    if (not(SvOK(possible_number_hashentry_value)))
	    {
	    	possible_number_hashentry_key = hv_iterkeysv(possible_number_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_number_hashentry_key_string = string(SvPV_nolen(possible_number_hashentry_key));
			possible_number_hashentry_key_string_pos = 0;
			while((possible_number_hashentry_key_string_pos = possible_number_hashentry_key_string.find("\\", possible_number_hashentry_key_string_pos)) != string::npos)
			{
				possible_number_hashentry_key_string.replace(possible_number_hashentry_key_string_pos, 1, "\\\\");
				possible_number_hashentry_key_string_pos += 2;
			}
			possible_number_hashentry_key_string_pos = 0;
			while((possible_number_hashentry_key_string_pos = possible_number_hashentry_key_string.find("'", possible_number_hashentry_key_string_pos)) != string::npos)
			{
				possible_number_hashentry_key_string.replace(possible_number_hashentry_key_string_pos, 1, "\\'");
				possible_number_hashentry_key_string_pos += 2;
			}

	    	croak("\nERROR ENVHVRV02, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashref element value expected but undefined/null value found at key '%s',\nin variable %s from subroutine %s,\ncroaking", possible_number_hashentry_key_string.c_str(), variable_name, subroutine_name);
	    }
		if (not(SvNOKp(possible_number_hashentry_value) || SvIOKp(possible_number_hashentry_value)))
		{
	    	possible_number_hashentry_key = hv_iterkeysv(possible_number_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_number_hashentry_key_string = string(SvPV_nolen(possible_number_hashentry_key));
			possible_number_hashentry_key_string_pos = 0;
			while((possible_number_hashentry_key_string_pos = possible_number_hashentry_key_string.find("\\", possible_number_hashentry_key_string_pos)) != string::npos)
			{
				possible_number_hashentry_key_string.replace(possible_number_hashentry_key_string_pos, 1, "\\\\");
				possible_number_hashentry_key_string_pos += 2;
			}
			possible_number_hashentry_key_string_pos = 0;
			while((possible_number_hashentry_key_string_pos = possible_number_hashentry_key_string.find("'", possible_number_hashentry_key_string_pos)) != string::npos)
			{
				possible_number_hashentry_key_string.replace(possible_number_hashentry_key_string_pos, 1, "\\'");
				possible_number_hashentry_key_string_pos += 2;
			}

			croak("\nERROR ENVHVRV03, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_hashref element value expected but non-number value found at key '%s',\nin variable %s from subroutine %s,\ncroaking", possible_number_hashentry_key_string.c_str(), variable_name, subroutine_name);
		}
	}
}

void string_hashref_CHECK(SV* possible_string_hashref)
{
    if ( not( SvOK(possible_string_hashref) ) ) { croak( "\nERROR EPVHVRV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashref value expected but undefined/null value found,\ncroaking" ); }
    if ( not( SvHROKp(possible_string_hashref) ) ) { croak( "\nERROR EPVHVRV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashref value expected but non-hashref value found,\ncroaking" ); }

    HV* possible_string_hash;
    integer possible_string_hash_num_keys;
    integer i;
    HE* possible_string_hashentry;
    SV* possible_string_hashentry_value;
    SV* possible_string_hashentry_key;
    string possible_string_hashentry_key_string;
    size_t possible_string_hashentry_key_string_pos;

	possible_string_hash = (HV*)SvRV(possible_string_hashref);
	possible_string_hash_num_keys = hv_iterinit(possible_string_hash);

	for (i = 0;  i < possible_string_hash_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		possible_string_hashentry = hv_iternext(possible_string_hash);

		if (possible_string_hashentry == NULL) { croak("\nERROR EPVHE00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashentry value expected but undefined/null value found,\ncroaking"); }
		possible_string_hashentry_value = hv_iterval(possible_string_hash, possible_string_hashentry);

	    if (not(SvOK(possible_string_hashentry_value)))
	    {
	    	possible_string_hashentry_key = hv_iterkeysv(possible_string_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_string_hashentry_key_string = string(SvPV_nolen(possible_string_hashentry_key));
			possible_string_hashentry_key_string_pos = 0;
			while((possible_string_hashentry_key_string_pos = possible_string_hashentry_key_string.find("\\", possible_string_hashentry_key_string_pos)) != string::npos)
			{
				possible_string_hashentry_key_string.replace(possible_string_hashentry_key_string_pos, 1, "\\\\");
				possible_string_hashentry_key_string_pos += 2;
			}
			possible_string_hashentry_key_string_pos = 0;
			while((possible_string_hashentry_key_string_pos = possible_string_hashentry_key_string.find("'", possible_string_hashentry_key_string_pos)) != string::npos)
			{
				possible_string_hashentry_key_string.replace(possible_string_hashentry_key_string_pos, 1, "\\'");
				possible_string_hashentry_key_string_pos += 2;
			}

	    	croak("\nERROR EPVHVRV02, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashref element value expected but undefined/null value found at key '%s',\ncroaking", possible_string_hashentry_key_string.c_str());
	    }
		if (not(SvPOKp(possible_string_hashentry_value)))
		{
	    	possible_string_hashentry_key = hv_iterkeysv(possible_string_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_string_hashentry_key_string = string(SvPV_nolen(possible_string_hashentry_key));
			possible_string_hashentry_key_string_pos = 0;
			while((possible_string_hashentry_key_string_pos = possible_string_hashentry_key_string.find("\\", possible_string_hashentry_key_string_pos)) != string::npos)
			{
				possible_string_hashentry_key_string.replace(possible_string_hashentry_key_string_pos, 1, "\\\\");
				possible_string_hashentry_key_string_pos += 2;
			}
			possible_string_hashentry_key_string_pos = 0;
			while((possible_string_hashentry_key_string_pos = possible_string_hashentry_key_string.find("'", possible_string_hashentry_key_string_pos)) != string::npos)
			{
				possible_string_hashentry_key_string.replace(possible_string_hashentry_key_string_pos, 1, "\\'");
				possible_string_hashentry_key_string_pos += 2;
			}

			croak("\nERROR EPVHVRV03, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashref element value expected but non-string value found at key '%s',\ncroaking", possible_string_hashentry_key_string.c_str());
		}
	}
}

void string_hashref_CHECKTRACE(SV* possible_string_hashref, const char* variable_name, const char* subroutine_name)
{
    if ( not( SvOK(possible_string_hashref) ) ) { croak( "\nERROR EPVHVRV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashref value expected but undefined/null value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name ); }
    if ( not( SvHROKp(possible_string_hashref) ) ) { croak( "\nERROR EPVHVRV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashref value expected but non-hashref value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name ); }

    HV* possible_string_hash;
    integer possible_string_hash_num_keys;
    integer i;
    HE* possible_string_hashentry;
    SV* possible_string_hashentry_value;
    SV* possible_string_hashentry_key;
    string possible_string_hashentry_key_string;
    size_t possible_string_hashentry_key_string_pos;

	possible_string_hash = (HV*)SvRV(possible_string_hashref);
	possible_string_hash_num_keys = hv_iterinit(possible_string_hash);

	for (i = 0;  i < possible_string_hash_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		possible_string_hashentry = hv_iternext(possible_string_hash);

		if (possible_string_hashentry == NULL) { croak("\nERROR EPVHE00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashentry value expected but undefined/null value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name); }
		possible_string_hashentry_value = hv_iterval(possible_string_hash, possible_string_hashentry);

	    if (not(SvOK(possible_string_hashentry_value)))
	    {
	    	possible_string_hashentry_key = hv_iterkeysv(possible_string_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_string_hashentry_key_string = string(SvPV_nolen(possible_string_hashentry_key));
			possible_string_hashentry_key_string_pos = 0;
			while((possible_string_hashentry_key_string_pos = possible_string_hashentry_key_string.find("\\", possible_string_hashentry_key_string_pos)) != string::npos)
			{
				possible_string_hashentry_key_string.replace(possible_string_hashentry_key_string_pos, 1, "\\\\");
				possible_string_hashentry_key_string_pos += 2;
			}
			possible_string_hashentry_key_string_pos = 0;
			while((possible_string_hashentry_key_string_pos = possible_string_hashentry_key_string.find("'", possible_string_hashentry_key_string_pos)) != string::npos)
			{
				possible_string_hashentry_key_string.replace(possible_string_hashentry_key_string_pos, 1, "\\'");
				possible_string_hashentry_key_string_pos += 2;
			}

	    	croak("\nERROR EPVHVRV02, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashref element value expected but undefined/null value found at key '%s',\nin variable %s from subroutine %s,\ncroaking", possible_string_hashentry_key_string.c_str(), variable_name, subroutine_name);
	    }
		if (not(SvPOKp(possible_string_hashentry_value)))
		{
	    	possible_string_hashentry_key = hv_iterkeysv(possible_string_hashentry);

			// escape all back-slash \ and single-quote ' characters with a back-slash \ character
			possible_string_hashentry_key_string = string(SvPV_nolen(possible_string_hashentry_key));
			possible_string_hashentry_key_string_pos = 0;
			while((possible_string_hashentry_key_string_pos = possible_string_hashentry_key_string.find("\\", possible_string_hashentry_key_string_pos)) != string::npos)
			{
				possible_string_hashentry_key_string.replace(possible_string_hashentry_key_string_pos, 1, "\\\\");
				possible_string_hashentry_key_string_pos += 2;
			}
			possible_string_hashentry_key_string_pos = 0;
			while((possible_string_hashentry_key_string_pos = possible_string_hashentry_key_string.find("'", possible_string_hashentry_key_string_pos)) != string::npos)
			{
				possible_string_hashentry_key_string.replace(possible_string_hashentry_key_string_pos, 1, "\\'");
				possible_string_hashentry_key_string_pos += 2;
			}

			croak("\nERROR EPVHVRV03, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring_hashref element value expected but non-string value found at key '%s',\nin variable %s from subroutine %s,\ncroaking", possible_string_hashentry_key_string.c_str(), variable_name, subroutine_name);
		}
	}
}

// [[[ TYPEMAP PACK/UNPACK FOR __CPP__TYPES ]]]
// [[[ TYPEMAP PACK/UNPACK FOR __CPP__TYPES ]]]
// [[[ TYPEMAP PACK/UNPACK FOR __CPP__TYPES ]]]

# ifdef __CPP__TYPES

// convert from (Perl SV containing reference to (Perl HV of (Perl SVs containing IVs))) to (C++ std::unordered_map of integers)
integer_hashref XS_unpack_integer_hashref(SV* input_hv_ref)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_integer_hashref(), top of subroutine\n");
//	integer_hashref_CHECK(input_hv_ref);
	integer_hashref_CHECKTRACE(input_hv_ref, "input_hv_ref", "XS_unpack_integer_hashref()");

    HV* input_hv;
    integer input_hv_num_keys;
    integer i;
    HE* input_hv_entry;
    SV* input_hv_entry_key;
    SV* input_hv_entry_value;
    integer_hashref output_unordered_map;

	input_hv = (HV*)SvRV(input_hv_ref);

	input_hv_num_keys = hv_iterinit(input_hv);
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_integer_hashref(), have input_hv_num_keys = %"INTEGER"\n", input_hv_num_keys);

	// UNORDERED MAP ENTRY ASSIGNMENT, OPTION A, SUBSCRIPT, KNOWN SIZE: unordered_map has programmer-provided const size or compiler-guessable size,
	// reserve() ahead of time to avoid resizing and rehashing in for() loop
	output_unordered_map.reserve((size_t)input_hv_num_keys);

	for (i = 0;  i < input_hv_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		// does not utilize i in entry retrieval
		input_hv_entry = hv_iternext(input_hv);
		// DEV NOTE: hash entry type-checking already done as part of integer_hashref_CHECKTRACE()
//		hashentry_CHECK(input_hv_entry);
//		hashentry_CHECKTRACE(input_hv_entry, "input_hv_entry", "XS_unpack_integer_hashref()");

		input_hv_entry_key = hv_iterkeysv(input_hv_entry);
		input_hv_entry_value = hv_iterval(input_hv, input_hv_entry);
		// DEV NOTE: integer type-checking already done as part of integer_hashref_CHECKTRACE()
//		integer_CHECK(input_hv_entry_value);
//		integer_CHECKTRACE(input_hv_entry_value, (char*)((string)"input_hv_entry_value at key '" + (string)SvPV_nolen(input_hv_entry_key) + "'").c_str(), "XS_unpack_integer_hashref()");

		// UNORDERED MAP ENTRY ASSIGNMENT, OPTION A, SUBSCRIPT, KNOWN SIZE: l-value subscript notation with no further reserve(); does not utilize i in assignment
		output_unordered_map[SvPV_nolen(input_hv_entry_key)] = SvIV(input_hv_entry_value);
	}

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_integer_hashref(), after for() loop, have output_unordered_map.size() = %"INTEGER"\n", output_unordered_map.size());
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_integer_hashref(), bottom of subroutine\n");

	return(output_unordered_map);
}

// convert from (C++ std::unordered_map of integers) to (Perl SV containing reference to (Perl HV of (Perl SVs containing IVs)))
void XS_pack_integer_hashref(SV* output_hv_ref, integer_hashref input_unordered_map)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_integer_hashref(), top of subroutine\n");

	HV* output_hv = newHV();  // initialize output hash to empty
	integer input_unordered_map_num_keys = input_unordered_map.size();
	integer_hashref_const_iterator i;
	SV* temp_sv_pointer;

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_integer_hashref(), have input_unordered_map_num_keys = %"INTEGER"\n", input_unordered_map_num_keys);

	if (input_unordered_map_num_keys > 0)
	{
		for (i = input_unordered_map.begin();  i != input_unordered_map.end();  ++i)
			{ hv_store(output_hv, (const char*)((i->first).c_str()), (U32)((i->first).size()), newSViv(i->second), (U32)0); }
	}
//	else warn("in CPPOPS_CPPTYPES XS_pack_integer_hashref(), hash was empty, returning empty hash via newHV()");

	temp_sv_pointer = newSVrv(output_hv_ref, NULL);	  // upgrade output stack SV to an RV
	SvREFCNT_dec(temp_sv_pointer);		 // discard temporary pointer
	SvRV(output_hv_ref) = (SV*)output_hv;	   // make output stack RV pointer at our output HV

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_integer_hashref(), bottom of subroutine\n");
}

// convert from (Perl SV containing reference to (Perl HV of (Perl SVs containing NVs))) to (C++ std::unordered_map of doubles)
number_hashref XS_unpack_number_hashref(SV* input_hv_ref)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_number_hashref(), top of subroutine\n");
//	number_hashref_CHECK(input_hv_ref);
	number_hashref_CHECKTRACE(input_hv_ref, "input_hv_ref", "XS_unpack_number_hashref()");

    HV* input_hv;
    integer input_hv_num_keys;
    integer i;
    HE* input_hv_entry;
    SV* input_hv_entry_key;
    SV* input_hv_entry_value;
    number_hashref output_unordered_map;

	input_hv = (HV*)SvRV(input_hv_ref);

	input_hv_num_keys = hv_iterinit(input_hv);
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_number_hashref(), have input_hv_num_keys = %"INTEGER"\n", input_hv_num_keys);

	// UNORDERED MAP ENTRY ASSIGNMENT, OPTION A, SUBSCRIPT, KNOWN SIZE: unordered_map has programmer-provided const size or compiler-guessable size,
	// reserve() ahead of time to avoid resizing and rehashing in for() loop
	output_unordered_map.reserve((size_t)input_hv_num_keys);

	for (i = 0;  i < input_hv_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		// does not utilize i in entry retrieval
		input_hv_entry = hv_iternext(input_hv);
		input_hv_entry_key = hv_iterkeysv(input_hv_entry);
		input_hv_entry_value = hv_iterval(input_hv, input_hv_entry);

		// UNORDERED MAP ENTRY ASSIGNMENT, OPTION A, SUBSCRIPT, KNOWN SIZE: l-value subscript notation with no further reserve(); does not utilize i in assignment
		output_unordered_map[SvPV_nolen(input_hv_entry_key)] = SvNV(input_hv_entry_value);
	}

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_number_hashref(), after for() loop, have output_unordered_map.size() = %"INTEGER"\n", output_unordered_map.size());
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_number_hashref(), bottom of subroutine\n");

	return(output_unordered_map);
}

// convert from (C++ std::unordered_map of doubles) to (Perl SV containing reference to (Perl HV of (Perl SVs containing NVs)))
void XS_pack_number_hashref(SV* output_hv_ref, number_hashref input_unordered_map)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_number_hashref(), top of subroutine\n");

	HV* output_hv = newHV();  // initialize output hash to empty
	integer input_unordered_map_num_keys = input_unordered_map.size();
	number_hashref_const_iterator i;
	SV* temp_sv_pointer;

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_number_hashref(), have input_unordered_map_num_keys = %"INTEGER"\n", input_unordered_map_num_keys);

	if (input_unordered_map_num_keys > 0)
	{
		for (i = input_unordered_map.begin();  i != input_unordered_map.end();  ++i)
			{ hv_store(output_hv, (const char*)((i->first).c_str()), (U32)((i->first).size()), newSVnv(i->second), (U32)0); }
	}
//	else warn("in CPPOPS_CPPTYPES XS_pack_number_hashref(), hash was empty, returning empty hash via newHV()");

	temp_sv_pointer = newSVrv(output_hv_ref, NULL);	  // upgrade output stack SV to an RV
	SvREFCNT_dec(temp_sv_pointer);		 // discard temporary pointer
	SvRV(output_hv_ref) = (SV*)output_hv;	   // make output stack RV pointer at our output HV

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_number_hashref(), bottom of subroutine\n");
}

// convert from (Perl SV containing reference to (Perl HV of (Perl SVs containing PVs))) to (C++ std::unordered_map of strings)
string_hashref XS_unpack_string_hashref(SV* input_hv_ref)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_string_hashref(), top of subroutine\n");
//	string_hashref_CHECK(input_hv_ref);
	string_hashref_CHECKTRACE(input_hv_ref, "input_hv_ref", "XS_unpack_string_hashref()");

    HV* input_hv;
    integer input_hv_num_keys;
    integer i;
    HE* input_hv_entry;
    SV* input_hv_entry_key;
    SV* input_hv_entry_value;
    string_hashref output_unordered_map;

	input_hv = (HV*)SvRV(input_hv_ref);

	input_hv_num_keys = hv_iterinit(input_hv);
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_string_hashref(), have input_hv_num_keys = %"INTEGER"\n", input_hv_num_keys);

	// UNORDERED MAP ENTRY ASSIGNMENT, OPTION A, SUBSCRIPT, KNOWN SIZE: unordered_map has programmer-provided const size or compiler-guessable size,
	// reserve() ahead of time to avoid resizing and rehashing in for() loop
	output_unordered_map.reserve((size_t)input_hv_num_keys);

	for (i = 0;  i < input_hv_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		// does not utilize i in entry retrieval
		input_hv_entry = hv_iternext(input_hv);
		input_hv_entry_key = hv_iterkeysv(input_hv_entry);
		input_hv_entry_value = hv_iterval(input_hv, input_hv_entry);

		// UNORDERED MAP ENTRY ASSIGNMENT, OPTION A, SUBSCRIPT, KNOWN SIZE: l-value subscript notation with no further reserve(); does not utilize i in assignment
		output_unordered_map[SvPV_nolen(input_hv_entry_key)] = SvPV_nolen(input_hv_entry_value);
	}

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_string_hashref(), after for() loop, have output_unordered_map.size() = %"INTEGER"\n", output_unordered_map.size());
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_unpack_string_hashref(), bottom of subroutine\n");

	return(output_unordered_map);
}

// convert from (C++ std::unordered_map of strings) to (Perl SV containing reference to (Perl HV of (Perl SVs containing PVs)))
void XS_pack_string_hashref(SV* output_hv_ref, string_hashref input_unordered_map)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_string_hashref(), top of subroutine\n");

	HV* output_hv = newHV();  // initialize output hash to empty
	integer input_unordered_map_num_keys = input_unordered_map.size();
	string_hashref_const_iterator i;
	SV* temp_sv_pointer;

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_string_hashref(), have input_unordered_map_num_keys = %"INTEGER"\n", input_unordered_map_num_keys);

	if (input_unordered_map_num_keys > 0)
	{
		for (i = input_unordered_map.begin();  i != input_unordered_map.end();  ++i)
			{ hv_store(output_hv, (const char*)((i->first).c_str()), (U32)((i->first).size()), newSVpv((i->second).c_str(), 0), (U32)0); }
	}
//	else warn("in CPPOPS_CPPTYPES XS_pack_string_hashref(), hash was empty, returning empty hash via newHV()");

	temp_sv_pointer = newSVrv(output_hv_ref, NULL);	  // upgrade output stack SV to an RV
	SvREFCNT_dec(temp_sv_pointer);		 // discard temporary pointer
	SvRV(output_hv_ref) = (SV*)output_hv;	   // make output stack RV pointer at our output HV

//	fprintf(stderr, "in CPPOPS_CPPTYPES XS_pack_string_hashref(), bottom of subroutine\n");
}

# endif

// [[[ STRINGIFY ]]]
// [[[ STRINGIFY ]]]
// [[[ STRINGIFY ]]]

# ifdef __PERL__TYPES

// convert from (Perl SV containing RV to (Perl HV of (Perl SVs containing IVs))) to Perl-parsable (Perl SV containing PV)
SV* integer_hashref_to_string(SV* input_hv_ref)
{
//	fprintf(stderr, "in CPPOPS_PERLTYPES integer_hashref_to_string(), top of subroutine\n");
//	integer_hashref_CHECK(input_hv_ref);
	integer_hashref_CHECKTRACE(input_hv_ref, "input_hv_ref", "integer_hashref_to_string()");

    HV* input_hv;
    integer input_hv_num_keys;
    integer i;
    boolean i_is_0 = 1;
    HE* input_hv_entry;
    SV* input_hv_entry_key;
    string input_hv_entry_key_string;
    size_t input_hv_entry_key_string_pos;
    SV* input_hv_entry_value;
    SV* output_sv = newSV(0);

	input_hv = (HV*)SvRV(input_hv_ref);
	input_hv_num_keys = hv_iterinit(input_hv);
//	fprintf(stderr, "in CPPOPS_PERLTYPES integer_hashref_to_string(), have input_hv_num_keys = %"INTEGER"\n", input_hv_num_keys);

	sv_setpvn(output_sv, "{", 1);

	for (i = 0;  i < input_hv_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
//		fprintf(stderr, "in CPPOPS_PERLTYPES integer_hashref_to_string(), top of loop i = %"INTEGER"\n", i);

		// does not utilize i in entry retrieval
		input_hv_entry = hv_iternext(input_hv);
		// DEV NOTE: hash entry type-checking already done as part of integer_hashref_CHECKTRACE()
//		hashentry_CHECK(input_hv_entry);
//		hashentry_CHECKTRACE(input_hv_entry, "input_hv_entry", "integer_hashref_to_string()");

		input_hv_entry_key = hv_iterkeysv(input_hv_entry);
		input_hv_entry_value = hv_iterval(input_hv, input_hv_entry);
		// DEV NOTE: integer type-checking already done as part of integer_hashref_CHECKTRACE()
//		integer_CHECK(input_hv_entry_value);
//		integer_CHECKTRACE(input_hv_entry_value, (char*)((string)"input_hv_entry_value at key '" + (string)SvPV_nolen(input_hv_entry_key) + "'").c_str(), "integer_hashref_to_string()");

		if (i_is_0) { i_is_0 = 0; } else { sv_catpvn(output_sv, ", ", 2); }

		// escape all back-slash \ and single-quote ' characters with a back-slash \ character
		input_hv_entry_key_string = string(SvPV_nolen(input_hv_entry_key));
		input_hv_entry_key_string_pos = 0;
		while((input_hv_entry_key_string_pos = input_hv_entry_key_string.find("\\", input_hv_entry_key_string_pos)) != string::npos)
		{
			input_hv_entry_key_string.replace(input_hv_entry_key_string_pos, 1, "\\\\");
			input_hv_entry_key_string_pos += 2;
		}
		input_hv_entry_key_string_pos = 0;
		while((input_hv_entry_key_string_pos = input_hv_entry_key_string.find("'", input_hv_entry_key_string_pos)) != string::npos)
		{
			input_hv_entry_key_string.replace(input_hv_entry_key_string_pos, 1, "\\'");
			input_hv_entry_key_string_pos += 2;
		}

//		sv_catpvf(output_sv, "'%s' => %"INTEGER"", SvPV_nolen(input_hv_entry_key), (integer)SvIV(input_hv_entry_value));
//		sv_catpvf(output_sv, "'%s' => %"INTEGER"", input_hv_entry_key_string.c_str(), (integer)SvIV(input_hv_entry_value));  // NO UNDERSCORES
		sv_catpvf(output_sv, "'%s' => ", input_hv_entry_key_string.c_str());  // YES UNDERSCORES
		sv_catsv(output_sv, integer_to_string(input_hv_entry_value));  // YES UNDERSCORES
	}

	sv_catpvn(output_sv, "}", 1);

//	fprintf(stderr, "in CPPOPS_PERLTYPES integer_hashref_to_string(), after for() loop, have output_sv =\n%s\n", SvPV_nolen(output_sv));
//	fprintf(stderr, "in CPPOPS_PERLTYPES integer_hashref_to_string(), bottom of subroutine\n");

	return(output_sv);
}

// convert from (Perl SV containing RV to (Perl HV of (Perl SVs containing NVs))) to Perl-parsable (Perl SV containing PV)
SV* number_hashref_to_string(SV* input_hv_ref)
{
//	fprintf(stderr, "in CPPOPS_PERLTYPES number_hashref_to_string(), top of subroutine\n");
//	number_hashref_CHECK(input_hv_ref);
	number_hashref_CHECKTRACE(input_hv_ref, "input_hv_ref", "number_hashref_to_string()");

    HV* input_hv;
    integer input_hv_num_keys;
    integer i;
    boolean i_is_0 = 1;
    HE* input_hv_entry;
    SV* input_hv_entry_key;
    string input_hv_entry_key_string;
    size_t input_hv_entry_key_string_pos;
    SV* input_hv_entry_value;
    SV* output_sv = newSV(0);
	ostringstream temp_stream;
	temp_stream.precision(std::numeric_limits<double>::digits10);

	input_hv = (HV*)SvRV(input_hv_ref);
	input_hv_num_keys = hv_iterinit(input_hv);
//	fprintf(stderr, "in CPPOPS_PERLTYPES number_hashref_to_string(), have input_hv_num_keys = %"INTEGER"\n", input_hv_num_keys);

	temp_stream << "{";

	for (i = 0;  i < input_hv_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		// does not utilize i in entry retrieval
		input_hv_entry = hv_iternext(input_hv);
		input_hv_entry_key = hv_iterkeysv(input_hv_entry);
		input_hv_entry_value = hv_iterval(input_hv, input_hv_entry);

		if (i_is_0) { i_is_0 = 0; } else { temp_stream << ", "; }

		// escape all back-slash \ and single-quote ' characters with a back-slash \ character
		input_hv_entry_key_string = string(SvPV_nolen(input_hv_entry_key));
		input_hv_entry_key_string_pos = 0;
		while((input_hv_entry_key_string_pos = input_hv_entry_key_string.find("\\", input_hv_entry_key_string_pos)) != string::npos)
		{
			input_hv_entry_key_string.replace(input_hv_entry_key_string_pos, 1, "\\\\");
			input_hv_entry_key_string_pos += 2;
		}
		input_hv_entry_key_string_pos = 0;
		while((input_hv_entry_key_string_pos = input_hv_entry_key_string.find("'", input_hv_entry_key_string_pos)) != string::npos)
		{
			input_hv_entry_key_string.replace(input_hv_entry_key_string_pos, 1, "\\'");
			input_hv_entry_key_string_pos += 2;
		}

//      temp_stream << "'" << SvPV_nolen(input_hv_entry_key) << "' => " << (double)SvNV(input_hv_entry_value);
		temp_stream << "'" << input_hv_entry_key_string << "' => " << (string)SvPV_nolen(number_to_string(input_hv_entry_value));
	}

	temp_stream << "}";
	sv_setpv(output_sv, (char*)(temp_stream.str().c_str()));

//	fprintf(stderr, "in CPPOPS_PERLTYPES number_hashref_to_string(), after for() loop, have output_sv =\n%s\n", SvPV_nolen(output_sv));
//	fprintf(stderr, "in CPPOPS_PERLTYPES number_hashref_to_string(), bottom of subroutine\n");

	return(output_sv);
}

// convert from (Perl SV containing RV to (Perl HV of (Perl SVs containing PVs))) to Perl-parsable (Perl SV containing PV)
SV* string_hashref_to_string(SV* input_hv_ref)
{
//	fprintf(stderr, "in CPPOPS_PERLTYPES string_hashref_to_string(), top of subroutine\n");
//	string_hashref_CHECK(input_hv_ref);
	string_hashref_CHECKTRACE(input_hv_ref, "input_hv_ref", "string_hashref_to_string()");

    HV* input_hv;
    integer input_hv_num_keys;
    integer i;
    boolean i_is_0 = 1;
    HE* input_hv_entry;
    SV* input_hv_entry_key;
    string input_hv_entry_key_string;
    size_t input_hv_entry_key_string_pos;
    SV* input_hv_entry_value;
    string input_hv_entry_value_string;
    size_t input_hv_entry_value_string_pos;
    SV* output_sv = newSV(0);

	input_hv = (HV*)SvRV(input_hv_ref);
	input_hv_num_keys = hv_iterinit(input_hv);
//	fprintf(stderr, "in CPPOPS_PERLTYPES string_hashref_to_string(), have input_hv_num_keys = %"INTEGER"\n", input_hv_num_keys);

	sv_setpvn(output_sv, "{", 1);

	for (i = 0;  i < input_hv_num_keys;  ++i)  // incrementing iteration, iterator i not actually used in loop body
	{
		// does not utilize i in entry retrieval
		input_hv_entry = hv_iternext(input_hv);
		input_hv_entry_key = hv_iterkeysv(input_hv_entry);
		input_hv_entry_value = hv_iterval(input_hv, input_hv_entry);

		if (i_is_0) { i_is_0 = 0; } else { sv_catpvn(output_sv, ", ", 2); }

		// escape all back-slash \ and single-quote ' characters with a back-slash \ character
		input_hv_entry_key_string = string(SvPV_nolen(input_hv_entry_key));
		input_hv_entry_key_string_pos = 0;
		while((input_hv_entry_key_string_pos = input_hv_entry_key_string.find("\\", input_hv_entry_key_string_pos)) != string::npos)
		{
			input_hv_entry_key_string.replace(input_hv_entry_key_string_pos, 1, "\\\\");
			input_hv_entry_key_string_pos += 2;
		}
		input_hv_entry_key_string_pos = 0;
		while((input_hv_entry_key_string_pos = input_hv_entry_key_string.find("'", input_hv_entry_key_string_pos)) != string::npos)
		{
			input_hv_entry_key_string.replace(input_hv_entry_key_string_pos, 1, "\\'");
			input_hv_entry_key_string_pos += 2;
		}

		// and again
		input_hv_entry_value_string = string(SvPV_nolen(input_hv_entry_value));
		input_hv_entry_value_string_pos = 0;
		while((input_hv_entry_value_string_pos = input_hv_entry_value_string.find("\\", input_hv_entry_value_string_pos)) != string::npos)
		{
			input_hv_entry_value_string.replace(input_hv_entry_value_string_pos, 1, "\\\\");
			input_hv_entry_value_string_pos += 2;
		}
		input_hv_entry_value_string_pos = 0;
		while((input_hv_entry_value_string_pos = input_hv_entry_value_string.find("'", input_hv_entry_value_string_pos)) != string::npos)
		{
			input_hv_entry_value_string.replace(input_hv_entry_value_string_pos, 1, "\\'");
			input_hv_entry_value_string_pos += 2;
		}

//		sv_catpvf(output_sv, "'%s' => '%s'", SvPV_nolen(input_hv_entry_key), SvPV_nolen(input_hv_entry_value));
		sv_catpvf(output_sv, "'%s' => '%s'", input_hv_entry_key_string.c_str(), input_hv_entry_value_string.c_str());
	}

	sv_catpvn(output_sv, "}", 1);

//	fprintf(stderr, "in CPPOPS_PERLTYPES string_hashref_to_string(), after for() loop, have output_sv =\n%s\n", SvPV_nolen(output_sv));
//	fprintf(stderr, "in CPPOPS_PERLTYPES string_hashref_to_string(), bottom of subroutine\n");

	return(output_sv);
}

# elif defined __CPP__TYPES

// convert from (C++ std::unordered_map of integers) to Perl-parsable (C++ std::string)
string integer_hashref_to_string(integer_hashref input_unordered_map)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES integer_hashref_to_string(), top of subroutine\n");

	ostringstream output_stream;
	integer_hashref_const_iterator i;
    boolean i_is_0 = 1;
    string key_string;
    size_t key_string_pos;

	output_stream << '{';

	for (i = input_unordered_map.begin();  i != input_unordered_map.end();  ++i)
	{
		if (i_is_0) { i_is_0 = 0; } else { output_stream << ", "; }

		// escape all back-slash \ and single-quote ' characters with a back-slash \ character
		key_string = i->first;
		key_string_pos = 0;
		while((key_string_pos = key_string.find("\\", key_string_pos)) != string::npos)
		{
			key_string.replace(key_string_pos, 1, "\\\\");
			key_string_pos += 2;
		}
		key_string_pos = 0;
		while((key_string_pos = key_string.find("'", key_string_pos)) != string::npos)
		{
			key_string.replace(key_string_pos, 1, "\\'");
			key_string_pos += 2;
		}

//		output_stream << "'" << (i->first).c_str() << "' => " << i->second;
//		output_stream << "'" << key_string.c_str() << "' => " << i->second;  // NO UNDERSCORES
		output_stream << "'" << key_string.c_str() << "' => " << integer_to_string(i->second);  // YES UNDERSCORES
	}

	output_stream << '}';

//	fprintf(stderr, "in CPPOPS_CPPTYPES integer_hashref_to_string(), after for() loop, have output_stream =\n%s\n", (char*)(output_stream.str().c_str()));
//	fprintf(stderr, "in CPPOPS_CPPTYPES integer_hashref_to_string(), bottom of subroutine\n");

	return(output_stream.str());
}

// convert from (C++ std::unordered_map of doubles) to Perl-parsable (C++ std::string)
string number_hashref_to_string(number_hashref input_unordered_map)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES number_hashref_to_string(), top of subroutine\n");

	ostringstream output_stream;
	number_hashref_const_iterator i;
    boolean i_is_0 = 1;
    string key_string;
    size_t key_string_pos;

	output_stream.precision(std::numeric_limits<double>::digits10);
	output_stream << '{';

	for (i = input_unordered_map.begin();  i != input_unordered_map.end();  ++i)
	{
		if (i_is_0) { i_is_0 = 0; } else { output_stream << ", "; }

		// escape all back-slash \ and single-quote ' characters with a back-slash \ character
		key_string = i->first;
		key_string_pos = 0;
		while((key_string_pos = key_string.find("\\", key_string_pos)) != string::npos)
		{
			key_string.replace(key_string_pos, 1, "\\\\");
			key_string_pos += 2;
		}
		key_string_pos = 0;
		while((key_string_pos = key_string.find("'", key_string_pos)) != string::npos)
		{
			key_string.replace(key_string_pos, 1, "\\'");
			key_string_pos += 2;
		}

//		output_stream << "'" << (i->first).c_str() << "' => " << i->second;
		output_stream << "'" << key_string.c_str() << "' => " << number_to_string(i->second);
	}

	output_stream << '}';

//	fprintf(stderr, "in CPPOPS_CPPTYPES number_hashref_to_string(), after for() loop, have output_stream =\n%s\n", (char*)(output_stream.str().c_str()));
//	fprintf(stderr, "in CPPOPS_CPPTYPES number_hashref_to_string(), bottom of subroutine\n");

	return(output_stream.str());
}

// convert from (C++ std::unordered_map of std::strings) to Perl-parsable (C++ std::string)
string string_hashref_to_string(string_hashref input_unordered_map)
{
//	fprintf(stderr, "in CPPOPS_CPPTYPES string_hashref_to_string(), top of subroutine\n");

	string output_string;
	string_hashref_const_iterator i;
    boolean i_is_0 = 1;
    string key_string;
    size_t key_string_pos;
    string value_string;
    size_t value_string_pos;

	output_string = "{";

	for (i = input_unordered_map.begin();  i != input_unordered_map.end();  ++i)
	{
		if (i_is_0) { i_is_0 = 0; } else { output_string += ", "; }

		// escape all back-slash \ and single-quote ' characters with a back-slash \ character
		key_string = i->first;
		key_string_pos = 0;
		while((key_string_pos = key_string.find("\\", key_string_pos)) != string::npos)
		{
			key_string.replace(key_string_pos, 1, "\\\\");
			key_string_pos += 2;
		}
		key_string_pos = 0;
		while((key_string_pos = key_string.find("'", key_string_pos)) != string::npos)
		{
			key_string.replace(key_string_pos, 1, "\\'");
			key_string_pos += 2;
		}

		// and again
		value_string = i->second;
		value_string_pos = 0;
		while((value_string_pos = value_string.find("\\", value_string_pos)) != string::npos)
		{
			value_string.replace(value_string_pos, 1, "\\\\");
			value_string_pos += 2;
		}
		value_string_pos = 0;
		while((value_string_pos = value_string.find("'", value_string_pos)) != string::npos)
		{
			value_string.replace(value_string_pos, 1, "\\'");
			value_string_pos += 2;
		}

//		output_string += "'" + (string)(i->first).c_str() + "' => '" + (string)(i->second) + "'";
		output_string += "'" + key_string + "' => '" + value_string + "'";
	}

	output_string += "}";

//	fprintf(stderr, "in CPPOPS_CPPTYPES string_hashref_to_string(), after for() loop, have output_string =\n%s\n", output_string.c_str());
//	fprintf(stderr, "in CPPOPS_CPPTYPES string_hashref_to_string(), bottom of subroutine\n");

	return(output_string);
}

# else

Purposefully_die_from_a_compile-time_error,_due_to_neither___PERL__TYPES_nor___CPP__TYPES_being_defined.__We_need_to_define_exactly_one!

# endif

// [[[ TYPE TESTING ]]]
// [[[ TYPE TESTING ]]]
// [[[ TYPE TESTING ]]]

# ifdef __PERL__TYPES

SV* integer_hashref__typetest0(SV* lucky_integers)
{
//	integer_hashref_CHECK(lucky_integers);
	integer_hashref_CHECKTRACE(lucky_integers, "lucky_integers", "integer_hashref__typetest0()");
	HV* lucky_integers_deref = (HV*)SvRV(lucky_integers);
	integer how_lucky = hv_iterinit(lucky_integers_deref);
	integer i;

	for (i = 0;  i < how_lucky;  ++i)
	{
		HE* lucky_integer_entry = hv_iternext(lucky_integers_deref);
		// DEV NOTE: hash entry type-checking already done as part of integer_hashref_CHECKTRACE()
//		hashentry_CHECK(lucky_integer_entry);
//		hashentry_CHECKTRACE(lucky_integer_entry, "lucky_integer_entry", "integer_hashref__typetest0()");

		// DEV NOTE: not using lucky_number variable as in Hash.pm
		// DEV NOTE: integer type-checking already done as part of integer_hashref_CHECKTRACE()
//		integer_CHECK(hv_iterval(lucky_integers_deref, lucky_integer_entry));
//		integer_CHECKTRACE(hv_iterval(lucky_integers_deref, lucky_integer_entry), (char*)((string)"hv_iterval(lucky_integers_deref, lucky_integer_entry) at key '" + (string)SvPV_nolen(hv_iterkeysv(lucky_integer_entry)) + "'").c_str(), "integer_hashref__typetest0()");

//		fprintf(stderr, "in CPPOPS_PERLTYPES integer_hashref__typetest0(), have lucky integer '%s' => %"INTEGER", BARSTOOL\n", SvPV_nolen(hv_iterkeysv(lucky_integer_entry)), (integer)SvIV(hv_iterval(lucky_integers_deref, lucky_integer_entry)));
	}

	return(newSVpvf("%s%s", SvPV_nolen(integer_hashref_to_string(lucky_integers)), "CPPOPS_PERLTYPES"));
}

SV* integer_hashref__typetest1(SV* my_size)
{
//	integer_CHECK(my_size);
	integer_CHECKTRACE(my_size, "my_size", "integer_hashref__typetest1()");
	HV* output_hv = newHV();
	integer i;
	char temp_key[30];

	for (i = 0;  i < SvIV(my_size);  ++i)
	{
		sprintf(temp_key, "CPPOPS_PERLTYPES_funkey%"INTEGER"", i);
		hv_store(output_hv, (const char*)temp_key, (U32)strlen(temp_key), newSViv(i * 5), (U32)0);
//		fprintf(stderr, "in CPPOPS_PERLTYPES integer_hashref__typetest1(), setting entry '%s' => %"INTEGER", BARBAT\n", temp_key, (integer)SvIV(*hv_fetch(output_hv, (const char*)temp_key, (U32)strlen(temp_key), (I32)0)));
	}

	return(newRV_noinc((SV*) output_hv));
}

SV* number_hashref__typetest0(SV* lucky_numbers)
{
//	number_hashref_CHECK(lucky_numbers);
	number_hashref_CHECKTRACE(lucky_numbers, "lucky_numbers", "number_hashref__typetest0()");
	/*
	HV* lucky_numbers_deref = (HV*)SvRV(lucky_numbers);
	integer how_lucky = hv_iterinit(lucky_numbers_deref);
	integer i;

	for (i = 0;  i < how_lucky;  ++i)
	{
		HE* lucky_number_entry = hv_iternext(lucky_numbers_deref);
//		fprintf(stderr, "in CPPOPS_PERLTYPES number_hashref__typetest0(), have lucky number '%s' => %Lf, BARSTOOP\n", SvPV_nolen(hv_iterkeysv(lucky_number_entry)), (double)SvNV(hv_iterval(lucky_numbers_deref, lucky_number_entry)));
	}
	*/

	return(newSVpvf("%s%s", SvPV_nolen(number_hashref_to_string(lucky_numbers)), "CPPOPS_PERLTYPES"));
}

SV* number_hashref__typetest1(SV* my_size)
{
//	integer_CHECK(my_size);
	integer_CHECKTRACE(my_size, "my_size", "number_hashref__typetest1()");
	HV* output_hv = newHV();
	integer i;
	char temp_key[30];

	for (i = 0;  i < SvIV(my_size);  ++i)
	{
		sprintf(temp_key, "CPPOPS_PERLTYPES_funkey%"INTEGER"", i);
		hv_store(output_hv, (const char*)temp_key, (U32)strlen(temp_key), newSVnv(i * 5.123456789), (U32)0);
//		fprintf(stderr, "in CPPOPS_PERLTYPES number_hashref__typetest1(), setting entry '%s' => %Lf, BARTAB\n", temp_key, (double)SvNV(*hv_fetch(output_hv, (const char*)temp_key, (U32)strlen(temp_key), (I32)0)));
	}

	return(newRV_noinc((SV*) output_hv));
}

SV* string_hashref__typetest0(SV* people)
{
//	string_hashref_CHECK(people);
	string_hashref_CHECKTRACE(people, "people", "string_hashref__typetest0()");
	/*
	HV* people_deref = (HV*)SvRV(people);
	integer how_crowded = hv_iterinit(people_deref);
	integer i;

	for (i = 0;  i < how_crowded;  ++i)
	{
		HE* person_entry = hv_iternext(people_deref);
//		fprintf(stderr, "in CPPOPS_PERLTYPES string_hashref__typetest0(), have person '%s' => '%s', BARSPOON\n", (char*)SvPV_nolen(hv_iterkeysv(person_entry)), (char*)SvPV_nolen(hv_iterval(people_deref, person_entry)));
	}
	*/

	return(newSVpvf("%s%s", SvPV_nolen(string_hashref_to_string(people)), "CPPOPS_PERLTYPES"));
}

SV* string_hashref__typetest1(SV* my_size)
{
//	integer_CHECK(my_size);
	integer_CHECKTRACE(my_size, "my_size", "string_hashref__typetest1()");
	HV* people = newHV();
	integer i;
	char temp_key[30];

	for (i = 0;  i < SvIV(my_size);  ++i)
	{
		sprintf(temp_key, "CPPOPS_PERLTYPES_Luker_key%"INTEGER"", i);
		hv_store(people, (const char*)temp_key, (U32)strlen(temp_key), newSVpvf("Jeffy Ten! %"INTEGER"/%"INTEGER"", i, (integer)(SvIV(my_size) - 1)), (U32)0);
//		fprintf(stderr, "in CPPOPS_PERLTYPES string_hashref__typetest1(), have temp_key = '%s', just set another Jeffy, BARTAT\n", temp_key);
	}

	return(newRV_noinc((SV*) people));
}

# elif defined __CPP__TYPES

string integer_hashref__typetest0(integer_hashref lucky_integers)
{
	/*
	integer_hashref_const_iterator i;
	for (i = lucky_integers.begin();  i != lucky_integers.end();  ++i)
	{
		fprintf(stderr, "in CPPOPS_CPPTYPES integer_hashref__typetest0(), have lucky integer '%s' => %"INTEGER", BARSTOOL\n", (i->first).c_str(), i->second);
	}
	*/
	return(integer_hashref_to_string(lucky_integers) + "CPPOPS_CPPTYPES");
}

integer_hashref integer_hashref__typetest1(integer my_size)
{
	integer_hashref new_unordered_map(my_size);
	integer i;
	string temp_key;
	for (i = 0;  i < my_size;  ++i)
	{
		temp_key = "CPPOPS_CPPTYPES_funkey" + std::to_string(i);
		new_unordered_map[temp_key] = i * 5;
//		fprintf(stderr, "in CPPOPS_CPPTYPES integer_hashref__typetest1(), setting entry '%s' => %"INTEGER", BARSTOOL\n", temp_key.c_str(), new_unordered_map[temp_key]);
	}
	return(new_unordered_map);
}

string number_hashref__typetest0(number_hashref lucky_numbers)
{
	/*
	number_hashref_const_iterator i;
	for (i = lucky_numbers.begin();  i != lucky_numbers.end();  ++i)
	{
		fprintf(stderr, "in CPPOPS_CPPTYPES number_hashref__typetest0(), have lucky number '%s' => %Lf, BARSTOOL\n", (i->first).c_str(), i->second);
	}
	*/
	return(number_hashref_to_string(lucky_numbers) + "CPPOPS_CPPTYPES");
}

number_hashref number_hashref__typetest1(integer my_size)
{
	number_hashref new_unordered_map(my_size);
	integer i;
	string temp_key;
	for (i = 0;  i < my_size;  ++i)
	{
		temp_key = "CPPOPS_CPPTYPES_funkey" + std::to_string(i);
		new_unordered_map[temp_key] = i * 5.123456789;
//		fprintf(stderr, "in CPPOPS_CPPTYPES number_hashref__typetest1(), setting entry '%s' => %Lf, BARSTOOL\n", temp_key.c_str(), new_unordered_map[temp_key]);
	}
	return(new_unordered_map);
}

string string_hashref__typetest0(string_hashref people)
{
	/*
	string_hashref_const_iterator i;
	for (i = people.begin();  i != people.end();  ++i)
	{
		fprintf(stderr, "in CPPOPS_CPPTYPES string_hashref__typetest0(), have person '%s' => '%s', STARBOOL\n", (i->first).c_str(), (i->second).c_str());
	}
	*/
	return(string_hashref_to_string(people) + "CPPOPS_CPPTYPES");
}

string_hashref string_hashref__typetest1(integer my_size)
{
	string_hashref people;
	integer i;
	people.reserve((size_t)my_size);
	for (i = 0;  i < my_size;  ++i)
	{
		people["CPPOPS_CPPTYPES_Luker_key" + std::to_string(i)] = "Jeffy Ten! " + std::to_string(i) + "/" + std::to_string(my_size - 1);
//		fprintf(stderr, "in CPPOPS_CPPTYPES string_hashref__typetest1(), bottom of for() loop, have i = %"INTEGER", just set another Jeffy!\n", i);
	}
	return(people);
}

# endif

#endif
