diff --git a/doc/dataflow.html b/doc/dataflow.html index 4ae3b3010..de1912d07 100644 --- a/doc/dataflow.html +++ b/doc/dataflow.html @@ -126,10 +126,29 @@
iterator_adaptor just
invokes the equality operator on the base iterators. Generally this is satisfactory.
-However, this implies that other operations (E. G. dereference) do not prematurely
+However, this implies that other operations (E. G. dereference) do not prematurely
increment the base iterator. Avoiding this can be surprisingly tricky in some cases.
(E.G. transform_width)
+
+An iterator whose output elements do not line up with its input ones cannot
+always avoid it. transform_width
+learns that the input is over only by reading past the end of it, which is
+undefined behaviour, and it does so whenever the length of the input is not a
+common multiple of the two widths. Decoding base64, any length of the form
+4n + 1 ends in six bits which do not make up a byte, and those six bits send
+the iterator looking for the two it is missing.
+
+
+Passing the end of the input as a second constructor argument avoids this.
+The iterator then stops there, discarding whatever is left over rather than
+reading on for it. Both
+transform_width and
+remove_whitespace accept it. The one
+argument form behaves as it always has, and remains the one to use for a
+composed sequence whose length divides evenly, which is how the archives
+themselves use these iterators.
+
Iterators which fulfill the above requirements should be composable and the above sample
code should implement our binary to base64 conversion.
diff --git a/include/boost/archive/iterators/transform_width.hpp b/include/boost/archive/iterators/transform_width.hpp
index bd64f78d9..5289071ec 100644
--- a/include/boost/archive/iterators/transform_width.hpp
+++ b/include/boost/archive/iterators/transform_width.hpp
@@ -72,8 +72,19 @@ class transform_width :
}
bool equal_impl(const this_t & rhs){
- if(BitsIn < BitsOut) // discard any left over bits
+ if(BitsIn < BitsOut){ // discard any left over bits
+ if(m_bounded){
+ // Fill here rather than on dereference. The bits left when
+ // the input runs out part way through an output value do not
+ // make a whole one, so the sequence has to end before that
+ // value is handed out.
+ if(! m_buffer_out_full && ! m_exhausted){
+ fill();
+ }
+ return m_exhausted;
+ }
return this->base_reference() == rhs.base_reference();
+ }
else{
// BitsIn > BitsOut // zero fill
if(this->base_reference() == rhs.base_reference()){
@@ -105,6 +116,12 @@ class transform_width :
// flag to indicate we've reached end of data.
bool m_end_of_sequence;
+ // end of the input, when one has been given
+ Base m_end;
+ bool m_bounded;
+ // set once the input can yield no further whole output value
+ bool m_exhausted;
+
public:
// make composable by using templated constructor
template
+#include