Skip to content

Instantly share code, notes, and snippets.

@qzchenwl
Created March 8, 2014 16:39
Show Gist options
  • Save qzchenwl/9434642 to your computer and use it in GitHub Desktop.
Save qzchenwl/9434642 to your computer and use it in GitHub Desktop.
SICP
#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