424 lines
8.1 KiB
C++
424 lines
8.1 KiB
C++
#include "stdutil.hpp"
|
|
|
|
#include <cmath>
|
|
#include <set>
|
|
#include <cstdlib>
|
|
|
|
#include <Windows.h>
|
|
|
|
using namespace std;
|
|
|
|
#ifdef MEMDEBUG
|
|
|
|
struct Mem {
|
|
Mem * next, *prev;
|
|
const char* file;
|
|
int line, size, tag;
|
|
};
|
|
|
|
static bool track;
|
|
|
|
static Mem head, tail;
|
|
static Mem x_head, x_tail;
|
|
|
|
static void remove(Mem* m)
|
|
{
|
|
m->next->prev = m->prev;
|
|
m->prev->next = m->next;
|
|
}
|
|
|
|
static void insert(Mem* m, Mem* next)
|
|
{
|
|
m->next = next;
|
|
m->prev = next->prev;
|
|
next->prev->next = m;
|
|
next->prev = m;
|
|
}
|
|
|
|
static void init()
|
|
{
|
|
if (head.next)
|
|
return;
|
|
head.next = head.prev = &tail;
|
|
head.tag = 'HEAD';
|
|
tail.next = tail.prev = &head;
|
|
tail.tag = 'TAIL';
|
|
x_head.next = x_head.prev = &x_tail;
|
|
x_head.tag = 'HEAD';
|
|
x_tail.next = x_tail.prev = &x_head;
|
|
x_tail.tag = 'TAIL';
|
|
}
|
|
|
|
static void check(Mem* m)
|
|
{
|
|
if (m->tag != 'DNEW') {
|
|
MessageBox(GetDesktopWindow(), "mem_check: pre_tag!='DNEW'", "Memory error", MB_OK | MB_ICONWARNING);
|
|
if (m->tag == 'NDWE') {
|
|
string t = "Probable double delete";
|
|
t += "- new file: " + string(m->file) + " line:" + itoa(m->line);
|
|
MessageBox(GetDesktopWindow(), t.c_str(), "Memory error", MB_OK | MB_ICONWARNING);
|
|
}
|
|
ExitProcess(0);
|
|
}
|
|
int* t = (int*)((char*)(m + 1) + m->size);
|
|
if (*t != 'dnew') {
|
|
MessageBox(GetDesktopWindow(), "mem_check: post_tag!='dnew'", "Memory error", MB_OK | MB_ICONWARNING);
|
|
string t = "Probable memory overwrite - new file: " + string(m->file) + " line:" + itoa(m->line);
|
|
MessageBox(GetDesktopWindow(), t.c_str(), "Memory error", MB_OK | MB_ICONWARNING);
|
|
ExitProcess(0);
|
|
}
|
|
}
|
|
|
|
static void* op_new(size_t size, const char* file = "<unknown>", int line = 0)
|
|
{
|
|
init();
|
|
Mem* m = (Mem*)malloc(sizeof(Mem) + size + sizeof(int));
|
|
memset(m + 1, 0xcc, size);
|
|
m->file = file;
|
|
m->line = line;
|
|
m->size = size;
|
|
m->tag = 'DNEW';
|
|
int* t = (int*)((char*)(m + 1) + size);
|
|
*t = 'dnew';
|
|
if (track)
|
|
insert(m, head.next);
|
|
else
|
|
insert(m, x_head.next);
|
|
return m + 1;
|
|
}
|
|
|
|
static void op_delete(void* q)
|
|
{
|
|
init();
|
|
if (!q)
|
|
return;
|
|
Mem* m = (Mem*)q - 1;
|
|
check(m);
|
|
remove(m);
|
|
m->tag = 'NDWE';
|
|
*(int*)((char*)(m + 1) + m->size) = 'ndwe';
|
|
free(m);
|
|
}
|
|
|
|
void trackmem(bool enable)
|
|
{
|
|
init();
|
|
if (track == enable)
|
|
return;
|
|
track = enable;
|
|
Mem* m;
|
|
while ((m = head.next) != &tail) {
|
|
remove(m);
|
|
insert(m, x_head.next);
|
|
}
|
|
}
|
|
|
|
void checkmem(ostream& out)
|
|
{
|
|
init();
|
|
Mem *m, *next;
|
|
int sum = 0, usum = 0, xsum = 0;
|
|
for (m = head.next; m != &tail; m = next) {
|
|
check(m);
|
|
next = m->next;
|
|
if (m->line) {
|
|
out << m->file << " line:" << m->line << " " << m->size << " bytes" << endl;
|
|
sum += m->size;
|
|
} else {
|
|
usum += m->size;
|
|
}
|
|
}
|
|
for (m = x_head.next; m != &x_tail; m = m->next) {
|
|
check(m);
|
|
xsum += m->size;
|
|
}
|
|
out << "Tracked blitz mem in use:" << sum << endl;
|
|
out << "Tracked other mem in use:" << usum << endl;
|
|
out << "Untracked mem in use:" << xsum << endl;
|
|
out << "Total mem in use:" << (sum + usum + xsum) << endl;
|
|
}
|
|
|
|
void* _cdecl operator new(size_t size)
|
|
{
|
|
return op_new(size);
|
|
}
|
|
void* _cdecl operator new[](size_t size)
|
|
{
|
|
return op_new(size);
|
|
}
|
|
void* _cdecl operator new(size_t size, const char* file, int line)
|
|
{
|
|
return op_new(size, file, line);
|
|
}
|
|
void* _cdecl operator new[](size_t size, const char* file, int line)
|
|
{
|
|
return op_new(size, file, line);
|
|
}
|
|
void _cdecl operator delete(void* q)
|
|
{
|
|
op_delete(q);
|
|
}
|
|
void _cdecl operator delete[](void* q)
|
|
{
|
|
op_delete(q);
|
|
}
|
|
void _cdecl operator delete(void* q, const char* file, int line)
|
|
{
|
|
op_delete(q);
|
|
}
|
|
void _cdecl operator delete[](void* q, const char* file, int line)
|
|
{
|
|
op_delete(q);
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
int atoi(const string& s)
|
|
{
|
|
return atoi(s.c_str());
|
|
}
|
|
|
|
double atof(const string& s)
|
|
{
|
|
return atof(s.c_str());
|
|
}
|
|
|
|
string itoa(int n)
|
|
{
|
|
char buff[32];
|
|
_itoa(n, buff, 10);
|
|
return string(buff);
|
|
}
|
|
|
|
//static int _finite(double n) { // definition: exponent anything but 2047.
|
|
//
|
|
// int e; // 11 bit exponent
|
|
// const int eMax = 2047; // 0x7ff, all bits = 1
|
|
//
|
|
// int *pn = (int *)&n;
|
|
//
|
|
// e = *++pn; // Intel order!
|
|
// e = (e >> 20) & eMax;
|
|
//
|
|
// return e != eMax;
|
|
//}
|
|
//
|
|
//static int _isnan(double n) { // definition: exponent 2047, nonzero fraction.
|
|
//
|
|
// int e; // 11 bit exponent
|
|
// const int eMax = 2047; // 0x7ff, all bits = 1
|
|
//
|
|
// int *pn = (int *)&n;
|
|
//
|
|
// e = *++pn; // Intel order!
|
|
// e = (e >> 20) & eMax;
|
|
//
|
|
// if (e != 2047) return 0; // almost always return here
|
|
//
|
|
// int fHi, fLo; // 52 bit fraction
|
|
//
|
|
// fHi = (*pn) & 0xfffff; // first 20 bits
|
|
// fLo = *--pn; // last 32 bits
|
|
//
|
|
// return (fHi | fLo) != 0; // returns 0,1 not just 0,nonzero
|
|
//}
|
|
|
|
/////////////
|
|
//By FLOYD!//
|
|
/////////////
|
|
string ftoa(float n)
|
|
{
|
|
static const int digits = 6;
|
|
|
|
int eNeg = -4, ePos = 8; // limits for e notation.
|
|
|
|
char buffer[50]; // from MSDN example, 25 would probably suffice
|
|
string t;
|
|
int dec, sign;
|
|
|
|
if (_finite(n)) {
|
|
// if ( digits < 1 ) digits = 1; // less than one digit is nonsense
|
|
// if ( digits > 8 ) digits = 8; // practical maximum for float
|
|
|
|
t = _ecvt(n, digits, &dec, &sign);
|
|
|
|
if (dec <= eNeg + 1 || dec > ePos) {
|
|
_gcvt(n, digits, buffer);
|
|
t = buffer;
|
|
return t;
|
|
}
|
|
|
|
// Here is the tricky case. We want a nicely formatted
|
|
// number with no e-notation or multiple trailing zeroes.
|
|
|
|
if (dec <= 0) {
|
|
t = "0." + string(-dec, '0') + t;
|
|
dec = 1; // new location for decimal point
|
|
|
|
} else if (dec < digits) {
|
|
t = t.substr(0, dec) + "." + t.substr(dec);
|
|
|
|
} else {
|
|
t = t + string(dec - digits, '0') + ".0";
|
|
dec += dec - digits;
|
|
}
|
|
|
|
// Finally, trim off excess zeroes.
|
|
|
|
int dp1 = dec + 1, p = t.length();
|
|
while (--p > dp1 && t[p] == '0')
|
|
;
|
|
t = string(t, 0, ++p);
|
|
|
|
return sign ? "-" + t : t;
|
|
|
|
} // end of finite case
|
|
|
|
if (_isnan(n))
|
|
return "NaN";
|
|
if (n > 0.0)
|
|
return "Infinity";
|
|
if (n < 0.0)
|
|
return "-Infinity";
|
|
|
|
abort();
|
|
}
|
|
|
|
/*
|
|
string ftoa( float n ){
|
|
|
|
static const float min=.000001f,max=9999999.0f;
|
|
|
|
int i=*(int*)&n;
|
|
int e=(i>>23)&0xff;
|
|
int f=i&0x007fffff;
|
|
|
|
if( e==0xff && f ) return "NAN";
|
|
|
|
string t;
|
|
int s=(i>>31)&0x01;
|
|
|
|
if( e==0xff ){
|
|
t="INFINITY";
|
|
}else if( !e && !f ){
|
|
t="0.000000";
|
|
}else if( n>=min && n<=max ){
|
|
int dec,sgn;
|
|
t=_fcvt( fabs(n),6,&dec,&sgn );
|
|
if( dec<=0 ){
|
|
t="0."+string( -dec,'0' )+t;
|
|
}else if( dec<t.size() ){
|
|
t=t.substr( 0,dec )+"."+t.substr( dec );
|
|
}else{
|
|
t=t+string( '0',dec-t.size() )+".000000";
|
|
}
|
|
}else{
|
|
char buff[32];
|
|
_gcvt( fabs(n),7,buff );
|
|
t=buff;
|
|
}
|
|
return s ? "-"+t : t;
|
|
}
|
|
*/
|
|
|
|
string tolower(const string& s)
|
|
{
|
|
string t = s;
|
|
for (unsigned int k = 0; k < t.size(); ++k)
|
|
t[k] = tolower(t[k]);
|
|
return t;
|
|
}
|
|
|
|
string toupper(const string& s)
|
|
{
|
|
string t = s;
|
|
for (unsigned int k = 0; k < t.size(); ++k)
|
|
t[k] = toupper(t[k]);
|
|
return t;
|
|
}
|
|
|
|
string fullfilename(const string& t)
|
|
{
|
|
char buff[MAX_PATH + 1], *p;
|
|
GetFullPathName(t.c_str(), MAX_PATH, buff, &p);
|
|
return string(buff);
|
|
}
|
|
|
|
string filenamepath(const string& t)
|
|
{
|
|
char buff[MAX_PATH + 1], *p;
|
|
GetFullPathName(t.c_str(), MAX_PATH, buff, &p);
|
|
if (!p)
|
|
return "";
|
|
*p = 0;
|
|
return string(buff);
|
|
}
|
|
|
|
string filenamefile(const string& t)
|
|
{
|
|
char buff[MAX_PATH + 1], *p;
|
|
GetFullPathName(t.c_str(), MAX_PATH, buff, &p);
|
|
if (!p)
|
|
return "";
|
|
return string(p);
|
|
}
|
|
|
|
const int MIN_SIZE = 256;
|
|
|
|
qstreambuf::qstreambuf()
|
|
{
|
|
buf = new char[MIN_SIZE];
|
|
setg(buf, buf, buf);
|
|
setp(buf, buf, buf + MIN_SIZE);
|
|
}
|
|
|
|
qstreambuf::~qstreambuf()
|
|
{
|
|
delete buf;
|
|
}
|
|
|
|
int qstreambuf::size()
|
|
{
|
|
return pptr() - gptr();
|
|
}
|
|
|
|
char* qstreambuf::data()
|
|
{
|
|
return gptr();
|
|
}
|
|
|
|
qstreambuf::int_type qstreambuf::underflow()
|
|
{
|
|
if (gptr() == egptr()) {
|
|
if (gptr() == pptr())
|
|
return traits_type::eof();
|
|
setg(gptr(), gptr(), pptr());
|
|
}
|
|
|
|
return traits_type::to_int_type(*gptr());
|
|
}
|
|
|
|
qstreambuf::int_type qstreambuf::overflow(qstreambuf::int_type c)
|
|
{
|
|
if (c == traits_type::eof())
|
|
return c;
|
|
|
|
if (pptr() == epptr()) {
|
|
int sz = size();
|
|
int n_sz = sz * 2;
|
|
if (n_sz < MIN_SIZE)
|
|
n_sz = MIN_SIZE;
|
|
char* n_buf = new char[n_sz];
|
|
memcpy(n_buf, gptr(), sz);
|
|
delete buf;
|
|
buf = n_buf;
|
|
setg(buf, buf, buf + sz);
|
|
setp(buf + sz, buf + sz, buf + n_sz);
|
|
}
|
|
|
|
*pptr() = traits_type::to_char_type(c);
|
|
pbump(1);
|
|
return traits_type::not_eof(c);
|
|
}
|