From eb924780ab1440c9fdb3f57ba9ead2c7b06dba59 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 6 Aug 2019 23:50:02 +0200 Subject: [PATCH] Refactor dataspecs to allow them to be used for other things too. --- lib/dataspec.cc | 56 +++++++++++++++++------- lib/dataspec.h | 56 ++++++++++++++++++------ lib/fluxsink/fluxsink.cc | 2 +- lib/fluxsink/fluxsink.h | 4 +- lib/fluxsource/fluxsource.cc | 2 +- lib/fluxsource/fluxsource.h | 4 +- lib/reader.cc | 8 ++-- lib/writer.cc | 4 +- src/fe-fluxtoau.cc | 5 ++- src/fe-fluxtovcd.cc | 5 ++- src/fe-rpm.cc | 3 +- tests/dataspec.cc | 84 ++++++++++++++++++++++++------------ 12 files changed, 160 insertions(+), 73 deletions(-) diff --git a/lib/dataspec.cc b/lib/dataspec.cc index d033b1d6..07e39e3d 100644 --- a/lib/dataspec.cc +++ b/lib/dataspec.cc @@ -74,28 +74,54 @@ void DataSpec::set(const std::string& spec) 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") && (mod.name != "d")) - Error() << fmt::format("unknown data modifier '{}'", mod.name); modifiers[mod.name] = mod; } + } +} - const auto& drives = modifiers["d"].data; - if (drives.size() != 1) - Error() << "you must specify exactly one drive"; - drive = *drives.begin(); +FluxSpec::FluxSpec(const DataSpec& spec) +{ + filename = spec.filename; - const auto& tracks = modifiers["t"].data; - const auto& sides = modifiers["s"].data; - for (auto track : tracks) - { - for (auto side : sides) - locations.push_back({ drive, track, side }); - } + locations.clear(); + + const auto& drives = spec.modifiers.at("d").data; + if (drives.size() != 1) + Error() << "you must specify exactly one drive"; + drive = *drives.begin(); + + const auto& tracks = spec.modifiers.at("t").data; + const auto& sides = spec.modifiers.at("s").data; + for (auto track : tracks) + { + for (auto side : sides) + locations.push_back({ drive, track, side }); + } + + for (const auto& e : spec.modifiers) + { + const auto name = e.second.name; + if ((name != "t") && (name != "s") && (name != "d")) + Error() << fmt::format("unknown fluxspec modifier '{}'", name); + } +} + +ImageSpec::ImageSpec(const DataSpec& spec) +{ + filename = spec.filename; + + tracks = spec.modifiers.at("t").only(); + heads = spec.modifiers.at("h").only(); + sectors = spec.modifiers.at("s").only(); + + for (const auto& e : spec.modifiers) + { + const auto name = e.second.name; + if ((name != "t") && (name != "h") && (name != "s")) + Error() << fmt::format("unknown fluxspec modifier '{}'", name); } } diff --git a/lib/dataspec.h b/lib/dataspec.h index d94096b4..efce7e72 100644 --- a/lib/dataspec.h +++ b/lib/dataspec.h @@ -4,19 +4,6 @@ class DataSpec { public: - struct Location - { - unsigned drive; - unsigned track; - unsigned side; - - bool operator == (const Location& other) const - { return (drive == other.drive) && (track == other.track) && (side == other.side); } - - bool operator != (const Location& other) const - { return (drive != other.drive) || (track != other.track) || (side != other.side); } - }; - struct Modifier { std::string name; @@ -28,6 +15,13 @@ public: bool operator != (const Modifier& other) const { return (name != other.name) || (data != other.data); } + + unsigned only() const + { + if (data.size() != 1) + Error() << "modifier " << name << " can only have one value"; + return *(data.begin()); + } }; public: @@ -44,9 +38,43 @@ public: std::string filename; std::map modifiers; +}; + +class FluxSpec +{ +public: + struct Location + { + unsigned drive; + unsigned track; + unsigned side; + + bool operator == (const Location& other) const + { return (drive == other.drive) && (track == other.track) && (side == other.side); } + + bool operator != (const Location& other) const + { return (drive != other.drive) || (track != other.track) || (side != other.side); } + }; + +public: + FluxSpec(const DataSpec& dataspec); + +public: + std::string filename; std::vector locations; unsigned drive; - unsigned revolutions; +}; + +class ImageSpec +{ +public: + ImageSpec(const DataSpec& dataspec); + +public: + std::string filename; + unsigned tracks; + unsigned heads; + unsigned sectors; }; static inline std::ostream& operator << (std::ostream& os, const DataSpec& dataSpec) diff --git a/lib/fluxsink/fluxsink.cc b/lib/fluxsink/fluxsink.cc index c6877b96..3d217e2d 100644 --- a/lib/fluxsink/fluxsink.cc +++ b/lib/fluxsink/fluxsink.cc @@ -10,7 +10,7 @@ static bool ends_with(const std::string& value, const std::string& ending) return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); } -std::unique_ptr FluxSink::create(const DataSpec& spec) +std::unique_ptr FluxSink::create(const FluxSpec& spec) { const auto& filename = spec.filename; diff --git a/lib/fluxsink/fluxsink.h b/lib/fluxsink/fluxsink.h index 6518af61..ea45109f 100644 --- a/lib/fluxsink/fluxsink.h +++ b/lib/fluxsink/fluxsink.h @@ -2,7 +2,7 @@ #define FLUXSINK_H class Fluxmap; -class DataSpec; +class FluxSpec; class FluxSink { @@ -14,7 +14,7 @@ private: static std::unique_ptr createHardwareFluxSink(unsigned drive); public: - static std::unique_ptr create(const DataSpec& spec); + static std::unique_ptr create(const FluxSpec& spec); public: virtual void writeFlux(int track, int side, Fluxmap& fluxmap) = 0; diff --git a/lib/fluxsource/fluxsource.cc b/lib/fluxsource/fluxsource.cc index 436a5e39..f8551fe4 100644 --- a/lib/fluxsource/fluxsource.cc +++ b/lib/fluxsource/fluxsource.cc @@ -10,7 +10,7 @@ static bool ends_with(const std::string& value, const std::string& ending) return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); } -std::unique_ptr FluxSource::create(const DataSpec& spec) +std::unique_ptr FluxSource::create(const FluxSpec& spec) { const auto& filename = spec.filename; diff --git a/lib/fluxsource/fluxsource.h b/lib/fluxsource/fluxsource.h index de50fb79..ac3c3865 100644 --- a/lib/fluxsource/fluxsource.h +++ b/lib/fluxsource/fluxsource.h @@ -6,7 +6,7 @@ extern FlagGroup hardwareFluxSourceFlags; class Fluxmap; -class DataSpec; +class FluxSpec; class FluxSource { @@ -19,7 +19,7 @@ private: static std::unique_ptr createStreamFluxSource(const std::string& path); public: - static std::unique_ptr create(const DataSpec& spec); + static std::unique_ptr create(const FluxSpec& spec); public: virtual std::unique_ptr readFlux(int track, int side) = 0; diff --git a/lib/reader.cc b/lib/reader.cc index b2285c39..862f69e6 100644 --- a/lib/reader.cc +++ b/lib/reader.cc @@ -71,9 +71,9 @@ void Track::readFluxmap() std::vector> readTracks() { - const DataSpec& dataSpec = source; + const FluxSpec spec(source); - std::cout << "Reading from: " << dataSpec << std::endl; + std::cout << "Reading from: " << source << std::endl; setHardwareFluxSourceDensity(highDensityFlag); @@ -92,10 +92,10 @@ std::vector> readTracks() ); } - std::shared_ptr fluxSource = FluxSource::create(dataSpec); + std::shared_ptr fluxSource = FluxSource::create(spec); std::vector> tracks; - for (const auto& location : dataSpec.locations) + for (const auto& location : spec.locations) { auto track = std::make_unique(location.track, location.side); track->fluxsource = fluxSource; diff --git a/lib/writer.cc b/lib/writer.cc index b497732d..44f85d70 100644 --- a/lib/writer.cc +++ b/lib/writer.cc @@ -36,9 +36,9 @@ void setWriterDefaultDest(const std::string& dest) void writeTracks( const std::function(int track, int side)> producer) { - const DataSpec& spec = dest; + const FluxSpec spec(dest); - std::cout << "Writing to: " << spec << std::endl; + std::cout << "Writing to: " << dest << std::endl; setHardwareFluxSourceDensity(highDensityFlag); setHardwareFluxSinkDensity(highDensityFlag); diff --git a/src/fe-fluxtoau.cc b/src/fe-fluxtoau.cc index 2ed06107..7957ebd4 100644 --- a/src/fe-fluxtoau.cc +++ b/src/fe-fluxtoau.cc @@ -34,14 +34,15 @@ int mainConvertFluxToAu(int argc, const char* argv[]) { flags.parseFlags(argc, argv); - const auto& locations = source.get().locations; + FluxSpec spec(source); + const auto& locations = spec.locations; if (locations.size() != 1) Error() << "the source dataspec must contain exactly one track (two sides count as two tracks)"; const auto& location = *(locations.begin()); std::cerr << "Reading source flux...\n"; setHardwareFluxSourceDensity(highDensityFlag); - std::shared_ptr fluxsource = FluxSource::create(source); + std::shared_ptr fluxsource = FluxSource::create(spec); const auto& fluxmap = fluxsource->readFlux(location.track, location.side); unsigned totalTicks = fluxmap->ticks() + 2; unsigned channels = withIndex ? 2 : 1; diff --git a/src/fe-fluxtovcd.cc b/src/fe-fluxtovcd.cc index afe261fb..3c235b1e 100644 --- a/src/fe-fluxtovcd.cc +++ b/src/fe-fluxtovcd.cc @@ -30,14 +30,15 @@ int mainConvertFluxToVcd(int argc, const char* argv[]) { flags.parseFlags(argc, argv); - const auto& locations = source.get().locations; + const FluxSpec spec(source); + const auto& locations = spec.locations; if (locations.size() != 1) Error() << "the source dataspec must contain exactly one track (two sides count as two tracks)"; const auto& location = *(locations.begin()); std::cerr << "Reading source flux...\n"; setHardwareFluxSourceDensity(highDensityFlag); - std::shared_ptr fluxsource = FluxSource::create(source); + std::shared_ptr fluxsource = FluxSource::create(spec); const auto& fluxmap = fluxsource->readFlux(location.track, location.side); std::cerr << "Writing destination VCD...\n"; diff --git a/src/fe-rpm.cc b/src/fe-rpm.cc index 16bd1f6d..86bc7b27 100644 --- a/src/fe-rpm.cc +++ b/src/fe-rpm.cc @@ -14,7 +14,8 @@ int mainRpm(int argc, const char* argv[]) { flags.parseFlags(argc, argv); - usbSetDrive(source.get().drive, false); + FluxSpec spec(source); + usbSetDrive(spec.drive, false); nanoseconds_t period = usbGetRotationalPeriod(); std::cout << "Rotational period is " << period/1000 << " ms (" << 60e6/period << " rpm)" << std::endl; diff --git a/tests/dataspec.cc b/tests/dataspec.cc index 3a85a838..94d2ca53 100644 --- a/tests/dataspec.cc +++ b/tests/dataspec.cc @@ -33,48 +33,78 @@ static void test_parsemod(void) == (DataSpec::Modifier{"x", {2, 4, 9}})); } -static void test_dataspec(void) +static void test_fluxspec(void) { DataSpec spec("foo:t=0-2:s=0-1:d=0"); - assert(spec.filename == "foo"); - assert((spec.locations - == std::vector - {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 2, 0}, {0, 2, 1}})); - assert((std::string)spec == "foo:d=0:s=0-1:t=0-2"); + + { + FluxSpec fspec(spec); + assert(fspec.filename == "foo"); + assert((fspec.locations + == std::vector + {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 2, 0}, {0, 2, 1}})); + assert((std::string)spec == "foo:d=0:s=0-1:t=0-2"); + } spec.set("bar"); - assert(spec.filename == "bar"); - assert((spec.locations - == std::vector - {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 2, 0}, {0, 2, 1}})); - assert((std::string)spec == "bar:d=0:s=0-1:t=0-2"); + { + FluxSpec fspec(spec); + assert(fspec.filename == "bar"); + assert((fspec.locations + == std::vector + {{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 2, 0}, {0, 2, 1}})); + assert((std::string)spec == "bar:d=0:s=0-1:t=0-2"); + } spec.set(":t=0"); - assert(spec.filename.empty()); - assert((spec.locations - == std::vector - {{0, 0, 0}, {0, 0, 1}})); - assert((std::string)spec == ":d=0:s=0-1:t=0"); + { + FluxSpec fspec(spec); + assert(fspec.filename.empty()); + assert((fspec.locations + == std::vector + {{0, 0, 0}, {0, 0, 1}})); + assert((std::string)spec == ":d=0:s=0-1:t=0"); + } spec.set(":s=1"); - assert(spec.filename.empty()); - assert((spec.locations - == std::vector - {{0, 0, 1}})); - assert((std::string)spec == ":d=0:s=1:t=0"); + { + FluxSpec fspec(spec); + assert(fspec.filename.empty()); + assert((fspec.locations + == std::vector + {{0, 0, 1}})); + assert((std::string)spec == ":d=0:s=1:t=0"); + } spec.set(":t=9:d=1"); - assert(spec.filename.empty()); - assert((spec.locations - == std::vector - {{1, 9, 1}})); - assert((std::string)spec == ":d=1:s=1:t=9"); + { + FluxSpec fspec(spec); + assert(fspec.filename.empty()); + assert((fspec.locations + == std::vector + {{1, 9, 1}})); + assert((std::string)spec == ":d=1:s=1:t=9"); + } +} + +static void test_imagespec(void) +{ + DataSpec spec("foo:t=9:h=2:s=99"); + + { + ImageSpec ispec(spec); + assert(ispec.filename == "foo"); + assert(ispec.tracks == 9); + assert(ispec.heads == 2); + assert(ispec.sectors == 99); + } } int main(int argc, const char* argv[]) { test_split(); test_parsemod(); - test_dataspec(); + test_fluxspec(); + test_imagespec(); return 0; }