Created
March 8, 2014 16:39
-
-
Save qzchenwl/9434642 to your computer and use it in GitHub Desktop.
SICP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cassert> | |
#include <functional> | |
#include <iostream> | |
#include <memory> | |
#include <string> | |
#include <vector> | |
using namespace std; | |
int inverter_delay = 2; | |
int and_gate_delay = 3; | |
int or_gate_delay = 5; | |
typedef function<void()> procedure; | |
class time_segment | |
{ | |
public: | |
time_segment(int time, const vector<procedure>& procedures): | |
_time(time), _procedures(procedures) {} | |
int segment_time() const | |
{ | |
return _time; | |
} | |
vector<procedure>& segment_queue() | |
{ | |
return _procedures; | |
} | |
private: | |
int _time; | |
vector<procedure> _procedures; | |
}; | |
class agenda | |
{ | |
public: | |
agenda(): _current_time(0), _segments() {} | |
bool empty_agenda() const | |
{ | |
return _segments.empty(); | |
} | |
int current_time() const | |
{ | |
return _current_time; | |
} | |
void add_to_agenda(int time, const procedure& action) | |
{ | |
bool done = false; | |
auto it = _segments.begin(); | |
for(; it != _segments.end(); it++) | |
{ | |
if (it->segment_time() > time) | |
{ | |
break; | |
} | |
if (it->segment_time() == time) | |
{ | |
it->segment_queue().push_back(action); | |
done = true; | |
} | |
} | |
if (!done) | |
{ | |
vector<procedure> actions = {action}; | |
time_segment segment(time, actions); | |
_segments.insert(it, segment); | |
} | |
} | |
const procedure& first_agenda_item() | |
{ | |
assert(!empty_agenda() && !_segments.front().segment_queue().empty()); | |
_current_time = _segments.front().segment_time(); | |
return _segments.front().segment_queue().front(); | |
} | |
void remove_first_agenda_item() | |
{ | |
assert(!empty_agenda() && !_segments.front().segment_queue().empty()); | |
auto& q = _segments.front().segment_queue(); | |
q.erase(q.begin()); | |
if (q.empty()) | |
{ | |
_segments.erase(_segments.begin()); | |
} | |
} | |
private: | |
int _current_time; | |
vector<time_segment> _segments; | |
}; | |
agenda the_agenda; | |
void after_delay(int delay, procedure proc) | |
{ | |
the_agenda.add_to_agenda(the_agenda.current_time() + delay, proc); | |
} | |
void propagate() | |
{ | |
if (the_agenda.empty_agenda()) | |
{ | |
return; | |
} | |
auto first_item = the_agenda.first_agenda_item(); | |
first_item(); | |
the_agenda.remove_first_agenda_item(); | |
propagate(); | |
} | |
class wire | |
{ | |
public: | |
wire(): _signal_value(0), _action_procedures() {} | |
int get_signal() const | |
{ | |
return _signal_value; | |
} | |
void set_signal(int new_value) | |
{ | |
if (_signal_value != new_value) | |
{ | |
_signal_value = new_value; | |
for(auto& proc : _action_procedures) | |
{ | |
proc(); | |
} | |
} | |
} | |
void add_action(const procedure& proc) | |
{ | |
_action_procedures.push_back(proc); | |
proc(); | |
} | |
private: | |
int _signal_value; | |
vector<procedure> _action_procedures; | |
}; | |
typedef const shared_ptr<wire>& wire_ptr; | |
void probe(string name, wire_ptr wire) | |
{ | |
wire->add_action([=] | |
{ | |
cout << endl; | |
cout << name << " " << the_agenda.current_time(); | |
cout << " New-value = " << wire->get_signal(); | |
}); | |
} | |
void inverter(wire_ptr input, wire_ptr output) | |
{ | |
auto invert_input = [=] | |
{ | |
auto new_value = input->get_signal() == 0 ? 1 : 0; | |
after_delay(inverter_delay, [=]{output->set_signal(new_value);}); | |
}; | |
input->add_action(invert_input); | |
} | |
void and_gate(wire_ptr a1, wire_ptr a2, wire_ptr output) | |
{ | |
auto and_action_procedure = [=] | |
{ | |
auto new_value = a1->get_signal() == 1 && a2->get_signal() == 1 ? 1 : 0; | |
after_delay(and_gate_delay, [=]{output->set_signal(new_value);}); | |
}; | |
a1->add_action(and_action_procedure); | |
a2->add_action(and_action_procedure); | |
} | |
void or_gate(wire_ptr a1, wire_ptr a2, wire_ptr output) | |
{ | |
auto and_action_procedure = [=] | |
{ | |
auto new_value = a1->get_signal() == 1 || a2->get_signal() == 1 ? 1 : 0; | |
after_delay(or_gate_delay, [=]{output->set_signal(new_value);}); | |
}; | |
a1->add_action(and_action_procedure); | |
a2->add_action(and_action_procedure); | |
} | |
void half_adder(wire_ptr a, wire_ptr b, wire_ptr s, wire_ptr c) | |
{ | |
auto d = make_shared<wire>(); | |
auto e = make_shared<wire>(); | |
or_gate(a, b, d); | |
and_gate(a, b, c); | |
inverter(c, e); | |
and_gate(d, e, s); | |
} | |
void full_adder(wire_ptr a, wire_ptr b, wire_ptr c_in, wire_ptr sum, wire_ptr c_out) | |
{ | |
auto s = make_shared<wire>(); | |
auto c1 = make_shared<wire>(); | |
auto c2 = make_shared<wire>(); | |
half_adder(b, c_in, s, c1); | |
half_adder(a, s, sum, c2); | |
or_gate(c1, c2, c_out); | |
} | |
int main(int argc, char const* argv[]) | |
{ | |
auto input_1 = make_shared<wire>(); | |
auto input_2 = make_shared<wire>(); | |
auto sum = make_shared<wire>(); | |
auto carry = make_shared<wire>(); | |
probe("sum", sum); | |
probe("carry", carry); | |
half_adder(input_1, input_2, sum, carry); | |
input_1->set_signal(1); | |
propagate(); | |
input_2->set_signal(1); | |
propagate(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment