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

#ifndef __CPP__INCLUDED__Perl__Type__String_h
#define __CPP__INCLUDED__Perl__Type__String_h 0.015_000

// [[[ TYPEDEFS ]]]
# ifndef __CPP__INCLUDED__Perl__Type__String_h__typedefs
#define __CPP__INCLUDED__Perl__Type__String_h__typedefs 1
typedef std::string string;
typedef std::ostringstream ostringstream;
# endif

// [[[ PRE-DECLARED TYPEDEFS ]]]
# ifndef __CPP__INCLUDED__Perl__Type__Boolean_h__typedefs
#define __CPP__INCLUDED__Perl__Type__Boolean_h__typedefs 1
typedef bool boolean;
# endif
# ifndef __CPP__INCLUDED__Perl__Type__NonsignedInteger_h__typedefs
#define __CPP__INCLUDED__Perl__Type__NonsignedInteger_h__typedefs 1
typedef unsigned long int nonsigned_integer;
# endif
# ifndef __CPP__INCLUDED__Perl__Type__Integer_h__typedefs
#define __CPP__INCLUDED__Perl__Type__Integer_h__typedefs 1
// DEV NOTE, CORRELATION #rp001: keep track of all these hard-coded "semi-dynamic" integer data types
#  ifdef __TYPE__INTEGER__LONG
typedef long integer;
#define INTEGER "ld"  // assume format code 'ld' exists if type 'long' exists
#  elif defined __TYPE__INTEGER__LONG_LONG
typedef long long integer;
#define INTEGER "lld"  // assume format code 'lld' exists if type 'long long' exists
#  elif defined __TYPE__INTEGER____INT8
typedef __int8 integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I8d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId8"
#   endif
#  elif defined __TYPE__INTEGER____INT16
typedef __int16 integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I16d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId16"
#   endif
#  elif defined __TYPE__INTEGER____INT32
typedef __int32 integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I32d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId32"
#   endif
#  elif defined __TYPE__INTEGER____INT64
typedef __int64 integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I64d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId64"
#   endif
#  elif defined __TYPE__INTEGER____INT128
typedef __int128 integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I128d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId128"
#   endif
#  elif defined __TYPE__INTEGER__INT8_T
typedef int8_t integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I8d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId8"
#   endif
#  elif defined __TYPE__INTEGER__INT16_T
typedef int16_t integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I16d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId16"
#   endif
#  elif defined __TYPE__INTEGER__INT32_T
typedef int32_t integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I32d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId32"
#   endif
#  elif defined __TYPE__INTEGER__INT64_T
typedef int64_t integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I64d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId64"
#   endif
#  elif defined __TYPE__INTEGER__INT128_T
typedef int128_t integer;
#   if defined(_MSC_VER) && (_MSC_VER < 1800)  // MSVC older-than-2013
#define INTEGER "I128d"
#   else  // non-Windows, Windows w/ GCC, or MSVC 2013-or-newer
#include <inttypes.h>
#define INTEGER "PRId128"
#   endif
#  else
typedef long integer;  // default
#define INTEGER "ld"  // assume format code 'ld' exists if type 'long' exists
#  endif
# endif
# ifndef __CPP__INCLUDED__Perl__Type__Number_h__typedefs
#define __CPP__INCLUDED__Perl__Type__Number_h__typedefs 1
#  ifdef __TYPE__NUMBER__DOUBLE
typedef double number;
#define NUMBER "f"
#  elif defined __TYPE__NUMBER__LONG__DOUBLE
typedef long double number;
#define NUMBER "Lf"  // assume format code 'Lf' exists if type 'long double' exists
#  else
typedef double number;  // default
#define NUMBER "f"
#  endif
# endif
# ifndef __CPP__INCLUDED__Perl__Type__Character_h__typedefs
#define __CPP__INCLUDED__Perl__Type__Character_h__typedefs 1
typedef char character;
# endif

// [[[ INCLUDES ]]]
#include <perltypes_mode.h> // for definitions of __PERL__TYPES or __CPP__TYPES

// [[[ TYPE-CHECKING MACROS ]]]
#define string_CHECK(possible_string) \
	(not(SvOK(possible_string)) ? \
			croak("\nERROR EPV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring value expected but undefined/null value found,\ncroaking") : \
			(not(SvPOKp(possible_string)) ? \
					croak("\nERROR EPV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring value expected but non-string value found,\ncroaking") : \
					(void)0))
#define string_CHECKTRACE(possible_string, variable_name, subroutine_name) \
	(not(SvOK(possible_string)) ? \
			croak("\nERROR EPV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring value expected but undefined/null value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name) : \
			(not(SvPOKp(possible_string)) ? \
					croak("\nERROR EPV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nstring value expected but non-string value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name) : \
					(void)0))

// [[[ GENERAL FUNCTIONS ]]]
string escape_backslash_singlequote(string unescaped_string);

// [[[ TYPE CHECKING ]]]
// DEPRECATED, SEE MACROS ABOVE
//void string_CHECK(SV* possible_string);
//void string_CHECKTRACE(SV* possible_string, const char* variable_name, const char* subroutine_name);

// [[[ OPERATIONS & DATA TYPES REPORTER ]]]
# ifdef __PERL__TYPES
SV* Perl__Type__String__MODE_ID() { return(newSViv(1)); }  // CPPOPS_PERLTYPES is 1
# elif defined __CPP__TYPES
int Perl__Type__String__MODE_ID() { return 2; }  // CPPOPS_CPPTYPES is 2
# 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

// [[[ TYPEMAP PACK/UNPACK FOR __CPP__TYPES ]]]
// DEV NOTE, CORRELATION #rp010: the pack/unpack subs (below) are called by number_to_string_CPPTYPES(), moved outside #ifdef blocks
//# ifdef __CPP__TYPES
string XS_unpack_string(SV* input_sv);
void XS_pack_string(SV* output_sv, string input_string);
//# endif

/* DEV NOTE, CORRELATION #rp502 COMPILER REFACTOR: must use "(const string&)" instead of "const string&" to avoid false error (or warning?) messages when running `perl t/04_type_scalar.t`...
ok 103 - mode 'CPP Operations & PERL Data Types' enabled
ok 104 - require Perl::Type::Integer_cpp;
No typemap for type string &. Skipping void string_substitute_global(SV *, string &, string &)
ok 105 - Perl::Type::Integer_cpp::cpp_load() lives
...
EXCEPT we had to undo previous #rp502 fix below, due to fatal compile errors...
In file included from lib/Perl/Type/String.cpp:7, ... lib/Perl/Type/String.h:185:49: error: expected identifier before ‘(’ token
*/

// [[[ SEARCH & REPLACE ]]]
# ifdef __PERL__TYPES
void string_substitute_global(SV* input_string, const string& find_string, const string& replace_string);  // FAKE ERROR OR WARNING? SEE DEV NOTE CORRELATION #rp502 ABOVE
//void string_substitute_global(SV* input_string, (const string&) find_string, (const string&) replace_string);
# elif defined __CPP__TYPES
void string_substitute_global(string& input_string, const string& find_string, const string& replace_string);  // FAKE ERROR OR WARNING? SEE DEV NOTE CORRELATION #rp502 ABOVE
//void string_substitute_global((string&) input_string, (const string&) find_string, (const string&) replace_string);
# endif

// [[[ BOOLEANIFY ]]]
# ifdef __PERL__TYPES
SV* string_to_boolean(SV* input_string);
# elif defined __CPP__TYPES
boolean string_to_boolean(string input_string);
# endif

// [[[ UNSIGNED INTEGERIFY ]]]
# ifdef __PERL__TYPES
SV* string_to_nonsigned_integer(SV* input_string);
# elif defined __CPP__TYPES
nonsigned_integer string_to_nonsigned_integer(string input_string);
# endif

// [[[ INTEGERIFY ]]]
# ifdef __PERL__TYPES
SV* string_to_integer(SV* input_string);
# elif defined __CPP__TYPES
integer string_to_integer(string input_string);
# endif

// [[[ NUMBERIFY ]]]
# ifdef __PERL__TYPES
SV* string_to_number(SV* input_string);
# elif defined __CPP__TYPES
number string_to_number(string input_string);
# endif

// [[[ CHARACTERIFY ]]]
# ifdef __PERL__TYPES
SV* string_to_character(SV* input_string);
# elif defined __CPP__TYPES
character string_to_character(string input_string);
# endif

// [[[ STRINGIFY ]]]
# ifdef __PERL__TYPES
SV* string_to_string(SV* input_sv);
# elif defined __CPP__TYPES
string string_to_string(string input_string);
# endif

// [[[ TYPE TESTING ]]]
# ifdef __PERL__TYPES
SV* string_typetest0();
SV* string_typetest1(SV* lucky_string);
# elif defined __CPP__TYPES
string string_typetest0();
string string_typetest1(string lucky_string);
# endif

#endif
