internal/impl: optimize reflect methods

This change performs two optimizations:
* It uses a pre-constructed rangeInfos slice to iterate over
all the fields. This is more performant since iterating over a slice
is faster than iterating over a map. Furthermore, this slice
does not contain fields that are part of a oneof. If a oneof has
N fields, the time to check presence on the oneof is now O(1)
instead of O(N).
* It uses a dense field info slice that is optmized for the common
case where the field number is relatively low and close in value
to the index itself.

We also fix a minor bug in the construction of oneofInfo where
it wasn't treating a typed nil pointer to a wrapper struct as if
it were unset. This ensures WhichOneof and Has always agree.

name             old time/op    new time/op    delta
Reflect/Has-4      7.81µs ± 3%    6.74µs ± 3%  -13.61%  (p=0.000 n=9+9)
Reflect/Get-4      12.7µs ± 1%    11.3µs ± 4%  -10.85%  (p=0.000 n=8+10)
Reflect/Set-4      19.5µs ± 5%    17.8µs ± 2%   -8.99%  (p=0.000 n=10+10)
Reflect/Clear-4    12.0µs ± 4%    10.2µs ± 3%  -14.86%  (p=0.000 n=9+10)
Reflect/Range-4    6.58µs ± 1%    4.17µs ± 2%  -36.65%  (p=0.000 n=8+9)

Change-Id: I2c48b4d3fb6103ab238924950529ded0d37f8c8a
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/196358
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/message_reflect_test.go b/internal/impl/message_reflect_test.go
index a836c89..6148d4d 100644
--- a/internal/impl/message_reflect_test.go
+++ b/internal/impl/message_reflect_test.go
@@ -1485,3 +1485,53 @@
 	})
 	runtime.KeepAlive(sink)
 }
+
+func BenchmarkReflect(b *testing.B) {
+	m := new(testpb.TestAllTypes).ProtoReflect()
+	fds := m.Descriptor().Fields()
+	vs := make([]pref.Value, fds.Len())
+	for i := range vs {
+		vs[i] = m.NewField(fds.Get(i))
+	}
+
+	b.Run("Has", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			for j := 0; j < fds.Len(); j++ {
+				m.Has(fds.Get(j))
+			}
+		}
+	})
+	b.Run("Get", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			for j := 0; j < fds.Len(); j++ {
+				m.Get(fds.Get(j))
+			}
+		}
+	})
+	b.Run("Set", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			for j := 0; j < fds.Len(); j++ {
+				m.Set(fds.Get(j), vs[j])
+			}
+		}
+	})
+	b.Run("Clear", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			for j := 0; j < fds.Len(); j++ {
+				m.Clear(fds.Get(j))
+			}
+		}
+	})
+	b.Run("Range", func(b *testing.B) {
+		b.ReportAllocs()
+		for i := 0; i < b.N; i++ {
+			m.Range(func(pref.FieldDescriptor, pref.Value) bool {
+				return true
+			})
+		}
+	})
+}