1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-11-25 04:18:05 +00:00
Files
CLK/Storage/Disk/Track/Track.hpp
2025-09-04 21:25:12 -04:00

118 lines
3.2 KiB
C++

//
// Track.hpp
// Clock Signal
//
// Created by Thomas Harte on 22/09/2017.
// Copyright 2017 Thomas Harte. All rights reserved.
//
#pragma once
#include "Storage/Storage.hpp"
#include <memory> // An arbitrary choice to get visibility of std::hash.
#include <tuple>
namespace Storage::Disk {
/*!
Contains a head position, with some degree of sub-integral precision.
*/
class HeadPosition {
public:
/// Creates an instance decribing position @c value at a resolution of @c scale ticks per track.
constexpr HeadPosition(int value, int scale) : position_(value * (4/scale)) {}
constexpr explicit HeadPosition(int value) : HeadPosition(value, 1) {}
constexpr HeadPosition() : HeadPosition(0) {}
/// @returns the whole number part of the position.
constexpr int as_int() const { return position_ >> 2; }
/// @returns n where n/2 is the head position.
constexpr int as_half() const { return position_ >> 1; }
/// @returns n where n/4 is the head position.
constexpr int as_quarter() const { return position_; }
/// @returns the head position at maximal but unspecified precision.
constexpr int as_largest() const { return as_quarter(); }
HeadPosition &operator +=(const HeadPosition &rhs) {
position_ += rhs.position_;
return *this;
}
constexpr auto operator <=>(const HeadPosition&) const = default;
private:
int position_ = 0;
};
/*!
Models a single track on a disk as a series of events, each event being of arbitrary length
and resulting in either a flux transition or the sensing of an index hole.
Subclasses should implement @c get_next_event.
*/
class Track {
public:
virtual ~Track() = default;
/*!
Describes the location of a track, implementing @c < and @c == (with std::hash specialised elsewhere)
to allow for use in both regular and unordered sets and maps.
*/
struct Address {
int head;
HeadPosition position;
constexpr auto operator <=>(const Address&) const = default;
constexpr Address(int head, HeadPosition position) : head(head), position(position) {}
};
/*!
Describes a detectable track event: either a flux transition or the passing of the index hole,
along with the length of time between the previous event and its occurance.
The sum of all lengths of time across an entire track should be 1; if an event is said to be
1/3 away then that means 1/3 of a rotation.
*/
struct Event {
enum Type {
IndexHole, FluxTransition
} type;
Time length;
};
/*!
@returns the next event that will be detected during rotation of this disk.
*/
virtual Event get_next_event() = 0;
/*!
Jumps to the start of the fist event that will occur after @c time_since_index_hole.
@returns the time jumped to.
*/
virtual float seek_to(float time_since_index_hole) = 0;
/*!
The virtual copy constructor pattern; returns a copy of the Track.
*/
virtual Track *clone() const = 0;
};
}
template <>
struct std::hash<Storage::Disk::HeadPosition> {
size_t operator()(const Storage::Disk::HeadPosition &position) const {
return size_t(position.as_largest());
}
};
template <>
struct std::hash<Storage::Disk::Track::Address> {
size_t operator()(const Storage::Disk::Track::Address &address) const {
std::hash<Storage::Disk::HeadPosition> position_hasher;
return size_t(address.head << 16) ^ position_hasher(address.position);
}
};