]> www.ginac.de Git - ginac.git/blob - ginac/container.h
Fix excessive backslashes in the LaTeX function names.
[ginac.git] / ginac / container.h
1 /** @file container.h
2  *
3  *  Wrapper template for making GiNaC classes out of STL containers. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2017 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #ifndef GINAC_CONTAINER_H
24 #define GINAC_CONTAINER_H
25
26 #include "ex.h"
27 #include "print.h"
28 #include "archive.h"
29 #include "assertion.h"
30 #include "compiler.h"
31
32 #include <algorithm>
33 #include <iterator>
34 #include <list>
35 #include <memory>
36 #include <stdexcept>
37 #include <vector>
38
39 namespace GiNaC {
40
41 /** Helper template for encapsulating the reserve() mechanics of STL containers. */
42 template <template <class T, class = std::allocator<T>> class C>
43 class container_storage {
44 protected:
45         typedef C<ex> STLT;
46
47         container_storage() {}
48         container_storage(size_t n, const ex & e) : seq(n, e) {}
49         container_storage(std::initializer_list<ex> il) : seq(il) {}
50
51         template <class In>
52         container_storage(In b, In e) : seq(b, e) {}
53
54         void reserve(size_t) {}
55         static void reserve(STLT &, size_t) {}
56
57         STLT seq;
58
59         // disallow destruction of container through a container_storage*
60 protected:
61         ~container_storage() {}
62 };
63
64 template <>
65 inline void container_storage<std::vector>::reserve(size_t n) { seq.reserve(n); }
66
67 template <>
68 inline void container_storage<std::vector>::reserve(std::vector<ex> & v, size_t n) { v.reserve(n); }
69
70
71 /** Helper template to allow initialization of containers via an overloaded
72  *  comma operator (idea stolen from Blitz++). */
73 template <typename T, typename STLT>
74 class container_init {
75 public:
76         container_init(STLT & s) : stlt(s) {}
77
78         container_init<T, STLT> operator,(const T & x)
79         {
80                 stlt.push_back(x);
81                 return container_init<T, STLT>(stlt);
82         }
83
84         // The following specializations produce much tighter code than the
85         // general case above
86
87         container_init<T, STLT> operator,(int x)
88         {
89                 stlt.push_back(x);
90                 return container_init<T, STLT>(stlt);
91         }
92
93         container_init<T, STLT> operator,(unsigned int x)
94         {
95                 stlt.push_back(x);
96                 return container_init<T, STLT>(stlt);
97         }
98
99         container_init<T, STLT> operator,(long x)
100         {
101                 stlt.push_back(x);
102                 return container_init<T, STLT>(stlt);
103         }
104
105         container_init<T, STLT> operator,(unsigned long x)
106         {
107                 stlt.push_back(x);
108                 return container_init<T, STLT>(stlt);
109         }
110
111         container_init<T, STLT> operator,(double x)
112         {
113                 stlt.push_back(x);
114                 return container_init<T, STLT>(stlt);
115         }
116
117         container_init<T, STLT> operator,(const symbol & x)
118         {
119                 stlt.push_back(T(x));
120                 return container_init<T, STLT>(stlt);
121         }
122
123 private:
124         container_init();
125         STLT & stlt;
126 };
127
128 /** Wrapper template for making GiNaC classes out of STL containers. */
129 template <template <class T, class = std::allocator<T>> class C>
130 class container : public basic, public container_storage<C> {
131         GINAC_DECLARE_REGISTERED_CLASS(container, basic)
132 protected:
133         typedef typename container_storage<C>::STLT STLT;
134
135 public:
136         typedef typename STLT::const_iterator const_iterator;
137         typedef typename STLT::const_reverse_iterator const_reverse_iterator;
138
139 protected:
140         // helpers
141         static unsigned get_default_flags() { return 0; }
142         static char get_open_delim() { return '('; }
143         static char get_close_delim() { return ')'; }
144
145         // constructors
146 public:
147         container(STLT const & s)
148         {
149                 setflag(get_default_flags());
150                 this->seq = s;
151         }
152
153         explicit container(STLT && v)
154         {
155                 setflag(get_default_flags());
156                 this->seq.swap(v);
157         }
158
159         container(exvector::const_iterator b, exvector::const_iterator e)
160          : container_storage<C>(b, e)
161         {
162                 setflag(get_default_flags());
163         }
164
165         container(std::initializer_list<ex> il)
166          : container_storage<C>(il)
167         {
168                 setflag(get_default_flags());
169         }
170
171         explicit container(const ex & p1) attribute_deprecated;
172         container(const ex & p1, const ex & p2) attribute_deprecated;
173         container(const ex & p1, const ex & p2, const ex & p3) attribute_deprecated;
174         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4) attribute_deprecated;
175         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5) attribute_deprecated;
176         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6) attribute_deprecated;
177         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7) attribute_deprecated;
178         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8) attribute_deprecated;
179         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
180                   const ex & p9) attribute_deprecated;
181         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
182                   const ex & p9, const ex & p10) attribute_deprecated;
183         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
184                   const ex & p9, const ex & p10, const ex & p11) attribute_deprecated;
185         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
186                   const ex & p9, const ex & p10, const ex & p11, const ex & p12) attribute_deprecated;
187         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
188                   const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13) attribute_deprecated;
189         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
190                   const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14) attribute_deprecated;
191         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
192                   const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15) attribute_deprecated;
193         container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
194                   const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15, const ex & p16) attribute_deprecated;
195
196         // First step of initialization of container with a comma-separated
197         // sequence of expressions. Subsequent steps are handled by
198         // container_init<>::operator,().
199         container_init<ex, STLT> operator=(const ex & x) attribute_deprecated;
200
201         // functions overriding virtual functions from base classes
202 public:
203         bool info(unsigned inf) const override { return inherited::info(inf); }
204         unsigned precedence() const override { return 10; }
205         size_t nops() const override { return this->seq.size(); }
206         ex op(size_t i) const override;
207         ex & let_op(size_t i) override;
208         ex subs(const exmap & m, unsigned options = 0) const override;
209
210         void read_archive(const archive_node &n, lst &sym_lst) override
211         {
212                 inherited::read_archive(n, sym_lst);
213                 setflag(get_default_flags());
214
215                 archive_node::archive_node_cit first = n.find_first("seq");
216                 archive_node::archive_node_cit last = n.find_last("seq");
217                 ++last;
218                 this->reserve(this->seq, last - first);
219                 for (archive_node::archive_node_cit i=first; i<last; ++i) {
220                         ex e;
221                         n.find_ex_by_loc(i, e, sym_lst);
222                         this->seq.push_back(e);
223                 }
224         }
225
226         /** Archive the object. */
227         void archive(archive_node &n) const override
228         {
229                 inherited::archive(n);
230                 for (auto & i : this->seq) {
231                         n.add_ex("seq", i);
232                 }
233         }
234
235 protected:
236         ex conjugate() const override
237         {
238                 STLT *newcont = nullptr;
239                 for (const_iterator i=this->seq.begin(); i!=this->seq.end(); ++i) {
240                         if (newcont) {
241                                 newcont->push_back(i->conjugate());
242                                 continue;
243                         }
244                         ex x = i->conjugate();
245                         if (are_ex_trivially_equal(x, *i)) {
246                                 continue;
247                         }
248                         newcont = new STLT;
249                         this->reserve(*newcont, this->seq.size());
250                         for (const_iterator j=this->seq.begin(); j!=i; ++j) {
251                                 newcont->push_back(*j);
252                         }
253                         newcont->push_back(x);
254                 }
255                 if (newcont) {
256                         ex result = thiscontainer(*newcont);
257                         delete newcont;
258                         return result;
259                 }
260                 return *this;
261         }
262
263         ex real_part() const override
264         {
265                 STLT cont;
266                 this->reserve(cont, nops());
267                 const_iterator b = begin();
268                 const_iterator e = end();
269                 for(const_iterator i=b; i!=e; ++i)
270                         cont.push_back(i->real_part());
271                 return thiscontainer(cont);
272         }
273
274         ex imag_part() const override
275         {
276                 STLT cont;
277                 this->reserve(cont, nops());
278                 const_iterator b = begin();
279                 const_iterator e = end();
280                 for(const_iterator i=b; i!=e; ++i)
281                         cont.push_back(i->imag_part());
282                 return thiscontainer(cont);
283         }
284
285         bool is_equal_same_type(const basic & other) const override;
286
287         // new virtual functions which can be overridden by derived classes
288 protected:
289         /** Similar to duplicate(), but with a preset sequence. Must be
290          *  overridden by derived classes. */
291         virtual ex thiscontainer(const STLT & v) const { return container(v); }
292
293         /** Similar to duplicate(), but with a preset sequence (which gets
294          *  pilfered). Must be overridden by derived classes. */
295         virtual ex thiscontainer(STLT && v) const { return container(std::move(v)); }
296
297         virtual void printseq(const print_context & c, char openbracket, char delim,
298                               char closebracket, unsigned this_precedence,
299                               unsigned upper_precedence = 0) const;
300
301         // non-virtual functions in this class
302 private:
303         void sort_(std::random_access_iterator_tag)
304         {
305                 std::sort(this->seq.begin(), this->seq.end(), ex_is_less());
306         }
307
308         void sort_(std::input_iterator_tag)
309         {
310                 this->seq.sort(ex_is_less());
311         }
312
313         void unique_()
314         {
315                 typename STLT::iterator p = std::unique(this->seq.begin(), this->seq.end(), ex_is_equal());
316                 this->seq.erase(p, this->seq.end());
317         }
318
319 public:
320         container & prepend(const ex & b);
321         container & append(const ex & b);
322         container & remove_first();
323         container & remove_last();
324         container & remove_all();
325         container & sort();
326         container & unique();
327
328         const_iterator begin() const {return this->seq.begin();}
329         const_iterator end() const {return this->seq.end();}
330         const_reverse_iterator rbegin() const {return this->seq.rbegin();}
331         const_reverse_iterator rend() const {return this->seq.rend();}
332
333 protected:
334         void do_print(const print_context & c, unsigned level) const;
335         void do_print_tree(const print_tree & c, unsigned level) const;
336         void do_print_python(const print_python & c, unsigned level) const;
337         void do_print_python_repr(const print_python_repr & c, unsigned level) const;
338         STLT subschildren(const exmap & m, unsigned options = 0) const;
339 };
340
341 /** Default constructor */
342 template <template <class T, class = std::allocator<T>> class C>
343 container<C>::container()
344 {
345         setflag(get_default_flags());
346 }
347
348 /** Deprecatd constructors (prefer initializer list) */
349 template <template <class T, class = std::allocator<T>> class C>
350 container<C>::container(const ex & p1)
351   : container_storage<C>(1, p1) { setflag(get_default_flags()); }
352
353 template <template <class T, class = std::allocator<T>> class C>
354 container<C>::container(const ex & p1, const ex & p2)
355   : container_storage<C>{p1, p2} { setflag(get_default_flags()); }
356
357 template <template <class T, class = std::allocator<T>> class C>
358 container<C>::container(const ex & p1, const ex & p2, const ex & p3)
359   : container_storage<C>{p1, p2, p3} { setflag(get_default_flags()); }
360
361 template <template <class T, class = std::allocator<T>> class C>
362 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4)
363   : container_storage<C>{p1, p2, p3, p4} { setflag(get_default_flags()); }
364
365 template <template <class T, class = std::allocator<T>> class C>
366 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5)
367   : container_storage<C>{p1, p2, p3, p4, p5} { setflag(get_default_flags()); }
368
369 template <template <class T, class = std::allocator<T>> class C>
370 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6)
371   : container_storage<C>{p1, p2, p3, p4, p5, p6} { setflag(get_default_flags()); }
372
373 template <template <class T, class = std::allocator<T>> class C>
374 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7)
375   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7} { setflag(get_default_flags()); }
376
377 template <template <class T, class = std::allocator<T>> class C>
378 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8)
379   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8} { setflag(get_default_flags()); }
380
381 template <template <class T, class = std::allocator<T>> class C>
382 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
383                         const ex & p9)
384   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9} { setflag(get_default_flags()); }
385
386 template <template <class T, class = std::allocator<T>> class C>
387 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
388                         const ex & p9, const ex & p10)
389   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10} { setflag(get_default_flags()); }
390
391 template <template <class T, class = std::allocator<T>> class C>
392 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
393                         const ex & p9, const ex & p10, const ex & p11)
394   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11} { setflag(get_default_flags()); }
395
396 template <template <class T, class = std::allocator<T>> class C>
397 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
398                         const ex & p9, const ex & p10, const ex & p11, const ex & p12)
399   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12} { setflag(get_default_flags()); }
400
401 template <template <class T, class = std::allocator<T>> class C>
402 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
403                         const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13)
404   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13} { setflag(get_default_flags()); }
405
406 template <template <class T, class = std::allocator<T>> class C>
407 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
408                         const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14)
409   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14} { setflag(get_default_flags()); }
410
411 template <template <class T, class = std::allocator<T>> class C>
412 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
413                         const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15)
414   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15} { setflag(get_default_flags()); }
415 template <template <class T, class = std::allocator<T>> class C>
416 container<C>::container(const ex & p1, const ex & p2, const ex & p3, const ex & p4, const ex & p5, const ex & p6, const ex & p7, const ex & p8,
417                         const ex & p9, const ex & p10, const ex & p11, const ex & p12, const ex & p13, const ex & p14, const ex & p15, const ex & p16)
418   : container_storage<C>{p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16} { setflag(get_default_flags()); }
419
420 template <template <class T, class = std::allocator<T>> class C>
421 container_init<ex, typename container_storage<C>::STLT> container<C>::operator=(const ex & x)
422 {
423         this->seq.push_back(x);
424         return container_init<ex, typename container_storage<C>::STLT>(this->seq);
425 }
426
427 template <template <class T, class = std::allocator<T>> class C>
428 void container<C>::do_print(const print_context & c, unsigned level) const
429 {
430         // always print brackets around seq, ignore upper_precedence
431         printseq(c, get_open_delim(), ',', get_close_delim(), precedence(), precedence()+1);
432 }
433
434 template <template <class T, class = std::allocator<T>> class C>
435 void container<C>::do_print_tree(const print_tree & c, unsigned level) const
436 {
437         c.s << std::string(level, ' ') << class_name() << " @" << this
438             << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
439             << ", nops=" << nops()
440             << std::endl;
441         const_iterator i = this->seq.begin(), end = this->seq.end();
442         while (i != end) {
443                 i->print(c, level + c.delta_indent);
444                 ++i;
445         }
446         c.s << std::string(level + c.delta_indent,' ') << "=====" << std::endl;
447 }
448
449 template <template <class T, class = std::allocator<T>> class C>
450 void container<C>::do_print_python(const print_python & c, unsigned level) const
451 {
452         printseq(c, '[', ',', ']', precedence(), precedence()+1);
453 }
454
455 template <template <class T, class = std::allocator<T>> class C>
456 void container<C>::do_print_python_repr(const print_python_repr & c, unsigned level) const
457 {
458         c.s << class_name();
459         printseq(c, '(', ',', ')', precedence(), precedence()+1);
460 }
461
462 template <template <class T, class = std::allocator<T>> class C>
463 ex container<C>::op(size_t i) const
464 {
465         GINAC_ASSERT(i < nops());
466
467         const_iterator it = this->seq.begin();
468         advance(it, i);
469         return *it;
470 }
471
472 template <template <class T, class = std::allocator<T>> class C>
473 ex & container<C>::let_op(size_t i)
474 {
475         GINAC_ASSERT(i < nops());
476
477         ensure_if_modifiable();
478         typename STLT::iterator it = this->seq.begin();
479         advance(it, i);
480         return *it;
481 }
482
483 template <template <class T, class = std::allocator<T>> class C>
484 ex container<C>::subs(const exmap & m, unsigned options) const
485 {
486         // After having subs'ed all children, this method subs'es one final
487         // level, but only if the intermediate result is a container! This is
488         // because if the intermediate result has eval'ed to a non-container a
489         // last level substitution would be wrong, as this example involving a
490         // function f and its inverse f^-1 shows:
491         // f(x).subs(x==f^-1(x))
492         //   -> f(f^-1(x))  [subschildren]
493         //   -> x           [eval]   /* must not subs(x==f^-1(x))! */
494         STLT subsed = subschildren(m, options);
495         if (!subsed.empty()) {
496                 ex result(thiscontainer(subsed));
497                 if (is_a<container<C>>(result))
498                         return ex_to<basic>(result).subs_one_level(m, options);
499                 else
500                         return result;
501         } else {
502                 if (is_a<container<C>>(*this))
503                         return subs_one_level(m, options);
504                 else
505                         return *this;
506         }
507 }
508
509 /** Compare two containers of the same type. */
510 template <template <class T, class = std::allocator<T>> class C>
511 int container<C>::compare_same_type(const basic & other) const
512 {
513         GINAC_ASSERT(is_a<container>(other));
514         const container & o = static_cast<const container &>(other);
515
516         const_iterator it1 = this->seq.begin(), it1end = this->seq.end(),
517                        it2 = o.seq.begin(), it2end = o.seq.end();
518
519         while (it1 != it1end && it2 != it2end) {
520                 int cmpval = it1->compare(*it2);
521                 if (cmpval)
522                         return cmpval;
523                 ++it1; ++it2;
524         }
525
526         return (it1 == it1end) ? (it2 == it2end ? 0 : -1) : 1;
527 }
528
529 template <template <class T, class = std::allocator<T>> class C>
530 bool container<C>::is_equal_same_type(const basic & other) const
531 {
532         GINAC_ASSERT(is_a<container>(other));
533         const container & o = static_cast<const container &>(other);
534
535         if (this->seq.size() != o.seq.size())
536                 return false;
537
538         const_iterator it1 = this->seq.begin(), it1end = this->seq.end(), it2 = o.seq.begin();
539         while (it1 != it1end) {
540                 if (!it1->is_equal(*it2))
541                         return false;
542                 ++it1; ++it2;
543         }
544
545         return true;
546 }
547
548 /** Add element at front. */
549 template <template <class T, class = std::allocator<T>> class C>
550 container<C> & container<C>::prepend(const ex & b)
551 {
552         ensure_if_modifiable();
553         this->seq.push_front(b);
554         return *this;
555 }
556
557 /** Add element at back. */
558 template <template <class T, class = std::allocator<T>> class C>
559 container<C> & container<C>::append(const ex & b)
560 {
561         ensure_if_modifiable();
562         this->seq.push_back(b);
563         return *this;
564 }
565
566 /** Remove first element. */
567 template <template <class T, class = std::allocator<T>> class C>
568 container<C> & container<C>::remove_first()
569 {
570         ensure_if_modifiable();
571         this->seq.pop_front();
572         return *this;
573 }
574
575 /** Remove last element. */
576 template <template <class T, class = std::allocator<T>> class C>
577 container<C> & container<C>::remove_last()
578 {
579         ensure_if_modifiable();
580         this->seq.pop_back();
581         return *this;
582 }
583
584 /** Remove all elements. */
585 template <template <class T, class = std::allocator<T>> class C>
586 container<C> & container<C>::remove_all()
587 {
588         ensure_if_modifiable();
589         this->seq.clear();
590         return *this;
591 }
592
593 /** Sort elements. */
594 template <template <class T, class = std::allocator<T>> class C>
595 container<C> & container<C>::sort()
596 {
597         ensure_if_modifiable();
598         sort_(typename std::iterator_traits<typename STLT::iterator>::iterator_category());
599         return *this;
600 }
601
602 /** Specialization of container::unique_() for std::list. */
603 template<> inline void container<std::list>::unique_()
604 {
605         this->seq.unique(ex_is_equal());
606 }
607
608 /** Remove adjacent duplicate elements. */
609 template <template <class T, class = std::allocator<T>> class C>
610 container<C> & container<C>::unique()
611 {
612         ensure_if_modifiable();
613         unique_();
614         return *this;
615 }
616
617 /** Print sequence of contained elements. */
618 template <template <class T, class = std::allocator<T>> class C>
619 void container<C>::printseq(const print_context & c, char openbracket, char delim,
620                             char closebracket, unsigned this_precedence,
621                             unsigned upper_precedence) const
622 {
623         if (this_precedence <= upper_precedence)
624                 c.s << openbracket;
625
626         if (!this->seq.empty()) {
627                 const_iterator it = this->seq.begin(), itend = this->seq.end();
628                 --itend;
629                 while (it != itend) {
630                         it->print(c, this_precedence);
631                         c.s << delim;
632                         ++it;
633                 }
634                 it->print(c, this_precedence);
635         }
636
637         if (this_precedence <= upper_precedence)
638                 c.s << closebracket;
639 }
640
641 template <template <class T, class = std::allocator<T>> class C>
642 typename container<C>::STLT container<C>::subschildren(const exmap & m, unsigned options) const
643 {
644         // returns an empty container if nothing had to be substituted
645         // returns a STLT with substituted elements otherwise
646
647         const_iterator cit = this->seq.begin(), end = this->seq.end();
648         while (cit != end) {
649                 const ex & subsed_ex = cit->subs(m, options);
650                 if (!are_ex_trivially_equal(*cit, subsed_ex)) {
651
652                         // copy first part of seq which hasn't changed
653                         STLT s(this->seq.begin(), cit);
654                         this->reserve(s, this->seq.size());
655
656                         // insert changed element
657                         s.push_back(subsed_ex);
658                         ++cit;
659
660                         // copy rest
661                         while (cit != end) {
662                                 s.push_back(cit->subs(m, options));
663                                 ++cit;
664                         }
665
666                         return s;
667                 }
668
669                 ++cit;
670         }
671         
672         return STLT(); // nothing has changed
673 }
674
675 } // namespace GiNaC
676
677 #endif // ndef GINAC_CONTAINER_H