Refactor rrdata handling

Makes savestate/loadstate fair bit faster
This commit is contained in:
Ilari Liusvaara 2013-10-08 21:35:01 +03:00
parent ecd8b74ee1
commit f19fea0ea4
15 changed files with 1419 additions and 428 deletions

View file

@ -1,136 +1,10 @@
#ifndef _rrdata__hpp__included__
#define _rrdata__hpp__included__
#define RRDATA_BYTES 32
#include <cstdint>
#include <stdexcept>
#include <vector>
#include "library/rrdata.hpp"
/**
* Set of load IDs
*/
class rrdata
{
public:
/**
* One load ID.
*/
struct instance
{
/**
* Create new random load ID.
*
* throws std::bad_alloc: Not enough memory
*/
instance() throw(std::bad_alloc);
/**
* Create new load id from bytes.
*
* parameter b: 32 byte array containing the new ID.
*/
instance(unsigned char* b) throw();
/**
* The load ID.
*/
unsigned char bytes[RRDATA_BYTES];
/**
* Is this ID before another one?
*
* parameter i: Another ID.
* returns: True if this ID is before another one, false otherwise.
*/
bool operator<(const struct instance& i) const throw();
/**
* Is this ID equal to another one?
*
* parameter i: Another ID.
* returns: True if this ID is equal to another one, false otherwise.
*/
bool operator==(const struct instance& i) const throw();
/**
* Increment this ID.
*
* returns: Copy of the ID before the increment.
*/
const struct instance operator++(int) throw();
/**
* Increment this ID.
*
* returns: Reference to this.
*/
struct instance& operator++() throw();
};
/**
* Read the saved set of load IDs for specified project and switch to that project.
*
* parameter project: The name of project.
* parameter lazy: If true, just switch to project, don't read the IDs.
* throws std::bad_alloc: Not enough memory
*/
static void read_base(const std::string& project, bool lazy) throw(std::bad_alloc);
/**
* Switch to no project, closing the load IDs.
*/
static void close() throw();
/**
* Add new specified instance to current project.
*
* Not allowed if there is no project open.
*
* parameter i: The load ID to add.
*/
static void add(const struct instance& i) throw(std::bad_alloc);
/**
* Generate new load ID and add it to the current proejct.
*
* Not allowed if there is no project open.
*
* throws std::bad_alloc: Not enough memory.
*/
static void add_internal() throw(std::bad_alloc);
/**
* Write compressed representation of current load ID set to stream.
*
* parameter strm: The stream to write to.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory.
*/
static uint64_t write(std::vector<char>& strm) throw(std::bad_alloc);
/**
* Load compressed representation of load ID set from stream and union it with current set to form new current
* set.
*
* parameter strm: The stream to read from.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory.
*/
static uint64_t read(std::vector<char>& strm, bool dummy = false) throw(std::bad_alloc);
/**
* Load compressed representation of load ID set from stream, but don't do anything to it.
*
* parameter strm: The stream to read from.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory.
*/
static uint64_t count(std::vector<char>& strm) throw(std::bad_alloc);
/**
* Count number of rerecords.
*
* returns: Rerecord count.
*/
static uint64_t count() throw();
/**
* Internal pointer used by add_internal.
*/
static struct instance* internal;
};
extern rrdata_set rrdata;
/**
* Print load ID. Mainly useful for deubugging.
*
* parameter os: Stream to print to.
* parameter i: load ID to print.
*/
std::ostream& operator<<(std::ostream& os, const struct rrdata::instance& i);
rrdata_set::instance random_rrdata();
#endif

171
include/library/rrdata.hpp Normal file
View file

@ -0,0 +1,171 @@
#ifndef _library_rrdata__hpp__included__
#define _library_rrdata__hpp__included__
#define RRDATA_BYTES 32
#include <cstdint>
#include <stdexcept>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <set>
class rrdata_set
{
public:
struct instance
{
/**
* Create new all zero load ID.
*/
instance() throw();
/**
* Create new load id from bytes.
*
* parameter b: 32 byte array containing the new ID.
*/
instance(const unsigned char* b) throw();
/**
* Create load id from string (mainly intended for debugging).
*/
instance(const std::string& id) throw();
/**
* The load ID.
*/
unsigned char bytes[RRDATA_BYTES];
/**
* Is this ID before another one?
*
* parameter i: Another ID.
* returns: True if this ID is before another one, false otherwise.
*/
bool operator<(const struct instance& i) const throw();
bool operator<=(const struct instance& i) const throw() { return !(i < *this); }
bool operator>=(const struct instance& i) const throw() { return !(*this < i); }
bool operator>(const struct instance& i) const throw() { return (i < *this); }
/**
* Is this ID equal to another one?
*
* parameter i: Another ID.
* returns: True if this ID is equal to another one, false otherwise.
*/
bool operator==(const struct instance& i) const throw();
bool operator!=(const struct instance& i) const throw() { return !(*this == i); }
/**
* Increment this ID.
*
* returns: Copy of the ID before the increment.
*/
const struct instance operator++(int) throw();
/**
* Increment this ID.
*
* returns: Reference to this.
*/
struct instance& operator++() throw();
/**
* Increment this ID by specified amount.
*
* returns: The incremented id.
*/
struct instance operator+(unsigned inc) const throw();
/**
* Difference.
*
* Returns: The difference, or UINT_MAX if too great.
*/
unsigned operator-(const struct instance& m) const throw();
};
/**
* Ctor
*/
rrdata_set() throw();
/**
* Read the saved set of load IDs for specified project and switch to that project.
*
* parameter projectfile: The name of project backing file.
* parameter lazy: If true, just switch to project, don't read the IDs.
* throws std::bad_alloc: Not enough memory
*/
void read_base(const std::string& projectfile, bool lazy) throw(std::bad_alloc);
/**
* Switch to no project, closing the load IDs.
*/
void close() throw();
/**
* Add new specified instance to current project.
*
* Not allowed if there is no project open.
*
* parameter i: The load ID to add.
*/
void add(const struct instance& i) throw(std::bad_alloc);
/**
* Add internal instance, doing post-increment.
*/
void add_internal() throw(std::bad_alloc);
/**
* Set internal instance.
*
* Parameter b: The new instance.
*/
void set_internal(const instance& b) throw();
/**
* Write compressed representation of current load ID set to stream.
*
* parameter strm: The stream to write to.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory.
*/
uint64_t write(std::vector<char>& strm) throw(std::bad_alloc);
/**
* Load compressed representation of load ID set from stream and union it with current set to form new current
* set.
*
* parameter strm: The stream to read from.
* parameter dummy: If true, don't actually do it, just simulate.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory.
*/
uint64_t read(std::vector<char>& strm, bool dummy = false) throw(std::bad_alloc);
/**
* Load compressed representation of load ID set from stream, but don't do anything to it.
*
* parameter strm: The stream to read from.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory.
*/
uint64_t count(std::vector<char>& strm) throw(std::bad_alloc);
/**
* Count number of rerecords.
*
* returns: Rerecord count.
*/
uint64_t count() throw();
/**
* Debugging functions.
*/
std::string debug_dump();
bool debug_add(const instance& b) { return _add(b); }
void debug_add(const instance& b, const instance& e) { return _add(b, e); }
bool debug_in_set(const instance& b) { return _in_set(b); }
bool debug_in_set(const instance& b, const instance& e) { return _in_set(b, e); }
private:
bool _add(const instance& b);
void _add(const instance& b, const instance& e);
bool _in_set(const instance& b) { return _in_set(b, b + 1); }
bool _in_set(const instance& b, const instance& e);
instance internal;
std::set<std::pair<instance, instance>> data;
std::ofstream ohandle;
bool handle_open;
std::string current_projectfile;
bool lazy_mode;
uint64_t rcount;
};
std::ostream& operator<<(std::ostream& os, const struct rrdata_set::instance& j);
#endif

View file

@ -497,7 +497,7 @@ namespace
"Syntax: count-rerecords\nCounts rerecords.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
std::vector<char> tmp;
uint64_t x = rrdata::write(tmp);
uint64_t x = rrdata.write(tmp);
messages << x << " rerecord(s)" << std::endl;
});

View file

@ -37,7 +37,7 @@ namespace
return x >> (8 * (offset & 7));
} else if(offset >= 24 && offset < 32 && !write) {
//Rerecord counter.
uint64_t x = rrdata::count();
uint64_t x = rrdata.count();
return x >> (8 * (offset & 7));
} else
return 0;

View file

@ -5,6 +5,7 @@
#include "core/memorymanip.hpp"
#include "core/misc.hpp"
#include "core/rom.hpp"
#include "core/rrdata.hpp"
#include "core/settings.hpp"
#include "core/window.hpp"
#include "library/sha256.hpp"
@ -102,6 +103,7 @@ void set_random_seed(const std::string& seed) throw(std::bad_alloc)
std::ostringstream str;
str << seed.length() << " " << seed;
rseed = str.str();
rrdata.set_internal(random_rrdata());
}
void set_random_seed() throw(std::bad_alloc)

View file

@ -327,8 +327,8 @@ void do_load_beginning(bool reload) throw(std::bad_alloc, std::runtime_error)
//Negative return.
if(!reload) {
//Force unlazy rrdata.
rrdata::read_base(our_movie.projectid, false);
rrdata::add_internal();
rrdata.read_base(our_movie.projectid, false);
rrdata.add_internal();
} else {
auto ctrldata = our_rom.rtype->controllerconfig(our_movie.settings);
port_type_set& portset = port_type_set::make(ctrldata.ports, ctrldata.portindex());
@ -470,9 +470,9 @@ void do_load_state(struct moviefile& _movie, int lmode)
port_type_set& portset = port_type_set::make(ctrldata.ports, ctrldata.portindex());
//Negative return.
rrdata::read_base(_movie.projectid, _movie.lazy_project_create);
rrdata::read(_movie.c_rrdata);
rrdata::add_internal();
rrdata.read_base(_movie.projectid, _movie.lazy_project_create);
rrdata.read(_movie.c_rrdata);
rrdata.add_internal();
try {
our_rom.region = _movie.gametype ? &(_movie.gametype->get_region()) : NULL;
random_seed_value = _movie.movie_rtc_second;
@ -566,7 +566,7 @@ void do_load_state(struct moviefile& _movie, int lmode)
x << std::setfill('0') << std::setw(3) << mlength / 1000000;
std::string rerecords = _movie.rerecords;
if(our_movie.is_savestate)
rerecords = (stringfmt() << rrdata::count()).str();
rerecords = (stringfmt() << rrdata.count()).str();
messages << "Rerecords " << rerecords << " length " << x.str() << " ("
<< _movie.get_frame_count() << " frames)" << std::endl;
}
@ -656,8 +656,8 @@ bool do_load_state(const std::string& filename, int lmode)
void mainloop_restore_state(const std::vector<char>& state, uint64_t secs, uint64_t ssecs)
{
//Force unlazy rrdata.
rrdata::read_base(our_movie.projectid, false);
rrdata::add_internal();
rrdata.read_base(our_movie.projectid, false);
rrdata.add_internal();
our_movie.rtc_second = secs;
our_movie.rtc_subsecond = ssecs;
our_rom.load_core_state(state, true);

View file

@ -281,7 +281,7 @@ void read_authors_file(zip_reader& r, std::vector<std::pair<std::string, std::st
std::string read_rrdata(zip_reader& r, std::vector<char>& out) throw(std::bad_alloc, std::runtime_error)
{
out = read_raw_file(r, "rrdata");
uint64_t count = rrdata::count(out);
uint64_t count = rrdata.count(out);
std::ostringstream x;
x << count;
return x.str();
@ -291,7 +291,7 @@ void write_rrdata(zip_writer& w) throw(std::bad_alloc, std::runtime_error)
{
uint64_t count;
std::vector<char> out;
count = rrdata::write(out);
count = rrdata.write(out);
write_raw_file(w, "rrdata", out);
std::ostream& m2 = w.create_file("rerecords");
try {
@ -511,7 +511,7 @@ void moviefile::brief_info::binary_io(std::istream& _stream)
}},{TAG_RRDATA, [this](binary_input_stream& s) {
std::vector<char> c_rrdata;
s.blob_implicit(c_rrdata);
this->rerecords = rrdata::count(c_rrdata);
this->rerecords = rrdata.count(c_rrdata);
}},{TAG_ROMHASH, [this](binary_input_stream& s) {
uint8_t n = s.byte();
std::string h = s.string_implicit();
@ -797,7 +797,7 @@ void moviefile::binary_io(std::ostream& _stream) throw(std::bad_alloc, std::runt
out.extension(TAG_RRDATA, [this](binary_output_stream& s) {
uint64_t count;
std::vector<char> rrd;
count = rrdata::write(rrd);
count = rrdata.write(rrd);
s.blob_implicit(rrd);
});
@ -937,7 +937,7 @@ void moviefile::binary_io(std::istream& _stream, core_type& romtype) throw(std::
namehint[n] = h;
}},{TAG_RRDATA, [this](binary_input_stream& s) {
s.blob_implicit(this->c_rrdata);
this->rerecords = (stringfmt() << rrdata::count(c_rrdata)).str();
this->rerecords = (stringfmt() << rrdata.count(c_rrdata)).str();
}},{TAG_SAVE_SRAM, [this](binary_input_stream& s) {
std::string a = s.string();
s.blob_implicit(this->sram[a]);

View file

@ -8,288 +8,15 @@
#include <fstream>
#include <sstream>
rrdata_set rrdata;
rrdata_set::instance random_rrdata()
{
return rrdata_set::instance(get_random_hexstring(2 * RRDATA_BYTES));
}
//
// XABCDEFXXXXXXXXX
// 0123456789XXXXXX
//
// ABCDEF0123456789XXXXXX
rrdata::instance::instance() throw(std::bad_alloc)
{
std::string rnd = get_random_hexstring(2 * RRDATA_BYTES);
memset(bytes, 0, RRDATA_BYTES);
for(unsigned i = 0; i < 2 * RRDATA_BYTES; i++) {
unsigned x = rnd[i];
x = x & 0x1F;
x = x - x / 16 * 9 - 1;
bytes[i / 2] = 16 * bytes[i / 2] + x;
}
}
rrdata::instance::instance(unsigned char* b) throw()
{
memcpy(bytes, b, RRDATA_BYTES);
}
bool rrdata::instance::operator<(const struct instance& i) const throw()
{
for(unsigned j = 0; j < RRDATA_BYTES; j++)
if(bytes[j] < i.bytes[j])
return true;
else if(bytes[j] > i.bytes[j])
return false;
return false;
}
bool rrdata::instance::operator==(const struct instance& i) const throw()
{
for(unsigned j = 0; j < RRDATA_BYTES; j++)
if(bytes[j] != i.bytes[j])
return false;
return true;
}
const struct rrdata::instance rrdata::instance::operator++(int) throw()
{
instance i = *this;
++*this;
return i;
}
struct rrdata::instance& rrdata::instance::operator++() throw()
{
unsigned carry = 1;
for(unsigned i = 31; i < 32; i--) {
unsigned newcarry = (bytes[i] == 255 && carry);
bytes[i] += carry;
carry = newcarry;
}
return *this;
}
namespace
{
std::set<rrdata::instance> rrset;
std::ifstream ihandle;
std::ofstream ohandle;
bool handle_open;
std::string current_project;
bool lazy_mode;
const char* hexes = "0123456789ABCDEF";
}
void rrdata::read_base(const std::string& project, bool lazy) throw(std::bad_alloc)
{
if(project == current_project && (!lazy_mode || lazy))
return;
if(lazy) {
std::set<rrdata::instance> new_rrset;
rrset = new_rrset;
current_project = project;
lazy_mode = true;
if(handle_open)
ohandle.close();
handle_open = false;
return;
}
std::set<rrdata::instance> new_rrset;
if(project == current_project)
new_rrset = rrset;
std::string filename = get_config_path() + "/" + safe_filename(project) + ".rr";
if(handle_open) {
ohandle.close();
handle_open = false;
}
ihandle.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
while(ihandle) {
unsigned char bytes[RRDATA_BYTES];
ihandle.read(reinterpret_cast<char*>(bytes), RRDATA_BYTES);
instance k(bytes);
//std::cerr << "Loaded symbol: " << k << std::endl;
new_rrset.insert(k);
}
ihandle.close();
ohandle.open(filename.c_str(), std::ios_base::out | std::ios_base::app | std::ios_base::binary);
if(ohandle)
handle_open = true;
if(project == current_project && lazy_mode && !lazy) {
//Finish the project creation, write all.
for(auto i : rrset) {
ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES);
ohandle.flush();
}
}
rrset = new_rrset;
current_project = project;
lazy_mode = lazy;
}
void rrdata::close() throw()
{
current_project = "";
if(handle_open)
ohandle.close();
handle_open = false;
}
void rrdata::add(const struct rrdata::instance& i) throw(std::bad_alloc)
{
if(rrset.insert(i).second && handle_open) {
//std::cerr << "New symbol: " << i << std::endl;
ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES);
ohandle.flush();
}
}
void rrdata::add_internal() throw(std::bad_alloc)
{
if(!internal)
internal = new instance();
add((*internal)++);
}
namespace
{
void flush_symbol(std::vector<char>& strm, const rrdata::instance& base, const rrdata::instance& predicted,
unsigned count)
{
char opcode;
char buf1[RRDATA_BYTES + 4];
char buf2[3];
unsigned bias;
if(count == 1) {
opcode = 0x00;
bias = 1;
} else if(count < 258) {
opcode = 0x20;
bias = 2;
} else if(count < 65794) {
opcode = 0x40;
bias = 258;
} else {
opcode = 0x60;
bias = 65794;
}
unsigned j;
for(j = 0; j < 31; j++)
if(base.bytes[j] != predicted.bytes[j])
break;
opcode += j;
buf1[0] = opcode;
memcpy(buf1 + 1, base.bytes + j, RRDATA_BYTES - j);
buf2[0] = (count - bias) >> 16;
buf2[1] = (count - bias) >> 8;
buf2[2] = (count - bias);
memcpy(buf1 + (RRDATA_BYTES - j + 1), buf2 + (3 - (opcode >> 5)), opcode >> 5);
for(size_t s = 0; s < (RRDATA_BYTES - j + 1) + (opcode >> 5); s++)
strm.push_back(buf1[s]);
//std::cerr << "Encoding " << count << " symbols starting from " << base << std::endl;
}
}
uint64_t rrdata::write(std::vector<char>& strm) throw(std::bad_alloc)
{
strm.clear();
uint64_t count = 0;
instance last_encode_end;
memset(last_encode_end.bytes, 0, RRDATA_BYTES);
instance predicted;
instance encode_base;
unsigned encode_count = 0;
for(auto i : rrset) {
//std::cerr << "Considering " << *i << std::endl;
count++;
if(encode_count == 0) {
//This is the first symbol.
encode_base = i;
encode_count = 1;
} else if(predicted == i && encode_count < 16843009) {
//Correct prediction.
encode_count++;
} else {
//Failed prediction
flush_symbol(strm, encode_base, last_encode_end, encode_count);
last_encode_end = predicted;
encode_base = i;
encode_count = 1;
}
predicted = i;
++predicted;
}
if(encode_count > 0)
flush_symbol(strm, encode_base, last_encode_end, encode_count);
if(count)
return count - 1;
else
return 0;
}
uint64_t rrdata::read(std::vector<char>& strm, bool dummy) throw(std::bad_alloc)
{
uint64_t count = 0;
instance decoding;
uint64_t ptr = 0;
memset(decoding.bytes, 0, RRDATA_BYTES);
while(ptr < strm.size()) {
char opcode;
unsigned char buf1[RRDATA_BYTES];
unsigned char buf2[3];
opcode = strm[ptr++];
unsigned validbytes = (opcode & 0x1F);
unsigned lengthbytes = (opcode & 0x60) >> 5;
unsigned repeat = 1;
memcpy(buf1, &strm[ptr], RRDATA_BYTES - validbytes);
ptr += (RRDATA_BYTES - validbytes);
memcpy(decoding.bytes + validbytes, buf1, RRDATA_BYTES - validbytes);
if(lengthbytes > 0) {
memcpy(buf2, &strm[ptr], lengthbytes);
ptr += lengthbytes;
}
if(lengthbytes == 1)
repeat = 2 + static_cast<unsigned>(buf2[0]);
if(lengthbytes == 2)
repeat = 258 + static_cast<unsigned>(buf2[0]) * 256 + buf2[1];
if(lengthbytes == 3)
repeat = 65794 + static_cast<unsigned>(buf2[0]) * 65536 + static_cast<unsigned>(buf2[1]) *
256 + buf2[2];
//std::cerr << "Decoding " << repeat << " symbols starting from " << decoding << std::endl;
if(!dummy)
for(unsigned i = 0; i < repeat; i++)
rrdata::add(decoding++);
count += repeat;
}
if(count)
return count - 1;
else
return 0;
}
uint64_t rrdata::count(std::vector<char>& strm) throw(std::bad_alloc)
{
return read(strm, true);
}
uint64_t rrdata::count() throw()
{
uint64_t c = rrset.size();
if(c)
return c - 1;
else
return 0;
}
std::ostream& operator<<(std::ostream& os, const struct rrdata::instance& j)
{
for(unsigned i = 0; i < 32; i++) {
os << hexes[j.bytes[i] / 16] << hexes[j.bytes[i] % 16];
}
return os;
}
rrdata::instance* rrdata::internal;
//DBC0AB8CBAAC6ED4B7781E34057891E8B9D93AAE733DEF764C06957FF705DE00
//DBC0AB8CBAAC6ED4B7781E34057891E8B9D93AAE733DEF764C06957FF705DDF3

440
src/library/rrdata.cpp Normal file
View file

@ -0,0 +1,440 @@
#include "rrdata.hpp"
#include <cstring>
#include <limits>
#define MAXRUN 16843009
namespace
{
const char* hexes = "0123456789ABCDEF";
}
rrdata_set::instance::instance() throw()
{
memset(bytes, 0, RRDATA_BYTES);
}
rrdata_set::instance::instance(const unsigned char* b) throw()
{
memcpy(bytes, b, RRDATA_BYTES);
}
rrdata_set::instance::instance(const std::string& id) throw()
{
memset(bytes, 0, RRDATA_BYTES);
for(unsigned i = 0; i < id.length() && i < 2 * RRDATA_BYTES; i++) {
unsigned h;
char ch = id[i];
if(ch >= '0' && ch <= '9')
h = ch - '0';
else if(ch >= 'A' && ch <= 'F')
h = ch - 'A' + 10;
else if(ch >= 'a' && ch <= 'f')
h = ch - 'a' + 10;
bytes[i / 2] = bytes[i / 2] * 16 + h;
}
}
bool rrdata_set::instance::operator<(const struct instance& i) const throw()
{
for(unsigned j = 0; j < RRDATA_BYTES; j++)
if(bytes[j] < i.bytes[j])
return true;
else if(bytes[j] > i.bytes[j])
return false;
return false;
}
bool rrdata_set::instance::operator==(const struct instance& i) const throw()
{
for(unsigned j = 0; j < RRDATA_BYTES; j++)
if(bytes[j] != i.bytes[j])
return false;
return true;
}
const struct rrdata_set::instance rrdata_set::instance::operator++(int) throw()
{
instance i = *this;
++*this;
return i;
}
struct rrdata_set::instance& rrdata_set::instance::operator++() throw()
{
unsigned carry = 1;
for(unsigned i = RRDATA_BYTES - 1; i < RRDATA_BYTES; i--) {
unsigned newcarry = (bytes[i] == 255 && carry);
bytes[i] += carry;
carry = newcarry;
}
return *this;
}
struct rrdata_set::instance rrdata_set::instance::operator+(unsigned inc) const throw()
{
rrdata_set::instance n = *this;
unsigned carry = inc;
for(unsigned i = RRDATA_BYTES - 1; i < RRDATA_BYTES; i--) {
unsigned newcarry = ((unsigned)n.bytes[i] + carry) >> 8;
if(newcarry == 0 && carry > 255)
newcarry = (1U << (8 * sizeof(unsigned) - 8));
n.bytes[i] += carry;
carry = newcarry;
}
return n;
}
unsigned rrdata_set::instance::operator-(const struct instance& m) const throw()
{
unsigned result = 0;
uint8_t diff[RRDATA_BYTES] = {0};
unsigned borrow = 0;
for(unsigned i = RRDATA_BYTES - 1; i < RRDATA_BYTES; i--) {
diff[i] = bytes[i] - m.bytes[i] - borrow;
borrow = ((unsigned)m.bytes[i] + borrow > (unsigned)bytes[i]) ? 1 : 0;
}
for(unsigned i = 0; i < RRDATA_BYTES; i++) {
if((result << 8 >> 8) != result)
return std::numeric_limits<unsigned>::max();
result <<= 8;
result |= diff[i];
}
return result;
}
rrdata_set::rrdata_set() throw()
{
rcount = 0;
lazy_mode = false;
handle_open = false;
}
void rrdata_set::read_base(const std::string& projectfile, bool lazy) throw(std::bad_alloc)
{
if(projectfile == current_projectfile && (!lazy_mode || lazy))
return;
if(lazy) {
std::set<std::pair<instance, instance>> new_rrset;
data = new_rrset;
current_projectfile = projectfile;
lazy_mode = true;
if(handle_open)
ohandle.close();
handle_open = false;
return;
}
std::set<std::pair<instance, instance>> new_rrset;
if(projectfile == current_projectfile)
new_rrset = data;
else
rcount = 0;
std::string filename = projectfile;
if(handle_open) {
ohandle.close();
handle_open = false;
}
std::ifstream ihandle(filename.c_str(), std::ios_base::in | std::ios_base::binary);
while(ihandle) {
unsigned char bytes[RRDATA_BYTES];
ihandle.read(reinterpret_cast<char*>(bytes), RRDATA_BYTES);
instance k(bytes);
//std::cerr << "Loaded symbol: " << k << std::endl;
_add(k, k + 1);
}
ihandle.close();
ohandle.open(filename.c_str(), std::ios_base::out | std::ios_base::app | std::ios_base::binary);
if(ohandle)
handle_open = true;
if(projectfile == current_projectfile && lazy_mode && !lazy) {
//Finish the project creation, write all.
for(auto i : data) {
instance tmp = i.first;
while(tmp != i.second) {
ohandle.write(reinterpret_cast<const char*>(tmp.bytes), RRDATA_BYTES);
++tmp;
}
ohandle.flush();
}
}
data = new_rrset;
current_projectfile = projectfile;
lazy_mode = lazy;
}
void rrdata_set::close() throw()
{
current_projectfile = "";
if(handle_open)
ohandle.close();
handle_open = false;
}
void rrdata_set::add(const struct rrdata_set::instance& i) throw(std::bad_alloc)
{
if(_add(i) && handle_open) {
//std::cerr << "New symbol: " << i << std::endl;
ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES);
ohandle.flush();
}
}
void rrdata_set::add_internal() throw(std::bad_alloc)
{
add(internal++);
}
namespace
{
void flush_symbol(std::vector<char>& strm, const rrdata_set::instance& base,
const rrdata_set::instance& predicted, unsigned count)
{
char opcode;
char buf1[RRDATA_BYTES + 4];
char buf2[3];
unsigned bias;
if(count == 1) {
opcode = 0x00;
bias = 1;
} else if(count < 258) {
opcode = 0x20;
bias = 2;
} else if(count < 65794) {
opcode = 0x40;
bias = 258;
} else {
opcode = 0x60;
bias = 65794;
}
unsigned j;
for(j = 0; j < 31; j++)
if(base.bytes[j] != predicted.bytes[j])
break;
opcode += j;
buf1[0] = opcode;
memcpy(buf1 + 1, base.bytes + j, RRDATA_BYTES - j);
buf2[0] = (count - bias) >> 16;
buf2[1] = (count - bias) >> 8;
buf2[2] = (count - bias);
memcpy(buf1 + (RRDATA_BYTES - j + 1), buf2 + (3 - (opcode >> 5)), opcode >> 5);
for(size_t s = 0; s < (RRDATA_BYTES - j + 1) + (opcode >> 5); s++)
strm.push_back(buf1[s]);
//std::cerr << "Encoding " << count << " symbols starting from " << base << std::endl;
}
uint64_t symbols_in_interval(const rrdata_set::instance& b, const rrdata_set::instance& e) throw()
{
uint64_t c = 0;
rrdata_set::instance x = b;
while(x != e) {
unsigned diff = e - x;
x = x + diff;
c = c + diff;
}
return c;
}
}
uint64_t rrdata_set::write(std::vector<char>& strm) throw(std::bad_alloc)
{
strm.clear();
uint64_t scount = 0;
instance last_encode_end;
memset(last_encode_end.bytes, 0, RRDATA_BYTES);
instance predicted;
instance encode_base;
unsigned encode_count = 0;
for(auto i : data) {
//std::cerr << "Considering " << *i << std::endl;
encode_base = i.first;
while(encode_base != i.second) {
unsigned syms = i.second - encode_base;
if(syms > MAXRUN)
syms = MAXRUN;
flush_symbol(strm, encode_base, predicted, syms);
scount += syms;
encode_base = encode_base + syms;
predicted = encode_base;
}
}
if(scount)
return scount - 1;
else
return 0;
}
uint64_t rrdata_set::read(std::vector<char>& strm, bool dummy) throw(std::bad_alloc)
{
uint64_t scount = 0;
instance decoding;
uint64_t ptr = 0;
memset(decoding.bytes, 0, RRDATA_BYTES);
while(ptr < strm.size()) {
char opcode;
unsigned char buf1[RRDATA_BYTES];
unsigned char buf2[3];
opcode = strm[ptr++];
unsigned validbytes = (opcode & 0x1F);
unsigned lengthbytes = (opcode & 0x60) >> 5;
unsigned repeat = 1;
memcpy(buf1, &strm[ptr], RRDATA_BYTES - validbytes);
ptr += (RRDATA_BYTES - validbytes);
memcpy(decoding.bytes + validbytes, buf1, RRDATA_BYTES - validbytes);
if(lengthbytes > 0) {
memcpy(buf2, &strm[ptr], lengthbytes);
ptr += lengthbytes;
}
if(lengthbytes == 1)
repeat = 2 + static_cast<unsigned>(buf2[0]);
if(lengthbytes == 2)
repeat = 258 + static_cast<unsigned>(buf2[0]) * 256 + buf2[1];
if(lengthbytes == 3)
repeat = 65794 + static_cast<unsigned>(buf2[0]) * 65536 + static_cast<unsigned>(buf2[1]) *
256 + buf2[2];
//std::cerr << "Decoding " << repeat << " symbols starting from " << decoding << std::endl;
if(!dummy) {
bool any = false;
if(!_in_set(decoding, decoding + repeat))
for(unsigned i = 0; i < repeat; i++) {
//TODO: Optimize this.
instance n = decoding + i;
if(!_in_set(n) && handle_open) {
ohandle.write(reinterpret_cast<const char*>(n.bytes), RRDATA_BYTES);
any = true;
}
}
if(any)
ohandle.flush();
rrdata_set::_add(decoding, decoding + repeat);
}
decoding = decoding + repeat;
scount += repeat;
}
if(scount)
return scount - 1;
else
return 0;
}
uint64_t rrdata_set::count(std::vector<char>& strm) throw(std::bad_alloc)
{
return read(strm, true);
}
uint64_t rrdata_set::count() throw()
{
uint64_t c = rcount;
if(c)
return c - 1;
else
return 0;
}
void rrdata_set::set_internal(const instance& b) throw()
{
internal = b;
}
std::ostream& operator<<(std::ostream& os, const struct rrdata_set::instance& j)
{
for(unsigned i = 0; i < 32; i++) {
os << hexes[j.bytes[i] / 16] << hexes[j.bytes[i] % 16];
}
return os;
}
bool rrdata_set::_add(const instance& b)
{
uint64_t c = rcount;
_add(b, b + 1);
return (c != rcount);
}
void rrdata_set::_add(const instance& b, const instance& e)
{
//Special case: Nothing.
if(data.empty()) {
data.insert(std::make_pair(b, e));
rcount += symbols_in_interval(b, e);
return;
}
//Just insert it.
auto itr = data.lower_bound(std::make_pair(b, e));
if(itr != data.end() && itr->first == b && itr->second == e)
return;
data.insert(std::make_pair(b, e));
rcount += symbols_in_interval(b, e);
itr = data.lower_bound(std::make_pair(b, e));
auto itr1 = itr;
auto itr2 = itr;
if(itr1 != data.begin()) itr1--;
itr2++;
bool have1 = (itr1 != itr);
instance rangebase = b;
//If the thing is entierely in itr1, undo the add.
if(have1 && b >= itr1->first && e <= itr1->second) {
rcount -= symbols_in_interval(b, e);
data.erase(itr);
return;
}
//Attach the thing to itr1 if appropriate.
if(have1 && b <= itr1->second) {
rcount -= symbols_in_interval(b, itr1->second);
rangebase = itr1->first;
data.insert(std::make_pair(itr1->first, e));
auto tmp = data.lower_bound(std::make_pair(itr1->first, e));
data.erase(itr1);
data.erase(itr);
itr = tmp;
have1 = false;
}
while(itr2 != data.end()) {
if(e < itr2->first)
break; //Nothing to merge anymore.
if(e >= itr2->second) {
//This entiere range is subsumed.
rcount -= symbols_in_interval(itr2->first, itr2->second);
auto tmp = itr2;
itr2++;
data.erase(tmp);
} else if(e < itr2->second) {
//Combines with range.
rcount -= symbols_in_interval(itr2->first, e);
data.insert(std::make_pair(rangebase, itr2->second));
data.erase(itr);
data.erase(itr2);
break;
}
}
}
bool rrdata_set::_in_set(const instance& b, const instance& e)
{
if(b == e)
return true;
if(data.empty())
return false;
auto itr = data.lower_bound(std::make_pair(b, e));
if(itr == data.end()) {
//If there is anything, it must be the last node.
auto r = *data.rbegin();
return (r.first <= b && r.second >= e);
} else {
//It may be this node or the previous one.
if(itr->first <= b && itr->second >= e)
return true;
itr--;
return (itr->first <= b && itr->second >= e);
}
}
std::string rrdata_set::debug_dump()
{
std::ostringstream x;
x << rcount << "[";
for(auto i : data)
x << "{" << i.first << "," << i.second << "}";
x << "]";
return x.str();
}

View file

@ -21,7 +21,7 @@ namespace
});
function_ptr_luafun mrrs(lua_func_misc, "movie.rerecords", [](lua_state& L, const std::string& fname) -> int {
L.pushnumber(rrdata::count());
L.pushnumber(rrdata.count());
return 1;
});

View file

@ -506,7 +506,7 @@ int lsnes_app::OnExit()
x->Destroy();
save_configuration();
information_dispatch::do_dump_end();
rrdata::close();
rrdata.close();
quit_lua();
joystick_driver_signal();
joystick_thread_handle->join();

777
src/test/rrdata-test.cpp Normal file
View file

@ -0,0 +1,777 @@
#include "rrdata.hpp"
#include "string.hpp"
#include "minmax.hpp"
#include <iostream>
#include <boost/filesystem.hpp>
#include <sstream>
#ifdef BOOST_FILESYSTEM3
namespace boost_fs = boost::filesystem3;
#else
namespace boost_fs = boost::filesystem;
#endif
uint64_t get_file_size(const std::string& filename)
{
uintmax_t size = boost_fs::file_size(boost_fs::path(filename));
if(size == static_cast<uintmax_t>(-1))
return 0;
return size;
}
struct test
{
const char* name;
std::function<bool()> run;
};
struct test tests[] = {
{"instance default ctor", []() {
rrdata_set::instance i;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000000";
}},{"instance bytes ctor", []() {
uint8_t buf[32] = {0};
buf[30] = 1;
rrdata_set::instance i(buf);
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000100";
}},{"instance string ctor #1", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000763234676");
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000763234676";
}},{"instance string ctor #2", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000763afba76");
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000763AFBA76";
}},{"instance string ctor #3", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000763AFBA76");
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000763AFBA76";
}},{"< #1", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000000");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000000");
return !(i1 < i2);
}},{"< #2", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000000");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000001");
return i1 < i2;
}},{"< #3", []() {
rrdata_set::instance i1("00000000000000000000000000000000000000000000000000000000000000FF");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000100");
return i1 < i2;
}},{"< #4", []() {
rrdata_set::instance i1("00000000000000000000000000000000000000000000000000000000000000FF");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000100");
return !(i2 < i1);
}},{"== #1", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000001");
return (i2 == i1);
}},{"== #2", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000101");
return !(i2 == i1);
}},{"== #3", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000000");
return !(i2 == i1);
}},{"post-++ #1", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000000");
i++;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000001";
}},{"post-++ #2", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000001");
i++;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000002";
}},{"post-++ #3", []() {
rrdata_set::instance i("000000000000000000000000000000000000000000000000000000000000000F");
i++;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000010";
}},{"post-++ #4", []() {
rrdata_set::instance i("00000000000000000000000000000000000000000000000000000000000000FF");
i++;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000100";
}},{"post-++ #5", []() {
rrdata_set::instance i("000000000000000000000000000000000000000000000000000000000000FFFF");
i++;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000010000";
}},{"post-++ #6", []() {
rrdata_set::instance i("000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF");
i++;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000010000000000000000";
}},{"post-++ #7", []() {
rrdata_set::instance i("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
i++;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000000";
}},{"post-++ #8", []() {
rrdata_set::instance i("00000000000000000000000000000000000000000000000000000000000000FE");
i++;
return (stringfmt() << i).str() == "00000000000000000000000000000000000000000000000000000000000000FF";
}},{"pre-++ #1", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000000");
++i;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000001";
}},{"pre-++ #2", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000001");
++i;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000002";
}},{"pre-++ #3", []() {
rrdata_set::instance i("000000000000000000000000000000000000000000000000000000000000000F");
++i;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000010";
}},{"pre-++ #4", []() {
rrdata_set::instance i("00000000000000000000000000000000000000000000000000000000000000FF");
++i;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000100";
}},{"pre-++ #5", []() {
rrdata_set::instance i("000000000000000000000000000000000000000000000000000000000000FFFF");
++i;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000010000";
}},{"pre-++ #6", []() {
rrdata_set::instance i("000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF");
++i;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000010000000000000000";
}},{"pre-++ #7", []() {
rrdata_set::instance i("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
++i;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000000";
}},{"pre-++ #8", []() {
rrdata_set::instance i("00000000000000000000000000000000000000000000000000000000000000FE");
++i;
return (stringfmt() << i).str() == "00000000000000000000000000000000000000000000000000000000000000FF";
}},{"Operator+ #1", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000000");
i = i + 0x12;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000012";
}},{"Operator+ #2", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000000");
i = i + 0x1234;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000001234";
}},{"Operator+ #3", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000001");
i = i + 0xFF;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000000100";
}},{"Operator+ #4", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000001");
i = i + 0xFFFF;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000010000";
}},{"Operator+ #4", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000102");
i = i + 0xFEFF;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000000010001";
}},{"Operator+ #4", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000002");
i = i + 0xFFFFFFFFU;
return (stringfmt() << i).str() == "0000000000000000000000000000000000000000000000000000000100000001";
}},{"Operator- #1", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000002");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000002");
return (i1 - i2) == 0;
}},{"Operator- #2", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000002");
return (i1 - i2) == std::numeric_limits<unsigned>::max();
}},{"Operator- #3", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000002");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000001");
return (i1 - i2) == 1;
}},{"Operator- #4", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000007");
return (i1 - i2) == std::numeric_limits<unsigned>::max();
}},{"Operator- #5", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000236");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000123");
return (i1 - i2) == 0x113;
}},{"Operator- #6", []() {
rrdata_set::instance i1("00000000000000000000000000000000000000000000000000000000FFFFFFFE");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000000");
return (i1 - i2) == 0xFFFFFFFEU;
}},{"Operator- #7", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000100000000");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000002");
return (i1 - i2) == 0xFFFFFFFEU;
}},{"Operator- #8", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000001000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000002");
return (i1 - i2) == 0xFFFFFFFFU;
}},{"Operator- #9", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000000");
rrdata_set::instance i2("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
return (i1 - i2) == 1;
}},{"rrdata init", []() {
rrdata_set s;
return s.debug_dump() == "0[]";
}},{"rrdata add", []() {
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000002");
rrdata_set s;
if(!s.debug_add(i2))
return false;
return s.debug_dump() == "1[{0000000000000000000000000000000000000000000000000000000000000002,"
"0000000000000000000000000000000000000000000000000000000000000003}]";
}},{"rrdata add disjoint", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000002");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000004");
rrdata_set s;
if(!s.debug_add(i1))
return false;
if(!s.debug_add(i2))
return false;
return s.debug_dump() == "2[{0000000000000000000000000000000000000000000000000000000000000002,"
"0000000000000000000000000000000000000000000000000000000000000003}{"
"0000000000000000000000000000000000000000000000000000000000000004,"
"0000000000000000000000000000000000000000000000000000000000000005}]";
}},{"rrdata add again", []() {
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000002");
rrdata_set s;
if(!s.debug_add(i2))
return false;
if(s.debug_add(i2))
return false;
return s.debug_dump() == "1[{0000000000000000000000000000000000000000000000000000000000000002,"
"0000000000000000000000000000000000000000000000000000000000000003}]";
}},{"rrdata extend range low", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000000");
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000004");
rrdata_set s;
s.debug_add(i1, i2);
if(!s.debug_add(i)) {
std::cout << "Collides..." << std::flush;
return false;
}
if(s.debug_dump() == "4[{0000000000000000000000000000000000000000000000000000000000000000,"
"0000000000000000000000000000000000000000000000000000000000000004}]")
return true;
std::cout << s.debug_dump() << "..." << std::flush;
return false;
}},{"rrdata extend range high", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000004");
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000004");
rrdata_set s;
s.debug_add(i1, i2);
if(!s.debug_add(i))
return false;
return s.debug_dump() == "4[{0000000000000000000000000000000000000000000000000000000000000001,"
"0000000000000000000000000000000000000000000000000000000000000005}]";
}},{"rrdata add again (range)", []() {
rrdata_set::instance i("0000000000000000000000000000000000000000000000000000000000000002");
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000004");
rrdata_set s;
s.debug_add(i1, i2);
if(s.debug_add(i))
return false;
return s.debug_dump() == "3[{0000000000000000000000000000000000000000000000000000000000000001,"
"0000000000000000000000000000000000000000000000000000000000000004}]";
}},{"rrdata partial overlap (previous)", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000009");
rrdata_set::instance i3("0000000000000000000000000000000000000000000000000000000000000007");
rrdata_set::instance i4("000000000000000000000000000000000000000000000000000000000000000F");
rrdata_set s;
s.debug_add(i1, i2);
s.debug_add(i3, i4);
return s.debug_dump() == "10[{0000000000000000000000000000000000000000000000000000000000000005,"
"000000000000000000000000000000000000000000000000000000000000000F}]";
}},{"rrdata bridging add", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000B");
rrdata_set::instance i4("000000000000000000000000000000000000000000000000000000000000000F");
rrdata_set::instance i5("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set s;
s.debug_add(i1, i2);
s.debug_add(i3, i4);
s.debug_add(i5);
return s.debug_dump() == "10[{0000000000000000000000000000000000000000000000000000000000000005,"
"000000000000000000000000000000000000000000000000000000000000000F}]";
}},{"rrdata bridging add #2", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000B");
rrdata_set::instance i4("000000000000000000000000000000000000000000000000000000000000000F");
rrdata_set::instance i5("0000000000000000000000000000000000000000000000000000000000000008");
rrdata_set::instance i6("000000000000000000000000000000000000000000000000000000000000000D");
rrdata_set s;
s.debug_add(i1, i2);
s.debug_add(i3, i4);
s.debug_add(i5, i6);
return s.debug_dump() == "10[{0000000000000000000000000000000000000000000000000000000000000005,"
"000000000000000000000000000000000000000000000000000000000000000F}]";
}},{"rrdata discontinuous reverse", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000009");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("000000000000000000000000000000000000000000000000000000000000000F");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i1, i2);
return s.debug_dump() == "9[{0000000000000000000000000000000000000000000000000000000000000005,"
"0000000000000000000000000000000000000000000000000000000000000009}{"
"000000000000000000000000000000000000000000000000000000000000000A,"
"000000000000000000000000000000000000000000000000000000000000000F}]";
}},{"rrdata elide next #1", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000010");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("000000000000000000000000000000000000000000000000000000000000000F");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i1, i2);
return s.debug_dump() == "11[{0000000000000000000000000000000000000000000000000000000000000005,"
"0000000000000000000000000000000000000000000000000000000000000010}]";
}},{"rrdata elide next #2", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000010");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000010");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i1, i2);
return s.debug_dump() == "11[{0000000000000000000000000000000000000000000000000000000000000005,"
"0000000000000000000000000000000000000000000000000000000000000010}]";
}},{"rrdata elide next multiple", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000050");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000014");
rrdata_set::instance i5("0000000000000000000000000000000000000000000000000000000000000020");
rrdata_set::instance i6("000000000000000000000000000000000000000000000000000000000000002F");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i5, i6);
s.debug_add(i1, i2);
return s.debug_dump() == "75[{0000000000000000000000000000000000000000000000000000000000000005,"
"0000000000000000000000000000000000000000000000000000000000000050}]";
}},{"rrdata elide next multiple (OOR)", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000050");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000014");
rrdata_set::instance i5("0000000000000000000000000000000000000000000000000000000000000020");
rrdata_set::instance i6("000000000000000000000000000000000000000000000000000000000000002F");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000060");
rrdata_set::instance i8("0000000000000000000000000000000000000000000000000000000000000070");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i5, i6);
s.debug_add(i7, i8);
s.debug_add(i1, i2);
return s.debug_dump() == "91[{0000000000000000000000000000000000000000000000000000000000000005,"
"0000000000000000000000000000000000000000000000000000000000000050}{"
"0000000000000000000000000000000000000000000000000000000000000060,"
"0000000000000000000000000000000000000000000000000000000000000070}]";
}},{"rrdata elide next onehalf", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000050");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000014");
rrdata_set::instance i5("0000000000000000000000000000000000000000000000000000000000000020");
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i5, i6);
s.debug_add(i1, i2);
return s.debug_dump() == "80[{0000000000000000000000000000000000000000000000000000000000000005,"
"0000000000000000000000000000000000000000000000000000000000000055}]";
}},{"rrdata elide next onehalf (OOR)", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000050");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000014");
rrdata_set::instance i5("0000000000000000000000000000000000000000000000000000000000000020");
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000056");
rrdata_set::instance i8("0000000000000000000000000000000000000000000000000000000000000057");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i5, i6);
s.debug_add(i7, i8);
s.debug_add(i1, i2);
return s.debug_dump() == "81[{0000000000000000000000000000000000000000000000000000000000000005,"
"0000000000000000000000000000000000000000000000000000000000000055}{"
"0000000000000000000000000000000000000000000000000000000000000056,"
"0000000000000000000000000000000000000000000000000000000000000057}]";
}},{"rrdata elide next onehalf and prev", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000050");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000014");
rrdata_set::instance i5("0000000000000000000000000000000000000000000000000000000000000020");
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i8("0000000000000000000000000000000000000000000000000000000000000006");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i5, i6);
s.debug_add(i7, i8);
s.debug_add(i1, i2);
return s.debug_dump() == "84[{0000000000000000000000000000000000000000000000000000000000000001,"
"0000000000000000000000000000000000000000000000000000000000000055}]";
}},{"rrdata elide next onehalf and prev (exact)", []() {
rrdata_set::instance i1("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set::instance i2("0000000000000000000000000000000000000000000000000000000000000050");
rrdata_set::instance i3("000000000000000000000000000000000000000000000000000000000000000A");
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000014");
rrdata_set::instance i5("0000000000000000000000000000000000000000000000000000000000000020");
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000001");
rrdata_set::instance i8("0000000000000000000000000000000000000000000000000000000000000005");
rrdata_set s;
s.debug_add(i3, i4);
s.debug_add(i5, i6);
s.debug_add(i7, i8);
s.debug_add(i1, i2);
return s.debug_dump() == "84[{0000000000000000000000000000000000000000000000000000000000000001,"
"0000000000000000000000000000000000000000000000000000000000000055}]";
}},{"In set (empty set, empty data)", []() {
rrdata_set s;
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
return s.debug_in_set(i6, i6);
}},{"In set (non empty set, empty data)", []() {
rrdata_set s;
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
return !s.debug_in_set(i6);
}},{"In set (empty set, non empty data)", []() {
rrdata_set s;
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000058");
s.debug_add(i6);
return s.debug_in_set(i7, i7);
}},{"In set (match)", []() {
rrdata_set s;
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
s.debug_add(i6);
return s.debug_in_set(i6);
}},{"In set (adjacent low)", []() {
rrdata_set s;
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000056");
s.debug_add(i7);
return !s.debug_in_set(i6);
}},{"In set (adjacent)", []() {
rrdata_set s;
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000056");
s.debug_add(i6);
return !s.debug_in_set(i7);
}},{"In set (match to larger)", []() {
rrdata_set s;
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000059");
rrdata_set::instance i8("0000000000000000000000000000000000000000000000000000000000000056");
s.debug_add(i6, i7);
return s.debug_in_set(i8);
}},{"In set (match to larger, exact end)", []() {
rrdata_set s;
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000059");
rrdata_set::instance i8("0000000000000000000000000000000000000000000000000000000000000058");
s.debug_add(i6, i7);
return s.debug_in_set(i8);
}},{"In set (match to larger, multiple)", []() {
rrdata_set s;
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000045");
rrdata_set::instance i5("0000000000000000000000000000000000000000000000000000000000000049");
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000055");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000059");
rrdata_set::instance i8("0000000000000000000000000000000000000000000000000000000000000046");
s.debug_add(i4, i5);
s.debug_add(i6, i7);
return s.debug_in_set(i8);
}},{"In set (split)", []() {
rrdata_set s;
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000045");
rrdata_set::instance i5("000000000000000000000000000000000000000000000000000000000000004F");
rrdata_set::instance i6("0000000000000000000000000000000000000000000000000000000000000050");
rrdata_set::instance i7("0000000000000000000000000000000000000000000000000000000000000059");
rrdata_set::instance i8("0000000000000000000000000000000000000000000000000000000000000046");
rrdata_set::instance i9("0000000000000000000000000000000000000000000000000000000000000053");
s.debug_add(i4, i5);
s.debug_add(i6, i7);
return !s.debug_in_set(i8, i9);
}},{"Set internal, add internal", []() {
rrdata_set s;
rrdata_set::instance i4("0000000000000000000000000000000000000000000000000000000000000045");
s.set_internal(i4);
s.add_internal();
return s.debug_dump() == "1[{0000000000000000000000000000000000000000000000000000000000000045,"
"0000000000000000000000000000000000000000000000000000000000000046}]";
}},{"Empty count", []() {
rrdata_set s;
return s.count() == 0;
}},{"count 1 node", []() {
rrdata_set s;
s.add_internal();
return s.count() == 0;
}},{"count 2 node", []() {
rrdata_set s;
s.add_internal();
s.add_internal();
return s.count() == 1;
}},{"count 3 node", []() {
rrdata_set s;
s.add_internal();
s.add_internal();
s.add_internal();
return s.count() == 2;
}},{"Count rrdata #1", []() {
rrdata_set s;
std::vector<char> data;
return s.count(data) == 0;
}},{"Count rrdata #2", []() {
rrdata_set s;
char _data[] = {0x1F,0x00};
std::vector<char> data(_data, _data + sizeof(_data));
return s.count(data) == 0;
}},{"Count rrdata #2", []() {
rrdata_set s;
char _data[] = {0x1F,0x00,0x1F,0x02};
std::vector<char> data(_data, _data + sizeof(_data));
return s.count(data) == 1;
}},{"Count rrdata #3", []() {
rrdata_set s;
char _data[] = {0x3F,0x01,0x07,0x1F,0x12};
std::vector<char> data(_data, _data + sizeof(_data));
return s.count(data) == 9;
}},{"Count rrdata #4", []() {
rrdata_set s;
char _data[] = {0x5F,0x01,0x07,0x45,0x1F,-1};
std::vector<char> data(_data, _data + sizeof(_data));
return s.count(data) == 0x847;
}},{"Count rrdata #5", []() {
rrdata_set s;
char _data[] = {0x7F,0x01,0x07,0x45,0x14,0x1F,-1};
std::vector<char> data(_data, _data + sizeof(_data));
return s.count(data) == 0x84616;
}},{"read rrdata #1", []() {
rrdata_set s;
char _data[] = {0x7F,0x01,0x07,0x45,0x14,0x1F,-1,0x1F,0x00};
std::vector<char> data(_data, _data + sizeof(_data));
s.read(data);
std::string ans = "542232[{0000000000000000000000000000000000000000000000000000000000000001,"
"0000000000000000000000000000000000000000000000000000000000084617}{"
"00000000000000000000000000000000000000000000000000000000000846FF,"
"0000000000000000000000000000000000000000000000000000000000084701}]";
return s.debug_dump() == ans;
}},{"read/write rrdata #1", []() {
rrdata_set s;
char _data[] = {0x7F,0x01,0x07,0x45,0x14,0x1F,-1,0x1F,0x00};
std::vector<char> data(_data, _data + sizeof(_data));
s.read(data);
std::vector<char> data2;
if(s.write(data2) != 0x84617)
return false;
char _data2[] = {0x7F,0x01,0x07,0x45,0x14,0x3F,-1,0x00};
return sizeof(_data2) == data2.size() && !memcmp(_data2, &data2[0], min(sizeof(_data2),
data2.size()));
}},{"Write blank", []() {
rrdata_set s;
std::vector<char> data2;
if(s.write(data2))
return false;
return data2.size() == 0;
}},{"Write oversize rrdata run", []() {
rrdata_set s;
rrdata_set::instance i;
s.debug_add(i,i + 0x2000000);
std::vector<char> data2;
if(s.write(data2) != 0x1FFFFFF)
return false;
char _data2[] = {0x7F,0x00,-1,-1,-1,0x7F,0x01,-3,-3,-3};
return sizeof(_data2) == data2.size() && !memcmp(_data2, &data2[0], min(sizeof(_data2),
data2.size()));
}},{"Decode split", []() {
rrdata_set s;
char _data[] = {0x7F,0x00,-1,-1,-1,0x7F,0x01,-3,-3,-3};
std::vector<char> data(_data, _data + sizeof(_data));
s.read(data);
std::string ans = "33554432[{0000000000000000000000000000000000000000000000000000000000000000,"
"0000000000000000000000000000000000000000000000000000000002000000}]";
return s.debug_dump() == ans;
}},{"Write 0-byte length", []() {
rrdata_set s;
rrdata_set::instance i;
s.debug_add(i);
std::vector<char> data2;
if(s.write(data2) != 0)
return false;
char _data2[] = {0x1F,0x00};
return sizeof(_data2) == data2.size() && !memcmp(_data2, &data2[0], min(sizeof(_data2),
data2.size()));
}},{"Write 1-byte length", []() {
rrdata_set s;
rrdata_set::instance i;
s.debug_add(i,i + 0x100);
std::vector<char> data2;
if(s.write(data2) != 0xFF)
return false;
char _data2[] = {0x3F,0x00,-2};
return sizeof(_data2) == data2.size() && !memcmp(_data2, &data2[0], min(sizeof(_data2),
data2.size()));
}},{"Write 2-byte length", []() {
rrdata_set s;
rrdata_set::instance i;
s.debug_add(i,i + 0x10000);
std::vector<char> data2;
if(s.write(data2) != 0xFFFF)
return false;
char _data2[] = {0x5F,0x00,-2,-2};
return sizeof(_data2) == data2.size() && !memcmp(_data2, &data2[0], min(sizeof(_data2),
data2.size()));
}},{"Write 2-byte length #2", []() {
rrdata_set s;
rrdata_set::instance i;
s.debug_add(i + 0x1424,i + 0x11425);
std::vector<char> data2;
if(s.write(data2) != 0x10000)
return false;
char _data2[] = {0x5E,0x14, 0x24,-2,-1};
return sizeof(_data2) == data2.size() && !memcmp(_data2, &data2[0], min(sizeof(_data2),
data2.size()));
}},{"Basic rrdata with backing file", []() {
rrdata_set s;
unlink("foo.tmp");
s.read_base("foo.tmp", false);
s.set_internal(rrdata_set::instance(
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD0A"));
if(get_file_size("foo.tmp") != 0)
return false;
s.add_internal();
if(get_file_size("foo.tmp") != 32)
return false;
s.add_internal();
if(get_file_size("foo.tmp") != 64)
return false;
s.add_internal();
if(get_file_size("foo.tmp") != 96)
return false;
s.add_internal();
if(get_file_size("foo.tmp") != 128)
return false;
s.add_internal();
if(get_file_size("foo.tmp") != 160)
return false;
return true;
}},{"Reopen backing file", []() {
rrdata_set s;
unlink("foo.tmp");
s.read_base("foo.tmp", false);
s.set_internal(rrdata_set::instance(
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD0A"));
if(get_file_size("foo.tmp") != 0)
return false;
s.add_internal();
if(get_file_size("foo.tmp") != 32)
return false;
s.close();
s.read_base("foo.tmp", false);
s.add_internal();
if(get_file_size("foo.tmp") != 64)
return false;
return true;
}},{"Close with no project", []() {
rrdata_set s;
unlink("foo.tmp");
s.close();
return true;
}},{"Switch to self", []() {
rrdata_set s;
unlink("foo.tmp");
s.read_base("foo.tmp", false);
s.set_internal(rrdata_set::instance(
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD0A"));
s.add_internal();
s.read_base("foo.tmp", false);
s.add_internal();
return s.count() == 1;
}},{"Switch to another", []() {
rrdata_set s;
unlink("foo.tmp");
unlink("foo2.tmp");
s.read_base("foo.tmp", false);
s.set_internal(rrdata_set::instance(
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD0A"));
s.add_internal();
s.read_base("foo2.tmp", false);
s.add_internal();
s.add_internal();
//std::cerr << s.debug_dump() << std::endl;
return s.count() == 1;
}},{"Lazy mode", []() {
rrdata_set s;
unlink("foo.tmp");
s.read_base("foo.tmp", true);
s.set_internal(rrdata_set::instance(
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD0A"));
s.add_internal();
s.add_internal();
s.read_base("foo.tmp", false);
s.add_internal();
s.add_internal();
if(get_file_size("foo.tmp") != 128)
return false;
return s.count() == 3;
}},{"Lazy mode with previous file", []() {
rrdata_set s;
unlink("foo.tmp");
unlink("foo2.tmp");
s.read_base("foo2.tmp", false);
s.read_base("foo.tmp", true);
s.set_internal(rrdata_set::instance(
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD0A"));
s.add_internal();
s.add_internal();
s.read_base("foo.tmp", false);
s.add_internal();
s.add_internal();
if(get_file_size("foo.tmp") != 128)
return false;
return s.count() == 3;
}},{"Reading a file", []() {
rrdata_set s;
unlink("foo.tmp");
s.read_base("foo.tmp", false);
char _data[] = {0x3F,0x01,0x07,0x1F,0x12};
std::vector<char> data(_data, _data + sizeof(_data));
s.read(data);
if(get_file_size("foo.tmp") != 320)
return false;
return true;
}},{"Reading a file /w existing entry", []() {
rrdata_set s;
unlink("foo.tmp");
rrdata_set::instance i;
i = i + 5;
s.add(i);
s.read_base("foo.tmp", false);
char _data[] = {0x3F,0x01,0x07,0x1F,0x12};
std::vector<char> data(_data, _data + sizeof(_data));
s.read(data);
if(get_file_size("foo.tmp") != 320)
return false;
return true;
}},
};
int main()
{
struct test* t = tests;
while(t->name) {
std::cout << t->name << "..." << std::flush;
try {
if(t->run())
std::cout << "\e[32mPASS\e[0m" << std::endl;
else {
std::cout << "\e[31mFAILED\e[0m" << std::endl;
return 1;
}
} catch(std::exception& e) {
std::cout << "\e[31mEXCEPTION: " << e.what() << "\e[0m" << std::endl;
return 1;
} catch(...) {
std::cout << "\e[31mUNKNOWN EXCEPTION\e[0m" << std::endl;
return 1;
}
t++;
}
return 0;
}

View file

@ -373,7 +373,7 @@ int main(int argc, char** argv)
return 1;
}
information_dispatch::do_dump_end();
rrdata::close();
rrdata.close();
quit_lua();
cleanup_all_keys();
return 0;

View file

@ -174,7 +174,7 @@ int main(int argc, char** argv)
dump_what_was_loaded(r, movie);
rrdata::close();
rrdata.close();
cleanup_all_keys();
return 0;
}