YSTest: textmgr.cpp 源文件

YSTest PreAlpha_b400_20130424 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

全部 类 命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义 组 页
textmgr.cpp
浏览该文件的文档.
1 ﻿/*
2 Copyright by FrankHB 2010 - 2013.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "YSLib/Service/textmgr.h"
29 #include "CHRLib/MapEx.h"
30 #include <ystdex/any_iterator.hpp>
31 #include "CHRLib/Convert.hpp"
32
33 YSL_BEGIN
34
35 YSL_BEGIN_NAMESPACE(Text)
36
37 namespace
38 {
39
41 yconstexpr auto& FetchMapperFunc(FetchMapperPtr<ConversionResult(ucs2_t&,
42 ystdex::input_monomorphic_iterator&&, ConversionState&&)>);
44 yconstexpr auto& FetchSkipMapperFunc(FetchMapperPtr<ConversionResult(
45 ystdex::input_monomorphic_iterator&&, ConversionState&&)>);
46
47 } // unnamed namespace;
48
49
50 TextFileBuffer::Iterator::Iterator(TextFileBuffer* pBuf, size_t b, size_t idx)
51 ynothrow
52 : pBuffer(pBuf), block(b), index(idx)
53 {}
54
55 TextFileBuffer::Iterator&
56 TextFileBuffer::Iterator::operator++() ynothrow
57 {
58 YAssert(pBuffer, "Null pointer found.");
59 YAssert(block < pBuffer->nBlock, "End iterator found.");
60
61 auto& vec((*pBuffer)[block].first);
62
63 YAssert(index < vec.size(), "Invalid index found.");
64
65 if(YB_UNLIKELY(++index == vec.size()))
66 yunseq(++block, index = 0);
67 return *this;
68 }
69
70 TextFileBuffer::Iterator&
71 TextFileBuffer::Iterator::operator--() ynothrow
72 {
73 YAssert(pBuffer, "Null buffer pointer found.");
74 YAssert(block != 0 || index != 0, "Begin iterator found."),
75 YAssert(block < pBuffer->nBlock || *this == pBuffer->GetEnd(),
76 "Invalid iterator found.");
77
78 if(index == 0)
79 {
80 index = (*pBuffer)[--block].first.size();
81
82 YAssert(index != 0, "Invalid index found.");
83 }
84 else
85 YAssert(index < (*pBuffer)[block].first.size(), "Invalid index found.");
86 --index;
87 return *this;
88 }
89
90 ucs2_t
91 TextFileBuffer::Iterator::operator*() const ynothrow
92 {
93 YAssert(pBuffer, "Null pointer found.");
94
95 auto& vec((*pBuffer)[block].first);
96
97 YAssert(!vec.empty(), "Empty block found.");
98 YAssert(index < vec.size(), "Invalid index found.");
99
100 return vec[index];
101 }
102
103 bool
104 operator==(const TextFileBuffer::Iterator& x, const TextFileBuffer::Iterator& y)
105 ynothrow
106 {
107 YAssert(x.pBuffer == y.pBuffer, "Iterators to different buffer are not"
108 " comparable.");
109
110 return x.block == y.block && x.index == y.index;
111 }
112
113
114 TextFileBuffer::TextFileBuffer(TextFile& file)
115 : File(file), nTextSize(File.GetTextSize()),
116 nBlock((nTextSize + BlockSize - 1) / BlockSize), Map(),
117 fixed_width(FetchFixedCharWidth(File.Encoding)), max_width(fixed_width
118 == 0 ? FetchMaxVariantCharWidth(File.Encoding) : fixed_width)
119 {
120 YAssert(max_width != 0, "Unknown encoding found.");
121
122 if(fixed_width == 0)
123 ++fixed_width;
124 // TODO: Implementation for non-fixed-width char streams.
125 }
126
127 TextFileBuffer::BlockType&
128 TextFileBuffer::operator[](size_t idx)
129 {
130 YAssert(idx < nBlock, "Invalid index found.");
131
132 auto& b(Map[idx]);
133 auto& vec(b.first);
134
135 if(YB_UNLIKELY(vec.empty() && bool(File)))
136 if(const auto pfun = FetchMapperFunc(File.Encoding))
137 {
138 File.Locate(idx * BlockSize);
139
140 size_t len(idx == nBlock - 1 && nTextSize % BlockSize != 0
141 ? nTextSize % BlockSize : BlockSize);
142
143 vec.reserve(len / fixed_width);
144
145 size_t n_byte(0);
146 ucs2_t c;
147 ystdex::ifile_iterator i(*File.GetPtr());
148
149 while(n_byte < len)
150 {
151 ConversionState st;
152
153 if(YB_LIKELY(ConvertCharacter(pfun, c, i, std::move(st))
154 == ConversionResult::OK))
155 vec.push_back(c);
156 n_byte += GetCountOf(st);
157 }
158 std::ungetc(*i, File.GetPtr()),
159 vec.shrink_to_fit();
160 }
161 return b;
162 }
163
164 TextFileBuffer::Iterator
165 TextFileBuffer::GetBegin() ynothrow
166 {
167 return TextFileBuffer::Iterator(this);
168 }
169 TextFileBuffer::Iterator
170 TextFileBuffer::GetEnd() ynothrow
171 {
172 return TextFileBuffer::Iterator(this, nBlock);
173 }
174 TextFileBuffer::Iterator
175 TextFileBuffer::GetIterator(size_t pos)
176 {
177 if(pos < nTextSize)
178 {
179 const size_t idx(pos / BlockSize);
180
181 pos %= BlockSize;
182 if(fixed_width == max_width)
183 return TextFileBuffer::Iterator(this, idx, pos / max_width);
184
185 YAssert(bool(File), "Invalid file found.");
186
187 if(const auto pfun = FetchSkipMapperFunc(File.Encoding))
188 {
189 File.Locate(idx * BlockSize);
190
191 size_t n_byte(0), n_char(0);
192 ystdex::ifile_iterator i(*File.GetPtr());
193
194 while(n_byte < pos)
195 {
196 ConversionState st;
197
198 if(YB_LIKELY(ConvertCharacter(pfun, i, std::move(st))
199 == ConversionResult::OK))
200 ++n_char;
201 n_byte += GetCountOf(st);
202 }
203 std::ungetc(*i, File.GetPtr());
204 return TextFileBuffer::Iterator(this, idx, n_char);
205 }
206 return TextFileBuffer::Iterator(this, idx, 0);
207 }
208 return GetEnd();
209 }
210 size_t
211 TextFileBuffer::GetPosition(TextFileBuffer::Iterator i)
212 {
213 if(i == GetEnd())
214 return nTextSize;
215
216 auto idx(i.GetBlockN());
217 const auto pos(i.GetIndexN());
218
219 if(fixed_width == max_width)
220 return idx * BlockSize + pos * max_width;
221
222 if(const auto pfun = FetchSkipMapperFunc(File.Encoding))
223 {
224 const auto& vec((*this)[idx].first);
225
226 YAssert(!vec.empty() && bool(File), "Block loading failed.");
227
228 File.Locate(idx *= BlockSize);
229
230 const auto mid(vec.cbegin() + pos);
231
232 YAssert(mid <= vec.cend(), "Wrong iterator found.");
233
234 auto it(vec.begin());
235
236 YAssert(it <= mid, "Wrong iterator found.");
237
238 ystdex::ifile_iterator i(*File.GetPtr());
239 size_t n_byte(0);
240
241 while(it != mid)
242 {
243 ConversionState st;
244
245 if(YB_LIKELY(ConvertCharacter(pfun, i, std::move(st))
246 == ConversionResult::OK))
247 ++it;
248 n_byte += GetCountOf(st);
249 }
250 return idx + n_byte;
251 }
252 return idx;
253 }
254
255
256 string
257 CopySliceFrom(TextFileBuffer& buf, size_t pos, size_t len)
258 ythrow(std::out_of_range)
259 {
260 const auto i_end(buf.GetEnd());
261 auto i_beg(buf.GetIterator(pos));
262
263 if(i_beg == i_end)
264 throw std::out_of_range("Wrong offset found.");
265 if(len == 0)
266 return {};
267
268 YAssert(pos < pos + len, "Unexpected unsigned integer round up.");
269
270 string str;
271
272 str.reserve(len * 2);
273 while(len != 0 && i_beg != i_end)
274 {
275 str.push_back(*i_beg);
276 yunseq(++i_beg, --len);
277 }
278 return std::move(str);
279 }
280
281 YSL_END_NAMESPACE(Text)
282
283 YSL_END
284