1// This file is part of the ustl library, an STL implementation.
2//
3// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net>
4// This file is free software, distributed under the MIT License.
5//
6/// \file uctrstrm.h
7///
8/// \brief Serialization templates for standard containers.
9/// Because containers are templates, a single operator>> is impossible.
10/// Making virtual read/write is also impossible because not all containers
11/// contain serializable elements. Therefore, use the macros in this file.
12///
13
14#ifndef UCTRSTRM_H_75B2C3EA4980DDDC6B6DFFF767A3B7AC
15#define UCTRSTRM_H_75B2C3EA4980DDDC6B6DFFF767A3B7AC
16
17#include "mistream.h"
18#include "sostream.h"
19#include "uiosfunc.h"
20
21namespace ustl {
22
23//----------------------------------------------------------------------
24// Macros for easily declaring a container streamable.
25//----------------------------------------------------------------------
26
27/// \brief Declares container template \p type streamable.
28///
29/// Use TEMPLATE_TYPE and TEMPLATE_DECL macros to pass in templated
30/// type with commas and the template declaration.
31///
32#define STD_TEMPLATE_CTR_STREAMABLE(type, template_decl)	\
33    template_decl						\
34    inline istream& operator>> (istream& is, type& v)		\
35    { return (container_read (is, v)); } 			\
36    template_decl						\
37    inline ostream& operator<< (ostream& os, const type& v)	\
38    { return (container_write (os, v)); } 			\
39    template_decl						\
40    inline ostringstream& operator<< (ostringstream& os, const type& v)	\
41    { return (container_text_write (os, v)); }			\
42    template_decl						\
43    inline size_t stream_size_of (const type& v)		\
44    { return (container_stream_size (v)); }
45
46/// \brief Declares non-resizable container template \p type streamable.
47#define STD_TEMPLATE_NR_CTR_STREAMABLE(type, template_decl)	\
48    template_decl						\
49    inline istream& operator>> (istream& is, type& v)		\
50    { return (nr_container_read (is, v)); } 			\
51    template_decl						\
52    inline ostream& operator<< (ostream& os, const type& v)	\
53    { return (nr_container_write (os, v)); } 			\
54    template_decl						\
55    inline ostringstream& operator<< (ostringstream& os, const type& v)	\
56    { return (container_text_write (os, v)); }			\
57    template_decl						\
58    inline size_t stream_size_of (const type& v)		\
59    { return (nr_container_stream_size (v)); }
60
61//----------------------------------------------------------------------
62// Fixed size container serialization.
63//----------------------------------------------------------------------
64
65/// Reads fixed size container \p v from stream \p is.
66template <typename Container>
67inline istream& nr_container_read (istream& is, Container& v)
68{
69    foreach (typename Container::iterator, i, v)
70	is >> *i;
71    return (is);
72}
73
74/// Writes fixed size container \p v into stream \p os.
75template <typename Container>
76inline ostream& nr_container_write (ostream& os, const Container& v)
77{
78    foreach (typename Container::const_iterator, i, v)
79	os << *i;
80    return (os);
81}
82
83/// Computes the stream size of a fixed size standard container.
84template <typename Container>
85size_t nr_container_stream_size (const Container& v)
86{
87    typedef typename Container::const_iterator vciter_t;
88    typedef typename iterator_traits<vciter_t>::value_type value_type;
89    size_t s = 0;
90    if (numeric_limits<value_type>::is_integral)
91	s += v.size() * stream_size_of(value_type());
92    else
93	foreach (vciter_t, i, v)
94	    s += stream_size_of(*i);
95    return (s);
96}
97
98//----------------------------------------------------------------------
99// Resizable container serialization.
100//----------------------------------------------------------------------
101
102/// Reads container \p v from stream \p is.
103template <typename Container>
104istream& container_read (istream& is, Container& v)
105{
106    typedef typename Container::value_type value_type;
107    typedef typename Container::iterator iterator;
108    typedef typename Container::written_size_type written_size_type;
109    written_size_type n;
110    is >> n;
111    const size_t expectedSize = n * stream_size_of(value_type());
112#if !PLATFORM_ANDROID
113    is.verify_remaining ("read", typeid(v).name(), expectedSize);
114#endif
115    if (alignof(value_type()) > alignof(n))
116	is >> ios::talign<value_type>();
117    v.resize (n);
118    nr_container_read (is, v);
119    is >> ios::talign<written_size_type>();
120    return (is);
121}
122
123/// Writes the vector to stream \p os.
124template <typename Container>
125ostream& container_write (ostream& os, const Container& v)
126{
127    typedef typename Container::value_type value_type;
128    typedef typename Container::written_size_type written_size_type;
129    const written_size_type sz (v.size());
130    os << sz;
131    if (alignof(value_type()) > alignof(sz))
132	os << ios::talign<value_type>();
133    nr_container_write (os, v);
134    os << ios::talign<written_size_type>();
135    return (os);
136}
137
138/// Computes the stream size of a standard container.
139template <typename Container>
140size_t container_stream_size (const Container& v)
141{
142    typedef typename Container::value_type value_type;
143    typedef typename Container::written_size_type written_size_type;
144    const written_size_type sz (v.size());
145    size_t sizeSize = stream_size_of (sz);
146    if (alignof(value_type()) > alignof(sz))
147	sizeSize = Align (sizeSize, alignof(value_type()));
148    return (Align (sizeSize + nr_container_stream_size (v), alignof(sz)));
149}
150
151/// \brief Writes element \p v into stream \p os as text.
152/// Specialize to custom print elements.
153template <typename T>
154inline ostringstream& container_element_text_write (ostringstream& os, const T& v)
155{ return (os << v); }
156
157/// Writes container \p v into stream \p os as text.
158template <typename Container>
159ostringstream& container_text_write (ostringstream& os, const Container& v)
160{
161    typename Container::const_iterator i = v.begin();
162    os << '(';
163    while (i < v.end()) {
164	container_element_text_write (os, *i);
165	if (++i >= v.end()) break;
166	os << ',';
167    }
168    os << ')';
169    return (os);
170}
171
172//----------------------------------------------------------------------
173
174} // namespace ustl
175
176#endif
177
178