map.cpp 5.36 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
8
9
10
11
12

namespace YAML
{
	Map::Map()
	{
	}
Jesse Beder's avatar
Jesse Beder committed
13
14
15
16
17
18
	
	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();
19
			AddEntry(pKey, pValue);
Jesse Beder's avatar
Jesse Beder committed
20
21
		}
	}
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

	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
37
38
39
40
41
	Content *Map::Clone() const
	{
		return new Map(m_data);
	}
	
42
43
44
45
46
47
48
49
50
51
52
53
	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;
	}

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

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

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

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

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

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

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

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

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

106
			AddEntry(pKey, pValue);
107
		}
108
109

		state.PopCollectionType(ParserState::BLOCK_MAP);
110
111
	}

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

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

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

131
132
133
134
135
136
			// grab key (if non-null)
			if(token.type == Token::KEY) {
				pScanner->pop();
				pKey->Parse(pScanner, state);
			}
			
137
			// now grab value (optional)
138
			if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
139
140
				pScanner->pop();
				pValue->Parse(pScanner, state);
141
			}
142
			
143
144
			// 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();
145
			if(nextToken.type == Token::FLOW_ENTRY)
146
				pScanner->pop();
147
			else if(nextToken.type != Token::FLOW_MAP_END)
148
				throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
149

150
			AddEntry(pKey, pValue);
151
		}
152
153

		state.PopCollectionType(ParserState::FLOW_MAP);
154
155
	}

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

163
164
165
		// grab key
		pScanner->pop();
		pKey->Parse(pScanner, state);
166
167
168
169
170
171
172
			
		// now grab value (optional)
		if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
			pScanner->pop();
			pValue->Parse(pScanner, state);
		}
			
173
		AddEntry(pKey, pValue);
174
		state.PopCollectionType(ParserState::COMPACT_MAP);
175
176
	}
	
177
	// ParseCompactWithNoKey
178
	// . Single ": value" pair in a flow sequence
179
	void Map::ParseCompactWithNoKey(Scanner *pScanner, ParserState& state)
180
	{
181
		state.PushCollectionType(ParserState::COMPACT_MAP);
182
183
184
185
186
		std::auto_ptr <Node> pKey(new Node), pValue(new Node);

		// grab value
		pScanner->pop();
		pValue->Parse(pScanner, state);
187
188

		AddEntry(pKey, pValue);
189
		state.PopCollectionType(ParserState::COMPACT_MAP);
190
191
	}
	
192
193
194
195
196
197
198
199
200
	void Map::AddEntry(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
	{
		node_map::const_iterator it = m_data.find(pKey.get());
		if(it != m_data.end())
			return;
		
		m_data[pKey.release()] = pValue.release();
	}

201
	void Map::Write(Emitter& out) const
202
	{
203
204
205
206
		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;
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
235
236
237
238
	}

	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;
	}
}