On 22 November 2017 at 18:57, 'simon place' via golang-nuts
<[email protected]> 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
>> <[email protected]> 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].
>> > 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.
--
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.