changeset 13:b9d124a15926

To improve cache performance, the enigma machine rotors are now stored together with the reflector in a vector.
author Brian Neal <bgneal@gmail.com>
date Mon, 02 Jul 2012 19:14:36 -0500
parents 424111a36ed7
children 919b7a0d1802
files enigma/machine.cpp enigma/machine.h enigma/tests/test_plugboard.t.h
diffstat 3 files changed, 71 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/enigma/machine.cpp	Sun Jul 01 12:53:10 2012 -0500
+++ b/enigma/machine.cpp	Mon Jul 02 19:14:36 2012 -0500
@@ -18,10 +18,14 @@
       const rotor_vector& rv,
       std::shared_ptr<rotor> reflector,
       const plugboard& pb)
- : rotors(rv),
-   reflector(reflector),
+ : rotors(),
    pb(pb)
 {
+   rotors.push_back(*reflector);
+   for (const auto& r : rv)
+   {
+      rotors.push_back(*r);
+   }
    rotor_count_check();
 }
 
@@ -30,10 +34,14 @@
 enigma_machine::enigma_machine(
       const rotor_vector& rv,
       std::shared_ptr<rotor> reflector)
- : rotors(rv),
-   reflector(reflector),
+ : rotors(),
    pb()
 {
+   rotors.push_back(*reflector);
+   for (const auto& r : rv)
+   {
+      rotors.push_back(*r);
+   }
    rotor_count_check();
 }
 
@@ -45,26 +53,28 @@
       const std::string& reflector_name,
       const std::string& plugboard_settings)
  : rotors(),
-   reflector(create_reflector(reflector_name.c_str())),
    pb(plugboard_settings)
 {
+   const auto ukw(create_reflector(reflector_name.c_str()));
+   rotors.push_back(*ukw);
    for (const auto& name : rotor_types)
    {
-      rotors.push_back(create_rotor(name.c_str()));
+      const auto r(create_rotor(name.c_str()));
+      rotors.push_back(*r);
    }
    rotor_count_check();
 
    // if ring settings are supplied, there has to be one for each rotor
    if (!ring_settings.empty())
    {
-      if (rotors.size() != ring_settings.size())
+      if (rotors.size() - 1 != ring_settings.size())
       {
          throw enigma_machine_error("rotor/ring setting count mismatch");
       }
 
-      for (std::size_t i = 0; i < rotors.size(); ++i)
+      for (std::size_t i = 1; i < rotors.size(); ++i)
       {
-         rotors[i]->set_ring_setting(ring_settings[i]);
+         rotors[i].set_ring_setting(ring_settings[i - 1]);
       }
    }
 }
@@ -73,22 +83,24 @@
 
 void enigma_machine::rotor_count_check()
 {
-   if (rotors.size() != 3 && rotors.size() != 4)
+   // the first rotor is actually the reflector; so we should have a total
+   // of 4 or 5 rotors
+   if (rotors.size() != 4 && rotors.size() != 5)
    {
       throw enigma_machine_error("rotor count");
    }
 
-   if (rotors.size() == 3)
+   if (rotors.size() == 4)
    {
-      r_rotor = rotors[2].get();
-      m_rotor = rotors[1].get();
-      l_rotor = rotors[0].get();
+      r_rotor = &rotors[3];
+      m_rotor = &rotors[2];
+      l_rotor = &rotors[1];
    }
    else
    {
-      r_rotor = rotors[3].get();
-      m_rotor = rotors[2].get();
-      l_rotor = rotors[1].get();
+      r_rotor = &rotors[4];
+      m_rotor = &rotors[3];
+      l_rotor = &rotors[2];
    }
 }
 
@@ -98,11 +110,11 @@
 {
    std::ostringstream os;
 
-   os << reflector->name() << ' ';
+   os << rotors[0].name() << ' ';
 
-   for (const auto& r : rotors)
+   for (std::size_t i = 1; i < rotors.size(); ++i)
    {
-      os << r->name() << '/' << r->get_ring_setting() << ' ';
+      os << rotors[i].name() << '/' << rotors[i].get_ring_setting() << ' ';
    }
 
    os << get_display() << ' ' << (army ? pb.army_str() : pb.navy_str());
--- a/enigma/machine.h	Sun Jul 01 12:53:10 2012 -0500
+++ b/enigma/machine.h	Mon Jul 02 19:14:36 2012 -0500
@@ -47,22 +47,22 @@
       // set the rotor display (starting position) - 3 rotor version
       void set_display(char left, char mid, char right)
       {
-         assert(rotors.size() == 3);
+         assert(rotors.size() == 4);
 
-         rotors[0]->set_display(left);
-         rotors[1]->set_display(mid);
-         rotors[2]->set_display(right);
+         rotors[1].set_display(left);
+         rotors[2].set_display(mid);
+         rotors[3].set_display(right);
       }
 
       // set the rotor display (starting position) - 4 rotor version
       void set_display(char c0, char c1, char c2, char c3)
       {
-         assert(rotors.size() == 4);
+         assert(rotors.size() == 5);
 
-         rotors[0]->set_display(c0);
-         rotors[1]->set_display(c1);
-         rotors[2]->set_display(c2);
-         rotors[3]->set_display(c3);
+         rotors[1].set_display(c0);
+         rotors[2].set_display(c1);
+         rotors[3].set_display(c2);
+         rotors[4].set_display(c3);
       }
 
       // Set the rotor display (starting position) using a string; the
@@ -70,11 +70,11 @@
       // enigma_machine_error exception will be thrown:
       void set_display(const std::string& val)
       {
-         if (val.size() == 3 && rotors.size() == 3)
+         if (val.size() == 3 && rotors.size() == 4)
          {
             set_display(val[0], val[1], val[2]);
          }
-         else if (val.size() == 4 && rotors.size() == 4)
+         else if (val.size() == 4 && rotors.size() == 5)
          {
             set_display(val[0], val[1], val[2], val[3]);
          }
@@ -88,9 +88,9 @@
       std::string get_display() const
       {
          std::string result;
-         for (const auto& r : rotors)
+         for (std::size_t i = 1; i < rotors.size(); ++i)
          {
-            result += r->get_display();
+            result += rotors[i].get_display();
          }
          return result;
       }
@@ -143,8 +143,9 @@
       std::string navy_str() const { return str(false); }
 
    private:
-      rotor_vector rotors;
-      std::shared_ptr<rotor> reflector;
+      // Note that to improve cache performance, the rotors and reflectors are stored
+      // in a contiguous vector.
+      std::vector<rotor> rotors;    // rotor & reflector array
       plugboard pb;
       rotor* r_rotor;      // rightmost rotor
       rotor* m_rotor;      // 2nd to right rotor
@@ -188,21 +189,31 @@
       // Returns a lamp number to light (an integer 0-25).
       int electric_signal(int signal_num)
       {
-         int pos = pb.signal(signal_num);
+         int n = pb.signal(signal_num);
 
-         for (auto r = rotors.rbegin(); r != rotors.rend(); ++r)
+         if (rotors.size() == 4)    // 3 rotors + reflector
          {
-            pos = (*r)->signal_in(pos);
+            n = rotors[3].signal_in(n);
+            n = rotors[2].signal_in(n);
+            n = rotors[1].signal_in(n);
+            n = rotors[0].signal_in(n);   // reflector
+            n = rotors[1].signal_out(n);
+            n = rotors[2].signal_out(n);
+            n = rotors[3].signal_out(n);
          }
-
-         pos = reflector->signal_in(pos);
-
-         for (const auto& r : rotors)
+         else  // Kriegsmarine 4 rotor + reflector
          {
-            pos = r->signal_out(pos);
+            n = rotors[4].signal_in(n);
+            n = rotors[3].signal_in(n);
+            n = rotors[2].signal_in(n);
+            n = rotors[1].signal_in(n);
+            n = rotors[0].signal_in(n);   // reflector
+            n = rotors[1].signal_out(n);
+            n = rotors[2].signal_out(n);
+            n = rotors[3].signal_out(n);
+            n = rotors[4].signal_out(n);
          }
-
-         return pb.signal(pos);
+         return pb.signal(n);
       }
 
       std::string str(bool army) const;
--- a/enigma/tests/test_plugboard.t.h	Sun Jul 01 12:53:10 2012 -0500
+++ b/enigma/tests/test_plugboard.t.h	Mon Jul 02 19:14:36 2012 -0500
@@ -143,7 +143,7 @@
    void test_get_wiring()
    {
       plugboard pb;
-      alpha_int_array w(pb.get_wiring());
+      auto w(pb.get_wiring());
 
       for (int i = 0; i < 26; ++i)
       {
@@ -161,7 +161,7 @@
       std::swap(w[8], w[20]);
       std::swap(w[24], w[25]);
 
-      alpha_int_array w1(pb.get_wiring());
+      auto w1(pb.get_wiring());
       for (int i = 0; i < 26; ++i)
       {
          TS_ASSERT_EQUALS(w[i], w1[i]);
@@ -182,7 +182,7 @@
       plugboard pb;
       pb.set_wiring(w);
 
-      alpha_int_array w2 = pb.get_wiring();
+      auto w2 = pb.get_wiring();
       TS_ASSERT_EQUALS(w, w2);
    }