Abstract the ELFStreamer class.

This enables other implementations, such as streaming to memory
instead of a file.

BUG=swiftshader:9

Change-Id: I2a780ee67e9bccd157c120b7a0895d9764117464
Reviewed-on: https://chromium-review.googlesource.com/384911
Reviewed-by: Jim Stichnoth <stichnot@chromium.org>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/IceBrowserCompileServer.cpp b/src/IceBrowserCompileServer.cpp
index ab2d69f..5fd1ab1 100644
--- a/src/IceBrowserCompileServer.cpp
+++ b/src/IceBrowserCompileServer.cpp
@@ -303,7 +303,7 @@
   EmitStream->SetBufferSize(1 << 14);
   std::unique_ptr<StringStream> ErrStrm(new StringStream());
   ErrorStream = std::move(ErrStrm);
-  ELFStream.reset(new ELFStreamer(*EmitStream.get()));
+  ELFStream.reset(new ELFFileStreamer(*EmitStream.get()));
   Ctx.reset(new GlobalContext(LogStream.get(), EmitStream.get(),
                               &ErrorStream->getStream(), ELFStream.get()));
   CompileThread = std::thread([this]() {
diff --git a/src/IceCompileServer.cpp b/src/IceCompileServer.cpp
index 994eae2..f4dacb8 100644
--- a/src/IceCompileServer.cpp
+++ b/src/IceCompileServer.cpp
@@ -208,7 +208,7 @@
           << ":\n" << EC.message() << "\n";
       return transferErrorCode(getReturnValue(Ice::EC_Args));
     }
-    ELFStr.reset(new ELFStreamer(*FdOs.get()));
+    ELFStr.reset(new ELFFileStreamer(*FdOs.get()));
     Os.reset(FdOs.release());
     // NaCl sets st_blksize to 0, and LLVM uses that to pick the default
     // preferred buffer size. Set to something non-zero.
diff --git a/src/IceDefs.h b/src/IceDefs.h
index 75a69d5..bffbd2d 100644
--- a/src/IceDefs.h
+++ b/src/IceDefs.h
@@ -57,6 +57,7 @@
 class Cfg;
 class CfgNode;
 class Constant;
+class ELFFileStreamer;
 class ELFObjectWriter;
 class ELFStreamer;
 class FunctionDeclaration;
diff --git a/src/IceELFStreamer.h b/src/IceELFStreamer.h
index a1c9b94..ad6feb9 100644
--- a/src/IceELFStreamer.h
+++ b/src/IceELFStreamer.h
@@ -23,14 +23,22 @@
 /// Low level writer that can that can handle ELFCLASS32/64. Little endian only
 /// for now.
 class ELFStreamer {
-  ELFStreamer() = delete;
   ELFStreamer(const ELFStreamer &) = delete;
   ELFStreamer &operator=(const ELFStreamer &) = delete;
 
 public:
-  explicit ELFStreamer(Fdstream &Out) : Out(Out) {}
+  ELFStreamer() = default;
+  virtual ~ELFStreamer() = default;
 
-  void write8(uint8_t Value) { Out << char(Value); }
+  virtual void write8(uint8_t Value) = 0;
+  virtual uint64_t tell() const = 0;
+  virtual void seek(uint64_t Off) = 0;
+
+  virtual void writeBytes(llvm::StringRef Bytes) {
+    for (char c : Bytes) {
+      write8(c);
+    }
+  }
 
   void writeLE16(uint16_t Value) {
     write8(uint8_t(Value));
@@ -65,20 +73,32 @@
       writeLE32(Value);
   }
 
-  void writeBytes(llvm::StringRef Bytes) { Out << Bytes; }
-
   void writeZeroPadding(SizeT N) {
     static const char Zeros[16] = {0};
 
     for (SizeT i = 0, e = N / 16; i != e; ++i)
-      Out << llvm::StringRef(Zeros, 16);
+      writeBytes(llvm::StringRef(Zeros, 16));
 
-    Out << llvm::StringRef(Zeros, N % 16);
+    writeBytes(llvm::StringRef(Zeros, N % 16));
   }
+};
 
-  uint64_t tell() const { return Out.tell(); }
+/// Implementation of ELFStreamer writing to a file.
+class ELFFileStreamer : public ELFStreamer {
+  ELFFileStreamer() = delete;
+  ELFFileStreamer(const ELFFileStreamer &) = delete;
+  ELFFileStreamer &operator=(const ELFFileStreamer &) = delete;
 
-  void seek(uint64_t Off) { Out.seek(Off); }
+public:
+  explicit ELFFileStreamer(Fdstream &Out) : Out(Out) {}
+
+  void write8(uint8_t Value) override { Out << char(Value); }
+
+  void writeBytes(llvm::StringRef Bytes) override { Out << Bytes; }
+
+  uint64_t tell() const override { return Out.tell(); }
+
+  void seek(uint64_t Off) override { Out.seek(Off); }
 
 private:
   Fdstream &Out;
@@ -86,4 +106,4 @@
 
 } // end of namespace Ice
 
-#endif // SUBZERO_SRC_ICEELFSTREAMER_H
+#endif // SUBZERO_SRC_ICEELFSTREAMER_H
\ No newline at end of file