thanks,
this cloning is an optimisation, slowing it down a lot makes it pointless
to begin with, but luckily really, the program produced has a built-in list
of selectable, std.lib., hash routines to select from.
i will add a warning for someone forking it about this.
BTW your improved cloning reflection code proved much faster;
func cloneHash(h hash.Hash) hash.Hash{
return clone(h).(hash.Hash)
}
func clone(i interface{}) interface{} {
hv := reflect.ValueOf(i)
hv1 := reflect.New(hv.Type().Elem())
hv1.Elem().Set(hv.Elem())
return hv1.Interface()
}
On Wednesday, 22 November 2017 13:16:01 UTC, rog wrote:
>
> On 21 November 2017 at 21:56, 'simon place' via golang-nuts
> <[email protected] <javascript:>> wrote:
> > i found this code, and use it on hash.Hash
> >
> > // copy an interface value using reflect (here for pointers to
> interfaces)
> > func clone(i interface{}) interface{} {
> > indirect := reflect.Indirect(reflect.ValueOf(i))
> > newIndirect := reflect.New(indirect.Type())
> > newIndirect.Elem().Set(reflect.ValueOf(indirect.Interface()))
> > return newIndirect.Interface()
> > }
> >
> > like this;
> >
> > branchHasher = clone(hasher).(hash.Hash)
>
> Although this works on most hash implementations in the standard library,
> I'm not sure I'd recommend doing this, as it depends on the fact that
> all the state in the hash implementations will copied with a shallow copy.
>
> Better (albeit less efficient) would be something like this, I think:
>
> func CloneHash(h hash.Hash) hash.Hash {
> type codec interface {
> hash.Hash
> encoding.BinaryMarshaler
> encoding.BinaryUnmarshaler
> }
> mh, ok := h.(codec)
> if !ok {
> panic(fmt.Errorf("hash %T cannot be cloned", h))
> }
> data, err := mh.MarshalBinary()
> if err != nil {
> panic(fmt.Errorf("hash %T marshal failed: %v", h, err))
> }
> t := reflect.TypeOf(h)
> if t.Kind() != reflect.Ptr {
> panic(fmt.Errorf("hash %T is not of pointer type", h))
> }
>
> mh1 := reflect.New(t.Elem()).Interface().(codec)
> if err := mh1.UnmarshalBinary(data); err != nil {
> panic(fmt.Errorf("hash %T unmarshal failed: %v", mh1, err))
> }
> return mh1
> }
>
> I could understand why you might use your original version for performance
> reasons, though. It could be a little simpler, I think:
>
> // CloneHash clones the current state of the given
> // hash. It works with most implementations in the standard
> // library but is not guaranteed to work with all Hash
> // implementations.
> func CloneHash(h hash.Hash) hash.Hash {
> hv := reflect.ValueOf(h)
> hv1 := reflect.New(hv.Type().Elem())
> hv1.Elem().Set(hv.Elem())
> return hv1.Interface().(hash.Hash)
> }
>
> If I was using it in production code, I'd probably be defensive and do
> something
> like this:
>
> https://play.golang.org/p/QDUlwuFAuv
>
> I think that even now that hashes that implement encoding.BinaryMarshaler
> and
> encoding.BinaryUnmarshaler, there's probably still room for a Clone method
> (or perhaps a top level hash.Clone function) in the standard library to
> avoid
> the necessity for this kind of thing.
>
> >
> >
> > On Wednesday, 8 November 2017 12:54:18 UTC, Christian LeMoussel wrote:
> >>
> >> Hi,
> >>
> >> I want to calculate hash on 3 strings. First string is always the same,
> >> the other may vary.
> >> The first approach is to calculate the hash each time for the 3 strings
> >> (BenchmarkHash)
> >> Another approach would be to calculate once for the first string, and
> then
> >> reuse this hash to calculate the hash with the other 2
> >> strings(BenchmarkCopyHash)
> >> The difficulty is that sha256.New() returns a pointer, we have to copy
> the
> >> first hash. To do this, I created the function copyHash()
> >> But the performances are not exceptional.
> >>
> >> Do you have another idea to do this in efficient way?
> >>
> >>
> >> BenchmarkHash-8 1000000 1761 ns/op
> >> 176 B/op 4 allocs/op
> >> BenchmarkCopyHash-8 1000000 1519 ns/op
> >> 240 B/op 4 allocs/op
> >>
> >>
> >> var m1 = strings.Repeat("a", 64)
> >> var m2 = strings.Repeat("b", 48)
> >> var m3 = strings.Repeat("c", 32)
> >>
> >> func BenchmarkHash(b *testing.B) {
> >> var (
> >> d hash.Hash
> >> )
> >>
> >> d = sha256.New()
> >> for n := 0; n < b.N; n++ {
> >> d.Reset()
> >> d.Write([]byte(m1))
> >> d.Write([]byte(m2))
> >> d.Write([]byte(m3))
> >> d.Sum(nil)
> >> }
> >> }
> >> func BenchmarkCopyHash(b *testing.B) {
> >> var (
> >> d1 hash.Hash
> >> d2 hash.Hash
> >> )
> >>
> >> d1 = sha256.New()
> >> d1.Write([]byte(m1))
> >>
> >> for n := 0; n < b.N; n++ {
> >> d2 = copyHash(d1)
> >> d2.Write([]byte(m2))
> >> d2.Write([]byte(m3))
> >> d2.Sum(nil)
> >> }
> >> }
> >>
> >> func copyHash(src hash.Hash) hash.Hash {
> >> typ := reflect.TypeOf(src).Elem()
> >> val := reflect.ValueOf(src).Elem()
> >> elem := reflect.New(typ).Elem()
> >> elem.Set(val)
> >> return elem.Addr().Interface().(hash.Hash)
> >> }
> >>
> >>
> >>
> >>
> >>
> >>
> > --
> > You received this message because you are subscribed to the Google
> Groups
> > "golang-nuts" group.
> > To unsubscribe from this group and stop receiving emails from it, send
> an
> > email to [email protected] <javascript:>.
> > For more options, visit https://groups.google.com/d/optout.
>
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.