﻿/************************************************
 *	ZPR - praca domowa
 *
 *	Temat: boost::iostreams (devices)
 *
 *	Autor: Łukasz Dańko	
 *	Grupa: N1-IBERE2
 ************************************************/

/*
		Devices są wprowadzoną w bibliotece booost::iostreams koncepcją obiektów zapewniających dostęp do ciągu znaków,
	w zależności od typu - wejściowego, wyjściowego albo obu. Wykorzystuje się je do tworzenia obiektów typu 
	stream lub stream_buffer.
		Device realizujący operację zapisu nazywa się sink, natomiast realizujący operację odczytu nazywa się source.
	Typowo obiekt taki posiada metody: read, write i seek (w zależności od typu), oraz definiuje typy char_type i category, na przykład
	prosty source mógłby wyglądać tak:
*/

#include <iosfwd>                          // streamsize
#include <boost/iostreams/categories.hpp>  // source_tag

using namespace boost::iostreams;

class source_dev {
public:
	// definicja typu znaków, jaki jest przez Device odczytywany
	// najczęściej jest to char
	typedef char        char_type;
	// kategoria Device'a - określa jakie operacje
	// wejścia/wyjścia są w tej klasie realizowane
	// zdefiniowane w bibliotece kategorie znajdują się w pliku
	// boost/iostreams/categories.hpp
	typedef source_tag  category;

	// Device jest źródłem (source), więc implementuje tylko metodę read
	std::streamsize read(char* s, std::streamsize n)
	{
		// Odczytaj n znaków ze źródła i zapisz je do bufora s
		// zwróć liczbę wczytanych znaków albo -1 w przypadku EOF
	}

};

/*
	Albo prościej, dziedzicząc po jednym z dostępnych
	w bibliotece boost::iostreams podstawowych Device'ów
	(znajdują się one w pliku boost/iostreams/concepts.hpp):
*/

#include <boost/iostreams/concepts.hpp>  // source

class source_dev_2 : public source {
public:
	std::streamsize read(char* s, std::streamsize n);
};

//******************************************************//
/*
	Pisanie własnych Device'ów daje szerokie możliwości, np. 
	można stworzyć Device zapisujący do kontenera STL
*/

#include <algorithm>                       // copy, min
#include <iosfwd>                          // streamsize
#include <boost/iostreams/categories.hpp>  // sink_tag

template<typename Container>
class container_sink {
public:
    typedef typename Container::value_type  char_type;
    typedef sink_tag                        category;
    container_sink(Container& container) : container_(container) { }
    std::streamsize write(const char_type* s, std::streamsize n)
    {
        container_.insert(container_.end(), s, s + n);
        return n;
    }
    Container& container() { return container_; }
private:
    Container& container_;
};

/*
	Biblioteka boost::iostreams udostępnia także gotowe Device, np. obsługujące operacje na plikach,
*/

#include <ostream>
#include <iostream>
#include <vector>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>

using namespace std;

int main()
{
	// Tworzenie stumienia zapisu do pliku:
	{
		stream_buffer<file_sink> out_buf("HelloWorld.txt");
		ostream                     file_out(&out_buf);
		file_out << "Hello World!" << endl;	// zapisuje do pliku HelloWorld.txt
	}	// faktyczny zapis do pliku dokonuje się dopiero w momencie niszczenia obiektu file_out
		// w tym przypadku po opuszczeniu powyższego bloku kodu

	string str;
	// Tworzenie strumienia odczytu z pliku
	stream_buffer<file_source> in_buf("HelloWorld.txt");
	istream							file_in(&in_buf);
	//file_in >> str;			// pobierze pojedyńcze słowa
	getline(file_in, str);	// pobierze całą linię
	assert(str == "Hello World!");

	string result;
	// Tworzenie strumienia zapisu do string'a
	stream<container_sink<string>>  str_out(result);
	str_out << "Hello World!";	// dopisze do zmiennej result tekst "Hello World!"
	str_out.flush();
	assert(result == "Hello World!");

	return 0;
}



