• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 24035539233

06 Apr 2026 02:21PM UTC coverage: 60.76% (+0.06%) from 60.696%
24035539233

push

github

web-flow
using fmt instead of ostringstream (#873)

* using fmt instead of ostringstream

misc cleanup

* missing external libs for clang tidy check

* added test for cprops ignore while stacking
door descriptor

* use contains instead of count, removed disabled ancient code

* pack/packonto simplification/speedup

instead of using ostream and convert to string, use format and directly
a string

90 of 141 new or added lines in 17 files covered. (63.83%)

17 existing lines in 10 files now uncovered.

44503 of 73244 relevant lines covered (60.76%)

514255.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.6
/pol-core/bscript/dict.cpp
1
/** @file
2
 *
3
 * @par History
4
 * - 2005/11/26 Shinigami: changed "strcmp" into "stricmp" to suppress Script Errors
5
 * - 2008/02/11 Turley:    BDictionary::unpack() will accept zero length Dictionarys
6
 * - 2009/12/21 Turley:    ._method() call fix
7
 */
8

9

10
#include "dict.h"
11

12
#include <fmt/compile.h>
13
#include <iterator>
14
#include <stddef.h>
15

16
#include "../clib/stlutil.h"
17
#include "berror.h"
18
#include "contiter.h"
19
#include "executor.h"
20
#include "impstr.h"
21
#include "objmethods.h"
22

23

24
namespace Pol::Bscript
25
{
26
BDictionary::BDictionary() : BObjectImp( OTDictionary ), contents_() {}
242✔
27

28
BDictionary::BDictionary( BObjectType type ) : BObjectImp( type ), contents_() {}
×
29

30
BDictionary::BDictionary( const BDictionary& dict, BObjectType type )
642✔
31
    : BObjectImp( type ), contents_()
642✔
32
{
33
  for ( const auto& elem : dict.contents_ )
807✔
34
  {
35
    const BObject& bkeyobj = elem.first;
165✔
36
    const BObjectRef& bvalref = elem.second;
165✔
37

38
    contents_[bkeyobj] = BObjectRef( new BObject( bvalref->impref().copy() ) );
165✔
39
  }
40
}
642✔
41

42
BDictionary::BDictionary( std::istream& is, unsigned size, BObjectType type )
9✔
43
    : BObjectImp( type ), contents_()
9✔
44
{
45
  for ( unsigned i = 0; i < size; ++i )
213✔
46
  {
47
    BObjectImp* keyimp = BObjectImp::unpack( is );
204✔
48
    BObjectImp* valimp = BObjectImp::unpack( is );
204✔
49
    if ( keyimp != nullptr && valimp != nullptr )
204✔
50
    {
51
      BObject keyobj( keyimp );
204✔
52
      contents_[keyobj].set( new BObject( valimp ) );
204✔
53
    }
204✔
54
    else
55
    {
56
      if ( keyimp )
×
57
        BObject objk( keyimp );
×
58
      if ( valimp )
×
59
        BObject objv( valimp );
×
60
    }
61
  }
62
}
9✔
63

64
class BDictionaryIterator final : public ContIterator
65
{
66
public:
67
  BDictionaryIterator( BDictionary* pDict, BObject* pIterVal );
68
  BObject* step() override;
69

70
private:
71
  BObject m_DictObj;
72
  BDictionary* m_pDict;
73
  BObjectRef m_IterVal;
74
  BObject m_Key;
75
  bool m_First;
76
};
77
BDictionaryIterator::BDictionaryIterator( BDictionary* pDict, BObject* pIterVal )
24✔
78
    : ContIterator(),
79
      m_DictObj( pDict ),
24✔
80
      m_pDict( pDict ),
24✔
81
      m_IterVal( pIterVal ),
24✔
82
      m_Key( UninitObject::create() ),
24✔
83
      m_First( true )
24✔
84
{
85
}
24✔
86

87
BObject* BDictionaryIterator::step()
93✔
88
{
89
  if ( m_First )
93✔
90
  {
91
    auto itr = m_pDict->contents_.begin();
24✔
92
    if ( itr == m_pDict->contents_.end() )
24✔
93
      return nullptr;
×
94

95
    m_First = false;
24✔
96
    const BObject& okey = ( *itr ).first;
24✔
97
    m_Key.setimp( okey.impptr()->copy() );
24✔
98
    m_IterVal->setimp( m_Key.impptr() );
24✔
99

100
    BObjectRef& oref = ( *itr ).second;
24✔
101
    return oref.get();
24✔
102
  }
103

104
  auto itr = m_pDict->contents_.find( m_Key );
69✔
105
  if ( itr == m_pDict->contents_.end() )
69✔
106
    return nullptr;
×
107
  ++itr;
69✔
108
  if ( itr == m_pDict->contents_.end() )
69✔
109
    return nullptr;
24✔
110

111
  const BObject& okey = ( *itr ).first;
45✔
112
  m_Key.setimp( okey.impptr()->copy() );
45✔
113
  m_IterVal->setimp( m_Key.impptr() );
45✔
114

115
  BObjectRef& oref = ( *itr ).second;
45✔
116
  return oref.get();
45✔
117
}
118

119
ContIterator* BDictionary::createIterator( BObject* pIterVal )
24✔
120
{
121
  return new BDictionaryIterator( this, pIterVal );
24✔
122
}
123

124
BObjectImp* BDictionary::copy() const
642✔
125
{
126
  return new BDictionary( *this );
642✔
127
}
128

129
size_t BDictionary::sizeEstimate() const
120✔
130
{
131
  return sizeof( BDictionary ) +
132
         Clib::memsize_keyvalue( contents_, []( const auto& v ) { return v.sizeEstimate(); } );
618✔
133
}
134

135
size_t BDictionary::mapcount() const
×
136
{
137
  return contents_.size();
×
138
}
139

140
BObjectRef BDictionary::set_member( const char* membername, BObjectImp* value, bool copy )
24✔
141
{
142
  BObject key( new String( membername ) );
24✔
143
  BObjectImp* target = copy ? value->copy() : value;
24✔
144

145
  auto itr = contents_.find( key );
24✔
146
  if ( itr != contents_.end() )
24✔
147
  {
148
    BObjectRef& oref = ( *itr ).second;
15✔
149
    oref->setimp( target );
15✔
150
    return oref;
15✔
151
  }
152

153
  BObjectRef ref( new BObject( target ) );
9✔
154
  contents_[key] = ref;
9✔
155
  return ref;
9✔
156
}
24✔
157

158
BObjectRef BDictionary::get_member( const char* membername )
67✔
159
{
160
  BObject key( new String( membername ) );
67✔
161

162
  auto itr = contents_.find( key );
67✔
163
  if ( itr != contents_.end() )
67✔
164
  {
165
    return ( *itr ).second;
61✔
166
  }
167

168
  return BObjectRef( UninitObject::create() );
6✔
169
}
67✔
170

171

172
BObjectRef BDictionary::OperSubscript( const BObject& obj )
137✔
173
{
174
  if ( obj->isa( OTString ) || obj->isa( OTLong ) || obj->isa( OTDouble ) ||
140✔
175
       obj->isa( OTApplicObj ) )
3✔
176
  {
177
    auto itr = contents_.find( obj );
134✔
178
    if ( itr != contents_.end() )
134✔
179
    {
180
      BObjectRef& oref = ( *itr ).second;
128✔
181
      return oref;
128✔
182
    }
183

184
    return BObjectRef( UninitObject::create() );
6✔
185
  }
186

187
  return BObjectRef( new BError( "Dictionary keys must be integer, real, or string" ) );
3✔
188
}
189

190
BObjectImp* BDictionary::array_assign( BObjectImp* idx, BObjectImp* target, bool copy )
190✔
191
{
192
  if ( idx->isa( OTString ) || idx->isa( OTLong ) || idx->isa( OTDouble ) ||
190✔
193
       idx->isa( OTApplicObj ) )
×
194
  {
195
    BObjectImp* new_target = copy ? target->copy() : target;
190✔
196

197
    BObject obj( idx );
190✔
198
    auto itr = contents_.find( obj );
190✔
199
    if ( itr != contents_.end() )
190✔
200
    {
201
      BObjectRef& oref = ( *itr ).second;
18✔
202
      oref->setimp( new_target );
18✔
203
      return new_target;
18✔
204
    }
205

206
    contents_[BObject( obj->copy() )].set( new BObject( new_target ) );
172✔
207
    return new_target;
172✔
208
  }
190✔
209

210
  return new BError( "Dictionary keys must be integer, real, or string" );
×
211
}
212

213
void BDictionary::addMember( const char* name, BObjectRef val )
×
214
{
215
  BObject key( new String( name ) );
×
216
  contents_[key] = std::move( val );
×
217
}
×
218

219
void BDictionary::addMember( const char* name, BObjectImp* imp )
×
220
{
221
  BObject key( new String( name ) );
×
222
  contents_[key] = BObjectRef( imp );
×
223
}
×
224

225
void BDictionary::addMember( BObjectImp* keyimp, BObjectImp* valimp )
190✔
226
{
227
  BObject key( keyimp );
190✔
228
  contents_[key] = BObjectRef( valimp );
190✔
229
}
190✔
230

231
BObjectImp* BDictionary::call_method_id( const int id, Executor& ex, bool /*forcebuiltin*/ )
241✔
232
{
233
  BObject* keyobj;
234
  BObject* valobj;
235
  switch ( id )
241✔
236
  {
237
  case MTH_SIZE:
27✔
238
    if ( ex.numParams() == 0 )
27✔
239
      return new BLong( static_cast<int>( contents_.size() ) );
27✔
240
    else
241
      return new BError( "dictionary.size() doesn't take parameters." );
×
242
    break;
243
  case MTH_ERASE:
49✔
244
    if ( ex.numParams() == 1 && ( keyobj = ex.getParamObj( 0 ) ) != nullptr )
49✔
245
    {
246
      if ( !( keyobj->isa( OTLong ) || keyobj->isa( OTString ) || keyobj->isa( OTDouble ) ||
49✔
247
              keyobj->isa( OTApplicObj ) ) )
×
248
        return new BError( "Dictionary keys must be integer, real, or string" );
×
249
      int nremove = static_cast<int>( contents_.erase( *keyobj ) );
49✔
250
      return new BLong( nremove );
49✔
251
    }
252
    else
253
    {
254
      return new BError( "dictionary.erase(key) requires a parameter." );
×
255
    }
256
    break;
257
  case MTH_INSERT:
51✔
258
    if ( ex.numParams() == 2 && ( keyobj = ex.getParamObj( 0 ) ) != nullptr &&
102✔
259
         ( valobj = ex.getParamObj( 1 ) ) != nullptr )
51✔
260
    {
261
      if ( !( keyobj->isa( OTLong ) || keyobj->isa( OTString ) || keyobj->isa( OTDouble ) ||
51✔
262
              keyobj->isa( OTApplicObj ) ) )
×
263
        return new BError( "Dictionary keys must be integer, real, or string" );
×
264
      BObject key( keyobj->impptr()->copy() );
51✔
265
      contents_[key] = BObjectRef( new BObject( valobj->impptr()->copy() ) );
51✔
266
      return new BLong( static_cast<int>( contents_.size() ) );
51✔
267
    }
51✔
268
    else
269
    {
270
      return new BError( "dictionary.insert(key,value) requires two parameters." );
×
271
    }
272
    break;
273
  case MTH_EXISTS:
111✔
274
    if ( ex.numParams() == 1 && ( keyobj = ex.getParamObj( 0 ) ) != nullptr )
111✔
275
    {
276
      if ( !( keyobj->isa( OTLong ) || keyobj->isa( OTString ) || keyobj->isa( OTDouble ) ||
111✔
277
              keyobj->isa( OTApplicObj ) ) )
×
278
        return new BError( "Dictionary keys must be integer, real, or string" );
×
279
      int count = static_cast<int>( contents_.count( *keyobj ) );
111✔
280
      return new BLong( count );
111✔
281
    }
282
    else
283
    {
284
      return new BError( "dictionary.exists(key) requires a parameter." );
×
285
    }
286
    break;
287
  case MTH_KEYS:
3✔
288
    if ( ex.numParams() == 0 )
3✔
289
    {
290
      auto arr = new ObjArray;
3✔
291
      for ( const auto& content : contents_ )
9✔
292
      {
293
        const BObject& bkeyobj = content.first;
6✔
294

295
        arr->addElement( bkeyobj.impref().copy() );
6✔
296
      }
297
      return arr;
3✔
298
    }
299
    else
300
      return new BError( "dictionary.keys() doesn't take parameters." );
×
301
    break;
302
  default:
×
303
    return nullptr;
×
304
  }
305
}
306

307
BObjectImp* BDictionary::call_method( const char* methodname, Executor& ex )
×
308
{
309
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
310
  if ( objmethod != nullptr )
×
311
    return this->call_method_id( objmethod->id, ex );
×
312
  return nullptr;
×
313
}
314

315
char BDictionary::packtype() const
9✔
316
{
317
  return 'd';
9✔
318
}
319

320
const char* BDictionary::typetag() const
861✔
321
{
322
  return "dict";
861✔
323
}
324

325
const char* BDictionary::typeOf() const
×
326
{
327
  return "Dictionary";
×
328
}
329
u8 BDictionary::typeOfInt() const
3✔
330
{
331
  return OTDictionary;
3✔
332
}
333

334
void BDictionary::packonto( std::string& str ) const
9✔
335
{
336
  using namespace fmt::literals;
337
  fmt::format_to( std::back_inserter( str ), "{}{}:"_cf, packtype(), contents_.size() );
9✔
338
  for ( const auto& [bkeyobj, bvalref] : contents_ )
36✔
339
  {
340
    bkeyobj.impref().packonto( str );
27✔
341
    bvalref->impref().packonto( str );
27✔
342
  }
343
}
9✔
344

345
BObjectImp* BDictionary::unpack( std::istream& is )
9✔
346
{
347
  unsigned size;
348
  char colon;
349
  if ( !( is >> size >> colon ) )
9✔
350
  {
351
    return new BError( "Unable to unpack dictionary elemcount" );
×
352
  }
353
  if ( (int)size < 0 )
9✔
354
  {
355
    return new BError(
356
        "Unable to unpack dictionary elemcount. Length given must be positive integer!" );
×
357
  }
358
  if ( colon != ':' )
9✔
359
  {
360
    return new BError( "Unable to unpack dictionary elemcount. Bad format. Colon not found!" );
×
361
  }
362
  return new BDictionary( is, size );
9✔
363
}
364

365
std::string BDictionary::getStringRep() const
861✔
366
{
367
  std::string rep = fmt::format( "{}{{ ", typetag() );
861✔
368
  bool any = false;
861✔
369

370
  for ( const auto& [bkeyobj, bvalref] : contents_ )
1,707✔
371
  {
372
    if ( any )
846✔
373
      rep += ", ";
414✔
374
    else
375
      any = true;
432✔
376

377
    FormatForStringRep( rep, bkeyobj, bvalref );
846✔
378
  }
379

380
  rep += " }";
861✔
381

382
  return rep;
861✔
UNCOV
383
}
×
384

385
void BDictionary::FormatForStringRep( std::string& rep, const BObject& bkeyobj,
846✔
386
                                      const BObjectRef& bvalref ) const
387
{
388
  fmt::format_to( std::back_inserter( rep ), "{} -> {}", bkeyobj.impref().getFormattedStringRep(),
1,692✔
389
                  bvalref->impref().getFormattedStringRep() );
1,692✔
390
}
846✔
391

392

393
BObjectRef BDictionary::operDotPlus( const char* name )
×
394
{
395
  BObject key( new String( name ) );
×
396
  if ( contents_.count( key ) == 0 )
×
397
  {
398
    auto pnewobj = new BObject( new UninitObject );
×
399
    contents_[key] = BObjectRef( pnewobj );
×
400
    return BObjectRef( pnewobj );
×
401
  }
402

403
  return BObjectRef( new BError( "Member already exists" ) );
×
404
}
×
405

406
const BDictionary::Contents& BDictionary::contents() const
42✔
407
{
408
  return contents_;
42✔
409
}
410
}  // namespace Pol::Bscript
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc