Add Exporter option (#176)

Add an Exporter option that accepts a function to determine
which struct types to permit access to unexported fields.
Treat this as a first-class option and implement AllowUnexported
in terms of the new Exporter option.

The new Exporter option:
* Better matches the existing style of top-level options
both by name (e.g., Comparer, Transformer, and Reporter)
and by API style (all accept a function).
* Is more flexible as it enables users to functionally
implement AllowAllUnexported by simply doing:
	Exporter(func(reflect.Type) bool { return true })

Fixes #40 
diff --git a/cmp/compare.go b/cmp/compare.go
index 2133562..8419fcc 100644
--- a/cmp/compare.go
+++ b/cmp/compare.go
@@ -22,8 +22,8 @@
 // equality is determined by recursively comparing the primitive kinds on both
 // values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, unexported
 // fields are not compared by default; they result in panics unless suppressed
-// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly compared
-// using the AllowUnexported option.
+// by using an Ignore option (see cmpopts.IgnoreUnexported) or explicitly
+// compared using the Exporter option.
 package cmp
 
 import (
@@ -62,8 +62,8 @@
 //
 // Structs are equal if recursively calling Equal on all fields report equal.
 // If a struct contains unexported fields, Equal panics unless an Ignore option
-// (e.g., cmpopts.IgnoreUnexported) ignores that field or the AllowUnexported
-// option explicitly permits comparing the unexported field.
+// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option
+// explicitly permits comparing the unexported field.
 //
 // Slices are equal if they are both nil or both non-nil, where recursively
 // calling Equal on all non-ignored slice or array elements report equal.
@@ -148,8 +148,8 @@
 	dynChecker dynChecker
 
 	// These fields, once set by processOption, will not change.
-	exporters map[reflect.Type]bool // Set of structs with unexported field visibility
-	opts      Options               // List of all fundamental and filter options
+	exporters []exporter // List of exporters for structs with unexported fields
+	opts      Options    // List of all fundamental and filter options
 }
 
 func newState(opts []Option) *state {
@@ -174,13 +174,8 @@
 			panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt))
 		}
 		s.opts = append(s.opts, opt)
-	case visibleStructs:
-		if s.exporters == nil {
-			s.exporters = make(map[reflect.Type]bool)
-		}
-		for t := range opt {
-			s.exporters[t] = true
-		}
+	case exporter:
+		s.exporters = append(s.exporters, opt)
 	case reporter:
 		s.reporters = append(s.reporters, opt)
 	default:
@@ -354,6 +349,7 @@
 func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) {
 	var vax, vay reflect.Value // Addressable versions of vx and vy
 
+	var mayForce, mayForceInit bool
 	step := StructField{&structField{}}
 	for i := 0; i < t.NumField(); i++ {
 		step.typ = t.Field(i).Type
@@ -375,7 +371,13 @@
 				vax = makeAddressable(vx)
 				vay = makeAddressable(vy)
 			}
-			step.mayForce = s.exporters[t]
+			if !mayForceInit {
+				for _, xf := range s.exporters {
+					mayForce = mayForce || xf(t)
+				}
+				mayForceInit = true
+			}
+			step.mayForce = mayForce
 			step.pvx = vax
 			step.pvy = vay
 			step.field = t.Field(i)
diff --git a/cmp/export_panic.go b/cmp/export_panic.go
index abc3a1c..dd03235 100644
--- a/cmp/export_panic.go
+++ b/cmp/export_panic.go
@@ -8,8 +8,8 @@
 
 import "reflect"
 
-const supportAllowUnexported = false
+const supportExporters = false
 
 func retrieveUnexportedField(reflect.Value, reflect.StructField) reflect.Value {
-	panic("retrieveUnexportedField is not implemented")
+	panic("no support for forcibly accessing unexported fields")
 }
diff --git a/cmp/export_unsafe.go b/cmp/export_unsafe.go
index 5f6ed93..57020e2 100644
--- a/cmp/export_unsafe.go
+++ b/cmp/export_unsafe.go
@@ -11,7 +11,7 @@
 	"unsafe"
 )
 
-const supportAllowUnexported = true
+const supportExporters = true
 
 // retrieveUnexportedField uses unsafe to forcibly retrieve any field from
 // a struct such that the value has read-write permissions.
diff --git a/cmp/options.go b/cmp/options.go
index a20390d..409e803 100644
--- a/cmp/options.go
+++ b/cmp/options.go
@@ -225,7 +225,7 @@
 
 	// Unable to Interface implies unexported field without visibility access.
 	if !vx.CanInterface() || !vy.CanInterface() {
-		const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider AllowUnexported or cmpopts.IgnoreUnexported"
+		const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported"
 		var name string
 		if t := s.curPath.Index(-2).Type(); t.Name() != "" {
 			// Named type with unexported fields.
@@ -372,9 +372,8 @@
 	return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc))
 }
 
-// AllowUnexported returns an Option that forcibly allows operations on
-// unexported fields in certain structs, which are specified by passing in a
-// value of each struct type.
+// Exporter returns an Option that specifies whether Equal is allowed to
+// introspect into the unexported fields of certain struct types.
 //
 // Users of this option must understand that comparing on unexported fields
 // from external packages is not safe since changes in the internal
@@ -398,10 +397,24 @@
 //
 // In other cases, the cmpopts.IgnoreUnexported option can be used to ignore
 // all unexported fields on specified struct types.
-func AllowUnexported(types ...interface{}) Option {
-	if !supportAllowUnexported {
-		panic("AllowUnexported is not supported on purego builds, Google App Engine Standard, or GopherJS")
+func Exporter(f func(reflect.Type) bool) Option {
+	if !supportExporters {
+		panic("Exporter is not supported on purego builds")
 	}
+	return exporter(f)
+}
+
+type exporter func(reflect.Type) bool
+
+func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption {
+	panic("not implemented")
+}
+
+// AllowUnexported returns an Options that allows Equal to forcibly introspect
+// unexported fields of the specified struct types.
+//
+// See Exporter for the proper use of this option.
+func AllowUnexported(types ...interface{}) Option {
 	m := make(map[reflect.Type]bool)
 	for _, typ := range types {
 		t := reflect.TypeOf(typ)
@@ -410,13 +423,7 @@
 		}
 		m[t] = true
 	}
-	return visibleStructs(m)
-}
-
-type visibleStructs map[reflect.Type]bool
-
-func (visibleStructs) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption {
-	panic("not implemented")
+	return exporter(func(t reflect.Type) bool { return m[t] })
 }
 
 // Result represents the comparison result for a single node and
diff --git a/cmp/path.go b/cmp/path.go
index 96fffd2..d7a420d 100644
--- a/cmp/path.go
+++ b/cmp/path.go
@@ -41,7 +41,7 @@
 	// In some cases, one or both may be invalid or have restrictions:
 	//	• For StructField, both are not interface-able if the current field
 	//	is unexported and the struct type is not explicitly permitted by
-	//	AllowUnexported to traverse unexported fields.
+	//	an Exporter to traverse unexported fields.
 	//	• For SliceIndex, one may be invalid if an element is missing from
 	//	either the x or y slice.
 	//	• For MapIndex, one may be invalid if an entry is missing from