Reduce BaseHookCollection API.

We don't need all array methods. The class definition
will load faster with fewer method defs. Also, static
method defs perform better than dynamic `define_method`
method defs since it doesn't need to activate the closure
environment.
Move hook selection into base hook collection.

Also, flatten the inheritance hierarchy a bit, which
should perform ever-so-slightly better since there are
fewer modules in the ancestor chain to check for method
defs when dispatching messages.
Combine filtering and running hooks into a single method.

Before, these things were split into separate methods (`for` and `run`),
even though they are never needed individually. The split caused us to
create extra unnecessary instances of `HookCollection` in order to
maintain the extra state between `for` and `run` without mutating the
existing instance.

The allocation benchmarks show that this reduces the number of objects
created per example group by 2 arrays and 2 HookCollection instances.
Move method def to be nearer to similar methods.
Refactor around hook execution.

- Prefer `yield` to `&block` -- it performs much better.
- Restore optimization from cd9185712375e7f81ac70531c681c1fa71a25a3e.
- This allows us to remove `empty?` from HookCollection.