mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-13 00:25:26 +00:00
Attempts to provide saner sequence point behaviour.
This commit is contained in:
@@ -26,6 +26,21 @@
|
|||||||
as and when sequence points are hit. Callers can use will_flush() to predict these.
|
as and when sequence points are hit. Callers can use will_flush() to predict these.
|
||||||
*/
|
*/
|
||||||
template <class T, int multiplier = 1, int divider = 1, class LocalTimeScale = HalfCycles, class TargetTimeScale = LocalTimeScale> class JustInTimeActor {
|
template <class T, int multiplier = 1, int divider = 1, class LocalTimeScale = HalfCycles, class TargetTimeScale = LocalTimeScale> class JustInTimeActor {
|
||||||
|
private:
|
||||||
|
class SequencePointAwareDeleter {
|
||||||
|
public:
|
||||||
|
explicit SequencePointAwareDeleter(JustInTimeActor<T, multiplier, divider, LocalTimeScale, TargetTimeScale> *actor) : actor_(actor) {}
|
||||||
|
|
||||||
|
void operator ()(const T *const) const {
|
||||||
|
if constexpr (has_sequence_points<T>::value) {
|
||||||
|
actor_->update_sequence_point();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JustInTimeActor<T, multiplier, divider, LocalTimeScale, TargetTimeScale> *const actor_;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructs a new JustInTimeActor using the same construction arguments as the included object.
|
/// Constructs a new JustInTimeActor using the same construction arguments as the included object.
|
||||||
template<typename... Args> JustInTimeActor(Args&&... args) : object_(std::forward<Args>(args)...) {}
|
template<typename... Args> JustInTimeActor(Args&&... args) : object_(std::forward<Args>(args)...) {}
|
||||||
@@ -41,25 +56,29 @@ template <class T, int multiplier = 1, int divider = 1, class LocalTimeScale = H
|
|||||||
|
|
||||||
if constexpr (has_sequence_points<T>::value) {
|
if constexpr (has_sequence_points<T>::value) {
|
||||||
time_until_event_ -= rhs;
|
time_until_event_ -= rhs;
|
||||||
if(time_until_event_ < LocalTimeScale(0)) {
|
if(time_until_event_ <= LocalTimeScale(0)) {
|
||||||
flush();
|
flush();
|
||||||
|
update_sequence_point();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flushes all accumulated time and returns a pointer to the included object.
|
/// Flushes all accumulated time and returns a pointer to the included object.
|
||||||
forceinline T *operator->() {
|
///
|
||||||
|
/// If this object provides sequence points, checks for changes to the next
|
||||||
|
/// sequence point upon deletion of the pointer.
|
||||||
|
forceinline auto operator->() {
|
||||||
flush();
|
flush();
|
||||||
// TODO: I actually need to update time_until_event_ after the access occurring here has ended.
|
return std::unique_ptr<T, SequencePointAwareDeleter>(&object_, SequencePointAwareDeleter(this));
|
||||||
// So I guess I need to supply some sort of proxy object and jump on its destructor?
|
|
||||||
return &object_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Acts exactly as per the standard ->, but preserves constness.
|
/// Acts exactly as per the standard ->, but preserves constness.
|
||||||
forceinline const T *operator -> () const {
|
///
|
||||||
|
/// Despite being const, this will flush the object and, if relevant, update the next sequence point.
|
||||||
|
forceinline auto operator -> () const {
|
||||||
auto non_const_this = const_cast<JustInTimeActor<T, multiplier, divider, LocalTimeScale, TargetTimeScale> *>(this);
|
auto non_const_this = const_cast<JustInTimeActor<T, multiplier, divider, LocalTimeScale, TargetTimeScale> *>(this);
|
||||||
non_const_this->flush();
|
non_const_this->flush();
|
||||||
return &object_;
|
return std::unique_ptr<const T, SequencePointAwareDeleter>(&object_, SequencePointAwareDeleter(non_const_this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a pointer to the included object without flushing time.
|
/// Returns a pointer to the included object without flushing time.
|
||||||
@@ -68,6 +87,8 @@ template <class T, int multiplier = 1, int divider = 1, class LocalTimeScale = H
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Flushes all accumulated time.
|
/// Flushes all accumulated time.
|
||||||
|
///
|
||||||
|
/// This does not affect this actor's record of when the next sequence point will occur.
|
||||||
forceinline void flush() {
|
forceinline void flush() {
|
||||||
if(!is_flushed_) {
|
if(!is_flushed_) {
|
||||||
is_flushed_ = true;
|
is_flushed_ = true;
|
||||||
@@ -79,12 +100,6 @@ template <class T, int multiplier = 1, int divider = 1, class LocalTimeScale = H
|
|||||||
if(duration > TargetTimeScale(0))
|
if(duration > TargetTimeScale(0))
|
||||||
object_.run_for(duration);
|
object_.run_for(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this probably shouldn't be per-flush(), merely per-operator-> and when a previous point is passed.
|
|
||||||
if constexpr (has_sequence_points<T>::value) {
|
|
||||||
time_until_event_ = object_.get_next_sequence_point();
|
|
||||||
assert(time_until_event_ > LocalTimeScale(0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +117,14 @@ template <class T, int multiplier = 1, int divider = 1, class LocalTimeScale = H
|
|||||||
return time_until_event_;
|
return time_until_event_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates this template's record of the next sequence point.
|
||||||
|
void update_sequence_point() {
|
||||||
|
if constexpr (has_sequence_points<T>::value) {
|
||||||
|
time_until_event_ = object_.get_next_sequence_point();
|
||||||
|
assert(time_until_event_ > LocalTimeScale(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T object_;
|
T object_;
|
||||||
LocalTimeScale time_since_update_, time_until_event_;
|
LocalTimeScale time_since_update_, time_until_event_;
|
||||||
|
@@ -116,6 +116,7 @@ Cycles VideoBase::get_next_sequence_point() const {
|
|||||||
if(row < 200) return Cycles(CyclesPerLine + sequence_point_offset - cycles_into_row);
|
if(row < 200) return Cycles(CyclesPerLine + sequence_point_offset - cycles_into_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate distance to the relevant point in row 0.
|
||||||
return Cycles(CyclesPerLine + sequence_point_offset - cycles_into_row + (Lines - row - 1)*CyclesPerLine);
|
return Cycles(CyclesPerLine + sequence_point_offset - cycles_into_row + (Lines - row - 1)*CyclesPerLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +209,9 @@ void VideoBase::output_row(int row, int start, int end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Post an interrupt if requested.
|
// Post an interrupt if requested.
|
||||||
if(line_control_ & 0x40) set_interrupts(0x20);
|
if(line_control_ & 0x40) {
|
||||||
|
set_interrupts(0x20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(next_pixel_) {
|
if(next_pixel_) {
|
||||||
|
Reference in New Issue
Block a user