C++進修之STL(一)—— erase和remove特異行動
阿新 • • 發佈:2019-01-02
1: //
2: //Source code originally MSDN Channel 9 Video
3: //Modified by techmush
4: //NOTE: the original code may be perfect, the modified version may be buggy!
5: //Modifies: add string container, add some template parameters, alert some name
6: // add some notes, code style.
7: //
8:
9: #pragma once
10:
11: #ifndef erasecontainer_h__
12: #define erasecontainer_h__
13:
14: #include <algorithm>
15: #include <deque>
16: #include <forward_list>
17: #include <list>
18: #include <map>
19: #include <set>
20: #include <vector>
21: #include <string> //string "as" a vector
22: #include <unordered_map>
23: #include <unordered_set>
24:
25: namespace techmush
26: {
27: namespace detail
28: {
29: //erasing behavior like vector: vector, queue, string
30: struct vector_like_tag
31: {
32: };
33:
34: //erasing behavior like list: list, forward_list
35: struct list_like_tag
36: {
37: };
38:
39: //erasing behaviod like set: set, map, multiset, multimap, unordered_set, unordered_map
40: //unordered_multiset, unordered_multimap
41: struct associative_like_tag
42: {
43: };
44:
45: //type traits for containers
46: template <typename Cont> struct container_traits;
47:
48: template <typename Elem, typename Alloc>
49: struct container_traits<std::vector<Elem,Alloc> >
50: {
51: typedef vector_like_tag container_category;
52: };
53:
54: template <typename Elem, typename Alloc>
55: struct container_traits<std::deque<Elem,Alloc> >
56: {
57: typedef vector_like_tag container_category;
58: };
59:
60: //full specialization traits for string
61: template <> struct container_traits<std::string>
62: {
63: typedef vector_like_tag container_category;
64: };
65:
66:
67: template <typename Elem, typename Alloc>
68: struct container_traits<std::list<Elem,Alloc> >
69: {
70: typedef list_like_tag container_category;
71: };
72:
73: template <typename Elem, typename Alloc>
74: struct container_traits<std::forward_list<Elem,Alloc> >
75: {
76: typedef list_like_tag container_category;
77: };
78:
79: template <typename Key, typename Pred, typename Alloc>
80: struct container_traits<std::set<Key,Pred,Alloc> >
81: {
82: typedef associative_like_tag container_category;
83:
84: };
85:
86: //If a multiset contains duplicates, you can""t use erase()
87: //to remove only the first element of these duplicates.
88: template <typename Key, typename Pred, typename Alloc>
89: struct container_traits<std::multiset<Key,Pred,Alloc> >
90: {
91: typedef associative_like_tag container_category;
92: };
93:
94: template <typename Key, typename Hash, typename Equal, typename Alloc>
95: struct container_traits<std::unordered_set<Key,Hash,Equal,Alloc> >
96: {
97: typedef associative_like_tag container_category;
98: };
99:
100: template <typename Key, typename Hash, typename Equal, typename Alloc>
101: struct container_traits<std::unordered_multiset<Key,Hash,Equal,Alloc> >
102: {
103: typedef associative_like_tag container_category;
104: };
105:
106: template <typename Key, typename Val, typename Pred, typename Alloc>
107: struct container_traits<std::map<Key,Val,Pred,Alloc> >
108: {
109: typedef associative_like_tag container_category;
110: };
111:
112: template <typename Key, typename Val, typename Pred, typename Alloc>
113: struct container_traits<std::multimap<Key,Val,Pred,Alloc> >
114: {
115: typedef associative_like_tag container_category;
116: };
117:
118: template <typename Key, typename Val, typename Hash, typename Equal, typename Alloc>
119: struct container_traits<std::unordered_map<Key,Val,Hash,Equal,Alloc> >
120: {
121: typedef associative_like_tag container_category;
122: };
123:
124: template <typename Key, typename Val, typename Hash, typename Equal, typename Alloc>
125: struct container_traits<std::unordered_multimap<Key,Val,Hash,Equal,Alloc> >
126: {
127: typedef associative_like_tag container_category;
128: };
129:
130:
131: //for vector-like containers, use the erase-remove idiom
132: template <typename Cont, typename Elem>
133: inline void erase_helper(Cont& c, const Elem& x, vector_like_tag /*ignored*/)
134: {
135: c.erase(std::remove(c.begin(), c.end(), x), c.end());
136: }
137:
138: //for vector-like containers, use the erase-remove_if idiom
139: template <typename Cont, typename Pred>
140: inline void erase_if_helper(Cont& c, Pred p, vector_like_tag)
141: {
142: c.erase(std::remove_if(c.begin(), c.end(), p), c.end());
143: }
144:
145: //for list-like containers, use the remove member-function
146: template <typename Cont, typename Elem>
147: inline void erase_helper(Cont& c, const Elem& x, list_like_tag)
148: {
149: c.remove(x);
150: }
151:
152: //for list-like containers, use the remove_if member-function
153: template <typename Cont, typename Pred>
154: inline void erase_if_helper(Cont& c, Pred p, list_like_tag)
155: {
156: c.remove_if(p);
157: }
158:
159: //for associative containers, use the erase member-function
160: template <typename Cont, typename Elem>
161: inline void erase_helper(Cont& c, const Elem& x, associative_like_tag)
162: {
163: c.erase(x);
164: }
165:
166: //When an element of a container is erased, all iterators that point to that
167: //element are invalidated. Once c.erase(it) reuturns, it has been invalidated.
168: template <typename Cont, typename Pred>
169: inline void erase_if_helper(Cont& c, Pred p, associative_like_tag)
170: {
171: for (auto it = c.begin(); it != c.end(); /*nothing*/)
172: {
173: if (p(*it))
174: c.erase(it++); //Rebalance the tree
175: //Must have an iterator to the next element
176: else //of c before call erase
177: ++ it;
178: }
179: }
180: }
181:
182: //Interface function for erase
183: template <typename Cont, typename Elem>
184: inline void erase(Cont& c, const Elem& x)
185: {
186: detail::erase_helper(c, x, typename /*a type*/detail::container_traits<Cont>::container_category());
187: }
188:
189:
190: //Interface function for erase_if
191: template <typename Cont, typename Pred>
192: inline void erase_if(Cont& c, Pred p)
193: {
194: detail::erase_if_helper(c, p, typename detail::container_traits<Cont>::container_category());
195: }
196: }
197: #endif // erasecontainer_h__