瀏覽代碼

codec: simplify how we store whether type implements an interface

Instead of tracking multiple levels of indirection, we just store if T or *T implements the interface.
This works because we always pass a base (non-ptr) reflect.Type to TypeInfos.get(...)

This simplified the codebase:
- encodeValue and decodeValue determine the appropriate reflect.Value (base or addressable)
  to use
- individual methods do not have to make that determinant themselves
- handling JsonMarshal, TextUnmarshal, Selfer, etc become simpler
Ugorji Nwoke 8 年之前
父節點
當前提交
3d21d421d8
共有 4 個文件被更改,包括 136 次插入185 次删除
  1. 5 22
      codec/decode.go
  2. 48 52
      codec/encode.go
  3. 83 79
      codec/helper.go
  4. 0 32
      codec/helper_internal.go

+ 5 - 22
codec/decode.go

@@ -895,29 +895,12 @@ func (d *Decoder) ext(f *codecFnInfo, rv reflect.Value) {
 	d.d.DecodeExt(rv2i(rv), f.xfTag, f.xfFn)
 }
 
-func (d *Decoder) getValueForUnmarshalInterface(rv reflect.Value, indir int8) (v interface{}) {
-	if indir == -1 {
-		v = rv2i(rv.Addr())
-	} else if indir == 0 {
-		v = rv2i(rv)
-	} else {
-		for j := int8(0); j < indir; j++ {
-			if rv.IsNil() {
-				rv.Set(reflect.New(rv.Type().Elem()))
-			}
-			rv = rv.Elem()
-		}
-		v = rv2i(rv)
-	}
-	return
-}
-
 func (d *Decoder) selferUnmarshal(f *codecFnInfo, rv reflect.Value) {
-	d.getValueForUnmarshalInterface(rv, f.ti.csIndir).(Selfer).CodecDecodeSelf(d)
+	rv2i(rv).(Selfer).CodecDecodeSelf(d)
 }
 
 func (d *Decoder) binaryUnmarshal(f *codecFnInfo, rv reflect.Value) {
-	bm := d.getValueForUnmarshalInterface(rv, f.ti.bunmIndir).(encoding.BinaryUnmarshaler)
+	bm := rv2i(rv).(encoding.BinaryUnmarshaler)
 	xbs := d.d.DecodeBytes(nil, true)
 	if fnerr := bm.UnmarshalBinary(xbs); fnerr != nil {
 		panic(fnerr)
@@ -925,7 +908,7 @@ func (d *Decoder) binaryUnmarshal(f *codecFnInfo, rv reflect.Value) {
 }
 
 func (d *Decoder) textUnmarshal(f *codecFnInfo, rv reflect.Value) {
-	tm := d.getValueForUnmarshalInterface(rv, f.ti.tunmIndir).(encoding.TextUnmarshaler)
+	tm := rv2i(rv).(encoding.TextUnmarshaler)
 	fnerr := tm.UnmarshalText(d.d.DecodeStringAsBytes())
 	if fnerr != nil {
 		panic(fnerr)
@@ -933,7 +916,7 @@ func (d *Decoder) textUnmarshal(f *codecFnInfo, rv reflect.Value) {
 }
 
 func (d *Decoder) jsonUnmarshal(f *codecFnInfo, rv reflect.Value) {
-	tm := d.getValueForUnmarshalInterface(rv, f.ti.junmIndir).(jsonUnmarshaler)
+	tm := rv2i(rv).(jsonUnmarshaler)
 	// bs := d.d.DecodeBytes(d.b[:], true, true)
 	// grab the bytes to be read, as UnmarshalJSON needs the full JSON so as to unmarshal it itself.
 	fnerr := tm.UnmarshalJSON(d.nextValueBytes())
@@ -2165,7 +2148,7 @@ func (d *Decoder) decodeValue(rv reflect.Value, fn *codecFn, tryRecognized, chkA
 		// always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer
 		fn = d.cf.get(rv.Type(), chkAll, true) // chkAll, chkAll)
 	}
-	if fn.i.addr {
+	if fn.i.addrD {
 		if rvpValid {
 			fn.fd(d, &fn.i, rvp)
 		} else if rv.CanAddr() {

+ 48 - 52
codec/encode.go

@@ -357,75 +357,55 @@ func (e *Encoder) raw(f *codecFnInfo, rv reflect.Value) {
 func (e *Encoder) rawExt(f *codecFnInfo, rv reflect.Value) {
 	// rev := rv2i(rv).(RawExt)
 	// e.e.EncodeRawExt(&rev, e)
-	var re *RawExt
-	if rv.CanAddr() {
-		re = rv2i(rv.Addr()).(*RawExt)
-	} else {
-		rev := rv2i(rv).(RawExt)
-		re = &rev
-	}
-	e.e.EncodeRawExt(re, e)
+	// var re *RawExt
+	// if rv.CanAddr() {
+	// 	re = rv2i(rv.Addr()).(*RawExt)
+	// } else {
+	// 	rev := rv2i(rv).(RawExt)
+	// 	re = &rev
+	// }
+	// e.e.EncodeRawExt(re, e)
+	e.e.EncodeRawExt(rv2i(rv).(*RawExt), e)
 }
 
 func (e *Encoder) ext(f *codecFnInfo, rv reflect.Value) {
 	// if this is a struct|array and it was addressable, then pass the address directly (not the value)
-	if k := rv.Kind(); (k == reflect.Struct || k == reflect.Array) && rv.CanAddr() {
-		rv = rv.Addr()
-	}
+	// if k := rv.Kind(); (k == reflect.Struct || k == reflect.Array) && rv.CanAddr() {
+	// 	rv = rv.Addr()
+	// }
 	e.e.EncodeExt(rv2i(rv), f.xfTag, f.xfFn, e)
 }
 
-func (e *Encoder) getValueForMarshalInterface(rv reflect.Value, indir int8) (v interface{}, proceed bool) {
-	if indir == 0 {
-		v = rv2i(rv)
-	} else if indir == -1 {
-		// If a non-pointer was passed to Encode(), then that value is not addressable.
-		// Take addr if addressable, else copy value to an addressable value.
-		if rv.CanAddr() {
-			v = rv2i(rv.Addr())
-		} else {
-			rv2 := reflect.New(rv.Type())
-			rv2.Elem().Set(rv)
-			v = rv2i(rv2)
-		}
-	} else {
-		for j := int8(0); j < indir; j++ {
-			if rv.IsNil() {
-				e.e.EncodeNil()
-				return
-			}
-			rv = rv.Elem()
-		}
-		v = rv2i(rv)
-	}
-	return v, true
-}
+// func rviptr(rv reflect.Value) (v interface{}) {
+// 	// If a non-pointer was passed to Encode(), then that value is not addressable.
+// 	// Take addr if addressable, else copy value to an addressable value.
+// 	if rv.CanAddr() {
+// 		v = rv2i(rv.Addr())
+// 	} else {
+// 		rv2 := reflect.New(rv.Type())
+// 		rv2.Elem().Set(rv)
+// 		v = rv2i(rv2)
+// 	}
+// 	return v
+// }
 
 func (e *Encoder) selferMarshal(f *codecFnInfo, rv reflect.Value) {
-	if v, proceed := e.getValueForMarshalInterface(rv, f.ti.csIndir); proceed {
-		v.(Selfer).CodecEncodeSelf(e)
-	}
+	rv2i(rv).(Selfer).CodecEncodeSelf(e)
 }
 
 func (e *Encoder) binaryMarshal(f *codecFnInfo, rv reflect.Value) {
-	if v, proceed := e.getValueForMarshalInterface(rv, f.ti.bmIndir); proceed {
-		bs, fnerr := v.(encoding.BinaryMarshaler).MarshalBinary()
-		e.marshal(bs, fnerr, false, c_RAW)
-	}
+	bs, fnerr := rv2i(rv).(encoding.BinaryMarshaler).MarshalBinary()
+	e.marshal(bs, fnerr, false, c_RAW)
 }
 
 func (e *Encoder) textMarshal(f *codecFnInfo, rv reflect.Value) {
-	if v, proceed := e.getValueForMarshalInterface(rv, f.ti.tmIndir); proceed {
-		bs, fnerr := v.(encoding.TextMarshaler).MarshalText()
-		e.marshal(bs, fnerr, false, c_UTF8)
-	}
+	bs, fnerr := rv2i(rv).(encoding.TextMarshaler).MarshalText()
+	e.marshal(bs, fnerr, false, c_UTF8)
 }
 
 func (e *Encoder) jsonMarshal(f *codecFnInfo, rv reflect.Value) {
-	if v, proceed := e.getValueForMarshalInterface(rv, f.ti.jmIndir); proceed {
-		bs, fnerr := v.(jsonMarshaler).MarshalJSON()
-		e.marshal(bs, fnerr, true, c_UTF8)
-	}
+	bs, fnerr := rv2i(rv).(jsonMarshaler).MarshalJSON()
+	e.marshal(bs, fnerr, true, c_UTF8)
 }
 
 func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) {
@@ -1294,6 +1274,8 @@ func (e *Encoder) encode(iv interface{}) {
 func (e *Encoder) encodeValue(rv reflect.Value, fn *codecFn, checkFastpath bool) {
 	// if a valid fn is passed, it MUST BE for the dereferenced type of rv
 	var sptr uintptr
+	var rvp reflect.Value
+	var rvpValid bool
 TOP:
 	switch rv.Kind() {
 	case reflect.Ptr:
@@ -1301,6 +1283,8 @@ TOP:
 			e.e.EncodeNil()
 			return
 		}
+		rvpValid = true
+		rvp = rv
 		rv = rv.Elem()
 		if e.h.CheckCircularRef && rv.Kind() == reflect.Struct {
 			// TODO: Movable pointers will be an issue here. Future problem.
@@ -1339,7 +1323,19 @@ TOP:
 		// always pass checkCodecSelfer=true, in case T or ****T is passed, where *T is a Selfer
 		fn = e.cf.get(rt, checkFastpath, true)
 	}
-	fn.fe(e, &fn.i, rv)
+	if fn.i.addrE {
+		if rvpValid {
+			fn.fe(e, &fn.i, rvp)
+		} else if rv.CanAddr() {
+			fn.fe(e, &fn.i, rv.Addr())
+		} else {
+			rv2 := reflect.New(rv.Type())
+			rv2.Elem().Set(rv)
+			fn.fe(e, &fn.i, rv2)
+		}
+	} else {
+		fn.fe(e, &fn.i, rv)
+	}
 	if sptr != 0 {
 		(&e.ci).remove(sptr)
 	}

+ 83 - 79
codec/helper.go

@@ -944,7 +944,7 @@ func baseStructRv(v reflect.Value, update bool) (v2 reflect.Value, valid bool) {
 	return v, true
 }
 
-// typeInfo keeps information about each type referenced in the encode/decode sequence.
+// typeInfo keeps information about each (non-ptr) type referenced in the encode/decode sequence.
 //
 // During an encode/decode sequence, we work as below:
 //   - If base is a built in type, en/decode base value
@@ -962,33 +962,46 @@ type typeInfo struct {
 
 	numMeth uint16 // number of methods
 
-	// baseId gives pointer to the base reflect.Type, after deferencing
-	// the pointers. E.g. base type of ***time.Time is time.Time.
-	base      reflect.Type
-	baseId    uintptr
-	baseIndir int8 // number of indirections to get to base
-
 	anyOmitEmpty bool
 
 	mbs bool // base type (T or *T) is a MapBySlice
 
-	bm        bool // base type (T or *T) is a binaryMarshaler
-	bunm      bool // base type (T or *T) is a binaryUnmarshaler
-	bmIndir   int8 // number of indirections to get to binaryMarshaler type
-	bunmIndir int8 // number of indirections to get to binaryUnmarshaler type
-
-	tm        bool // base type (T or *T) is a textMarshaler
-	tunm      bool // base type (T or *T) is a textUnmarshaler
-	tmIndir   int8 // number of indirections to get to textMarshaler type
-	tunmIndir int8 // number of indirections to get to textUnmarshaler type
-
-	jm        bool // base type (T or *T) is a jsonMarshaler
-	junm      bool // base type (T or *T) is a jsonUnmarshaler
-	jmIndir   int8 // number of indirections to get to jsonMarshaler type
-	junmIndir int8 // number of indirections to get to jsonUnmarshaler type
-
-	cs      bool // base type (T or *T) is a Selfer
-	csIndir int8 // number of indirections to get to Selfer type
+	// [btj][mu]p? OR csp?
+
+	bm  bool // T is a binaryMarshaler
+	bmp bool // *T is a binaryMarshaler
+	bu  bool // T is a binaryUnmarshaler
+	bup bool // *T is a binaryUnmarshaler
+	tm  bool // T is a textMarshaler
+	tmp bool // *T is a textMarshaler
+	tu  bool // T is a textUnmarshaler
+	tup bool // *T is a textUnmarshaler
+	jm  bool // T is a jsonMarshaler
+	jmp bool // *T is a jsonMarshaler
+	ju  bool // T is a jsonUnmarshaler
+	jup bool // *T is a jsonUnmarshaler
+	cs  bool // T is a Selfer
+	csp bool // *T is a Selfer
+	// su  bool // T is a
+	// sup  bool // *T is a
+
+	// bm        bool // base type (T or *T) is a binaryMarshaler
+	// bunm      bool // base type (T or *T) is a binaryUnmarshaler
+	// bmIndir   bool // is *T binaryMarshaler type
+	// bunmIndir bool // number of indirections to get to binaryUnmarshaler type
+
+	// tm        bool // base type (T or *T) is a textMarshaler
+	// tunm      bool // base type (T or *T) is a textUnmarshaler
+	// tmIndir   bool // number of indirections to get to textMarshaler type
+	// tunmIndir bool // number of indirections to get to textUnmarshaler type
+
+	// jm        bool // base type (T or *T) is a jsonMarshaler
+	// junm      bool // base type (T or *T) is a jsonUnmarshaler
+	// jmIndir   bool // number of indirections to get to jsonMarshaler type
+	// junmIndir bool // number of indirections to get to jsonUnmarshaler type
+
+	// cs      bool // base type (T or *T) is a Selfer
+	// csIndir bool // number of indirections to get to Selfer type
 
 	toArray bool // whether this (struct) type should be encoded as an array
 }
@@ -1092,56 +1105,29 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
 		}
 	}
 
+	rk := rt.Kind()
+
+	if rk == reflect.Ptr { // || (rk == reflect.Interface && rtid != intfTypId) {
+		panic(fmt.Errorf("invalid kind passed to TypeInfos.get: %v - %v", rk, rt))
+	}
+
 	// do not hold lock while computing this.
 	// it may lead to duplication, but that's ok.
 	ti := typeInfo{rt: rt, rtid: rtid}
 	// ti.rv0 = reflect.Zero(rt)
 
 	ti.numMeth = uint16(rt.NumMethod())
-	var ok bool
-	var indir int8
-	if ok, indir = implementsIntf(rt, binaryMarshalerTyp); ok {
-		ti.bm, ti.bmIndir = true, indir
-	}
-	if ok, indir = implementsIntf(rt, binaryUnmarshalerTyp); ok {
-		ti.bunm, ti.bunmIndir = true, indir
-	}
-	if ok, indir = implementsIntf(rt, textMarshalerTyp); ok {
-		ti.tm, ti.tmIndir = true, indir
-	}
-	if ok, indir = implementsIntf(rt, textUnmarshalerTyp); ok {
-		ti.tunm, ti.tunmIndir = true, indir
-	}
-	if ok, indir = implementsIntf(rt, jsonMarshalerTyp); ok {
-		ti.jm, ti.jmIndir = true, indir
-	}
-	if ok, indir = implementsIntf(rt, jsonUnmarshalerTyp); ok {
-		ti.junm, ti.junmIndir = true, indir
-	}
-	if ok, indir = implementsIntf(rt, selferTyp); ok {
-		ti.cs, ti.csIndir = true, indir
-	}
-	if ok, _ = implementsIntf(rt, mapBySliceTyp); ok {
-		ti.mbs = true
-	}
 
-	pt := rt
-	var ptIndir int8
-	// for ; pt.Kind() == reflect.Ptr; pt, ptIndir = pt.Elem(), ptIndir+1 { }
-	for pt.Kind() == reflect.Ptr {
-		pt = pt.Elem()
-		ptIndir++
-	}
-	if ptIndir == 0 {
-		ti.base = rt
-		ti.baseId = rtid
-	} else {
-		ti.base = pt
-		ti.baseId = rt2id(pt)
-		ti.baseIndir = ptIndir
-	}
+	ti.bm, ti.bmp = implIntf(rt, binaryMarshalerTyp)
+	ti.bu, ti.bup = implIntf(rt, binaryUnmarshalerTyp)
+	ti.tm, ti.tmp = implIntf(rt, textMarshalerTyp)
+	ti.tu, ti.tup = implIntf(rt, textUnmarshalerTyp)
+	ti.jm, ti.jmp = implIntf(rt, jsonMarshalerTyp)
+	ti.ju, ti.jup = implIntf(rt, jsonUnmarshalerTyp)
+	ti.cs, ti.csp = implIntf(rt, selferTyp)
+	ti.mbs, _ = implIntf(rt, mapBySliceTyp)
 
-	if rt.Kind() == reflect.Struct {
+	if rk == reflect.Struct {
 		var omitEmpty bool
 		if f, ok := rt.FieldByName(structInfoFieldName); ok {
 			siInfo := parseStructFieldInfo(structInfoFieldName, x.structTag(f.Tag))
@@ -1150,7 +1136,7 @@ func (x *TypeInfos) get(rtid uintptr, rt reflect.Type) (pti *typeInfo) {
 		}
 		pp, pi := pool.tiLoad()
 		pv := pi.(*typeInfoLoadArray)
-		pv.etypes[0] = ti.baseId
+		pv.etypes[0] = ti.rtid
 		vv := typeInfoLoad{pv.fNames[:0], pv.encNames[:0], pv.etypes[:1], pv.sfis[:0]}
 		x.rget(rt, rtid, omitEmpty, nil, &vv)
 		ti.sfip, ti.sfi, ti.anyOmitEmpty = rgetResolveSFI(vv.sfis, pv.sfiidx[:0])
@@ -1348,6 +1334,10 @@ func rgetResolveSFI(x []*structFieldInfo, pv []sfiIdx) (y, z []*structFieldInfo,
 	return
 }
 
+func implIntf(rt, iTyp reflect.Type) (base bool, indir bool) {
+	return rt.Implements(iTyp), reflect.PtrTo(rt).Implements(iTyp)
+}
+
 func xprintf(format string, a ...interface{}) {
 	if xDebug {
 		fmt.Fprintf(os.Stderr, format, a...)
@@ -1409,7 +1399,8 @@ type codecFnInfo struct {
 	xfFn  Ext
 	xfTag uint64
 	seq   seqType
-	addr  bool
+	addrD bool
+	addrE bool
 }
 
 // codecFn encapsulates the captured variables and the encode function.
@@ -1482,43 +1473,56 @@ func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (
 	fi := &(fn.i)
 	fi.ti = ti
 
-	if checkCodecSelfer && ti.cs {
+	rk := rt.Kind()
+
+	if checkCodecSelfer && (ti.cs || ti.csp) {
 		fn.fe = (*Encoder).selferMarshal
 		fn.fd = (*Decoder).selferUnmarshal
+		fi.addrD = ti.csp
+		fi.addrE = ti.csp
 	} else if rtid == rawTypId {
 		fn.fe = (*Encoder).raw
 		fn.fd = (*Decoder).raw
 	} else if rtid == rawExtTypId {
 		fn.fe = (*Encoder).rawExt
 		fn.fd = (*Decoder).rawExt
-		fn.i.addr = true
+		fi.addrD = true
+		fi.addrE = true
 	} else if c.hh.IsBuiltinType(rtid) {
 		fn.fe = (*Encoder).builtin
 		fn.fd = (*Decoder).builtin
-		fn.i.addr = true
+		fi.addrD = true
 	} else if xfFn := c.h.getExt(rtid); xfFn != nil {
 		fi.xfTag, fi.xfFn = xfFn.tag, xfFn.ext
 		fn.fe = (*Encoder).ext
 		fn.fd = (*Decoder).ext
-		fn.i.addr = true
-	} else if supportMarshalInterfaces && c.be && ti.bm && ti.bunm {
+		fi.addrD = true
+		if rk == reflect.Struct || rk == reflect.Array {
+			fi.addrE = true
+		}
+	} else if supportMarshalInterfaces && c.be && (ti.bm || ti.bmp) && (ti.bu || ti.bup) {
 		fn.fe = (*Encoder).binaryMarshal
 		fn.fd = (*Decoder).binaryUnmarshal
-	} else if supportMarshalInterfaces && !c.be && c.js && ti.jm && ti.junm {
+		fi.addrD = ti.bup
+		fi.addrE = ti.bmp
+	} else if supportMarshalInterfaces && !c.be && c.js && (ti.jm || ti.jmp) && (ti.ju || ti.jup) {
 		//If JSON, we should check JSONMarshal before textMarshal
 		fn.fe = (*Encoder).jsonMarshal
 		fn.fd = (*Decoder).jsonUnmarshal
-	} else if supportMarshalInterfaces && !c.be && ti.tm && ti.tunm {
+		fi.addrD = ti.jup
+		fi.addrE = ti.jmp
+	} else if supportMarshalInterfaces && !c.be && (ti.tm || ti.tmp) && (ti.tu || ti.tup) {
 		fn.fe = (*Encoder).textMarshal
 		fn.fd = (*Decoder).textUnmarshal
+		fi.addrD = ti.tup
+		fi.addrE = ti.tmp
 	} else {
-		rk := rt.Kind()
 		if fastpathEnabled && checkFastpath && (rk == reflect.Map || rk == reflect.Slice) {
 			if rt.PkgPath() == "" { // un-named slice or map
 				if idx := fastpathAV.index(rtid); idx != -1 {
 					fn.fe = fastpathAV[idx].encfn
 					fn.fd = fastpathAV[idx].decfn
-					fn.i.addr = true
+					fi.addrD = true
 				}
 			} else {
 				// use mapping for underlying type if there
@@ -1535,7 +1539,7 @@ func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (
 					fn.fe = func(e *Encoder, xf *codecFnInfo, xrv reflect.Value) {
 						xfnf(e, xf, xrv.Convert(xrt))
 					}
-					fn.i.addr = true
+					fi.addrD = true
 					xfnf2 := fastpathAV[idx].decfn
 					fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) {
 						xfnf2(d, xf, xrv.Convert(reflect.PtrTo(xrt)))
@@ -1605,7 +1609,7 @@ func (c *codecFner) get(rt reflect.Type, checkFastpath, checkCodecSelfer bool) (
 			case reflect.Array:
 				fi.seq = seqTypeArray
 				fn.fe = (*Encoder).kSlice
-				fi.addr = false
+				fi.addrD = false
 				rt2 := reflect.SliceOf(rt.Elem())
 				fn.fd = func(d *Decoder, xf *codecFnInfo, xrv reflect.Value) {
 					// println(">>>>>> decoding an array ... ")

+ 0 - 32
codec/helper_internal.go

@@ -9,7 +9,6 @@ package codec
 import (
 	"errors"
 	"fmt"
-	"math"
 	"reflect"
 )
 
@@ -86,37 +85,6 @@ func pruneSignExt(v []byte, pos bool) (n int) {
 	return
 }
 
-func implementsIntf(typ, iTyp reflect.Type) (success bool, indir int8) {
-	if typ == nil {
-		return
-	}
-	rt := typ
-	// The type might be a pointer and we need to keep
-	// dereferencing to the base type until we find an implementation.
-	for {
-		if rt.Implements(iTyp) {
-			return true, indir
-		}
-		if p := rt; p.Kind() == reflect.Ptr {
-			indir++
-			if indir >= math.MaxInt8 { // insane number of indirections
-				return false, 0
-			}
-			rt = p.Elem()
-			continue
-		}
-		break
-	}
-	// No luck yet, but if this is a base type (non-pointer), the pointer might satisfy.
-	if typ.Kind() != reflect.Ptr {
-		// Not a pointer, but does the pointer work?
-		if reflect.PtrTo(typ).Implements(iTyp) {
-			return true, -1
-		}
-	}
-	return false, 0
-}
-
 // validate that this function is correct ...
 // culled from OGRE (Object-Oriented Graphics Rendering Engine)
 // function: halfToFloatI (http://stderr.org/doc/ogre-doc/api/OgreBitwise_8h-source.html)