Bonjour
J'ai crée deux classes de streambuf filtrant en suivant les explications que James Kanze en fait dans son article, et deux classes d'insert/extractor basique pour fonctionner avec mes streambuf, les voici :
basic_extractor et filtering_input_streambuf
basic_inserter et filtering_output_streambuf
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 #ifndef FILTERING_INPUT_STREAMBUF_H_INCLUDED #define FILTERING_INPUT_STREAMBUF_H_INCLUDED #include <streambuf> #include <limits> template<class charT, class traits = std::char_traits<charT> > class basic_extractor { typedef typename traits::int_type int_type; public: virtual int_type operator()(std::basic_streambuf<charT, traits> &) = 0; }; template<class charT, class extractor = basic_extractor<charT>, class traits = std::char_traits<charT> > class filtering_input_streambuf : public std::basic_streambuf<charT, traits> { typedef charT char_type; typedef typename traits::int_type int_type; std::basic_streambuf<charT, traits> * m_source; char_type m_push_back_buffer; extractor * m_extractor; public : filtering_input_streambuf(std::basic_streambuf<charT, traits> * source, extractor * x) : m_source(source), m_extractor(x) { } ~filtering_input_streambuf() { m_source = NULL; filtering_input_streambuf::setg(NULL, NULL, NULL); } virtual int_type underflow() { int_type result(traits::eof()); if (filtering_input_streambuf::gptr() < filtering_input_streambuf::egptr()) result = static_cast<int_type>(*filtering_input_streambuf::gptr()); else if (m_source != NULL) { result = extract(*m_source); if (result != traits::eof()) { assert(result >= std::numeric_limits<int_type>::min() && result <= std::numeric_limits<int_type>::max()) ; m_push_back_buffer = result; filtering_input_streambuf::setg(&m_push_back_buffer, &m_push_back_buffer, &m_push_back_buffer + 1); } } return result; } int_type sync() { int_type result(traits::eof()); if (m_source != NULL) { if (filtering_input_streambuf::gptr() == filtering_input_streambuf::egptr() || m_source->sputbackc(*filtering_input_streambuf::gptr()) != traits::eof()) result = m_source->pubsync() ; filtering_input_streambuf::setg(NULL, NULL, NULL); } return result ; } protected : virtual int extract(std::basic_streambuf<charT, traits> & source) { return (*m_extractor)(source); } }; #endif // FILTERING_INPUT_STREAMBUF_H_INCLUDED
Pour tester mes classe j'ai cré un extractor et un inserter assez simple (ils font la même choses que ceux de James dans son article) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 #ifndef FILTERING_OUTPUT_STREAMBUF_H_INCLUDED #define FILTERING_OUTPUT_STREAMBUF_H_INCLUDED #include <streambuf> template<class charT, class traits = std::char_traits<charT> > class basic_inserter { typedef typename traits::int_type int_type; public: virtual int_type operator()(std::basic_streambuf<charT, traits> &, int_type) = 0; }; template<class charT, class inserter = basic_inserter<charT> , class traits = std::char_traits<charT> > class filtering_output_streambuf : public std::basic_streambuf<charT, traits> { typedef typename traits::int_type int_type; std::basic_streambuf<charT, traits> * m_dest; inserter * m_inserter; public : filtering_output_streambuf(std::basic_streambuf<charT, traits> * dest, inserter * i) : m_dest(dest), m_inserter(i) { } ~filtering_output_streambuf() { m_dest = NULL; } virtual int_type overflow(int_type c) { int_type result(traits::eof()); if (c == traits::eof()) result = sync(); else if (m_dest != NULL) result = insert(*m_dest, c); return result; } virtual int_type sync() { int_type result(traits::eof()); if (m_dest != NULL) result = m_dest->pubsync(); return result; } protected : virtual int_type insert(std::basic_streambuf<charT, traits> & dest, int_type c) { return (*m_inserter)(dest, c); } }; #endif // FILTERING_OUTPUT_STREAMBUF_H_INCLUDED
Et j'ai mis tout ca dans le main :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 #ifndef ALGO_H_INCLUDED #define ALGO_H_INCLUDED #include "filtering_output_streambuf.h" #include "filtering_input_streambuf.h" template<class charT, class traits = std::char_traits<charT> > class extractor_test : public basic_extractor<charT, traits> { typedef typename traits::int_type int_type; public: virtual int_type operator()(std::basic_streambuf<charT, traits> & source) { int_type c = source.sbumpc(); if (c == '/') { while (c != '\n' && c != traits::eof()) c = source.sbumpc(); } return c; } }; template<class charT, class traits = std::char_traits<charT> > class inserter_test : public basic_inserter<charT, traits> { typedef typename traits::int_type int_type; bool m_line; public: inserter_test() : m_line(true) { } virtual int_type operator()(std::basic_streambuf<charT, traits> & dest, int_type c) { if (m_line && c != '\n') dest.sputc('#'); m_line = (c == '\n'); return dest.sputc(c); } }; #endif // ALGO_H_INCLUDED
Ce code marche, cependant il suffit de créer une 2° variable string pour que ca plante (3 variable string ca ne plante pas), ou de commenter certaines lignes pour que ca ne marche plus (par exemple laissez juste les déclarations de f_i et f_o, ou que l'une des deux, et la le comportement sera indeterminé, une fois ca s'executera sans probleme une autre ca plantera). Si quelqu'un pourrait me dire ce qui provoque ce comportement, ca m'aiderai.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #include <iostream> #include <string> #include "filtering_output_streambuf.h" #include "filtering_input_streambuf.h" #include "algo.h" int main() { std::string s; filtering_input_streambuf<char> f_i(std::cin.rdbuf(), new extractor_test<char>); std::cin.rdbuf(&f_i); std::cin >> s; filtering_output_streambuf<char> f_o(std::cout.rdbuf(), new inserter_test<char>); std::cout.rdbuf(&f_o); std::cout << s; return EXIT_SUCCESS; }
Merci d'avance.
Partager