Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the standard have both seekpos() and seekoff()?

The title pretty much says it all.

I am implementing my own streambuf class, and I am wondering what the Committee was thinking when they decided to include both std::streambuf::seekpos() and std::streambuf::seekoff() (and similarly for the related pubseekpos() and pubseekoff()).

It seems to me that seekpos(x) should have the same effect as seekoff(x, std::ios::beg) in every circumstance I can imagine. But perhaps my imagination is not good enough. So, why would you want to have both when seekpos is completely subsumed by seekoff? Or at least, why would you not make the default implementation of the former simply invoke the latter?

If the answer is "because that is what the STL did" or similar, then assume I am asking about the rationale for the STL or similar.

(I realize that the first argument of seekpos is a streampos while the first argument of seekoff is a streamoff. But note that 27.4.3.2 [lib.fpos.operations] requires that stream positions be convertible to stream offsets and back, so I do not think this is the answer.)

like image 382
Nemo Avatar asked Mar 18 '15 20:03

Nemo


2 Answers

The two functions use different parameters:

  • seekpos() positions you in a stream, using an absolute streampos position
  • seekoff() positions you in a stream, using a relative streamoff offset compared to a given position (begin, current, or end)

You are perfectly right: they can be converted in both direction. But there is a subtle semantic difference:

  • streampos is intuitively related to a fixed position whereas streamoff is somehow related to motion in a file.
  • substracting one streampos from another streampos makes a streamoff.
  • adding a streampos to a streamoff makes a new streampos.
  • other combinations are valid, thanks to the easy conversion, but require more care.
  • wide streams use wstreampos for the position (because obviously a position within a wchar_t has a different meaning as a position in a char stream).
  • but wide streams use streamoff for motion, as it is a relative movement compared to a position.

If you use template programming, these semantic differences are more explicit with the traits: S::pos_type and S::off_type.

Real origin

Regardless of these semantic subtilities, the real origin of this difference is historical, and related to the C standard library, as explained by Mr. Plauger in this article:

  • streamoff was designed with fseek() and ftell() of the C standard library in mind, which use a long for positioning.
  • streampos was meant for fgetpos() and fsetpos() which use an fpos_t argument.

I could verify that this was already the case in C89 standard. As neither of these functions were mentionned in the original K&R, maybe a UNIX historian could tell more about an even more distant path.

This paper explains the more recent thoughts of the standard committee. It appears that the historic difference is questioned and that it is no longer clear whether it is still really needed.

like image 135
Christophe Avatar answered Oct 19 '22 00:10

Christophe


I am wondering what the Committee was thinking when they decided to include both std::streambuf::seekpos() and std::streambuf::seekoff() (and similarly for the related pubseekpos() and pubseekoff()).

streampos represents an absolute position from the beginning of the stream. Thus, seekpos() seeks to a specific position.

streamoff represents an offset from a given position. Thus, seekoff() can seek relative to any given position. That is why it has a dir parameter to specify how the offset is to be interpreted - an offset from the beginning/end of the stream, or an offset relative to the stream's current position.

Different semantics, so different functions provided.

It seems to me that seekpos(x) should have the same effect as seekoff(x, std::ios::beg) in every circumstance I can imagine.

That is logically what it does, yes. Though the actual implementation could be optimized, such as by taking the current position into account to minimize the amount of physical seeking involved, especially for file streams. It is not always efficient to make the OS go all the way back to the beginning of the file just to move forward again.

So, why would you want to have both when seekpos is completely subsumed by seekoff?

Because sometimes it makes sense to seek to a specific position directly, and sometimes it makes sense to seek to a relative offset. It depends on the circumstance. Both cases have their uses.

So, why would you want to have both when seekpos is completely subsumed by seekoff?

Convenience. Depends on the design of the calling code, whether it keeps track of absolute positions or relative offsets.

Or at least, why would you not make the default implementation of the former simply invoke the latter?

It could be. It is implementation-defined.

But note that 27.4.3.2 [lib.fpos.operations] requires that stream positions be convertible to stream offsets and back, so I do not think this is the answer.)

Convertible being the key word here. Just because they can be converted to each other does not mean they are semantically equal to each other.

like image 2
Remy Lebeau Avatar answered Oct 19 '22 00:10

Remy Lebeau