mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-23 05:29:23 +00:00
Shift back to original name.
This commit is contained in:
parent
d36a88dd11
commit
1d8bc41724
@ -1,174 +0,0 @@
|
||||
//
|
||||
// RangeDispatcher.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 29/05/2023.
|
||||
// Copyright © 2023 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef RangeDispatcher_hpp
|
||||
#define RangeDispatcher_hpp
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Reflection {
|
||||
|
||||
/*!
|
||||
Calls @c t.dispatch<c>(args...) as efficiently as possible.
|
||||
*/
|
||||
template <typename TargetT, typename... Args> void dispatch(TargetT &t, uint8_t c, Args &&... args) {
|
||||
#define Opt(x) case x: t.template dispatch<x>(std::forward<Args>(args)...); break
|
||||
#define Opt4(x) Opt(x + 0x00); Opt(x + 0x01); Opt(x + 0x02); Opt(x + 0x03)
|
||||
#define Opt16(x) Opt4(x + 0x00); Opt4(x + 0x04); Opt4(x + 0x08); Opt4(x + 0x0c)
|
||||
#define Opt64(x) Opt16(x + 0x00); Opt16(x + 0x10); Opt16(x + 0x20); Opt16(x + 0x30)
|
||||
#define Opt256(x) Opt64(x + 0x00); Opt64(x + 0x40); Opt64(x + 0x80); Opt64(x + 0xc0)
|
||||
|
||||
switch(c) {
|
||||
Opt256(0);
|
||||
}
|
||||
|
||||
#undef Opt256
|
||||
#undef Opt64
|
||||
#undef Opt16
|
||||
#undef Opt4
|
||||
#undef Opt
|
||||
}
|
||||
|
||||
// Yes, macros, yuck. But I want an actual switch statement for the dispatch to start
|
||||
// and to allow a simple [[fallthrough]] through all subsequent steps up until end.
|
||||
// So I don't think I have much in the way of options here.
|
||||
//
|
||||
// Sensible choices by the optimiser are assumed.
|
||||
#define index2(n) index(n); index(n+1);
|
||||
#define index4(n) index2(n); index2(n+2);
|
||||
#define index8(n) index4(n); index4(n+4);
|
||||
#define index16(n) index8(n); index8(n+8);
|
||||
#define index32(n) index16(n); index16(n+16);
|
||||
#define index64(n) index32(n); index32(n+32);
|
||||
#define index128(n) index64(n); index64(n+64);
|
||||
#define index256(n) index128(n); index128(n+128);
|
||||
#define index512(n) index256(n); index256(n+256);
|
||||
#define index1024(n) index512(n); index512(n+512);
|
||||
#define index2048(n) index1024(n); index1024(n+1024);
|
||||
|
||||
#define switch_indices(x) switch(x) { default: assert(false); index2048(0); }
|
||||
static constexpr int switch_max = 2048;
|
||||
|
||||
/// Provides glue for a run of calls like:
|
||||
///
|
||||
/// SequencerT.perform<0>(...)
|
||||
/// SequencerT.perform<1>(...)
|
||||
/// SequencerT.perform<2>(...)
|
||||
/// ...etc...
|
||||
///
|
||||
/// Allowing the caller to execute any subrange of the calls.
|
||||
template <typename SequencerT>
|
||||
struct RangeDispatcher {
|
||||
static_assert(SequencerT::max < switch_max);
|
||||
|
||||
/// Perform @c target.perform<n>() for the input range `begin <= n < end`.
|
||||
template <typename... Args>
|
||||
static void dispatch(SequencerT &target, int begin, int end, Args&&... args) {
|
||||
|
||||
// Minor optimisation: do a comparison with end once outside the loop and if it implies so
|
||||
// then do no further comparisons within the loop. This is somewhat targetted at expected
|
||||
// use cases.
|
||||
if(end < SequencerT::max) {
|
||||
dispatch<true>(target, begin, end, args...);
|
||||
} else {
|
||||
dispatch<false>(target, begin, end, args...);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool use_end, typename... Args> static void dispatch(SequencerT &target, int begin, int end, Args&&... args) {
|
||||
#define index(n) \
|
||||
case n: \
|
||||
if constexpr (n <= SequencerT::max) { \
|
||||
if constexpr (n == SequencerT::max) return; \
|
||||
if constexpr (n < SequencerT::max) { \
|
||||
if(use_end && end == n) return; \
|
||||
} \
|
||||
target.template perform<n>(args...); \
|
||||
} \
|
||||
[[fallthrough]];
|
||||
|
||||
switch_indices(begin);
|
||||
|
||||
#undef index
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// Uses a classifier to divide a range into typed subranges and issues calls to a target of the form:
|
||||
///
|
||||
/// * begin<type>(location) upon entering a new region;
|
||||
/// * end<type>(location) upon entering a region; and
|
||||
/// * advance<type>(distance) in as many chunks as required to populate the inside of the region.
|
||||
///
|
||||
/// @c begin and @c end have iterator-style semantics: begin's location will be the first location in the relevant subrange and
|
||||
/// end's will be the first location not in the relevant subrange.
|
||||
template <typename ClassifierT, typename TargetT>
|
||||
struct SubrangeDispatcher {
|
||||
static_assert(ClassifierT::max < switch_max);
|
||||
|
||||
static void dispatch(TargetT &target, int begin, int end) {
|
||||
#define index(n) \
|
||||
case n: \
|
||||
if constexpr (n <= ClassifierT::max) { \
|
||||
constexpr auto region = ClassifierT::region(n); \
|
||||
if constexpr (n == find_begin(n)) { \
|
||||
if(n >= end) { \
|
||||
return; \
|
||||
} \
|
||||
target.template begin<region>(n); \
|
||||
} \
|
||||
if constexpr (n == find_end(n) - 1) { \
|
||||
const auto clipped_begin = std::max(begin, find_begin(n)); \
|
||||
const auto clipped_end = std::min(end, find_end(n)); \
|
||||
target.template advance<region>(clipped_end - clipped_begin); \
|
||||
\
|
||||
if(clipped_end == n + 1) { \
|
||||
target.template end<region>(n + 1); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
[[fallthrough]];
|
||||
|
||||
switch_indices(begin);
|
||||
|
||||
#undef index
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int find_begin(int n) {
|
||||
const auto type = ClassifierT::region(n);
|
||||
while(n && ClassifierT::region(n - 1) == type) --n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static constexpr int find_end(int n) {
|
||||
const auto type = ClassifierT::region(n);
|
||||
while(n < ClassifierT::max && ClassifierT::region(n) == type) ++n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
#undef switch_indices
|
||||
|
||||
#undef index2
|
||||
#undef index4
|
||||
#undef index8
|
||||
#undef index16
|
||||
#undef index32
|
||||
#undef index64
|
||||
#undef index128
|
||||
#undef index256
|
||||
#undef index512
|
||||
#undef index1024
|
||||
#undef index2048
|
||||
|
||||
}
|
||||
|
||||
#endif /* RangeDispatcher_hpp */
|
@ -1102,7 +1102,6 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
428168372A16C25C008ECD27 /* LineLayout.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LineLayout.hpp; sourceTree = "<group>"; };
|
||||
428168382A254FBE008ECD27 /* RangeDispatcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RangeDispatcher.hpp; sourceTree = "<group>"; };
|
||||
428168392A37AFB4008ECD27 /* DispatcherTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DispatcherTests.mm; sourceTree = "<group>"; };
|
||||
42AD552E2A0C4D5000ACE410 /* 68000.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 68000.hpp; sourceTree = "<group>"; };
|
||||
42AD55302A0C4D5000ACE410 /* 68000Storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 68000Storage.hpp; sourceTree = "<group>"; };
|
||||
@ -2783,10 +2782,10 @@
|
||||
4B3AF7CF2413470E00873C0B /* Reflection */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B3AF7D02413470E00873C0B /* Enum.hpp */,
|
||||
4B3AF7D12413472200873C0B /* Struct.hpp */,
|
||||
4B47F6C4241C87A100ED06F7 /* Struct.cpp */,
|
||||
4BDA7F8129C4C223007A10A5 /* Dispatcher.hpp */,
|
||||
4B3AF7D02413470E00873C0B /* Enum.hpp */,
|
||||
4B47F6C4241C87A100ED06F7 /* Struct.cpp */,
|
||||
4B3AF7D12413472200873C0B /* Struct.hpp */,
|
||||
);
|
||||
name = Reflection;
|
||||
path = ../../Reflection;
|
||||
@ -4975,7 +4974,6 @@
|
||||
4BB06B211F316A3F00600C7A /* ForceInline.hpp */,
|
||||
4B80214322EE7C3E00068002 /* JustInTime.hpp */,
|
||||
4B644ED023F0FB55006C0CC5 /* ScanSynchroniser.hpp */,
|
||||
428168382A254FBE008ECD27 /* RangeDispatcher.hpp */,
|
||||
4B449C942063389900A095C8 /* TimeTypes.hpp */,
|
||||
4B996B2D2496DAC2001660EF /* VSyncPredictor.hpp */,
|
||||
);
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include "RangeDispatcher.hpp"
|
||||
#include "Dispatcher.hpp"
|
||||
#include "../../../InstructionSets/6809/OperationMapper.hpp"
|
||||
|
||||
using namespace InstructionSet::M6809;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include "RangeDispatcher.hpp"
|
||||
#include "Dispatcher.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
@ -17,14 +17,7 @@
|
||||
@interface DispatcherTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation DispatcherTests {
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
}
|
||||
@implementation DispatcherTests
|
||||
|
||||
struct DoStep {
|
||||
static constexpr int max = 100;
|
||||
|
@ -9,11 +9,165 @@
|
||||
#ifndef Dispatcher_hpp
|
||||
#define Dispatcher_hpp
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Reflection {
|
||||
|
||||
/*!
|
||||
Calls @c t.dispatch<c>(args...) as efficiently as possible.
|
||||
*/
|
||||
template <typename TargetT, typename... Args> void dispatch(TargetT &t, uint8_t c, Args &&... args) {
|
||||
#define Opt(x) case x: t.template dispatch<x>(std::forward<Args>(args)...); break
|
||||
#define Opt4(x) Opt(x + 0x00); Opt(x + 0x01); Opt(x + 0x02); Opt(x + 0x03)
|
||||
#define Opt16(x) Opt4(x + 0x00); Opt4(x + 0x04); Opt4(x + 0x08); Opt4(x + 0x0c)
|
||||
#define Opt64(x) Opt16(x + 0x00); Opt16(x + 0x10); Opt16(x + 0x20); Opt16(x + 0x30)
|
||||
#define Opt256(x) Opt64(x + 0x00); Opt64(x + 0x40); Opt64(x + 0x80); Opt64(x + 0xc0)
|
||||
|
||||
switch(c) {
|
||||
Opt256(0);
|
||||
}
|
||||
|
||||
#undef Opt256
|
||||
#undef Opt64
|
||||
#undef Opt16
|
||||
#undef Opt4
|
||||
#undef Opt
|
||||
}
|
||||
|
||||
// Yes, macros, yuck. But I want an actual switch statement for the dispatch to start
|
||||
// and to allow a simple [[fallthrough]] through all subsequent steps up until end.
|
||||
// So I don't think I have much in the way of options here.
|
||||
//
|
||||
// Sensible choices by the optimiser are assumed.
|
||||
#define index2(n) index(n); index(n+1);
|
||||
#define index4(n) index2(n); index2(n+2);
|
||||
#define index8(n) index4(n); index4(n+4);
|
||||
#define index16(n) index8(n); index8(n+8);
|
||||
#define index32(n) index16(n); index16(n+16);
|
||||
#define index64(n) index32(n); index32(n+32);
|
||||
#define index128(n) index64(n); index64(n+64);
|
||||
#define index256(n) index128(n); index128(n+128);
|
||||
#define index512(n) index256(n); index256(n+256);
|
||||
#define index1024(n) index512(n); index512(n+512);
|
||||
#define index2048(n) index1024(n); index1024(n+1024);
|
||||
|
||||
#define switch_indices(x) switch(x) { default: assert(false); index2048(0); }
|
||||
static constexpr int switch_max = 2048;
|
||||
|
||||
/// Provides glue for a run of calls like:
|
||||
///
|
||||
/// SequencerT.perform<0>(...)
|
||||
/// SequencerT.perform<1>(...)
|
||||
/// SequencerT.perform<2>(...)
|
||||
/// ...etc...
|
||||
///
|
||||
/// Allowing the caller to execute any subrange of the calls.
|
||||
template <typename SequencerT>
|
||||
struct RangeDispatcher {
|
||||
static_assert(SequencerT::max < switch_max);
|
||||
|
||||
/// Perform @c target.perform<n>() for the input range `begin <= n < end`.
|
||||
template <typename... Args>
|
||||
static void dispatch(SequencerT &target, int begin, int end, Args&&... args) {
|
||||
|
||||
// Minor optimisation: do a comparison with end once outside the loop and if it implies so
|
||||
// then do no further comparisons within the loop. This is somewhat targetted at expected
|
||||
// use cases.
|
||||
if(end < SequencerT::max) {
|
||||
dispatch<true>(target, begin, end, args...);
|
||||
} else {
|
||||
dispatch<false>(target, begin, end, args...);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool use_end, typename... Args> static void dispatch(SequencerT &target, int begin, int end, Args&&... args) {
|
||||
#define index(n) \
|
||||
case n: \
|
||||
if constexpr (n <= SequencerT::max) { \
|
||||
if constexpr (n == SequencerT::max) return; \
|
||||
if constexpr (n < SequencerT::max) { \
|
||||
if(use_end && end == n) return; \
|
||||
} \
|
||||
target.template perform<n>(args...); \
|
||||
} \
|
||||
[[fallthrough]];
|
||||
|
||||
switch_indices(begin);
|
||||
|
||||
#undef index
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// Uses a classifier to divide a range into typed subranges and issues calls to a target of the form:
|
||||
///
|
||||
/// * begin<type>(location) upon entering a new region;
|
||||
/// * end<type>(location) upon entering a region; and
|
||||
/// * advance<type>(distance) in as many chunks as required to populate the inside of the region.
|
||||
///
|
||||
/// @c begin and @c end have iterator-style semantics: begin's location will be the first location in the relevant subrange and
|
||||
/// end's will be the first location not in the relevant subrange.
|
||||
template <typename ClassifierT, typename TargetT>
|
||||
struct SubrangeDispatcher {
|
||||
static_assert(ClassifierT::max < switch_max);
|
||||
|
||||
static void dispatch(TargetT &target, int begin, int end) {
|
||||
#define index(n) \
|
||||
case n: \
|
||||
if constexpr (n <= ClassifierT::max) { \
|
||||
constexpr auto region = ClassifierT::region(n); \
|
||||
if constexpr (n == find_begin(n)) { \
|
||||
if(n >= end) { \
|
||||
return; \
|
||||
} \
|
||||
target.template begin<region>(n); \
|
||||
} \
|
||||
if constexpr (n == find_end(n) - 1) { \
|
||||
const auto clipped_begin = std::max(begin, find_begin(n)); \
|
||||
const auto clipped_end = std::min(end, find_end(n)); \
|
||||
target.template advance<region>(clipped_end - clipped_begin); \
|
||||
\
|
||||
if(clipped_end == n + 1) { \
|
||||
target.template end<region>(n + 1); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
[[fallthrough]];
|
||||
|
||||
switch_indices(begin);
|
||||
|
||||
#undef index
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int find_begin(int n) {
|
||||
const auto type = ClassifierT::region(n);
|
||||
while(n && ClassifierT::region(n - 1) == type) --n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static constexpr int find_end(int n) {
|
||||
const auto type = ClassifierT::region(n);
|
||||
while(n < ClassifierT::max && ClassifierT::region(n) == type) ++n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
#undef switch_indices
|
||||
|
||||
#undef index2
|
||||
#undef index4
|
||||
#undef index8
|
||||
#undef index16
|
||||
#undef index32
|
||||
#undef index64
|
||||
#undef index128
|
||||
#undef index256
|
||||
#undef index512
|
||||
#undef index1024
|
||||
#undef index2048
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user