-
Notifications
You must be signed in to change notification settings - Fork 0
/
_l_user.h
411 lines (398 loc) · 18.9 KB
/
_l_user.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
#pragma once
// Copyright David Lawrence Bien 1997 - 2021.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt).
// _l_user.h
// "User" objects for the lexical analyzer.
// dbien
// 17DEC2020
// These provide a "default translation" that many lexical analyzers can just use as-is.
// Users may want to override the methods in some cases - especially where character translation is required.
// A good example is where a piece of text may represent a hexidecimal number, etc. The translator in the overridden
// user object would translate and also potentially check for overflow, etc.
#include "_l_ns.h"
#include "_l_types.h"
#include "_l_data.h"
__LEXOBJ_BEGIN_NAMESPACE
// _l_user_context:
// This produces an aggregate which provides customizable treatment of a token's constituent _l_data_typed_range objects.
template < class t_TyTransportCtxt, class t_TyUserObj, class t_TyTpValueTraits >
class _l_user_context : public t_TyTransportCtxt
{
typedef _l_user_context _TyThis;
typedef t_TyTransportCtxt _TyBase;
public:
typedef t_TyTransportCtxt _TyTransportCtxt;
typedef t_TyUserObj _TyUserObj;
typedef t_TyTpValueTraits _TyTpValueTraits;
typedef typename _TyTransportCtxt::_TyChar _TyChar;
typedef _l_token< _TyTransportCtxt, _TyUserObj, _TyTpValueTraits > _TyToken;
typedef _l_value< _TyChar, _TyTpValueTraits > _TyValue;
_l_user_context() = delete;
// We are copyable.
_l_user_context( _TyThis const & ) = default;
// But not assignable.
_l_user_context & operator =( _l_user_context const & ) = delete;
_l_user_context( _l_user_context && _rr )
: m_ruoUserObj( _rr.m_ruoUserObj ),
_TyBase( std::move( static_cast< _TyBase && >( _rr ) ) )
{
}
_l_user_context & operator =( _l_user_context && _rr )
{
_TyThis acquire( std::move( _rr ) );
swap( acquire );
return *this;
}
_l_user_context( _TyUserObj & _ruo )
: m_ruoUserObj( _ruo )
{
}
template < class ... t_TysArgs >
_l_user_context( _TyUserObj & _ruo, t_TysArgs && ... _args )
: m_ruoUserObj( _ruo ),
_TyBase( std::forward< t_TysArgs >(_args) ... )
{
}
void swap( _TyThis & _r )
{
Assert( &m_ruoUserObj == &_r.m_ruoUserObj );
_TyBase::swap( _r );
}
void AssertValid() const
{
#if ASSERTSENABLED
_TyBase::AssertValid();
#endif //ASSERTSENABLED
}
bool FIsNull() const
{
AssertValid();
return _TyBase::FIsNull();
}
// casting utilities:
t_TyTransportCtxt & GetTransportCtxt()
{
return *this;
}
const t_TyTransportCtxt & GetTransportCtxt() const
{
return *this;
}
// Generic initialization of transport context.
template < class ... t_TysArgs >
void InitTransportCtxt( t_TysArgs && ... _args )
{
_TyBase::InitTransportCtxt( std::forward< t_TysArgs>( _args ) ... );
}
template < class t_TyStringView >
void GetStringView( t_TyStringView & _rsvDest, _TyToken & _rtok, _TyValue & _rval )
{
// yet another delegation...and add another parameter.
m_ruoUserObj.GetStringView( _rsvDest, *(_TyBase*)this, _rtok, _rval );
}
template < class t_TyStringView >
void KGetStringView( t_TyStringView & _rsvDest, _TyToken const & _rtok, _TyValue const & _rval ) const
{
// yet another delegation...and add another parameter.
m_ruoUserObj.KGetStringView( _rsvDest, *(_TyBase*)this, _rtok, _rval );
}
template < class t_TyStringView >
void KGetStringView( t_TyStringView & _rsvDest, _TyToken const & _rtok, _l_data_range const & _rdr ) const
{
// yet another delegation...and add another parameter.
m_ruoUserObj.KGetStringView( _rsvDest, *(_TyBase*)this, _rtok, _rdr );
}
template < class t_TyStringView, class t_TyString >
bool FGetStringViewOrString( t_TyStringView & _rsvDest, t_TyString & _rstrDest,_TyToken const & _rtok, _TyValue const & _rval ) const
{
// yet another delegation...and add another parameter.
return m_ruoUserObj.FGetStringViewOrString( _rsvDest, _rstrDest, *(_TyBase*)this, _rtok, _rval );
}
template < class t_TyString >
void GetString( t_TyString & _rstrDest, _TyToken const & _rtok, _TyValue const & _rval ) const
{
// yet another delegation...and add another parameter.
m_ruoUserObj.GetString( _rstrDest, *(_TyBase*)this, _rtok, _rval );
}
protected:
_TyUserObj & m_ruoUserObj; // This is a reference to the user object that was passed into the _l_stream constructor.
};
template < class t_TyChar >
class _l_default_user_obj
{
typedef _l_default_user_obj _TyThis;
public:
typedef t_TyChar _TyChar;
typedef _l_data<> _TyData;
typedef _l_transport_backed_ctxt< _TyChar > _TyTransportCtxtBacked;
typedef _l_transport_fixedmem_ctxt< _TyChar > _TyTransportCtxtFixedMem;
typedef _l_action_object_base< _TyChar, false > _TyAxnObjBase;
template < class t_TyStream >
bool FProcessAndFilterToken( const _TyAxnObjBase * _paobCurToken, t_TyStream const & _rstrm, vtyDataPosition _posEndToken ) const
{
return false;
}
// These are the default GetString*() impls. They just concatenates segmented strings regardless of the m_nType value.
// _rval is a constituent value of _rtok.m_value or may be _rtok.m_value itself. We expect _rval's _TyData object to be
// occupied and we will convert it to either a string or a string_view depending on various things...
// 1) If the character type of the returned string matches _TyChar:
// a) If _rval<_TyData> contains only a single value and it doesn't cross a segmented memory boundary then we can return a
// stringview and we will also update the value with a stringview as it is inexpensive.
// b) If _rval<_TyData> contains only a single value but it cross a segmented memory boundary then we will create a string
// of the appropriate length and then stream the segarray data into the string.
// c) If _rval<_TyData> contains multiple values then we have to create a string of length adding all the sub-lengths together
// and then stream each piece.
// 2) If the character type doesn't match then need to first create the string - hopefully on the stack using alloca() - and then
// pass it to the string conversion.
// In all cases where we produce a new string we store that string in _rval - we must because we are returning a stringview to it.
// This means that we may store data in a character representation that isn't _TyChar in _rval and that's totally fine (at least for me).
// Generic transport methods:
// For all transport types these converting methods are exactly the same.
template < class t_TyStringView, class t_TyToken, class t_TyTransportCtxt >
static void GetStringView( t_TyStringView & _rsvDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, typename t_TyToken::_TyValue & _rval )
requires ( sizeof( typename t_TyStringView::value_type ) != sizeof( _TyChar ) )
{
typedef typename t_TyStringView::value_type _TyCharConvertTo;
typedef typename t_TyToken::_TyValue::template get_string_type< _TyCharConvertTo > _TyStrConvertTo;
_TyStrConvertTo strConverted;
GetString( strConverted, _rcxt, _rtok, _rval );
_TyStrConvertTo & rstr = _rval.emplaceVal( std::move( strConverted ) );
_rsvDest = t_TyStringView( (const _TyCharConvertTo*)&rstr[0], rstr.length() );
}
template < class t_TyStringView, class t_TyString, class t_TyToken, class t_TyTransportCtxt >
static bool FGetStringViewOrString( t_TyStringView & _rsvDest, t_TyString & _rstrDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, typename t_TyToken::_TyValue const & _rval )
requires ( sizeof( typename t_TyStringView::value_type ) != sizeof( _TyChar ) )
{
static_assert( sizeof( typename t_TyStringView::value_type ) == sizeof( typename t_TyString::value_type ) );
Assert( _rsvDest.empty() );
Assert( _rstrDest.empty() );
t_TyString strConverted;
GetString( strConverted, _rcxt, _rtok, _rval );
_rstrDest = std::move( strConverted );
_rsvDest = t_TyStringView( ( const typename t_TyStringView::value_type *)&_rstrDest[0], _rstrDest.length() );
return false;
}
// var transport:
template < class t_TyStringView, class t_TyToken, class t_TyTransportCtxt >
static void GetStringView( t_TyStringView & _rsvDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, typename t_TyToken::_TyValue & _rval )
requires ( TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
return visit(_VisitHelpOverloadFCall {
[&_rsvDest,&_rtok,&_rval]( auto & _rcxtTransport )
{
_rcxtTransport.GetStringView( _rsvDest, _rcxtTransport, _rtok, _rval );
}
}, _rcxt.GetVariant() );
}
template < class t_TyStringView, class t_TyToken, class t_TyTransportCtxt >
static void KGetStringView( t_TyStringView & _rsvDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, typename t_TyToken::_TyValue const & _rval )
requires ( TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
return visit(_VisitHelpOverloadFCall {
[&_rsvDest,&_rtok,&_rval]( auto & _rcxtTransport )
{
_rcxtTransport.KGetStringView( _rsvDest, _rcxtTransport, _rtok, _rval );
}
}, _rcxt.GetVariant() );
}
template < class t_TyStringView, class t_TyToken, class t_TyTransportCtxt >
static void KGetStringView( t_TyStringView & _rsvDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, _l_data_range const & _rdr )
requires ( TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
return visit(_VisitHelpOverloadFCall {
[&_rsvDest,&_rtok,&_rdr]( auto & _rcxtTransport )
{
_rcxtTransport.KGetStringView( _rsvDest, _rcxtTransport, _rtok, _rdr );
}
}, _rcxt.GetVariant() );
}
template < class t_TyStringView, class t_TyString, class t_TyToken, class t_TyTransportCtxt >
static bool FGetStringViewOrString( t_TyStringView & _rsvDest, t_TyString & _rstrDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, const typename t_TyToken::_TyValue& _rval )
requires ( TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
return visit(_VisitHelpOverloadFCall {
[&_rsvDest,&_rstrDest,&_rtok,&_rval]( auto & _rcxtTransport )
{
_rcxtTransport.FGetStringViewOrString( _rsvDest, _rstrDest, _rcxtTransport, _rtok, _rval );
}
}, _rcxt.GetVariant() );
}
template < class t_TyString, class t_TyToken, class t_TyTransportCtxt >
static void GetString( t_TyString & _rstrDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, const typename t_TyToken::_TyValue& _rval )
requires ( TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
return visit(_VisitHelpOverloadFCall {
[&_rstrDest,&_rtok,&_rval]( auto & _rcxtTransport )
{
_rcxtTransport.GetString( _rstrDest, _rcxtTransport, _rtok, _rval );
}
}, _rcxt.GetVariant() );
}
// Non-converting GetString*.
template < class t_TyStringView, class t_TyToken, class t_TyTransportCtxt >
static void GetStringView( t_TyStringView & _rsvDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, typename t_TyToken::_TyValue & _rval )
requires ( ( sizeof( typename t_TyStringView::value_type ) == sizeof( _TyChar ) ) && !TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
Assert( _rsvDest.empty() );
Assert( _rval.FHasTypedData() ); // We are converting the _TyData object that is in _rval.
const _TyData kdtr = _rval.template GetVal< _TyData >();
_rcxt.AssertValidDataRange( kdtr );
if ( !kdtr.FContainsSingleDataRange() )
{
typedef typename t_TyToken::_TyValue::template get_string_type< _TyChar > _TyStringImpl;
_TyStringImpl strBacking;
GetString( strBacking, _rcxt, _rtok, _rval );
_TyStringImpl & rstr = _rval.emplaceVal( std::move( strBacking ) );;
_rsvDest = t_TyStringView( (const typename t_TyStringView::value_type*)&rstr[0], rstr.length() );
}
else
{
// We could set the stringview into the object since it doesn't really hurt:
_rcxt.GetStringView( _rsvDest, kdtr );
_rval.SetVal( _rsvDest );
}
}
template < class t_TyStringView, class t_TyToken, class t_TyTransportCtxt >
static void KGetStringView( t_TyStringView & _rsvDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, typename t_TyToken::_TyValue const & _rval )
requires ( ( sizeof( typename t_TyStringView::value_type ) == sizeof( _TyChar ) ) && !TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
Assert( _rsvDest.empty() );
Assert( _rval.FHasTypedData() ); // We are converting the _TyData object that is in _rval.
const _TyData kdtr = _rval.template GetVal< _TyData >();
_rcxt.AssertValidDataRange( kdtr );
VerifyThrowSz( kdtr.FContainsSingleDataRange(), "KGetStringView() is only valid for single data ranges." );
_rcxt.GetStringView( _rsvDest, kdtr );
}
template < class t_TyStringView, class t_TyToken, class t_TyTransportCtxt >
static void KGetStringView( t_TyStringView & _rsvDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, _l_data_range const & _rdr )
requires ( ( sizeof( typename t_TyStringView::value_type ) == sizeof( _TyChar ) ) && !TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
Assert( _rsvDest.empty() );
_rcxt.AssertValidDataRange( _rdr );
_rcxt.GetStringView( _rsvDest, _rdr );
}
template < class t_TyStringView, class t_TyString, class t_TyToken, class t_TyTransportCtxt >
static bool FGetStringViewOrString( t_TyStringView & _rsvDest, t_TyString & _rstrDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, const typename t_TyToken::_TyValue & _rval )
requires ( ( sizeof( typename t_TyStringView::value_type ) == sizeof( _TyChar ) ) && !TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
static_assert( sizeof( typename t_TyStringView::value_type ) == sizeof( typename t_TyString::value_type ) );
Assert( _rsvDest.empty() );
Assert( _rstrDest.empty() );
Assert( _rval.FHasTypedData() ); // We are converting the _TyData object that is in _rval.
const _TyData kdtr = _rval.template GetVal< _TyData >();
_rcxt.AssertValidDataRange( kdtr );
if ( !kdtr.FContainsSingleDataRange() )
{
GetString( _rstrDest, _rcxt, _rtok, _rval );
_rsvDest = t_TyStringView( ( const typename t_TyStringView::value_type *)&_rstrDest[0], _rstrDest.length() );
return false;
}
else
{
_rcxt.GetStringView( _rsvDest, kdtr );
return true;
}
}
template < class t_TyString, class t_TyToken, class t_TyTransportCtxt >
static void GetString( t_TyString & _rstrDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, const typename t_TyToken::_TyValue & _rval )
requires ( ( sizeof( typename t_TyString::value_type ) == sizeof( _TyChar ) ) && !TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
Assert( _rstrDest.empty() );
Assert( _rval.FHasTypedData() ); // We are converting the _TyData object that is in _rval.
const _TyData kdtr = _rval.template GetVal< _TyData >();
if ( kdtr.FIsNull() )
return;
_rcxt.AssertValidDataRange( kdtr );
// Then we must back with a string:
size_t nCharsCount = kdtr.CountChars();
size_t nCharsRemaining = nCharsCount;
t_TyString strBacking( nCharsRemaining, 0 ); // Return the type the caller asked for.
if ( kdtr.FContainsSingleDataRange() )
{
memcpy( &strBacking[0], _rcxt.GetTokenBuffer().begin() + kdtr.DataRangeGetSingle().begin() - _rcxt.PosTokenStart(), nCharsRemaining * sizeof( _TyChar ) );
nCharsRemaining = 0;
}
else
{
_TyChar * pcCur = (_TyChar*)&strBacking[0]; // Current output pointer.
kdtr.GetSegArrayDataRanges().ApplyContiguous( 0, kdtr.GetSegArrayDataRanges().NElements(),
[&pcCur,&nCharsRemaining,&_rcxt]( const _l_data_typed_range * _pdtrBegin, const _l_data_typed_range * _pdtrEnd )
{
const _l_data_typed_range * pdtrCur = _pdtrBegin;
for ( ; nCharsRemaining && ( _pdtrEnd != pdtrCur ); ++pdtrCur )
{
Assert( nCharsRemaining >= pdtrCur->length() );
size_t nCharsCopy = min( nCharsRemaining, pdtrCur->length() );
Assert( nCharsCopy == pdtrCur->length() ); // should have reserved enough.
memcpy( pcCur, _rcxt.GetTokenBuffer().begin() + pdtrCur->begin() - _rcxt.PosTokenStart(), nCharsCopy * sizeof( _TyChar ) );
pcCur += nCharsCopy;
nCharsRemaining -= nCharsCopy;
}
}
);
Assert( !nCharsRemaining ); // Should have eaten everything.
}
strBacking.resize( nCharsCount - nCharsRemaining );
_rstrDest = std::move( strBacking );
}
// Converting GetString*.
template < class t_TyString, class t_TyToken, class t_TyTransportCtxt >
static void GetString( t_TyString & _rstrDest, t_TyTransportCtxt & _rcxt, t_TyToken & _rtok, typename t_TyToken::_TyValue const & _rval )
requires ( ( sizeof( typename t_TyString::value_type ) != sizeof( _TyChar ) ) && !TFIsTransportVarCtxt_v< t_TyTransportCtxt > )
{
Assert( _rstrDest.empty() );
typedef typename t_TyString::value_type _TyCharConvertTo;
Assert( _rval.FHasTypedData() ); // We are converting the _TyData object that is in _rval.
const _TyData kdtr = _rval.template GetVal< _TyData >();
if ( kdtr.FIsNull() )
return;
_rcxt.AssertValidDataRange( kdtr );
// Then we must back with a converted string, attempt to use an alloca() buffer:
static size_t knchMaxAllocaSize = vknbyMaxAllocaSize / sizeof( _TyChar );
typename t_TyToken::_TyValue::template get_string_type< _TyChar > strTempBuf; // For when we have more than knchMaxAllocaSize.
size_t nCharsCount = kdtr.CountChars();
size_t nCharsRemaining = nCharsCount;
_TyChar * pcBuf;
if ( nCharsCount > knchMaxAllocaSize )
{
strTempBuf.resize( nCharsCount );
pcBuf = &strTempBuf[0];
}
else
pcBuf = (_TyChar*)alloca( nCharsCount * sizeof( _TyChar ) );
if ( kdtr.FContainsSingleDataRange() )
{
// REVIEW: Could just use a string view here instead and not copy to the stack.
memcpy( pcBuf, _rcxt.GetTokenBuffer().begin() + kdtr.DataRangeGetSingle().begin() - _rcxt.PosTokenStart(), nCharsRemaining * sizeof( _TyChar ) );
nCharsRemaining = 0;
}
else
{
_TyChar * pcCur = pcBuf; // Current output pointer.
kdtr.GetSegArrayDataRanges().ApplyContiguous( 0, kdtr.GetSegArrayDataRanges().NElements(),
[&pcCur,&nCharsRemaining,&_rcxt]( const _l_data_typed_range * _pdtrBegin, const _l_data_typed_range * _pdtrEnd )
{
const _l_data_typed_range * pdtrCur = _pdtrBegin;
for ( ; nCharsRemaining && ( _pdtrEnd != pdtrCur ); ++pdtrCur )
{
Assert( nCharsRemaining >= pdtrCur->length() );
size_t nCharsCopy = min( nCharsRemaining, pdtrCur->length() );
Assert( nCharsCopy == pdtrCur->length() ); // should have reserved enough.
memcpy( pcCur, _rcxt.GetTokenBuffer().begin() + pdtrCur->begin() - _rcxt.PosTokenStart(), nCharsCopy * sizeof( _TyChar ) );
pcCur += nCharsCopy;
nCharsRemaining -= nCharsCopy;
}
}
);
Assert( !nCharsRemaining );
}
if ( nCharsRemaining )
nCharsCount -= nCharsRemaining;
t_TyString strConverted;
ConvertString( strConverted, pcBuf, nCharsCount );
_rstrDest = std::move( strConverted );
}
};
__LEXOBJ_END_NAMESPACE