From 8f937ceac8dc438e95a8aeb76637725a1dab5a4b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Dec 2016 07:42:43 -0500 Subject: [PATCH] Made an attempt to come up with a data structure that actually makes sense (though perhaps this is textbook `list` rather than `vector` stuff? I guess it depends on the frequency I expect inserts to occur versus reads) and to implement inserts. Though the `Period`s aren't yet honoured. --- Storage/Disk/PCMPatchedTrack.cpp | 73 +++++++++++++++++++++++++++++--- Storage/Disk/PCMPatchedTrack.hpp | 22 +++++++--- Storage/Storage.hpp | 1 + 3 files changed, 82 insertions(+), 14 deletions(-) diff --git a/Storage/Disk/PCMPatchedTrack.cpp b/Storage/Disk/PCMPatchedTrack.cpp index 46e2e0737..ddc43de8d 100644 --- a/Storage/Disk/PCMPatchedTrack.cpp +++ b/Storage/Disk/PCMPatchedTrack.cpp @@ -11,18 +11,77 @@ using namespace Storage::Disk; PCMPatchedTrack::PCMPatchedTrack(std::shared_ptr underlying_track) : - underlying_track_(underlying_track), - active_patch_((size_t)-1) -{} - -void PCMPatchedTrack::add_segment(const Time &start_position, const PCMSegment &segment) + underlying_track_(underlying_track) { - patches_.emplace_back(start_position, segment); + Time zero(0); + Time one(1); + periods_.emplace_back(zero, one, zero, nullptr); + active_period_ = &periods_.back(); +} + +void PCMPatchedTrack::add_segment(const Time &start_time, const PCMSegment &segment) +{ + event_sources_.emplace_back(segment); + + Time zero(0); + Period insertion_period(start_time, start_time + event_sources_.back().get_length(), zero, &event_sources_.back()); + + // the new segment may wrap around, so divide it up into track-length parts if required + Time one = Time(1); + while(insertion_period.end_time > one) + { + Time next_end_time = insertion_period.end_time - one; + insertion_period.end_time = one; + insert_period(insertion_period); + + insertion_period.start_time = zero; + insertion_period.end_time = next_end_time; + } + insert_period(insertion_period); +} + +void PCMPatchedTrack::insert_period(const Period &period) +{ + // find the existing period that the new period starts in + size_t start_index = 0; + while(periods_[start_index].start_time >= period.end_time) start_index++; + + // find the existing period that the new period end in + size_t end_index = 0; + while(periods_[end_index].end_time < period.end_time) end_index++; + + // perform a division if called for + if(start_index == end_index) + { + Period right_period = periods_[start_index]; + + Time adjustment = period.start_time - right_period.start_time; + right_period.end_time += adjustment; + right_period.segment_start_time += adjustment; + + periods_[start_index].end_time = period.start_time; + periods_.insert(periods_.begin() + (int)start_index + 1, period); + periods_.insert(periods_.begin() + (int)start_index + 2, right_period); + } + else + { + // perform a left chop on the thing at the start and a right chop on the thing at the end + periods_[start_index].end_time = period.start_time; + + Time adjustment = period.start_time - periods_[end_index].start_time; + periods_[end_index].end_time += adjustment; + periods_[end_index].segment_start_time += adjustment; + + // remove anything in between + periods_.erase(periods_.begin() + (int)start_index + 1, periods_.begin() + (int)end_index - 1); + + // insert the new period + periods_.insert(periods_.begin() + (int)start_index + 1, period); + } } Track::Event PCMPatchedTrack::get_next_event() { -// if(active_patch_ == (size_t)-1) return underlying_track_->get_next_event(); } diff --git a/Storage/Disk/PCMPatchedTrack.hpp b/Storage/Disk/PCMPatchedTrack.hpp index 7b3721708..d26f46de4 100644 --- a/Storage/Disk/PCMPatchedTrack.hpp +++ b/Storage/Disk/PCMPatchedTrack.hpp @@ -10,6 +10,7 @@ #define PCMPatchedTrack_hpp #include "PCMTrack.hpp" +#include "PCMSegment.hpp" namespace Storage { namespace Disk { @@ -29,7 +30,7 @@ class PCMPatchedTrack: public Track { Replaces whatever is currently on the track from @c start_position to @c start_position + segment length with the contents of @c segment. */ - void add_segment(const Time &start_position, const PCMSegment &segment); + void add_segment(const Time &start_time, const PCMSegment &segment); // To satisfy Storage::Disk::Track Event get_next_event(); @@ -37,13 +38,20 @@ class PCMPatchedTrack: public Track { private: std::shared_ptr underlying_track_; - struct Patch { - Time start_position; - PCMSegment segment; - Patch(const Time &start_position, const PCMSegment &segment) : start_position(start_position), segment(segment) {} + std::vector event_sources_; + + struct Period { + Time start_time, end_time; + Time segment_start_time; + PCMSegmentEventSource *event_source; // nullptr => use the underlying track + + Period(const Time &start_time, const Time &end_time, const Time &segment_start_time, PCMSegmentEventSource *event_source) : + start_time(start_time), end_time(end_time), segment_start_time(segment_start_time), event_source(event_source) {} }; - std::vector patches_; - size_t active_patch_; + std::vector periods_; + Period *active_period_; + + void insert_period(const Period &period); }; } diff --git a/Storage/Storage.hpp b/Storage/Storage.hpp index b8418c97b..e86c0bfea 100644 --- a/Storage/Storage.hpp +++ b/Storage/Storage.hpp @@ -20,6 +20,7 @@ namespace Storage { struct Time { unsigned int length, clock_rate; Time() : length(0), clock_rate(1) {} + Time(unsigned int int_value) : length(int_value), clock_rate(1) {} Time(unsigned int length, unsigned int clock_rate) : length(length), clock_rate(clock_rate) {} /*!