On 22 November 2017 at 18:57, 'simon place' via golang-nuts <golang-nuts@googlegroups.com> wrote: > 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;
That's good to hear :) > > 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> 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. >> > 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. -- 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.