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 
> <golan...@googlegroups.com <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 golang-nuts...@googlegroups.com <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 golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to