psarna/seastar

Implement input_stream and output_stream classes

Opened this issue · 0 comments

Currently in serialize and deserialize functions I use std::istream and std::ostream for input/output data. To create streams backed by array/vector I use implementation from boost, however:

  • It lacks some functionality, which in turn requires me to copy the data too many times.
  • std::ostream backed by std::vector might be slower, because it has buffering (the data copied twice and need to remember to flush()).

Implement alternatives with this specification:

class input_stream {
private:
	const char *_data;
	size_t _length;

	size_t _current_position = 0;

public:
	input_stream(const char *data, size_t *length) noexcept;

	// Should read length characters
	// beginning from current_position in data, copying them into destination.
	// It should update the current_position (+= length).
	// It should check for possible errors (out-of-bounds length).
	// In case of error should throw parsing_exception.
	// (parsing_exception might not be merged into zpp_kafka, so
	// use some normal std::exception instead for now)
	// Use std::copy instead of manual loops.
	inline void read(char *destination, size_t *length);

	// Get the pointer to _data starting from _current_position.
	// It should throw if _current_position == _length
	// (the whole stream has been read).
	inline const char *get() const;

	inline size_t get_position() const noexcept;

	// It should also check for possible out-of-bounds.
	inline void set_position(size_t new_position);

	// Move current_position by delta. Check if new
	// position >= 0 && < size. (else throw exception)
        // Delta can be negative (go back in stream).
	inline void move_position(ssize_t delta);

        size_t size() const noexcept;
}

class output_stream {
private:
	vector<char> _data;

	size_t _current_position = 0;
	bool _is_resizable;

public:
	// Return a new stream with _data resized to size bytes.
	// It will not be resizable.
	static output_stream fixed_size_stream(size_t size);

	// Return a new stream with empty _data and _is_resizable = true.
	static output_stream resizable_stream();

	// It should copy bytes from source into _data at
	// current_position. It should add length to current_position.
	//
	// Example:
	// _data = [0, 1, 2, 3, 4]
	// _current_position = 1
	// write([7, 7], 2);
	// _data = [0, 7, 7, 3, 4]
	// _current_position = 3
	// 
	// If it is not resizable and we try to write
	// out-of-bounds, it should throw parsing_exception.
	//
	// If it is resizable and we try to write out of bounds
	// it should resize _data:
	//
	// _data = []
	// _current_position = 0
	// write([7, 7], 2);
	// _data = [7, 7]
	// _current_position = 2
	inline void write(const char *source, size_t *length);

	// Get the pointer to _data from _current_position.
	// It should throw if _current_position == _length.
	inline char *get();
	inline const char *get() const;

	// Get reference to _data.
	inline vector<char>& get_vector() noexcept;
	inline const vector<char>& get_vector() const noexcept;

	inline size_t get_position() const noexcept;

	// It should also check for possible out-of-bounds.
	// If resizable it should resize stream (and not check).
	inline void set_position(size_t new_position);

	// Move current_position by delta. Check if new
	// position >= 0 && < size.  (else throw exception)
	// If resizable it should resize stream (not checking < 0
	// but checking >= 0).
	inline void move_position(ssize_t delta);

        size_t size() const noexcept;
}

Please also implement tests, which should test edge cases (writing/reading out-of-bounds).

The file should be header-only (no .cc .cpp file).