mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Add the DataSpec class.
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
|||||||
all: .obj/build.ninja
|
all: .obj/build.ninja
|
||||||
@ninja -C .obj
|
@ninja -C .obj test
|
||||||
|
|
||||||
.obj/build.ninja:
|
.obj/build.ninja:
|
||||||
@mkdir -p .obj
|
@mkdir -p .obj
|
||||||
|
|||||||
92
lib/dataspec.cc
Normal file
92
lib/dataspec.cc
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include "globals.h"
|
||||||
|
#include "dataspec.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
static const std::regex MOD_REGEX("([a-z]*)=([-x+0-9,]*)");
|
||||||
|
static const std::regex DATA_REGEX("([0-9]+)(?:(?:-([0-9]+))|(?:\\+([0-9]+)))?(?:x([0-9]+))?");
|
||||||
|
|
||||||
|
std::vector<std::string> DataSpec::split(
|
||||||
|
const std::string& s, const std::string& delimiter)
|
||||||
|
{
|
||||||
|
std::vector<std::string> ret;
|
||||||
|
|
||||||
|
size_t start = 0;
|
||||||
|
size_t end = 0;
|
||||||
|
size_t len = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
end = s.find(delimiter,start);
|
||||||
|
len = end - start;
|
||||||
|
std::string token = s.substr(start, len);
|
||||||
|
ret.emplace_back( token );
|
||||||
|
start += len + delimiter.length();
|
||||||
|
}
|
||||||
|
while (end != std::string::npos);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSpec::Modifier DataSpec::parseMod(const std::string& spec)
|
||||||
|
{
|
||||||
|
std::smatch match;
|
||||||
|
if (!std::regex_match(spec, match, MOD_REGEX))
|
||||||
|
Error() << "invalid data modifier syntax '" << spec << "'";
|
||||||
|
|
||||||
|
Modifier m;
|
||||||
|
m.name = match[1];
|
||||||
|
for (auto& data : split(match[2], ","))
|
||||||
|
{
|
||||||
|
int start = 0;
|
||||||
|
int count = 1;
|
||||||
|
int step = 1;
|
||||||
|
|
||||||
|
std::smatch dmatch;
|
||||||
|
if (!std::regex_match(data, dmatch, DATA_REGEX))
|
||||||
|
Error() << "invalid data in mod '" << data << "'";
|
||||||
|
|
||||||
|
start = std::stoi(dmatch[1]);
|
||||||
|
if (!dmatch[2].str().empty())
|
||||||
|
count = std::stoi(dmatch[2]) - start + 1;
|
||||||
|
if (!dmatch[3].str().empty())
|
||||||
|
count = std::stoi(dmatch[3]);
|
||||||
|
if (!dmatch[4].str().empty())
|
||||||
|
step = std::stoi(dmatch[4]);
|
||||||
|
|
||||||
|
if (count < 0)
|
||||||
|
Error() << "mod '" << data << "' specifies an illegal quantity";
|
||||||
|
|
||||||
|
for (int i = start; i < (start+count); i += step)
|
||||||
|
m.data.insert(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataSpec::set(const std::string& spec)
|
||||||
|
{
|
||||||
|
std::vector<std::string> words = split(spec, ":");
|
||||||
|
if (words.size() == 0)
|
||||||
|
Error() << "empty data specification (you have to specify *something*)";
|
||||||
|
|
||||||
|
filename = words[0];
|
||||||
|
if (words.size() > 1)
|
||||||
|
{
|
||||||
|
locations.clear();
|
||||||
|
|
||||||
|
for (size_t i = 1; i < words.size(); i++)
|
||||||
|
{
|
||||||
|
auto mod = parseMod(words[i]);
|
||||||
|
if ((mod.name != "t") && (mod.name != "s"))
|
||||||
|
Error() << fmt::format("unknown data modifier '{}'", mod.name);
|
||||||
|
modifiers[mod.name] = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& tracks = modifiers["t"].data;
|
||||||
|
const auto& sides = modifiers["s"].data;
|
||||||
|
for (auto track : tracks)
|
||||||
|
{
|
||||||
|
for (auto side : sides)
|
||||||
|
locations.push_back({ track, side });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
lib/dataspec.h
Normal file
47
lib/dataspec.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef DATASPEC_H
|
||||||
|
#define DATASPEC_H
|
||||||
|
|
||||||
|
class DataSpec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Location
|
||||||
|
{
|
||||||
|
unsigned track;
|
||||||
|
unsigned side;
|
||||||
|
|
||||||
|
bool operator == (const Location& other) const
|
||||||
|
{ return (track == other.track) && (side == other.side); }
|
||||||
|
|
||||||
|
bool operator != (const Location& other) const
|
||||||
|
{ return (track != other.track) || (side != other.side); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Modifier
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::set<unsigned> data;
|
||||||
|
|
||||||
|
bool operator == (const Modifier& other) const
|
||||||
|
{ return (name == other.name) && (data == other.data); }
|
||||||
|
|
||||||
|
bool operator != (const Modifier& other) const
|
||||||
|
{ return (name != other.name) || (data != other.data); }
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::vector<std::string> split(
|
||||||
|
const std::string& s, const std::string& delimiter);
|
||||||
|
static Modifier parseMod(const std::string& spec);
|
||||||
|
|
||||||
|
public:
|
||||||
|
DataSpec(const std::string& spec)
|
||||||
|
{ set(spec); }
|
||||||
|
|
||||||
|
void set(const std::string& spec);
|
||||||
|
|
||||||
|
std::string filename;
|
||||||
|
std::map<std::string, Modifier> modifiers;
|
||||||
|
std::vector<Location> locations;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
typedef int nanoseconds_t;
|
typedef int nanoseconds_t;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "reader.h"
|
#include "reader.h"
|
||||||
#include "fluxmap.h"
|
#include "fluxmap.h"
|
||||||
#include "sql.h"
|
#include "sql.h"
|
||||||
|
#include "dataspec.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
@@ -30,6 +31,8 @@ static IntFlag revolutions(
|
|||||||
"read this many revolutions of the disk",
|
"read this many revolutions of the disk",
|
||||||
1);
|
1);
|
||||||
|
|
||||||
|
static DataSpec readerspec("foo:f=7:z=9-10");
|
||||||
|
|
||||||
static std::string basefilename;
|
static std::string basefilename;
|
||||||
static int starttrack = 0;
|
static int starttrack = 0;
|
||||||
static int endtrack = 79;
|
static int endtrack = 79;
|
||||||
|
|||||||
10
meson.build
10
meson.build
@@ -14,15 +14,16 @@ fmtinc = include_directories('dep/fmt')
|
|||||||
|
|
||||||
felib = shared_library('felib',
|
felib = shared_library('felib',
|
||||||
[
|
[
|
||||||
|
'lib/crc.cc',
|
||||||
|
'lib/dataspec.cc',
|
||||||
|
'lib/hexdump.cc',
|
||||||
|
'lib/sectorset.cc',
|
||||||
'lib/flags.cc',
|
'lib/flags.cc',
|
||||||
'lib/fluxmap.cc',
|
'lib/fluxmap.cc',
|
||||||
'lib/globals.cc',
|
'lib/globals.cc',
|
||||||
'lib/usb.cc',
|
|
||||||
'lib/image.cc',
|
'lib/image.cc',
|
||||||
'lib/crc.cc',
|
|
||||||
'lib/hexdump.cc',
|
|
||||||
'lib/sector.cc',
|
'lib/sector.cc',
|
||||||
'lib/sectorset.cc',
|
'lib/usb.cc',
|
||||||
],
|
],
|
||||||
include_directories: [fmtinc],
|
include_directories: [fmtinc],
|
||||||
link_with: [fmtlib],
|
link_with: [fmtlib],
|
||||||
@@ -89,3 +90,4 @@ executable('fe-testbulktransport', ['src/fe-testbulktransport.cc'], include_dire
|
|||||||
executable('fe-writebrother', ['src/fe-writebrother.cc'], include_directories: [feinc, fmtinc, brotherinc], link_with: [felib, writerlib, encoderlib, brotherencoderlib, fmtlib])
|
executable('fe-writebrother', ['src/fe-writebrother.cc'], include_directories: [feinc, fmtinc, brotherinc], link_with: [felib, writerlib, encoderlib, brotherencoderlib, fmtlib])
|
||||||
executable('fe-writeflux', ['src/fe-writeflux.cc'], include_directories: [feinc, fmtinc], link_with: [felib, readerlib, writerlib, fmtlib])
|
executable('fe-writeflux', ['src/fe-writeflux.cc'], include_directories: [feinc, fmtinc], link_with: [felib, readerlib, writerlib, fmtlib])
|
||||||
|
|
||||||
|
test('DataSpec', executable('dataspec-test', ['tests/dataspec.cc'], include_directories: [feinc], link_with: [felib]))
|
||||||
|
|||||||
74
tests/dataspec.cc
Normal file
74
tests/dataspec.cc
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "globals.h"
|
||||||
|
#include "dataspec.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
static void test_split(void)
|
||||||
|
{
|
||||||
|
assert((DataSpec::split("1,2,3", ",")
|
||||||
|
== std::vector<std::string>{"1", "2", "3"}));
|
||||||
|
assert((DataSpec::split(",2,3", ",")
|
||||||
|
== std::vector<std::string>{"", "2", "3"}));
|
||||||
|
assert((DataSpec::split(",2,", ",")
|
||||||
|
== std::vector<std::string>{"", "2", ""}));
|
||||||
|
assert((DataSpec::split("2", ",")
|
||||||
|
== std::vector<std::string>{"2"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_parsemod(void)
|
||||||
|
{
|
||||||
|
assert(DataSpec::parseMod("x=1")
|
||||||
|
== (DataSpec::Modifier{"x", {1}}));
|
||||||
|
assert(DataSpec::parseMod("x=1,3,5")
|
||||||
|
== (DataSpec::Modifier{"x", {1, 3, 5}}));
|
||||||
|
assert(DataSpec::parseMod("x=1,1,1")
|
||||||
|
== (DataSpec::Modifier{"x", {1}}));
|
||||||
|
assert(DataSpec::parseMod("x=2-3")
|
||||||
|
== (DataSpec::Modifier{"x", {2, 3}}));
|
||||||
|
assert(DataSpec::parseMod("x=2+3")
|
||||||
|
== (DataSpec::Modifier{"x", {2, 3, 4}}));
|
||||||
|
assert(DataSpec::parseMod("x=2+3x2")
|
||||||
|
== (DataSpec::Modifier{"x", {2, 4}}));
|
||||||
|
assert(DataSpec::parseMod("x=9,2+3x2")
|
||||||
|
== (DataSpec::Modifier{"x", {2, 4, 9}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_dataspec(void)
|
||||||
|
{
|
||||||
|
DataSpec spec("foo:t=0-2:s=0-1");
|
||||||
|
assert(spec.filename == "foo");
|
||||||
|
assert((spec.locations
|
||||||
|
== std::vector<DataSpec::Location>
|
||||||
|
{{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 1}}));
|
||||||
|
|
||||||
|
spec.set("bar");
|
||||||
|
assert(spec.filename == "bar");
|
||||||
|
assert((spec.locations
|
||||||
|
== std::vector<DataSpec::Location>
|
||||||
|
{{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 1}}));
|
||||||
|
|
||||||
|
spec.set(":t=0");
|
||||||
|
assert(spec.filename.empty());
|
||||||
|
assert((spec.locations
|
||||||
|
== std::vector<DataSpec::Location>
|
||||||
|
{{0, 0}, {0, 1}}));
|
||||||
|
|
||||||
|
spec.set(":s=1");
|
||||||
|
assert(spec.filename.empty());
|
||||||
|
assert((spec.locations
|
||||||
|
== std::vector<DataSpec::Location>
|
||||||
|
{{0, 1}}));
|
||||||
|
|
||||||
|
spec.set(":t=9");
|
||||||
|
assert(spec.filename.empty());
|
||||||
|
assert((spec.locations
|
||||||
|
== std::vector<DataSpec::Location>
|
||||||
|
{{9, 1}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[])
|
||||||
|
{
|
||||||
|
test_split();
|
||||||
|
test_parsemod();
|
||||||
|
test_dataspec();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user