-
Notifications
You must be signed in to change notification settings - Fork 189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add (*Reader).CopyNext(w) (int64, error) #167
Conversation
I think the errors returned from |
Actually, as I squint harder at this, it's not clear that |
Ah. Any ideas on how to fix this or otherwise do it correctly? |
My implementation was inspired by |
|
Oh, crap, I have not pushed the latest commit. Oops. |
2cdb467
to
8a1bc12
Compare
Force pushed. |
Will fix Error return, too. |
Ok cool; this looks correct. I might suggest |
Also, given the non-obvious nature of |
Nice idea for For Still fixing the error contract. |
|
n, err := m.R.ReadFull(p[:sz])
if err != nil {
return 0, err
}
if uintptr(n) != sz {
return 0, fmt.Errorf("wrong # bytes read (%d != %d)", n, int64(sz))
} |
(If (3) is necessary, does it want to be yet another named error in Thanks for the rapid review by the way. |
The caller doesn't necessarily lose control of the buffer. The size check should be unnecessary; it's a bug if |
(The |
But in order to call the |
Yeah; you'd need to refactor the code a bit. |
|
It is useful to be able to efficiently copy objects without decoding them. My use case is filtering when I already know the indices of the objects I want to keep, and for rewriting a dictionary of objects as a column of objects.
200fd71
to
5ca5615
Compare
That was the bit I was missing. That is freaking awesome: --- a/msgp/read.go
+++ b/msgp/read.go
@@ -180,6 +180,32 @@ func (m *Reader) ReadNext(p []byte) (int, error) {
return tot, nil
}
+// CopyNext reads the next object from m without decoding it and writes it to w.
+// It avoids unnecessary copies internally.
+func (m *Reader) CopyNext(w io.Writer) (int64, error) {
+ sz, o, err := getNextSize(m.R)
+ if err != nil {
+ return 0, err
+ }
+
+ // avoids allocating because m.R implements WriteTo.
+ n, err := io.CopyN(w, m.R, int64(sz))
+ if err != nil {
+ return 0, err
+ }
+
+ // for maps and slices, read elements
+ for x := uintptr(0); x < o; x++ {
+ var n2 int64
+ n2, err = m.CopyNext(w)
+ if err != nil {
+ return n, err
+ }
+ n += n2
+ }
+ return n, nil
+}
+
// ReadFull implements `io.ReadFull`
func (m *Reader) ReadFull(p []byte) (int, error) {
return m.R.ReadFull(p) I have fully squashed my patches and force pushed. |
Sorry, please hold, I forgot to remove Also, do we need to revisit in light of your strikeout in the above comment? |
I would use |
2d1a0cb
to
eef5f70
Compare
Pushed. My current status: happy. Taking a break for a bit. I learned some neat tricks tonight, thanks for that 😎 |
@pwaller hey, did you want to finish this off? If not, I'm happy to do so myself. |
AFAIK, I think it's done? I've ticked "Allow edits from maintainers" if you would like to make any additional changes. |
- only call (*Reader).Next() when we're sure it won't realloc its buffer - promote io.ErrUnexpectedEOF to msgp.ErrShortBytes
Cool. Pushed a small change in the error handling to make it a little more consistent with the rest of the code. Thanks again! |
👍 |
* Add (*Reader).CopyNext(w) (int64, error) It is useful to be able to efficiently copy objects without decoding them. My use case is filtering when I already know the indices of the objects I want to keep, and for rewriting a dictionary of objects as a column of objects. * Remove ReadNext * Add opportunistic optimization with m.R.Next * Remove unused ReadNextError * Remove commented code * small fixup - only call (*Reader).Next() when we're sure it won't realloc its buffer - promote io.ErrUnexpectedEOF to msgp.ErrShortBytes
It is useful to be able to efficiently copy objects without
decoding them.
My use case is filtering when I already know the indices of
the objects I want to keep, and for rewriting a dictionary
of objects as a column of objects.
This commit:
GetNextSize
.ReadNext(p)
to*Reader
.I wasn't sure about exporting
GetNextSize
, but I can't see theharm in it, and it may be useful for finer-grained control in
the copying.
I also experimented with a
NextReader() io.Reader
method whichreturned
io.LimitReader(m.R, GetNextSize())
, but for my use casethis was twice as slow and also did not handle nested objects.
In principle that might be useful for very large simple objects,
but is not included in this PR.
This change is![Reviewable](https://camo.githubusercontent.com/23b05f5fb48215c989e92cc44cf6512512d083132bd3daf689867c8d9d386888/68747470733a2f2f72657669657761626c652e696f2f7265766965775f627574746f6e2e737667)