Convert bpf_module structures to use vector instead of map for tables

It was bothering me that a whole bunch of accesses to the tables were
based on a string hash lookup, in addition to the vectors that were kept
to convert ids to names. Switch those around, as well as the api
internally.

Signed-off-by: Brenden Blanco <bblanco@plumgrid.com>
diff --git a/src/cc/bpf_module.cc b/src/cc/bpf_module.cc
index 707e979..448ee23 100644
--- a/src/cc/bpf_module.cc
+++ b/src/cc/bpf_module.cc
@@ -225,9 +225,10 @@
   // separate module to hold the reader functions
   auto m = make_unique<Module>("sscanf", *ctx_);
 
+  size_t id = 0;
   for (auto table : *tables_) {
-    table_names_.push_back(table.first);
-    GlobalValue *gvar = mod_->getNamedValue(table.first);
+    table_names_[table.name] = id++;
+    GlobalValue *gvar = mod_->getNamedValue(table.name);
     if (!gvar) continue;
     if (PointerType *pt = dyn_cast<PointerType>(gvar->getType())) {
       if (StructType *st = dyn_cast<StructType>(pt->getElementType())) {
@@ -366,66 +367,66 @@
 }
 
 size_t BPFModule::num_tables() const {
-  return table_names_.size();
+  return tables_->size();
 }
 
 int BPFModule::table_fd(const string &name) const {
-  auto table_it = tables_->find(name);
-  if (table_it == tables_->end()) return -1;
-  return table_it->second.fd;
+  auto it = table_names_.find(name);
+  if (it == table_names_.end()) return -1;
+  return table_fd(it->second);
 }
 
 int BPFModule::table_fd(size_t id) const {
-  if (id >= table_names_.size()) return -1;
-  return table_fd(table_names_[id]);
+  if (id >= tables_->size()) return -1;
+  return (*tables_)[id].fd;
 }
 
 const char * BPFModule::table_name(size_t id) const {
-  if (id >= table_names_.size()) return nullptr;
-  return table_names_[id].c_str();
+  if (id >= tables_->size()) return nullptr;
+  return (*tables_)[id].name.c_str();
 }
 
 const char * BPFModule::table_key_desc(size_t id) const {
-  if (id >= table_names_.size()) return nullptr;
-  return table_key_desc(table_names_[id]);
+  if (b_loader_) return nullptr;
+  if (id >= tables_->size()) return nullptr;
+  return (*tables_)[id].key_desc.c_str();
 }
 
 const char * BPFModule::table_key_desc(const string &name) const {
-  if (b_loader_) return nullptr;
-  auto table_it = tables_->find(name);
-  if (table_it == tables_->end()) return nullptr;
-  return table_it->second.key_desc.c_str();
+  auto it = table_names_.find(name);
+  if (it == table_names_.end()) return nullptr;
+  return table_key_desc(it->second);
 }
 
 const char * BPFModule::table_leaf_desc(size_t id) const {
-  if (id >= table_names_.size()) return nullptr;
-  return table_leaf_desc(table_names_[id]);
+  if (b_loader_) return nullptr;
+  if (id >= tables_->size()) return nullptr;
+  return (*tables_)[id].leaf_desc.c_str();
 }
 
 const char * BPFModule::table_leaf_desc(const string &name) const {
-  if (b_loader_) return nullptr;
-  auto table_it = tables_->find(name);
-  if (table_it == tables_->end()) return nullptr;
-  return table_it->second.leaf_desc.c_str();
+  auto it = table_names_.find(name);
+  if (it == table_names_.end()) return nullptr;
+  return table_leaf_desc(it->second);
 }
 size_t BPFModule::table_key_size(size_t id) const {
-  if (id >= table_names_.size()) return 0;
-  return table_key_size(table_names_[id]);
+  if (id >= tables_->size()) return 0;
+  return (*tables_)[id].key_size;
 }
 size_t BPFModule::table_key_size(const string &name) const {
-  auto table_it = tables_->find(name);
-  if (table_it == tables_->end()) return 0;
-  return table_it->second.key_size;
+  auto it = table_names_.find(name);
+  if (it == table_names_.end()) return 0;
+  return table_key_size(it->second);
 }
 
 size_t BPFModule::table_leaf_size(size_t id) const {
-  if (id >= table_names_.size()) return 0;
-  return table_leaf_size(table_names_[id]);
+  if (id >= tables_->size()) return 0;
+  return (*tables_)[id].leaf_size;
 }
 size_t BPFModule::table_leaf_size(const string &name) const {
-  auto table_it = tables_->find(name);
-  if (table_it == tables_->end()) return 0;
-  return table_it->second.leaf_size;
+  auto it = table_names_.find(name);
+  if (it == table_names_.end()) return 0;
+  return table_leaf_size(it->second);
 }
 
 // load a B file, which comes in two parts
diff --git a/src/cc/bpf_module.h b/src/cc/bpf_module.h
index f8d0a7a..2a4d26d 100644
--- a/src/cc/bpf_module.h
+++ b/src/cc/bpf_module.h
@@ -87,8 +87,8 @@
   std::unique_ptr<BLoader> b_loader_;
   std::unique_ptr<ClangLoader> clang_loader_;
   std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_;
-  std::unique_ptr<std::map<std::string, TableDesc>> tables_;
-  std::vector<std::string> table_names_;
+  std::unique_ptr<std::vector<TableDesc>> tables_;
+  std::map<std::string, size_t> table_names_;
   std::vector<std::string> function_names_;
   std::map<llvm::Type *, llvm::Function *> readers_;
 };
diff --git a/src/cc/frontends/b/codegen_llvm.cc b/src/cc/frontends/b/codegen_llvm.cc
index 26cc063..f470e81 100644
--- a/src/cc/frontends/b/codegen_llvm.cc
+++ b/src/cc/frontends/b/codegen_llvm.cc
@@ -1218,7 +1218,7 @@
   return mkstatus(0);
 }
 
-StatusTuple CodegenLLVM::visit(Node* root, map<string, TableDesc> &tables) {
+StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) {
   scopes_->set_current(scopes_->top_state());
   scopes_->set_current(scopes_->top_var());
 
@@ -1232,13 +1232,14 @@
   //TRY2(print_parser());
 
   for (auto table : tables_) {
-    TableDesc desc = {
+    tables.push_back({
+      table.first->id_->name_,
       table_fds_[table.first],
       table.first->key_type_->bit_width_ >> 3,
       table.first->leaf_type_->bit_width_ >> 3,
       table.first->size_,
-    };
-    tables[table.first->id_->name_] = desc;
+      "", "",
+    });
   }
   return mkstatus(0);
 }
diff --git a/src/cc/frontends/b/codegen_llvm.h b/src/cc/frontends/b/codegen_llvm.h
index d63375f..47ffef9 100644
--- a/src/cc/frontends/b/codegen_llvm.h
+++ b/src/cc/frontends/b/codegen_llvm.h
@@ -63,7 +63,7 @@
   EXPAND_NODES(VISIT)
 #undef VISIT
 
-  virtual STATUS_RETURN visit(Node* n, std::map<string, TableDesc> &tables);
+  virtual STATUS_RETURN visit(Node* n, std::vector<TableDesc> &tables);
 
   int get_table_fd(const std::string &name) const;
 
diff --git a/src/cc/frontends/b/loader.cc b/src/cc/frontends/b/loader.cc
index cd7ea64..92d32fc 100644
--- a/src/cc/frontends/b/loader.cc
+++ b/src/cc/frontends/b/loader.cc
@@ -21,9 +21,9 @@
 #include "table_desc.h"
 
 using std::get;
-using std::map;
 using std::string;
 using std::unique_ptr;
+using std::vector;
 
 namespace ebpf {
 
@@ -34,7 +34,7 @@
 }
 
 int BLoader::parse(llvm::Module *mod, const string &filename, const string &proto_filename,
-                   unique_ptr<map<string, TableDesc>> *tables) {
+                   unique_ptr<vector<TableDesc>> *tables) {
   int rc;
 
   proto_parser_ = make_unique<ebpf::cc::Parser>(proto_filename);
@@ -61,7 +61,7 @@
     return -1;
   }
 
-  *tables = make_unique<map<string, TableDesc>>();
+  *tables = make_unique<vector<TableDesc>>();
 
   codegen_ = ebpf::make_unique<ebpf::cc::CodegenLLVM>(mod, parser_->scopes_.get(), proto_parser_->scopes_.get());
   ret = codegen_->visit(parser_->root_node_, **tables);
diff --git a/src/cc/frontends/b/loader.h b/src/cc/frontends/b/loader.h
index 50ef0da..d928023 100644
--- a/src/cc/frontends/b/loader.h
+++ b/src/cc/frontends/b/loader.h
@@ -38,7 +38,7 @@
   BLoader();
   ~BLoader();
   int parse(llvm::Module *mod, const std::string &filename, const std::string &proto_filename,
-            std::unique_ptr<std::map<std::string, TableDesc>> *tables);
+            std::unique_ptr<std::vector<TableDesc>> *tables);
  private:
   std::unique_ptr<cc::Parser> parser_;
   std::unique_ptr<cc::Parser> proto_parser_;
diff --git a/src/cc/frontends/clang/b_frontend_action.cc b/src/cc/frontends/clang/b_frontend_action.cc
index 8c3330a..14bad3b 100644
--- a/src/cc/frontends/clang/b_frontend_action.cc
+++ b/src/cc/frontends/clang/b_frontend_action.cc
@@ -87,65 +87,7 @@
   return true;
 }
 
-BScanfVisitor::BScanfVisitor(ASTContext &C)
-    : C(C), n_args_(0) {}
-
-bool BScanfVisitor::VisitFieldDecl(FieldDecl *D) {
-  args_ += "&val->" + D->getName().str();
-  ++n_args_;
-  return true;
-}
-
-bool BScanfVisitor::TraverseRecordDecl(RecordDecl *D) {
-  // skip children, handled in Visit...
-  if (!WalkUpFromRecordDecl(D))
-    return false;
-  return true;
-}
-
-bool BScanfVisitor::VisitRecordDecl(RecordDecl *D) {
-  if (type_.empty())
-    type_ = "struct " + D->getDefinition()->getName().str();
-  fmt_ += "{ ";
-  for (auto F : D->getDefinition()->fields()) {
-    TraverseDecl(F);
-    if (F->isBitField())
-      fmt_ += ", " + to_string(F->getBitWidthValue(C));
-    fmt_ += ", ";
-    args_ += ", ";
-  }
-  if (!D->getDefinition()->field_empty()) {
-    fmt_.erase(fmt_.end() - 2);
-    args_.erase(args_.end() - 2);
-  }
-  fmt_ += "}";
-  return true;
-}
-bool BScanfVisitor::VisitTagType(const TagType *T) {
-  return TraverseDecl(T->getDecl()->getDefinition());
-}
-bool BScanfVisitor::VisitTypedefType(const TypedefType *T) {
-  return TraverseDecl(T->getDecl());
-}
-bool BScanfVisitor::VisitBuiltinType(const BuiltinType *T) {
-  if (type_.empty()) {
-    type_ = T->getName(C.getPrintingPolicy());
-    args_ += "val";
-    ++n_args_;
-  }
-  fmt_ += "%i";
-  return true;
-}
-void BScanfVisitor::finalize(string &result) {
-  result  = "int read_entry(const char *str, void *buf) {\n";
-  result += "  " + type_ + " *val = buf;\n";
-  result += "  int n = sscanf(str, \"" + fmt_ + "\", " + args_ + ");\n";
-  result += "  if (n < " + std::to_string(n_args_) + ") return -1;\n";
-  result += "  return 0;\n";
-  result += "}\n";
-}
-
-BTypeVisitor::BTypeVisitor(ASTContext &C, Rewriter &rewriter, map<string, TableDesc> &tables)
+BTypeVisitor::BTypeVisitor(ASTContext &C, Rewriter &rewriter, vector<TableDesc> &tables)
     : C(C), rewriter_(rewriter), out_(llvm::errs()), tables_(tables) {
 }
 
@@ -200,13 +142,15 @@
         string args = rewriter_.getRewrittenText(argRange);
 
         // find the table fd, which was opened at declaration time
-        auto table_it = tables_.find(Ref->getDecl()->getName());
+        auto table_it = tables_.begin();
+        for (; table_it != tables_.end(); ++table_it)
+          if (table_it->name == Ref->getDecl()->getName()) break;
         if (table_it == tables_.end()) {
           C.getDiagnostics().Report(Ref->getLocEnd(), diag::err_expected)
               << "initialized handle for bpf_table";
           return false;
         }
-        string fd = to_string(table_it->second.fd);
+        string fd = to_string(table_it->fd);
         string prefix, suffix;
         string map_update_policy = "BPF_ANY";
         string txt;
@@ -419,7 +363,10 @@
       return false;
     }
     const RecordDecl *RD = R->getDecl()->getDefinition();
+
     TableDesc table;
+    table.name = Decl->getName();
+
     unsigned i = 0;
     for (auto F : RD->fields()) {
       size_t sz = C.getTypeSize(F->getType()) >> 3;
@@ -428,19 +375,11 @@
         BMapDeclVisitor visitor(C, table.key_desc);
         if (!visitor.TraverseType(F->getType()))
           return false;
-        BScanfVisitor scanf_visitor(C);
-        if (!scanf_visitor.TraverseType(F->getType()))
-          return false;
-        scanf_visitor.finalize(table.key_reader);
       } else if (F->getName() == "leaf") {
         table.leaf_size = sz;
         BMapDeclVisitor visitor(C, table.leaf_desc);
         if (!visitor.TraverseType(F->getType()))
           return false;
-        BScanfVisitor scanf_visitor(C);
-        if (!scanf_visitor.TraverseType(F->getType()))
-          return false;
-        scanf_visitor.finalize(table.leaf_reader);
       } else if (F->getName() == "data") {
         table.max_entries = sz / table.leaf_size;
       }
@@ -472,7 +411,7 @@
            << "valid bpf fd";
       return false;
     }
-    tables_[Decl->getName()] = std::move(table);
+    tables_.push_back(std::move(table));
   } else if (const PointerType *P = Decl->getType()->getAs<PointerType>()) {
     // if var is a pointer to a packet type, clone the annotation into the var
     // decl so that the packet dext/dins rewriter can catch it
@@ -489,7 +428,7 @@
   return true;
 }
 
-BTypeConsumer::BTypeConsumer(ASTContext &C, Rewriter &rewriter, map<string, TableDesc> &tables)
+BTypeConsumer::BTypeConsumer(ASTContext &C, Rewriter &rewriter, vector<TableDesc> &tables)
     : visitor_(C, rewriter, tables) {
 }
 
@@ -500,7 +439,7 @@
 }
 
 BFrontendAction::BFrontendAction(llvm::raw_ostream &os)
-    : rewriter_(new Rewriter), os_(os), tables_(new map<string, TableDesc>) {
+    : rewriter_(new Rewriter), os_(os), tables_(new vector<TableDesc>) {
 }
 
 void BFrontendAction::EndSourceFileAction() {
diff --git a/src/cc/frontends/clang/b_frontend_action.h b/src/cc/frontends/clang/b_frontend_action.h
index 6491326..b21e72a 100644
--- a/src/cc/frontends/clang/b_frontend_action.h
+++ b/src/cc/frontends/clang/b_frontend_action.h
@@ -53,25 +53,6 @@
   std::string &result_;
 };
 
-// Helper visitor for constructing a fscanf routine for key/leaf decl
-class BScanfVisitor : public clang::RecursiveASTVisitor<BScanfVisitor> {
- public:
-  explicit BScanfVisitor(clang::ASTContext &C);
-  bool TraverseRecordDecl(clang::RecordDecl *Decl);
-  bool VisitRecordDecl(clang::RecordDecl *Decl);
-  bool VisitFieldDecl(clang::FieldDecl *Decl);
-  bool VisitBuiltinType(const clang::BuiltinType *T);
-  bool VisitTypedefType(const clang::TypedefType *T);
-  bool VisitTagType(const clang::TagType *T);
-  void finalize(std::string &result);
- private:
-  clang::ASTContext &C;
-  size_t n_args_;
-  std::string fmt_;
-  std::string args_;
-  std::string type_;
-};
-
 // Type visitor and rewriter for B programs.
 // It will look for B-specific features and rewrite them into a valid
 // C program. As part of the processing, open the necessary BPF tables
@@ -79,7 +60,7 @@
 class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
  public:
   explicit BTypeVisitor(clang::ASTContext &C, clang::Rewriter &rewriter,
-                        std::map<std::string, TableDesc> &tables);
+                        std::vector<TableDesc> &tables);
   bool TraverseCallExpr(clang::CallExpr *Call);
   bool TraverseMemberExpr(clang::MemberExpr *E);
   bool VisitFunctionDecl(clang::FunctionDecl *D);
@@ -94,7 +75,7 @@
   clang::ASTContext &C;
   clang::Rewriter &rewriter_;  /// modifications to the source go into this class
   llvm::raw_ostream &out_;  /// for debugging
-  std::map<std::string, TableDesc> &tables_;  /// store the open FDs
+  std::vector<TableDesc> &tables_;  /// store the open FDs
   std::vector<clang::ParmVarDecl *> fn_args_;
 };
 
@@ -102,7 +83,7 @@
 class BTypeConsumer : public clang::ASTConsumer {
  public:
   explicit BTypeConsumer(clang::ASTContext &C, clang::Rewriter &rewriter,
-                         std::map<std::string, TableDesc> &tables);
+                         std::vector<TableDesc> &tables);
   bool HandleTopLevelDecl(clang::DeclGroupRef D) override;
  private:
   BTypeVisitor visitor_;
@@ -125,11 +106,11 @@
       CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile) override;
 
   // take ownership of the table-to-fd mapping data structure
-  std::unique_ptr<std::map<std::string, TableDesc>> take_tables() { return move(tables_); }
+  std::unique_ptr<std::vector<TableDesc>> take_tables() { return move(tables_); }
  private:
   std::unique_ptr<clang::Rewriter> rewriter_;
   llvm::raw_ostream &os_;
-  std::unique_ptr<std::map<std::string, TableDesc>> tables_;
+  std::unique_ptr<std::vector<TableDesc>> tables_;
 };
 
 }  // namespace visitor
diff --git a/src/cc/frontends/clang/loader.cc b/src/cc/frontends/clang/loader.cc
index eea2ff2..c4ee097 100644
--- a/src/cc/frontends/clang/loader.cc
+++ b/src/cc/frontends/clang/loader.cc
@@ -64,8 +64,7 @@
 
 ClangLoader::~ClangLoader() {}
 
-int ClangLoader::parse(unique_ptr<llvm::Module> *mod,
-                       unique_ptr<map<string, TableDesc>> *tables,
+int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDesc>> *tables,
                        const string &file, bool in_memory) {
   using namespace clang;
 
diff --git a/src/cc/frontends/clang/loader.h b/src/cc/frontends/clang/loader.h
index d8b72fc..c657d5c 100644
--- a/src/cc/frontends/clang/loader.h
+++ b/src/cc/frontends/clang/loader.h
@@ -38,8 +38,7 @@
  public:
   explicit ClangLoader(llvm::LLVMContext *ctx);
   ~ClangLoader();
-  int parse(std::unique_ptr<llvm::Module> *mod,
-            std::unique_ptr<std::map<std::string, TableDesc>> *tables,
+  int parse(std::unique_ptr<llvm::Module> *mod, std::unique_ptr<std::vector<TableDesc>> *tables,
             const std::string &file, bool in_memory);
  private:
   llvm::LLVMContext *ctx_;
diff --git a/src/cc/table_desc.h b/src/cc/table_desc.h
index ca067f6..d2e762b 100644
--- a/src/cc/table_desc.h
+++ b/src/cc/table_desc.h
@@ -20,14 +20,13 @@
 namespace ebpf {
 
 struct TableDesc {
+  std::string name;
   int fd;
   size_t key_size;  // sizes are in bytes
   size_t leaf_size;
   size_t max_entries;
   std::string key_desc;
   std::string leaf_desc;
-  std::string key_reader;
-  std::string leaf_reader;
 };
 
 }  // namespace ebpf