docs: Clarify control flow C++ style

Add a section clarifying expected control flow style; in particular,
that early return and continue is preferred over right-creeping
functions and loops.

Change-Id: I3068780a9b50ca92adc62d160915205131309274
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/97806
Commit-Queue: Auto-Submit <auto-submit@pigweed.google.com.iam.gserviceaccount.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Pigweed-Auto-Submit: Keir Mierle <keir@google.com>
diff --git a/docs/style_guide.rst b/docs/style_guide.rst
index 67bc4be..afee356 100644
--- a/docs/style_guide.rst
+++ b/docs/style_guide.rst
@@ -209,10 +209,250 @@
 
 Control statements
 ==================
-All loops and conditional statements must use braces.
+
+Loops and conditionals
+----------------------
+All loops and conditional statements must use braces, and be on their own line.
+
+.. admonition:: **Yes**: Always use braces for line conditionals and loops:
+   :class: checkmark
+
+   .. code:: cpp
+
+      while (SomeCondition()) {
+        x += 2;
+      }
+      if (OtherCondition()) {
+        DoTheThing();
+      }
+
+
+.. admonition:: **No**: Missing braces
+   :class: error
+
+   .. code:: cpp
+
+      while (SomeCondition())
+        x += 2;
+      if (OtherCondition())
+        DoTheThing();
+
+.. admonition:: **No**: Statement on same line as condition
+   :class: error
+
+   .. code:: cpp
+
+      while (SomeCondition()) { x += 2; }
+      if (OtherCondition()) { DoTheThing(); }
+
 
 The syntax ``while (true)`` is preferred over ``for (;;)`` for infinite loops.
 
+.. admonition:: **Yes**:
+   :class: checkmark
+
+   .. code:: cpp
+
+      while (true) {
+        DoSomethingForever();
+      }
+
+.. admonition:: **No**:
+   :class: error
+
+   .. code:: cpp
+
+      for (;;) {
+        DoSomethingForever();
+      }
+
+
+Prefer early exit with ``return`` and ``continue``
+--------------------------------------------------
+Prefer to exit early from functions and loops to simplify code. This is the
+same same conventions as `LLVM
+<https://llvm.org/docs/CodingStandards.html#use-early-exits-and-continue-to-simplify-code>`_.
+We find this approach is superior to the "one return per function" style for a
+multitude of reasons:
+
+* **Visually**, the code is easier to follow, and takes less horizontal screen
+  space.
+* It makes it clear what part of the code is the **"main business" versus "edge
+  case handling"**.
+* For **functions**, parameter checking is in its own section at the top of the
+  function, rather than scattered around in the fuction body.
+* For **loops**, element checking is in its own section at the top of the loop,
+  rather than scattered around in the loop body.
+* Commit **deltas are simpler to follow** in code reviews; since adding a new
+  parameter check or loop element condition doesn't cause an indentation change
+  in the rest of the function.
+
+The guidance applies in two cases:
+
+* **Function early exit** - Early exits are for function parameter checking
+  and edge case checking at the top. The main functionality follows.
+* **Loop early exit** - Early exits in loops are for skipping an iteration
+  due to some edge case with an item getting iterated over. Loops may also
+  contain function exits, which should be structured the same way (see example
+  below).
+
+.. admonition:: **Yes**: Exit early from functions; keeping the main handling
+   at the bottom and de-dentend.
+   :class: checkmark
+
+   .. code:: cpp
+
+      Status DoSomething(Parameter parameter) {
+        // Parameter validation first; detecting incoming use errors.
+        PW_CHECK_INT_EQ(parameter.property(), 3, "Programmer error: frobnitz");
+
+        // Error case: Not in correct state.
+        if (parameter.other() == MyEnum::kBrokenState) {
+          LOG_ERROR("Device in strange state: %s", parametr.state_str());
+          return Status::InvalidPrecondition();
+        }
+
+        // Error case: Not in low power mode; shouldn't do anything.
+        if (parameter.power() != MyEnum::kLowPower) {
+          LOG_ERROR("Not in low power mode");
+          return Status::InvalidPrecondition();
+        }
+
+        // Main business for the function here.
+        MainBody();
+        MoreMainBodyStuff();
+      }
+
+.. admonition:: **No**: Main body of function is buried and right creeping.
+   Even though this is shorter than the version preferred by Pigweed due to
+   factoring the return statement, the logical structure is less obvious. A
+   function in Pigweed containing **nested conditionals indicates that
+   something complicated is happening with the flow**; otherwise it would have
+   the early bail structure; so pay close attention.
+   :class: error
+
+   .. code:: cpp
+
+      Status DoSomething(Parameter parameter) {
+        // Parameter validation first; detecting incoming use errors.
+        PW_CHECK_INT_EQ(parameter.property(), 3, "Programmer error: frobnitz");
+
+        // Error case: Not in correct state.
+        if (parameter.other() != MyEnum::kBrokenState) {
+          // Error case: Not in low power mode; shouldn't do anything.
+          if (parameter.power() == MyEnum::kLowPower) {
+            // Main business for the function here.
+            MainBody();
+            MoreMainBodyStuff();
+          } else {
+            LOG_ERROR("Not in low power mode");
+          }
+        } else {
+          LOG_ERROR("Device in strange state: %s", parametr.state_str());
+        }
+        return Status::InvalidPrecondition();
+      }
+
+.. admonition:: **Yes**: Bail early from loops; keeping the main handling at
+   the bottom and de-dentend.
+   :class: checkmark
+
+   .. code:: cpp
+
+      for (int i = 0; i < LoopSize(); ++i) {
+        // Early skip of item based on edge condition.
+        if (!CommonCase()) {
+          continue;
+        }
+        // Early exit of function based on error case.
+        int my_measurement = GetSomeMeasurement();
+        if (my_measurement < 10) {
+          LOG_ERROR("Found something strange; bailing");
+          return Status::Unknown();
+        }
+
+        // Main body of the loop.
+        ProcessItem(my_items[i], my_measurement);
+        ProcessItemMore(my_items[i], my_measurement, other_details);
+        ...
+      }
+
+.. admonition:: **No**: Right-creeping code with the main body buried inside
+   some nested conditional. This makes it harder to understand what is the
+   main purpose of the loop versus what is edge case handling.
+   :class: error
+
+   .. code:: cpp
+
+      for (int i = 0; i < LoopSize(); ++i) {
+        if (CommonCase()) {
+          int my_measurement = GetSomeMeasurement();
+          if (my_measurement >= 10) {
+            // Main body of the loop.
+            ProcessItem(my_items[i], my_measurement);
+            ProcessItemMore(my_items[i], my_measurement, other_details);
+            ...
+          } else {
+            LOG_ERROR("Found something strange; bailing");
+            return Status::Unknown();
+          }
+        }
+      }
+
+There are cases where this structure doesn't work, and in those cases, it is
+fine to structure the code differently.
+
+No ``else`` after ``return`` or ``continue``
+--------------------------------------------
+Do not put unnecessary ``} else {`` blocks after blocks that terminate with a
+return, since this causes unnecessary rightward indentation creep. This
+guidance pairs with the preference for early exits to reduce code duplication
+and standardize loop/function structure.
+
+.. admonition:: **Yes**: No else after return or continue
+   :class: checkmark
+
+   .. code:: cpp
+
+      // Note lack of else block due to return.
+      if (Failure()) {
+        DoTheThing();
+        return Status::ResourceExausted();
+      }
+
+      // Note lack of else block due to continue.
+      while (MyCondition()) {
+        if (SomeEarlyBail()) {
+          continue;
+        }
+        // Main handling of item
+        ...
+      }
+
+      DoOtherThing();
+      return OkStatus();
+
+.. admonition:: **No**: Else after return needlessly creeps right
+   :class: error
+
+   .. code:: cpp
+
+      if (Failure()) {
+        DoTheThing();
+        return Status::ResourceExausted();
+      } else {
+        while (MyCondition()) {
+          if (SomeEarlyBail()) {
+            continue;
+          } else {
+            // Main handling of item
+            ...
+          }
+        }
+        DoOtherThing();
+        return OkStatus();
+      }
+
 Include guards
 ==============
 The first non-comment line of every header file must be ``#pragma once``. Do
@@ -276,6 +516,16 @@
   ``foo_bar`` style naming.  For consistency with other variables whose value is
   always fixed for the duration of the program, the naming convention is
   ``kCamelCase``, and so that is the style we use in Pigweed.
+* Trivial membor accessors should be named with ``snake_case()``. The Google
+  C++ style allows either ``snake_case()`` or ``CapsCase()``, but Pigweed
+  always uses ``snake_case()``.
+* Abstract base classes should be named generically, with derived types named
+  specifically. For example, ``Stream`` is an abstract base, and
+  ``SocketStream`` and ``StdioStream`` are an implementations of that
+  interface.  Any prefix or postfix indicating whether something is abstract or
+  concrete is not permitted; for example, ``IStream`` or ``SocketStreamImpl``
+  are both not permitted. These pre-/post-fixes add additional visual noise and
+  are irrelevant to consumers of these interfaces.
 
 C code
 ------