From fcff618e6f09baf8fb69ed6d4d5c9be94a433511 Mon Sep 17 00:00:00 2001
From: Craig Tiller <craig.tiller@gmail.com>
Date: Fri, 5 Jun 2015 10:56:10 -0700
Subject: [PATCH] Clarify some of the call stuff

---
 include/grpc++/impl/call.h | 68 +++++++++++++++++++++++---------------
 1 file changed, 42 insertions(+), 26 deletions(-)

diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h
index 0951bf0320..30260d2a2f 100644
--- a/include/grpc++/impl/call.h
+++ b/include/grpc++/impl/call.h
@@ -59,6 +59,9 @@ void FillMetadataMap(grpc_metadata_array* arr,
 grpc_metadata* FillMetadataArray(
     const std::multimap<grpc::string, grpc::string>& metadata);
 
+/// Default argument for CallOpSet. I is unused by the class, but can be
+/// used for generating multiple names for the same thing.
+template <int I>
 class CallNoOp {
  protected:
   void AddOp(grpc_op* ops, size_t* nops) {}
@@ -344,9 +347,16 @@ class CallOpClientRecvStatus {
   size_t status_details_capacity_;
 };
 
+/// An abstract collection of call ops, used to generate the
+/// grpc_call_op structure to pass down to the lower layers,
+/// and as it is-a CompletionQueueTag, also massages the final
+/// completion into the correct form for consumption in the C++
+/// API.
 class CallOpSetInterface : public CompletionQueueTag {
  public:
   CallOpSetInterface() : max_message_size_(0) {}
+  /// Fills in grpc_op, starting from ops[*nops] and moving
+  /// upwards.
   virtual void FillOps(grpc_op* ops, size_t* nops) = 0;
 
   void set_max_message_size(int max_message_size) {
@@ -357,36 +367,39 @@ class CallOpSetInterface : public CompletionQueueTag {
   int max_message_size_;
 };
 
-template <class T, int I>
-class WrapAndDerive : public T {};
-
-template <class Op1 = CallNoOp, class Op2 = CallNoOp, class Op3 = CallNoOp,
-          class Op4 = CallNoOp, class Op5 = CallNoOp, class Op6 = CallNoOp>
+/// Primary implementaiton of CallOpSetInterface.
+/// Since we cannot use variadic templates, we declare slots up to
+/// the maximum count of ops we'll need in a set. We leverage the
+/// empty base class optimization to slim this class (especially
+/// when there are many unused slots used). To avoid duplicate base classes,
+/// the template parmeter for CallNoOp is varied by argument position.
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>, class Op3 = CallNoOp<3>,
+          class Op4 = CallNoOp<4>, class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
 class CallOpSet : public CallOpSetInterface,
-                  public WrapAndDerive<Op1, 1>,
-                  public WrapAndDerive<Op2, 2>,
-                  public WrapAndDerive<Op3, 3>,
-                  public WrapAndDerive<Op4, 4>,
-                  public WrapAndDerive<Op5, 5>,
-                  public WrapAndDerive<Op6, 6> {
+                  public Op1,
+                  public Op2,
+                  public Op3,
+                  public Op4,
+                  public Op5,
+                  public Op6 {
  public:
   CallOpSet() : return_tag_(this) {}
   void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE {
-    this->WrapAndDerive<Op1, 1>::AddOp(ops, nops);
-    this->WrapAndDerive<Op2, 2>::AddOp(ops, nops);
-    this->WrapAndDerive<Op3, 3>::AddOp(ops, nops);
-    this->WrapAndDerive<Op4, 4>::AddOp(ops, nops);
-    this->WrapAndDerive<Op5, 5>::AddOp(ops, nops);
-    this->WrapAndDerive<Op6, 6>::AddOp(ops, nops);
+    this->Op1::AddOp(ops, nops);
+    this->Op2::AddOp(ops, nops);
+    this->Op3::AddOp(ops, nops);
+    this->Op4::AddOp(ops, nops);
+    this->Op5::AddOp(ops, nops);
+    this->Op6::AddOp(ops, nops);
   }
 
   bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
-    this->WrapAndDerive<Op1, 1>::FinishOp(status, max_message_size_);
-    this->WrapAndDerive<Op2, 2>::FinishOp(status, max_message_size_);
-    this->WrapAndDerive<Op3, 3>::FinishOp(status, max_message_size_);
-    this->WrapAndDerive<Op4, 4>::FinishOp(status, max_message_size_);
-    this->WrapAndDerive<Op5, 5>::FinishOp(status, max_message_size_);
-    this->WrapAndDerive<Op6, 6>::FinishOp(status, max_message_size_);
+    this->Op1::FinishOp(status, max_message_size_);
+    this->Op2::FinishOp(status, max_message_size_);
+    this->Op3::FinishOp(status, max_message_size_);
+    this->Op4::FinishOp(status, max_message_size_);
+    this->Op5::FinishOp(status, max_message_size_);
+    this->Op6::FinishOp(status, max_message_size_);
     *tag = return_tag_;
     return true;
   }
@@ -397,9 +410,12 @@ class CallOpSet : public CallOpSetInterface,
   void* return_tag_;
 };
 
-// SneakyCallOpBuffer does not post completions to the completion queue
-template <class Op1 = CallNoOp, class Op2 = CallNoOp, class Op3 = CallNoOp,
-          class Op4 = CallNoOp, class Op5 = CallNoOp, class Op6 = CallNoOp>
+/// A CallOpSet that does not post completions to the completion queue.
+///
+/// Allows hiding some completions that the C core must generate from
+/// C++ users.
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>, class Op3 = CallNoOp<3>,
+          class Op4 = CallNoOp<4>, class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
 class SneakyCallOpSet GRPC_FINAL
     : public CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> {
  public:
-- 
GitLab