mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
635 lines
18 KiB
C++
635 lines
18 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _PSTYPES_H
|
|
#define _PSTYPES_H
|
|
|
|
|
|
|
|
#include "windows_stub/config.h"
|
|
#include "globalincs/scp_defines.h"
|
|
#include "globalincs/toolchain.h"
|
|
#include "globalincs/vmallocator.h"
|
|
#include "utils/strings.h"
|
|
|
|
#include <cstdio> // For NULL, etc
|
|
#include <cstdlib>
|
|
#include <memory.h>
|
|
#include <cstring>
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
|
|
// value to represent an uninitialized state in any int or uint
|
|
#define UNINITIALIZED 0x7f8e6d9c
|
|
|
|
#define MAX_PLAYERS 12
|
|
|
|
#ifdef LOCAL
|
|
#undef LOCAL
|
|
#endif
|
|
|
|
#define LOCAL static // make module local varilable static.
|
|
|
|
#ifdef _WIN32
|
|
#define DIR_SEPARATOR_CHAR '\\'
|
|
#define DIR_SEPARATOR_STR "\\"
|
|
#else
|
|
#define DIR_SEPARATOR_CHAR '/'
|
|
#define DIR_SEPARATOR_STR "/"
|
|
#endif
|
|
|
|
constexpr char COMMENT_CHAR = static_cast<char>(';');
|
|
constexpr char EOLN = static_cast<char>(0x0a);
|
|
constexpr char CARRIAGE_RETURN = static_cast<char>(0x0d);
|
|
|
|
#ifndef NDEBUG
|
|
constexpr bool FSO_DEBUG = true;
|
|
#else
|
|
constexpr bool FSO_DEBUG = false;
|
|
#endif
|
|
|
|
typedef std::int32_t _fs_time_t; // time_t here is 64-bit and we need 32-bit
|
|
typedef std::int32_t fix;
|
|
|
|
// PTR compatible sizes
|
|
typedef ptrdiff_t ptr_s;
|
|
typedef size_t ptr_u;
|
|
|
|
typedef std::int64_t longlong;
|
|
typedef std::uint64_t ulonglong;
|
|
typedef std::uint8_t ubyte;
|
|
typedef std::uint16_t ushort;
|
|
typedef std::uint32_t uint;
|
|
typedef unsigned long ulong;
|
|
|
|
//Stucture to store clipping codes in a word
|
|
typedef struct ccodes {
|
|
ubyte cc_or, cc_and; //or is low byte, and is high byte
|
|
} ccodes;
|
|
|
|
struct vertex;
|
|
|
|
typedef struct vec4 {
|
|
union {
|
|
struct {
|
|
float x,y,z,w;
|
|
} xyzw;
|
|
float a1d[4];
|
|
};
|
|
} vec4;
|
|
|
|
struct bvec4 {
|
|
bool x;
|
|
bool y;
|
|
bool z;
|
|
bool w;
|
|
};
|
|
|
|
// sometimes, you just need some integers
|
|
typedef struct ivec3 {
|
|
int x, y, z;
|
|
} ivec3;
|
|
|
|
struct ivec2 {
|
|
int x, y;
|
|
};
|
|
|
|
inline bool operator<(const ivec3& l, const ivec3& r){
|
|
return l.x < r.x || (l.x == r.x && (l.y < r.y || (l.y == r.y && l.z < r.z)));
|
|
}
|
|
|
|
inline bool operator<(const ivec2& l, const ivec2& r){
|
|
return l.x < r.x || (l.x == r.x && l.y < r.y);
|
|
}
|
|
|
|
namespace scripting {
|
|
class ade_table_entry;
|
|
}
|
|
namespace luacpp {
|
|
class LuaValue;
|
|
}
|
|
struct lua_State;
|
|
|
|
/** Represents a point in 3d space.
|
|
|
|
Note: this is a struct, not a class, so no member functions. */
|
|
typedef struct vec3d {
|
|
union {
|
|
struct {
|
|
float x,y,z;
|
|
} xyz;
|
|
float a1d[3];
|
|
};
|
|
} vec3d;
|
|
|
|
typedef struct vec2d {
|
|
float x, y;
|
|
} vec2d;
|
|
|
|
// Euler angles for a rotation: h=heading, b=bank and p=pitch; angles are around the y, z and x axes
|
|
// respectively and are performed in that order. (Strictly speaking these are Tait-Bryan angles,
|
|
// not classic Euler angles.)
|
|
typedef struct angles {
|
|
float p, b, h;
|
|
} angles_t;
|
|
|
|
// For the avoidance of doubt, this is a row-major order matrix.
|
|
typedef struct matrix {
|
|
union {
|
|
struct {
|
|
vec3d rvec, uvec, fvec;
|
|
} vec;
|
|
float a2d[3][3];
|
|
float a1d[9];
|
|
};
|
|
} matrix;
|
|
|
|
// You might think this is also row-major. You fool! It is actually column-major.
|
|
typedef struct matrix4 {
|
|
union {
|
|
struct {
|
|
vec4 rvec, uvec, fvec, pos;
|
|
} vec;
|
|
float a2d[4][4];
|
|
float a1d[16];
|
|
};
|
|
} matrix4;
|
|
|
|
typedef struct uv_pair {
|
|
float u,v;
|
|
} uv_pair;
|
|
|
|
/** Compares two uv_pairs */
|
|
inline bool operator==(const uv_pair &left, const uv_pair &right)
|
|
{
|
|
return (left.u == right.u) && (left.v == right.v);
|
|
}
|
|
|
|
/** Represents a point in 3d screen space. 'w' is 1/z.
|
|
|
|
Like vec3d but for screens.
|
|
|
|
Note: this is a struct, not a class, so no member functions. */
|
|
typedef struct screen3d
|
|
{
|
|
union {
|
|
struct {
|
|
float x,y,w;
|
|
} xyw;
|
|
float a1d[3];
|
|
};
|
|
} screen3d;
|
|
|
|
/** Compares two screen3ds */
|
|
inline bool operator==(const screen3d &self, const screen3d &other)
|
|
{
|
|
return (self.xyw.x == other.xyw.x
|
|
&& self.xyw.y == other.xyw.y
|
|
&& self.xyw.w == other.xyw.w
|
|
);
|
|
}
|
|
|
|
/** Used to store rotated points for mines. Has flag to indicate if projected.
|
|
|
|
Note: this is a struct, not a class, so no memeber functions. */
|
|
typedef struct vertex {
|
|
vec3d world; // world space position
|
|
screen3d screen; // screen space position (sw == 1/z)
|
|
uv_pair texture_position; // texture position
|
|
ubyte r, g, b, a; // color. Use b for darkening;
|
|
ubyte codes; // what sides of view pyramid this point is on/off. 0 = Inside view pyramid.
|
|
ubyte flags; // Projection flags. Indicates whether it is projected or not or if projection overflowed.
|
|
ubyte pad[2]; // pad structure to be 4 byte aligned.
|
|
} vertex;
|
|
|
|
typedef struct effect_vertex {
|
|
vec3d position;
|
|
uv_pair tex_coord;
|
|
float radius;
|
|
ubyte r, g, b, a;
|
|
} effect_vertex;
|
|
|
|
struct particle_pnt {
|
|
vec3d position;
|
|
float size;
|
|
vec3d up;
|
|
};
|
|
|
|
// for compiler compatibility, even though C++17 supports omitting the template type...
|
|
|
|
//def_list
|
|
template<typename T>
|
|
struct flag_def_list_templated {
|
|
const char *name;
|
|
T def;
|
|
ubyte var;
|
|
};
|
|
using flag_def_list = flag_def_list_templated<int>;
|
|
|
|
//A list of parse names for a flag enum
|
|
template<typename T>
|
|
struct flag_def_list_new {
|
|
const char* name; // The parseable representation of this flag
|
|
T def; // The flag definition for this flag
|
|
bool in_use; // Whether or not this flag is currently in use or obsolete
|
|
bool is_special; // Whether this flag requires special processing. See parse_string_flag_list<T, T> for details
|
|
};
|
|
|
|
//A list of parse names for a flag enum. Instead of specifying whether an argument needs special handling,
|
|
//a functor can passed that is called to handle an argument proceeding the flag. If used with parse_string_flag_list_special,
|
|
//these will automatically be called when a special argument is encountered
|
|
template<class T, typename... additional_args>
|
|
struct special_flag_def_list_new : public flag_def_list_new<T> {
|
|
std::function<void(const SCP_string&, additional_args...)> parse_special;
|
|
|
|
special_flag_def_list_new(const char* name, T flag, bool in_use) : flag_def_list_new<T>{ name, flag, in_use, false } {}
|
|
special_flag_def_list_new(const char* name, T flag, bool in_use, const decltype(parse_special)& parseSpecial) : flag_def_list_new<T>{ name, flag, in_use, true }, parse_special(parseSpecial) { }
|
|
};
|
|
|
|
// weapon count list (mainly for pilot files)
|
|
typedef struct wep_t {
|
|
int index;
|
|
int count;
|
|
} wep_t;
|
|
|
|
typedef struct coord2d {
|
|
int x,y;
|
|
} coord2d;
|
|
|
|
#include "osapi/dialogs.h"
|
|
|
|
extern int Global_warning_count;
|
|
extern int Global_error_count;
|
|
|
|
enum class ErrorType : ubyte { NONE = 0, WARNING, FATAL_ERROR };
|
|
|
|
#include "osapi/outwnd.h"
|
|
|
|
// To debug printf do this:
|
|
// mprintf(( "Error opening %s\n", filename ));
|
|
#ifndef NDEBUG
|
|
constexpr bool LoggingEnabled = true;
|
|
#else
|
|
#ifdef SCP_RELEASE_LOGGING
|
|
constexpr bool LoggingEnabled = true;
|
|
#else
|
|
constexpr bool LoggingEnabled = false;
|
|
#endif
|
|
#endif
|
|
|
|
#define mprintf(args) do { if (LoggingEnabled) { outwnd_printf2 args; } } while (false)
|
|
#define nprintf(args) do { if (LoggingEnabled) { outwnd_printf args; } } while (false)
|
|
|
|
#define LOCATION __FILE__,__LINE__
|
|
|
|
// To flag an error, you can do this:
|
|
// Error( __FILE__, __LINE__, "Error opening %s", filename );
|
|
// or,
|
|
// Error( LOCATION, "Error opening %s", filename );
|
|
|
|
/*******************NEVER COMMENT Assert ************************************************/
|
|
// Please never comment the functionality of Assert in debug
|
|
// The code, as with all development like this is littered with Asserts which are designed to throw
|
|
// up an error message if variables are out of range.
|
|
// Disabling this functionality is dangerous, crazy values can run rampant unchecked, and the longer it's disabled
|
|
// the more likely you are to have problems getting it working again.
|
|
#if defined(NDEBUG)
|
|
# define Assert(expr) do { ASSUME(expr); (void)sizeof(expr); } while (false)
|
|
#else
|
|
# define Assert(expr) do {\
|
|
if (!(expr)) {\
|
|
os::dialogs::AssertMessage(#expr,__FILE__,__LINE__);\
|
|
}\
|
|
ASSUME( expr );\
|
|
} while (false)
|
|
#endif
|
|
|
|
template <typename T>
|
|
bool CallAssert(bool val, const char *msg, const char *filename, int linenum, T assertMsgFunc)
|
|
{
|
|
if (!val)
|
|
assertMsgFunc(msg, filename, linenum, nullptr);
|
|
ASSUME(val);
|
|
return true;
|
|
}
|
|
#if defined(NDEBUG)
|
|
# define AssertExpr(expr) (true)
|
|
#else
|
|
# define AssertExpr(expr) CallAssert(expr, #expr, __FILE__, __LINE__, os::dialogs::AssertMessage)
|
|
#endif
|
|
/*******************NEVER COMMENT Assert ************************************************/
|
|
|
|
// Goober5000 - define Verify for use in both release and debug mode
|
|
#define Verify(x) do { if (!(x)){ Error(LOCATION, "Verify failure: %s\n", #x); } ASSUME(x); } while(false)
|
|
|
|
// Verification (like Assertion)
|
|
#ifndef _MSC_VER // non MS compilers
|
|
# define Verification(x, y, ...) do { if (!(x)) { Error(LOCATION, "Verify failure: %s with help text " #y "\n", #x, ##__VA_ARGS__); } ASSUME(x); } while(false)
|
|
#else
|
|
# define Verification(x, y, ...) do { if (!(x)) { Error(LOCATION, "Verify failure: %s with help text " #y "\n", #x, __VA_ARGS__); } ASSUME(x); } while(false)
|
|
#endif
|
|
|
|
#if defined(NDEBUG)
|
|
// No debug version of Int3
|
|
#define Int3() do { } while (false)
|
|
#else
|
|
void debug_int3(const char *file, int line);
|
|
|
|
// Debug version of Int3
|
|
#define Int3() debug_int3(__FILE__, __LINE__)
|
|
#endif // NDEBUG
|
|
|
|
|
|
// the older MIN and MAX macros were vulnerable to performance issues since they duplicated their tokens
|
|
|
|
#ifndef MIN
|
|
#define MIN(a,b) std::min(a,b)
|
|
#endif
|
|
#ifndef MAX
|
|
#define MAX(a,b) std::max(a,b)
|
|
#endif
|
|
|
|
|
|
#define PI 3.141592654f
|
|
// twice values
|
|
const float PI2 = (PI*2.0f);
|
|
// half values
|
|
const float PI_2 = (PI/2.0f);
|
|
const float PI_4 = (PI/4.0f);
|
|
|
|
// not defined generally on Windows, no longer included in SDL
|
|
#ifndef M_PI
|
|
#define M_PI SDL_PI_F
|
|
#endif
|
|
|
|
extern int Fred_running; // Is Fred running, or FreeSpace?
|
|
extern int Qtfred_running; // Distinguishes QtFRED from legacy Fred2; Fred_running is set in both, but Qtfred_running only in QtFRED.
|
|
extern bool running_unittests;
|
|
|
|
const size_t INVALID_SIZE = static_cast<size_t>(-1);
|
|
|
|
//======================================================================================
|
|
//======================================================================================
|
|
//======================================================================================
|
|
|
|
|
|
#include "math/fix.h"
|
|
#include "math/floating.h"
|
|
|
|
// Some constants for stuff
|
|
#define MAX_FILENAME_LEN 32 // Length for filenames, ie "title.pcx"
|
|
#define MAX_PATH_LEN 256 // Length for pathnames, ie "c:\bitmaps\title.pcx"
|
|
|
|
// contants and defined for byteswapping routines (useful for mac)
|
|
|
|
#ifdef SCP_SOLARIS // Solaris
|
|
#define INTEL_INT(x) x
|
|
#define INTEL_LONG(x) x
|
|
#define INTEL_SHORT(x) x
|
|
#define INTEL_FLOAT(x) (*x)
|
|
#elif BYTE_ORDER == BIG_ENDIAN
|
|
// turn off inline asm
|
|
#undef USE_INLINE_ASM
|
|
|
|
#define INTEL_INT(x) SDL_Swap32LE(x)
|
|
#define INTEL_LONG(x) SDL_Swap64LE(x)
|
|
#define INTEL_SHORT(x) SDL_Swap16LE(x)
|
|
#define INTEL_FLOAT(x) SDL_SwapFloatLE((*x))
|
|
|
|
#else // Little Endian -
|
|
#define INTEL_INT(x) x
|
|
#define INTEL_LONG(x) x
|
|
#define INTEL_SHORT(x) x
|
|
#define INTEL_FLOAT(x) (*x)
|
|
#endif // BYTE_ORDER
|
|
|
|
// since a lot of header files will try to #define TRUE and FALSE,
|
|
// making them constexpr here doesn't gain us much
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
// the trailing underscores are to avoid conflicts with previously #define'd tokens
|
|
enum class TriStateBool : int { FALSE_ = 0, TRUE_ = 1, UNKNOWN_ = -1 };
|
|
|
|
// Callback Loading function.
|
|
// If you pass a function to this, that function will get called
|
|
// around 10x per second, so you can update the screen.
|
|
// Pass NULL to turn it off.
|
|
// Call this with the name of a function. That function will
|
|
// then get called around 10x per second. The callback function
|
|
// gets passed a 'count' which is how many times game_busy has
|
|
// been called since the callback was set. It gets called
|
|
// one last time with count=-1 when you turn off the callback
|
|
// by calling game_busy_callback(NULL). Game_busy_callback
|
|
// returns the current count, so you can tell how many times
|
|
// game_busy got called.
|
|
// If delta_step is above 0, then it will also make sure it
|
|
// calls the callback each time count steps 'delta_step' even
|
|
// if 1/10th of a second hasn't elapsed.
|
|
extern int game_busy_callback( void (*callback)(int count), int delta_step = -1 );
|
|
|
|
// Call whenever loading to display cursor
|
|
extern void game_busy(const char *filename = NULL);
|
|
|
|
#define NOX(s) s
|
|
|
|
const char *XSTR(const char *str, int index, bool force_lookup = false);
|
|
|
|
// The older CLAMP macro was vulnerable to performance issues since it duplicated its tokens. (The older CAP was a function.) Technically
|
|
// the new macro duplicates the LHS, but that should be ok.
|
|
|
|
// Ensure that x is at least min and at most max.
|
|
#define CLAMP(x, min, max) { x = std::clamp(x, min, max); }
|
|
|
|
// Ensure that x is at least min and at most max.
|
|
#define CAP(v, mn, mx) CLAMP(v, mn, mx)
|
|
|
|
|
|
//=========================================================
|
|
// Memory management functions
|
|
//=========================================================
|
|
|
|
#include "globalincs/fsmemory.h"
|
|
|
|
class camid
|
|
{
|
|
private:
|
|
int sig;
|
|
size_t idx;
|
|
public:
|
|
camid();
|
|
camid(size_t n_idx, int n_sig);
|
|
|
|
class camera *getCamera();
|
|
size_t getIndex();
|
|
int getSignature();
|
|
bool isValid() const;
|
|
};
|
|
|
|
#include "globalincs/vmallocator.h"
|
|
#include "globalincs/safe_strings.h"
|
|
|
|
// check to see that a passed sting is valid, ie:
|
|
// - has >0 length
|
|
// - is not "none"
|
|
// - is not "<none>"
|
|
inline bool VALID_FNAME(const char* x) {
|
|
return (x != nullptr) && (x[0] != '\0') && stricmp(x, "none") != 0 && stricmp(x, "<none>") != 0;
|
|
}
|
|
/**
|
|
* @brief Checks if the specified string may be a valid file name
|
|
*
|
|
* @warning This only does a quick check against an empty string and a few known invalid names. It does not check if the
|
|
* file actually exists.
|
|
*
|
|
* @param x The file name to check
|
|
* @return @c true if the name is valid, @c false otherwise
|
|
*/
|
|
inline bool VALID_FNAME(const SCP_string& x) {
|
|
if (x.empty()) {
|
|
return false;
|
|
}
|
|
if (!stricmp(x.c_str(), "none")) {
|
|
return false;
|
|
}
|
|
if (!stricmp(x.c_str(), "<none>")) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Function to generate a stacktrace
|
|
SCP_string dump_stacktrace();
|
|
|
|
// DEBUG compile time catch for dangerous uses of memset/memcpy/memmove
|
|
// This is disabled for VS2013 and lower since that doesn't support the necessary features
|
|
#if !defined(NDEBUG) && !defined(USING_THIRD_PARTY_LIBS) && (!defined(_MSC_VER) || _MSC_VER >= 1900)
|
|
// feature support seems to be: gcc clang msvc
|
|
// auto 4.4 2.9 2010
|
|
// std::is_trivial 4.5 ? 2012 (2010 only duplicates std::is_pod)
|
|
// static_assert 4.3 2.9 2010
|
|
#include <type_traits>
|
|
#include <cstring>
|
|
|
|
// MEMSET!
|
|
const auto ptr_memset = std::memset;
|
|
#define memset memset_if_trivial_else_error
|
|
|
|
// Forward declarations from libraries
|
|
struct ImDrawListSplitter;
|
|
|
|
// Put into std to be compatible with code that uses std::mem*
|
|
namespace std
|
|
{
|
|
template <typename T>
|
|
using trivial_check = std::is_trivially_copyable<T>;
|
|
|
|
template <typename T>
|
|
void* memset_if_trivial_else_error(
|
|
typename std::enable_if<!std::is_same<T, ImDrawListSplitter>::value, T>::type* memset_data,
|
|
int ch,
|
|
size_t count)
|
|
{
|
|
static_assert(trivial_check<T>::value, "memset on non-trivial object");
|
|
return ptr_memset(memset_data, ch, count);
|
|
}
|
|
|
|
// assume memset on a void* is "safe"
|
|
// only used in cutscene/mveplayer.cpp:mve_video_createbuf()
|
|
inline void* memset_if_trivial_else_error(void* memset_data, int ch, size_t count)
|
|
{
|
|
return ptr_memset(memset_data, ch, count);
|
|
}
|
|
|
|
// Dear ImGui triggers these as well, so we need to let them pass
|
|
inline void* memset_if_trivial_else_error(ImDrawListSplitter* memset_data, int ch, size_t count)
|
|
{
|
|
return ptr_memset(memset_data, ch, count);
|
|
}
|
|
|
|
// MEMCPY!
|
|
const auto ptr_memcpy = std::memcpy;
|
|
#define memcpy memcpy_if_trivial_else_error
|
|
|
|
template<typename T, typename U>
|
|
void *memcpy_if_trivial_else_error(T *memcpy_dest, U *src, size_t count)
|
|
{
|
|
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
|
|
static_assert(trivial_check<U>::value, "memcpy on non-trivial object U");
|
|
return ptr_memcpy(memcpy_dest, src, count);
|
|
}
|
|
|
|
// assume memcpy with void* is "safe"
|
|
// used in:
|
|
// globalincs/systemvars.cpp:insertion_sort()
|
|
// network/chat_api.cpp:AddChatCommandToQueue()
|
|
// network/multi_obj.cpp:multi_oo_sort_func()
|
|
// parse/lua.cpp:ade_get_args() && ade_set_args()
|
|
//
|
|
// probably should setup a static_assert on insertion_sort as well
|
|
template<typename U>
|
|
void *memcpy_if_trivial_else_error(void *memcpy_dest, U *memcpy_src, size_t count)
|
|
{
|
|
static_assert(trivial_check<U>::value, "memcpy on non-trivial object U");
|
|
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
|
}
|
|
|
|
template<typename T>
|
|
void *memcpy_if_trivial_else_error(T *memcpy_dest, void *memcpy_src, size_t count)
|
|
{
|
|
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
|
|
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
|
}
|
|
template<typename T>
|
|
void *memcpy_if_trivial_else_error(T *memcpy_dest, const void *memcpy_src, size_t count)
|
|
{
|
|
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
|
|
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
|
}
|
|
|
|
inline void *memcpy_if_trivial_else_error(void *memcpy_dest, void *memcpy_src, size_t count)
|
|
{
|
|
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
|
}
|
|
|
|
inline void *memcpy_if_trivial_else_error(void *memcpy_dest, const void *memcpy_src, size_t count)
|
|
{
|
|
return ptr_memcpy(memcpy_dest, memcpy_src, count);
|
|
}
|
|
|
|
// MEMMOVE!
|
|
const auto ptr_memmove = std::memmove;
|
|
#define memmove memmove_if_trivial_else_error
|
|
|
|
template<typename T, typename U>
|
|
inline void *memmove_if_trivial_else_error(T *memmove_dest, U *memmove_src, size_t count)
|
|
{
|
|
static_assert(trivial_check<T>::value, "memmove on non-trivial object T");
|
|
static_assert(trivial_check<U>::value, "memmove on non-trivial object U");
|
|
return ptr_memmove(memmove_dest, memmove_src, count);
|
|
}
|
|
|
|
// Not really needed but else clang thinks ptr_memmove isn't used
|
|
inline void *memmove_if_trivial_else_error(void *memmove_dest, void *memmove_src, size_t count)
|
|
{
|
|
return ptr_memmove(memmove_dest, memmove_src, count);
|
|
}
|
|
}
|
|
// Put into global namespace
|
|
using std::memcpy_if_trivial_else_error;
|
|
using std::memmove_if_trivial_else_error;
|
|
using std::memset_if_trivial_else_error;
|
|
|
|
#endif // NDEBUG
|
|
|
|
#endif // _PSTYPES_H
|