Refactor rrdata handling
Makes savestate/loadstate fair bit faster
This commit is contained in:
parent
ecd8b74ee1
commit
f19fea0ea4
15 changed files with 1419 additions and 428 deletions
|
@ -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
171
include/library/rrdata.hpp
Normal 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
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
440
src/library/rrdata.cpp
Normal 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();
|
||||
}
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
|
@ -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
777
src/test/rrdata-test.cpp
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue