2005-08-27 10:38:52 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Copyright (c) 2005 by Andrei Alexandrescu
|
|
|
|
// Permission to use, copy, modify, distribute, and sell this software for any
|
|
|
|
// purpose is hereby granted without fee, provided that the above copyright
|
|
|
|
// notice appear in all copies and that both that copyright notice and this
|
|
|
|
// permission notice appear in supporting documentation.
|
2005-11-29 13:20:54 +00:00
|
|
|
// The author makes no representations about the suitability of this software
|
|
|
|
// for any purpose. It is provided "as is" without express or implied
|
2005-08-27 10:38:52 +00:00
|
|
|
// warranty.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2006-01-05 00:23:44 +00:00
|
|
|
#include <loki/SafeFormat.h>
|
2005-08-27 10:38:52 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <cassert>
|
|
|
|
#include <utility>
|
|
|
|
|
2005-11-29 14:20:23 +00:00
|
|
|
#include "../SmallObj/timer.h"
|
|
|
|
|
2006-01-07 10:31:24 +00:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
#define sprintf sprintf_s
|
|
|
|
#define _snprintf _snprintf_s
|
|
|
|
#endif
|
|
|
|
|
2005-08-27 10:38:52 +00:00
|
|
|
using namespace std;
|
2006-01-05 21:28:37 +00:00
|
|
|
using namespace Loki;
|
2005-08-27 10:38:52 +00:00
|
|
|
|
|
|
|
template <class Integral1, class Integral2>
|
|
|
|
Integral2 RandomInt(Integral1 low, Integral2 up)
|
|
|
|
{
|
|
|
|
// From ``Accelerated C++'', page 135:
|
|
|
|
// random integer in the range [0, n)
|
|
|
|
// We adjust to generate in the range [0, n]
|
2005-11-29 13:20:54 +00:00
|
|
|
const Integral2
|
|
|
|
low2 = low,
|
|
|
|
n = up - low;
|
|
|
|
|
2005-08-27 10:38:52 +00:00
|
|
|
assert(n > 0);
|
|
|
|
|
2006-01-07 10:31:24 +00:00
|
|
|
const size_t bucket_size = RAND_MAX / n;
|
2005-08-27 10:38:52 +00:00
|
|
|
assert(bucket_size > 0);
|
2005-11-29 13:20:54 +00:00
|
|
|
|
2005-08-27 10:38:52 +00:00
|
|
|
Integral2 r;
|
2005-11-29 13:20:54 +00:00
|
|
|
do
|
|
|
|
r = Integral2(rand() / bucket_size);
|
2005-08-27 10:38:52 +00:00
|
|
|
while (r > n);
|
|
|
|
|
2006-01-07 10:31:24 +00:00
|
|
|
r = r + low2;
|
2005-08-27 10:38:52 +00:00
|
|
|
assert(r >= low2 && r <= up);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
string RandomString(unsigned int maxSize)
|
|
|
|
{
|
|
|
|
string result(RandomInt(0, maxSize), '\0');
|
|
|
|
unsigned int i = 0;
|
2005-11-29 13:20:54 +00:00
|
|
|
for (; i != result.size(); ++i)
|
|
|
|
{
|
2005-08-27 10:38:52 +00:00
|
|
|
result[i] = RandomInt('a', 'z');
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
2005-11-29 13:20:54 +00:00
|
|
|
void TestCase(const string& fmt, T value)
|
|
|
|
{
|
2005-08-27 10:38:52 +00:00
|
|
|
char buf[4096];
|
|
|
|
std::string s;
|
2005-11-29 13:20:54 +00:00
|
|
|
const int i1 = SPrintf(s, fmt.c_str())(value);
|
2005-11-29 14:20:23 +00:00
|
|
|
|
2005-11-29 13:20:54 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
const int i2 = _snprintf(buf, sizeof(buf), fmt.c_str(), value);
|
2005-09-24 23:09:13 +00:00
|
|
|
#else
|
2005-11-29 13:20:54 +00:00
|
|
|
const int i2 = snprintf(buf, sizeof(buf), fmt.c_str(), value);
|
2005-09-24 23:09:13 +00:00
|
|
|
#endif
|
2005-11-29 13:20:54 +00:00
|
|
|
|
|
|
|
if (i1 != i2 || s != buf)
|
2005-11-29 13:17:20 +00:00
|
|
|
{
|
|
|
|
cout << endl
|
2005-11-29 13:20:54 +00:00
|
|
|
<< "Reference: " << i2 << "; Actual: " << i1 << ", Difference = " << i2-i1 << endl
|
|
|
|
<< "V: [" << value << "]" << endl
|
|
|
|
<< "F: [" << fmt << "]" << endl
|
|
|
|
<< "R: [" << buf << "]" << endl
|
|
|
|
<< "A: [" << s.c_str() << "]" << endl;
|
|
|
|
assert(false);
|
2005-08-27 10:38:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T, class U>
|
2005-11-29 13:20:54 +00:00
|
|
|
void TestCase2(const string& fmt, T value, U value2)
|
|
|
|
{
|
2005-08-27 10:38:52 +00:00
|
|
|
char buf[4096];
|
|
|
|
std::string s;
|
2005-11-29 13:20:54 +00:00
|
|
|
const int i1 = SPrintf(s, fmt.c_str())(value)(value2);
|
|
|
|
const int i2 = snprintf(buf, sizeof(buf), fmt.c_str(), value, value2);
|
|
|
|
assert(i1 == i2);
|
|
|
|
assert(s == buf);
|
2005-08-27 10:38:52 +00:00
|
|
|
}
|
|
|
|
|
2005-11-29 13:20:54 +00:00
|
|
|
int main(int argc, char** argv)
|
2006-01-05 10:24:39 +00:00
|
|
|
{
|
2006-01-04 22:58:58 +00:00
|
|
|
|
2005-11-29 14:20:23 +00:00
|
|
|
if (argc == 2)
|
2005-11-29 13:20:54 +00:00
|
|
|
{
|
2005-08-27 10:38:52 +00:00
|
|
|
// test speed
|
2005-11-29 14:20:23 +00:00
|
|
|
|
|
|
|
Timer t;
|
|
|
|
|
|
|
|
int loop = atoi(argv[1]);
|
|
|
|
|
|
|
|
if(loop < 100)
|
|
|
|
loop = 100;
|
|
|
|
|
|
|
|
t.start();
|
|
|
|
for (int i=loop; i > 0; --i)
|
|
|
|
printf("Hey, %u frobnicators and %u twiddlicators\n",i, i);
|
|
|
|
t.stop();
|
|
|
|
t.t100 = t.t();
|
|
|
|
int t_printf = t.t();
|
|
|
|
|
|
|
|
|
|
|
|
t.start();
|
|
|
|
for (int i=loop; i > 0; --i)
|
|
|
|
Printf("Hey, %u frobnicators and %u twiddlicators\n")(i)(i);
|
|
|
|
t.stop();
|
|
|
|
int t_Printf = t.t();
|
|
|
|
|
|
|
|
|
|
|
|
t.start();
|
|
|
|
for (int i=loop; i > 0; --i)
|
|
|
|
cout << "Hey, " << i << " frobnicators and " << i <<" twiddlicators\n";
|
|
|
|
t.stop();
|
|
|
|
int t_cout = t.t();
|
|
|
|
|
|
|
|
|
|
|
|
Printf("\n\nElapsed time for %i outputs\n\n")(loop);
|
|
|
|
t.print(t_printf,"printf : ");
|
|
|
|
t.print(t_Printf,"Printf : ");
|
|
|
|
t.print(t_cout, "std::cout: ");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//srand(time(0));
|
|
|
|
srand(0);
|
|
|
|
printf("\nNumber of tests:\n");
|
|
|
|
for (unsigned i = 0; ; ++i)
|
2005-11-29 13:20:54 +00:00
|
|
|
{
|
2005-11-29 14:20:23 +00:00
|
|
|
printf("%u\r", i);
|
|
|
|
|
|
|
|
// Generate a random string for the head
|
|
|
|
string lead = RandomString(100);
|
|
|
|
// This string will hold a random format specification
|
|
|
|
string formatSpec(lead + "|%");
|
|
|
|
// Generate a random set of flags
|
|
|
|
static const string flags("-+0 #");
|
2006-01-07 10:31:24 +00:00
|
|
|
size_t maxFlags = RandomInt(0u, flags.length() - 1);
|
|
|
|
for (size_t i = 0; i != maxFlags; ++i)
|
2005-11-29 13:20:54 +00:00
|
|
|
{
|
2005-11-29 14:20:23 +00:00
|
|
|
formatSpec += flags[RandomInt(0u, flags.length() - 1)];
|
2005-11-29 13:20:54 +00:00
|
|
|
}
|
2005-11-29 14:20:23 +00:00
|
|
|
// Generate an optional random width
|
|
|
|
if (RandomInt(0, 1))
|
2005-11-29 13:20:54 +00:00
|
|
|
{
|
2005-11-29 14:20:23 +00:00
|
|
|
const unsigned int width = RandomInt(0, 100);
|
|
|
|
char buf[4];
|
|
|
|
sprintf(buf, "%u", width);
|
|
|
|
formatSpec += buf;
|
2005-11-29 13:20:54 +00:00
|
|
|
}
|
2005-11-29 14:20:23 +00:00
|
|
|
// Generate an optional random precision
|
|
|
|
if (RandomInt(0, 1))
|
2005-11-29 13:20:54 +00:00
|
|
|
{
|
2005-11-29 14:20:23 +00:00
|
|
|
const unsigned int prec = RandomInt(0, 100);
|
|
|
|
char buf[4];
|
|
|
|
sprintf(buf, "%u", prec);
|
|
|
|
formatSpec += '.';
|
|
|
|
formatSpec += buf;
|
2005-11-29 13:20:54 +00:00
|
|
|
}
|
|
|
|
|
2005-11-29 14:20:23 +00:00
|
|
|
// Generate a random type character
|
2006-01-08 14:38:29 +00:00
|
|
|
static const string type("cdeEfgGinopsuxX");
|
2005-11-29 13:20:54 +00:00
|
|
|
|
2006-01-07 10:31:24 +00:00
|
|
|
const char typeSpec = type[RandomInt(0u, type.size() - 1)];
|
2005-11-29 14:20:23 +00:00
|
|
|
// Generate an optional type prefix
|
|
|
|
static const string prefix("hl");
|
|
|
|
if (typeSpec != 's' && RandomInt(0, 1))
|
|
|
|
{
|
2006-01-07 10:31:24 +00:00
|
|
|
formatSpec += prefix[RandomInt(0u, prefix.size() - 1)];
|
2005-11-29 14:20:23 +00:00
|
|
|
}
|
|
|
|
formatSpec += typeSpec;
|
|
|
|
formatSpec += '|';
|
|
|
|
formatSpec += RandomString(100);
|
|
|
|
|
|
|
|
switch (typeSpec)
|
2005-08-27 10:38:52 +00:00
|
|
|
{
|
2005-11-29 14:20:23 +00:00
|
|
|
case 'c':
|
|
|
|
TestCase(formatSpec, RandomInt(1, 127));
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
case 'i':
|
|
|
|
case 'o':
|
|
|
|
case 'u':
|
|
|
|
case 'x':
|
|
|
|
case 'X':
|
2006-01-04 22:58:58 +00:00
|
|
|
//TestCase(formatSpec, RandomInt(-10000, 10000));
|
2006-01-05 10:24:39 +00:00
|
|
|
// don't test negative values on 64bit systems, because
|
|
|
|
// snprintf does not support 64 Bit values
|
|
|
|
TestCase(formatSpec, RandomInt( -10000 * (sizeof(size_t)>4 ? 0 : 1) , 10000));
|
2005-11-29 14:20:23 +00:00
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
case 'E':
|
|
|
|
case 'f':
|
|
|
|
case 'g':
|
|
|
|
case 'G':
|
|
|
|
TestCase(formatSpec,
|
|
|
|
RandomInt(-10000, 10000) / double(RandomInt(1, 100)));
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
{
|
|
|
|
void * p = malloc(RandomInt(1, 1000));
|
|
|
|
TestCase(formatSpec, p);
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
TestCase(formatSpec, RandomString(100).c_str());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
break;
|
2005-08-27 10:38:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|