Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libgambatte/src/minkeeper.h
2 views
1
/***************************************************************************
2
* Copyright (C) 2009 by Sindre AamÄs *
3
* [email protected] *
4
* *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License version 2 as *
7
* published by the Free Software Foundation. *
8
* *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License version 2 for more details. *
13
* *
14
* You should have received a copy of the GNU General Public License *
15
* version 2 along with this program; if not, write to the *
16
* Free Software Foundation, Inc., *
17
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18
***************************************************************************/
19
#ifndef MINKEEPER_H
20
#define MINKEEPER_H
21
22
#include <algorithm>
23
#include "newstate.h"
24
25
namespace MinKeeperUtil {
26
template<int n> struct CeiledLog2 { enum { R = 1 + CeiledLog2<(n + 1) / 2>::R }; };
27
template<> struct CeiledLog2<1> { enum { R = 0 }; };
28
29
template<int v, int n> struct RoundedDiv2n { enum { R = RoundedDiv2n<(v + 1) / 2, n - 1>::R }; };
30
template<int v> struct RoundedDiv2n<v,1> { enum { R = v }; };
31
32
template<template<int> class T, int n> struct Sum { enum { R = T<n-1>::R + Sum<T, n-1>::R }; };
33
template<template<int> class T> struct Sum<T,0> { enum { R = 0 }; };
34
}
35
36
// Keeps track of minimum value identified by id as values change.
37
// Higher ids prioritized (as min value) if values are equal. Can easily be reversed by swapping < for <=.
38
// Higher ids can be faster to change when the number of ids isn't a power of 2.
39
// Thus the ones that change more frequently should have higher ids if priority allows it.
40
template<int ids>
41
class MinKeeper {
42
enum { LEVELS = MinKeeperUtil::CeiledLog2<ids>::R };
43
template<int l> struct Num { enum { R = MinKeeperUtil::RoundedDiv2n<ids, LEVELS + 1 - l>::R }; };
44
template<int l> struct Sum { enum { R = MinKeeperUtil::Sum<Num, l>::R }; };
45
46
template<int id, int level>
47
struct UpdateValue {
48
enum { P = Sum<level-1>::R + id };
49
enum { C0 = Sum<level>::R + id * 2 };
50
51
static void updateValue(MinKeeper<ids> &m) {
52
// GCC 4.3 generates better code with the ternary operator on i386.
53
m.a[P] = (id * 2 + 1 == Num<level>::R || m.values[m.a[C0]] < m.values[m.a[C0 + 1]]) ? m.a[C0] : m.a[C0 + 1];
54
UpdateValue<id / 2, level - 1>::updateValue(m);
55
}
56
};
57
58
template<int id>
59
struct UpdateValue<id,0> {
60
static void updateValue(MinKeeper<ids> &m) {
61
m.minValue_ = m.values[m.a[0]];
62
}
63
};
64
65
class UpdateValueLut {
66
template<int id, int dummy> struct FillLut {
67
static void fillLut(UpdateValueLut & l) {
68
l.lut_[id] = updateValue<id>;
69
FillLut<id-1,dummy>::fillLut(l);
70
}
71
};
72
73
template<int dummy> struct FillLut<-1,dummy> {
74
static void fillLut(UpdateValueLut &) {}
75
};
76
77
void (*lut_[Num<LEVELS-1>::R])(MinKeeper<ids>&);
78
79
public:
80
UpdateValueLut() { FillLut<Num<LEVELS-1>::R-1,0>::fillLut(*this); }
81
void call(int id, MinKeeper<ids> &mk) const { lut_[id](mk); }
82
};
83
84
static UpdateValueLut updateValueLut;
85
unsigned long values[ids];
86
unsigned long minValue_;
87
int a[Sum<LEVELS>::R];
88
89
template<int id> static void updateValue(MinKeeper<ids> &m);
90
91
public:
92
explicit MinKeeper(unsigned long initValue = 0xFFFFFFFF);
93
94
int min() const { return a[0]; }
95
unsigned long minValue() const { return minValue_; }
96
97
template<int id>
98
void setValue(const unsigned long cnt) {
99
values[id] = cnt;
100
updateValue<id / 2>(*this);
101
}
102
103
void setValue(const int id, const unsigned long cnt) {
104
values[id] = cnt;
105
updateValueLut.call(id >> 1, *this);
106
}
107
108
unsigned long value(const int id) const { return values[id]; }
109
110
// not sure if i understood everything in minkeeper correctly, so something might be missing here?
111
template<bool isReader>
112
void SyncState(gambatte::NewState *ns)
113
{
114
NSS(values);
115
NSS(minValue_);
116
NSS(a);
117
}
118
};
119
120
template<int ids> typename MinKeeper<ids>::UpdateValueLut MinKeeper<ids>::updateValueLut;
121
122
template<int ids>
123
MinKeeper<ids>::MinKeeper(const unsigned long initValue) {
124
std::fill(values, values + ids, initValue);
125
126
for (int i = 0; i < Num<LEVELS-1>::R; ++i) {
127
a[Sum<LEVELS-1>::R + i] = (i * 2 + 1 == ids || values[i * 2] < values[i * 2 + 1]) ? i * 2 : i * 2 + 1;
128
}
129
130
int n = Num<LEVELS-1>::R;
131
int off = Sum<LEVELS-1>::R;
132
133
while (off) {
134
const int pn = (n + 1) >> 1;
135
const int poff = off - pn;
136
137
for (int i = 0; i < pn; ++i) {
138
a[poff + i] = (i * 2 + 1 == n ||
139
values[a[off + i * 2]] < values[a[off + i * 2 + 1]]) ?
140
a[off + i * 2] : a[off + i * 2 + 1];
141
}
142
143
off = poff;
144
n = pn;
145
}
146
147
minValue_ = values[a[0]];
148
}
149
150
template<int ids>
151
template<int id>
152
void MinKeeper<ids>::updateValue(MinKeeper<ids> &m) {
153
m.a[Sum<LEVELS-1>::R + id] = (id * 2 + 1 == ids || m.values[id * 2] < m.values[id * 2 + 1]) ? id * 2 : id * 2 + 1;
154
UpdateValue<id / 2, LEVELS-1>::updateValue(m);
155
}
156
157
#endif
158
159