map.cpp 5.43 KB
Newer Older
1
2
3
4
5
#include "map.h"
#include "node.h"
#include "scanner.h"
#include "token.h"
#include "exceptions.h"
6
#include "emitter.h"
7
#include <memory>
8
9
10
11
12
13

namespace YAML
{
	Map::Map()
	{
	}
Jesse Beder's avatar
Jesse Beder committed
14
15
16
17
18
19
20
21
22
	
	Map::Map(const node_map& data)
	{
		for(node_map::const_iterator it=data.begin();it!=data.end();++it) {
			std::auto_ptr<Node> pKey = it->first->Clone();
			std::auto_ptr<Node> pValue = it->second->Clone();
			m_data[pKey.release()] = pValue.release();
		}
	}
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

	Map::~Map()
	{
		Clear();
	}

	void Map::Clear()
	{
		for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
			delete it->first;
			delete it->second;
		}
		m_data.clear();
	}

Jesse Beder's avatar
Jesse Beder committed
38
39
40
41
42
	Content *Map::Clone() const
	{
		return new Map(m_data);
	}
	
43
44
45
46
47
48
49
50
51
52
53
54
	bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const
	{
		it = m_data.begin();
		return true;
	}

	bool Map::GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const
	{
		it = m_data.end();
		return true;
	}

55
56
57
58
59
	std::size_t Map::GetSize() const
	{
		return m_data.size();
	}

60
	void Map::Parse(Scanner *pScanner, ParserState& state)
61
62
63
64
65
	{
		Clear();

		// split based on start token
		switch(pScanner->peek().type) {
66
67
			case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break;
			case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break;
68
			case Token::KEY: ParseCompact(pScanner, state); break;
69
			case Token::VALUE: ParseCompactWithNoKey(pScanner, state); break;
Jesse Beder's avatar
Jesse Beder committed
70
			default: break;
71
72
73
		}
	}

74
	void Map::ParseBlock(Scanner *pScanner, ParserState& state)
75
76
77
	{
		// eat start token
		pScanner->pop();
78
		state.PushCollectionType(ParserState::BLOCK_MAP);
79
80
81

		while(1) {
			if(pScanner->empty())
82
				throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP);
83
84

			Token token = pScanner->peek();
85
			if(token.type != Token::KEY && token.type != Token::VALUE && token.type != Token::BLOCK_MAP_END)
86
				throw ParserException(token.mark, ErrorMsg::END_OF_MAP);
87

88
			if(token.type == Token::BLOCK_MAP_END) {
89
				pScanner->pop();
90
				break;
91
			}
92

93
			std::auto_ptr <Node> pKey(new Node), pValue(new Node);
94
95
			
			// grab key (if non-null)
96
			if(token.type == Token::KEY) {
97
98
99
				pScanner->pop();
				pKey->Parse(pScanner, state);
			}
100

101
			// now grab value (optional)
102
			if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
103
104
				pScanner->pop();
				pValue->Parse(pScanner, state);
105
			}
106
107
108

			// assign the map with the actual pointers
			m_data[pKey.release()] = pValue.release();
109
		}
110
111

		state.PopCollectionType(ParserState::BLOCK_MAP);
112
113
	}

114
	void Map::ParseFlow(Scanner *pScanner, ParserState& state)
115
116
117
	{
		// eat start token
		pScanner->pop();
118
		state.PushCollectionType(ParserState::FLOW_MAP);
119
120
121

		while(1) {
			if(pScanner->empty())
122
				throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP_FLOW);
123
124
125

			Token& token = pScanner->peek();
			// first check for end
126
			if(token.type == Token::FLOW_MAP_END) {
127
128
129
				pScanner->pop();
				break;
			}
130
			
131
132
			std::auto_ptr <Node> pKey(new Node), pValue(new Node);

133
134
135
136
137
138
			// grab key (if non-null)
			if(token.type == Token::KEY) {
				pScanner->pop();
				pKey->Parse(pScanner, state);
			}
			
139
			// now grab value (optional)
140
			if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
141
142
				pScanner->pop();
				pValue->Parse(pScanner, state);
143
			}
144
			
145
146
			// now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)
			Token& nextToken = pScanner->peek();
147
			if(nextToken.type == Token::FLOW_ENTRY)
148
				pScanner->pop();
149
			else if(nextToken.type != Token::FLOW_MAP_END)
150
				throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
151
152
153

			// assign the map with the actual pointers
			m_data[pKey.release()] = pValue.release();
154
		}
155
156

		state.PopCollectionType(ParserState::FLOW_MAP);
157
158
	}

159
	// ParseCompact
160
	// . Single "key: value" pair in a flow sequence
161
	void Map::ParseCompact(Scanner *pScanner, ParserState& state)
162
	{
163
		state.PushCollectionType(ParserState::COMPACT_MAP);
164
165
		std::auto_ptr <Node> pKey(new Node), pValue(new Node);

166
167
168
		// grab key
		pScanner->pop();
		pKey->Parse(pScanner, state);
169
170
171
172
173
174
175
176
177
			
		// now grab value (optional)
		if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
			pScanner->pop();
			pValue->Parse(pScanner, state);
		}
			
		// assign the map with the actual pointers
		m_data[pKey.release()] = pValue.release();
178
		state.PopCollectionType(ParserState::COMPACT_MAP);
179
180
	}
	
181
	// ParseCompactWithNoKey
182
	// . Single ": value" pair in a flow sequence
183
	void Map::ParseCompactWithNoKey(Scanner *pScanner, ParserState& state)
184
	{
185
		state.PushCollectionType(ParserState::COMPACT_MAP);
186
187
188
189
190
191
192
193
		std::auto_ptr <Node> pKey(new Node), pValue(new Node);

		// grab value
		pScanner->pop();
		pValue->Parse(pScanner, state);
			
		// assign the map with the actual pointers
		m_data[pKey.release()] = pValue.release();
194
		state.PopCollectionType(ParserState::COMPACT_MAP);
195
196
	}
	
197
	void Map::Write(Emitter& out) const
198
	{
199
200
201
202
		out << BeginMap;
		for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it)
			out << Key << *it->first << Value << *it->second;
		out << EndMap;
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
	}

	int Map::Compare(Content *pContent)
	{
		return -pContent->Compare(this);
	}

	int Map::Compare(Map *pMap)
	{
		node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin();
		while(1) {
			if(it == m_data.end()) {
				if(jt == pMap->m_data.end())
					return 0;
				else
					return -1;
			}
			if(jt == pMap->m_data.end())
				return 1;

			int cmp = it->first->Compare(*jt->first);
			if(cmp != 0)
				return cmp;

			cmp = it->second->Compare(*jt->second);
			if(cmp != 0)
				return cmp;
		}

		return 0;
	}
}