commit 4ccbc1cabae78a3e7d2710d17d0a23f9fd872032
parent ca4d6c590e23e3bce47d357a363e4284ebb0f65a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 14 Apr 2015 10:35:51 +0200
Add and test the read/write RNG functions
Diffstat:
3 files changed, 115 insertions(+), 8 deletions(-)
diff --git a/src/ssp.h b/src/ssp.h
@@ -71,6 +71,8 @@ struct ssp_rng_type {
(void* state, const unsigned long min, const unsigned long max);
double (*uniform_double)(void* state, const double min, const double max);
double (*canonical)(void* state);
+ res_T (*read)(void* state, FILE* file);
+ res_T (*write)(const void* state, FILE* file);
unsigned long min;
unsigned long max;
@@ -141,6 +143,16 @@ SSP_API unsigned long
ssp_rng_max
(struct ssp_rng* rng);
+SSP_API res_T
+ssp_rng_write
+ (const struct ssp_rng* rng,
+ FILE* stream);
+
+SSP_API res_T
+ssp_rng_read
+ (struct ssp_rng* rng,
+ FILE* stream);
+
/*******************************************************************************
* Hemisphere distribution
******************************************************************************/
diff --git a/src/ssp_rng.c b/src/ssp_rng.c
@@ -35,6 +35,7 @@
#include <rsys/ref_count.h>
#include <random>
+#include <sstream>
struct ssp_rng {
struct ssp_rng_type type;
@@ -103,6 +104,26 @@ rng_kiss_canonical(void* data)
return (double)rng_kiss_get(data) / ((double)UINT32_MAX + 1);
}
+static res_T
+rng_kiss_read(void* data, FILE* file)
+{
+ struct rng_kiss* rng = (struct rng_kiss*)data;
+ int res;
+ ASSERT(data && file);
+ res = fscanf(file, "%u %u %u %u", &rng->x, &rng->y, &rng->z, &rng->c);
+ return res == EOF ? RES_IO_ERR : RES_OK;
+}
+
+static res_T
+rng_kiss_write(const void* data, FILE* file)
+{
+ const struct rng_kiss* rng = (const struct rng_kiss*)data;
+ int res;
+ ASSERT(data && file);
+ res = fprintf(file, "%u %u %u %u", rng->x, rng->y, rng->z, rng->c);
+ return res < 0 ? RES_IO_ERR : RES_OK;
+}
+
static void
rng_kiss_init(struct mem_allocator* allocator, void* data)
{
@@ -125,6 +146,8 @@ struct ssp_rng_type ssp_rng_kiss = {
rng_kiss_uniform_int,
rng_kiss_uniform_double,
rng_kiss_canonical,
+ rng_kiss_read,
+ rng_kiss_write,
0,
UINT32_MAX,
sizeof(struct rng_kiss)
@@ -181,6 +204,34 @@ rng_cxx_canonical(void* data)
}
template<typename RNG>
+static res_T
+rng_cxx_write(const void* data, FILE* file)
+{
+ size_t i;
+ std::stringstream stream;
+ RNG* rng = (RNG*)data;
+ ASSERT(rng);
+ stream << *rng;
+ i = fwrite(stream.str().c_str(), 1, stream.str().size(), file);
+ return i == stream.str().size() ? RES_OK : RES_IO_ERR;
+}
+
+template<typename RNG>
+static res_T
+rng_cxx_read(void* data, FILE* file)
+{
+ std::stringstream stream;
+ char buf[512];
+ char* s;
+ RNG* rng = (RNG*)data;
+ ASSERT(rng);
+ while((s = fgets(buf, sizeof(buf), file)))
+ stream << std::string(s);
+ stream >> *rng;
+ return stream.fail() ? RES_IO_ERR : RES_OK;
+}
+
+template<typename RNG>
static void
rng_cxx_init(struct mem_allocator* allocator, void* data)
{
@@ -189,7 +240,6 @@ rng_cxx_init(struct mem_allocator* allocator, void* data)
new (data) RNG;
}
-
template<typename RNG>
static void
rng_cxx_release(void* data)
@@ -208,6 +258,8 @@ struct ssp_rng_type ssp_rng_mt19937_64 = {
rng_cxx_uniform_int<std::mt19937_64>,
rng_cxx_uniform_double<std::mt19937_64>,
rng_cxx_canonical<std::mt19937_64>,
+ rng_cxx_read<std::mt19937_64>,
+ rng_cxx_write<std::mt19937_64>,
std::mt19937_64::min(),
std::mt19937_64::max(),
sizeof(std::mt19937_64)
@@ -222,6 +274,8 @@ struct ssp_rng_type ssp_rng_ranlux48 = {
rng_cxx_uniform_int<std::ranlux48>,
rng_cxx_uniform_double<std::ranlux48>,
rng_cxx_canonical<std::ranlux48>,
+ rng_cxx_read<std::ranlux48>,
+ rng_cxx_write<std::ranlux48>,
std::ranlux48::min(),
std::ranlux48::max(),
sizeof(std::ranlux48)
@@ -234,13 +288,15 @@ static char
check_type(const struct ssp_rng_type* type)
{
ASSERT(type);
- return type->init != NULL
- && type->release != NULL
- && type->set != NULL
- && type->get != NULL
- && type->uniform_int != NULL
- && type->uniform_double != NULL
- && type->canonical != NULL
+ return NULL != type->init
+ && NULL != type->release
+ && NULL != type->set
+ && NULL != type->get
+ && NULL != type->uniform_int
+ && NULL != type->uniform_double
+ && NULL != type->canonical
+ && NULL != type->read
+ && NULL != type->write
&& type->min <= type->max;
}
@@ -371,3 +427,17 @@ ssp_rng_set(struct ssp_rng* rng, const unsigned long seed)
return RES_OK;
}
+res_T
+ssp_rng_read(struct ssp_rng* rng, FILE* stream)
+{
+ if(!rng || !stream) return RES_BAD_ARG;
+ return rng->type.read(rng->state, stream);
+}
+
+res_T
+ssp_rng_write(const struct ssp_rng* rng, FILE* stream)
+{
+ if(!rng || !stream) return RES_BAD_ARG;
+ return rng->type.write(rng->state, stream);
+}
+
diff --git a/src/test_ssp_rng.c b/src/test_ssp_rng.c
@@ -40,6 +40,7 @@
static void /* Really basic test */
test_rng(struct ssp_rng_type* type)
{
+ FILE* stream;
struct ssp_rng* rng;
struct mem_allocator allocator;
struct time t0, t1;
@@ -128,6 +129,30 @@ test_rng(struct ssp_rng_type* type)
time_dump(&t0, TIME_SEC|TIME_MSEC|TIME_USEC, NULL, buf, sizeof(buf));
printf("1,000,000 random numbers in %s\n", buf);
+
+ stream = tmpfile();
+ NCHECK(stream, NULL);
+ CHECK(ssp_rng_write(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssp_rng_write(rng, NULL), RES_BAD_ARG);
+ CHECK(ssp_rng_write(NULL, stream), RES_BAD_ARG);
+ CHECK(ssp_rng_write(rng, stream), RES_OK);
+
+ FOR_EACH(i, 0, NRAND)
+ datai0[i] = ssp_rng_get(rng);
+
+ CHECK(ssp_rng_read(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssp_rng_read(rng, NULL), RES_BAD_ARG);
+ CHECK(ssp_rng_read(NULL, stream), RES_BAD_ARG);
+ CHECK(ssp_rng_read(rng, stream), RES_IO_ERR);
+ rewind(stream);
+ CHECK(ssp_rng_read(rng, stream), RES_OK);
+
+ FOR_EACH(i, 0, NRAND) {
+ unsigned long r = ssp_rng_get(rng);
+ CHECK(r, datai0[i]);
+ }
+ fclose(stream);
+
CHECK(ssp_rng_ref_put(rng), RES_OK);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);