• 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

78.71
/pol-core/bscript/bstruct.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:    BStruct::unpack() will accept zero length Structs
6
 * - 2009/09/05 Turley:    Added struct .? and .- as shortcut for .exists() and .erase()
7
 * - 2009/12/21 Turley:    ._method() call fix
8
 */
9

10

11
#include "bstruct.h"
12

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

17
#include "../clib/passert.h"
18
#include "../clib/stlutil.h"
19
#include "berror.h"
20
#include "bobject.h"
21
#include "contiter.h"
22
#include "executor.h"
23
#include "impstr.h"
24
#include "objmethods.h"
25

26

27
namespace Pol::Bscript
28
{
29
BStruct::BStruct() : BObjectImp( OTStruct ), contents_() {}
3,093✔
30

31
BStruct::BStruct( BObjectType type ) : BObjectImp( type ), contents_() {}
6,164✔
32

33
BStruct::BStruct( const BStruct& other, BObjectType type ) : BObjectImp( type ), contents_()
2,713✔
34
{
35
  for ( const auto& elem : other.contents_ )
10,510✔
36
  {
37
    const std::string& key = elem.first;
7,797✔
38
    const BObjectRef& bvalref = elem.second;
7,797✔
39

40
    contents_[key] = BObjectRef( new BObject( bvalref->impref().copy() ) );
7,797✔
41
  }
42
}
2,713✔
43

44
BStruct::BStruct( std::istream& is, unsigned size, BObjectType type )
3✔
45
    : BObjectImp( type ), contents_()
3✔
46
{
47
  for ( unsigned i = 0; i < size; ++i )
6✔
48
  {
49
    BObjectImp* keyimp = BObjectImp::unpack( is );
3✔
50
    BObjectImp* valimp = BObjectImp::unpack( is );
3✔
51
    if ( auto* key = impptrIf<String>( keyimp ); valimp && key )
3✔
52
    {
53
      contents_[key->value()].set( new BObject( valimp ) );
3✔
54

55
      BObject cleaner( key );
3✔
56
    }
3✔
57
    else
58
    {
59
      if ( keyimp )
×
60
        BObject objk( keyimp );
×
61
      if ( valimp )
×
62
        BObject objv( valimp );
×
63
    }
64
  }
65
}
3✔
66

67
BObjectImp* BStruct::copy() const
2,607✔
68
{
69
  passert( isa( OTStruct ) );
2,607✔
70
  return new BStruct( *this, OTStruct );
2,607✔
71
}
72
char BStruct::packtype() const
6✔
73
{
74
  return 't';
6✔
75
}
76

77
const char* BStruct::typetag() const
1,625✔
78
{
79
  return "struct";
1,625✔
80
}
81

82
const char* BStruct::typeOf() const
13✔
83
{
84
  return "Struct";
13✔
85
}
86
u8 BStruct::typeOfInt() const
6✔
87
{
88
  return OTStruct;
6✔
89
}
90

91

92
BObjectImp* BStruct::unpack( std::istream& is )
×
93
{
94
  unsigned size;
95
  char colon;
96
  if ( !( is >> size >> colon ) )
×
97
  {
98
    return new BError( "Unable to unpack struct elemcount" );
×
99
  }
100
  if ( (int)size < 0 )
×
101
  {
102
    return new BError(
103
        "Unable to unpack struct elemcount. Length given must be positive integer!" );
×
104
  }
105
  if ( colon != ':' )
×
106
  {
107
    return new BError( "Unable to unpack struct elemcount. Bad format. Colon not found!" );
×
108
  }
109
  return new BStruct( is, size, OTStruct );
×
110
}
111

112
void BStruct::FormatForStringRep( std::string& rep, const std::string& key,
3,119✔
113
                                  const BObjectRef& bvalref ) const
114
{
115
  fmt::format_to( std::back_inserter( rep ), "{} = {}", key,
3,119✔
116
                  bvalref->impref().getFormattedStringRep() );
6,238✔
117
}
3,119✔
118

119
class BStructIterator final : public ContIterator
120
{
121
public:
122
  BStructIterator( BStruct* pDict, BObject* pIterVal );
123
  BObject* step() override;
124

125
private:
126
  BObject m_StructObj;
127
  BStruct* m_pStruct;
128
  BObjectRef m_IterVal;
129
  std::string key;
130
  bool m_First;
131
};
132
BStructIterator::BStructIterator( BStruct* pStruct, BObject* pIterVal )
61✔
133
    : m_StructObj( pStruct ),
61✔
134
      m_pStruct( pStruct ),
61✔
135
      m_IterVal( pIterVal ),
61✔
136
      key( "" ),
61✔
137
      m_First( true )
61✔
138
{
139
}
61✔
140

141
BObject* BStructIterator::step()
221✔
142
{
143
  if ( m_First )
221✔
144
  {
145
    auto itr = m_pStruct->contents_.begin();
61✔
146
    if ( itr == m_pStruct->contents_.end() )
61✔
147
      return nullptr;
×
148

149
    m_First = false;
61✔
150
    key = ( *itr ).first;
61✔
151
    m_IterVal->setimp( new String( key ) );
61✔
152

153
    BObjectRef& oref = ( *itr ).second;
61✔
154
    return oref.get();
61✔
155
  }
156

157
  auto itr = m_pStruct->contents_.find( key );
160✔
158
  if ( itr == m_pStruct->contents_.end() )
160✔
159
    return nullptr;
×
160
  ++itr;
160✔
161
  if ( itr == m_pStruct->contents_.end() )
160✔
162
    return nullptr;
61✔
163

164
  key = ( *itr ).first;
99✔
165
  m_IterVal->setimp( new String( key ) );
99✔
166

167
  BObjectRef& oref = ( *itr ).second;
99✔
168
  return oref.get();
99✔
169
}
170

171
ContIterator* BStruct::createIterator( BObject* pIterVal )
61✔
172
{
173
  return new BStructIterator( this, pIterVal );
61✔
174
}
175

176
size_t BStruct::sizeEstimate() const
343✔
177
{
178
  return sizeof( BStruct ) +
179
         Clib::memsize( contents_, []( const auto& v ) { return v.sizeEstimate(); } );
776✔
180
}
181

182
size_t BStruct::mapcount() const
3✔
183
{
184
  return contents_.size();
3✔
185
}
186

187

188
BObjectRef BStruct::set_member( const char* membername, BObjectImp* value, bool copy )
618✔
189
{
190
  BObjectImp* target = copy ? value->copy() : value;
618✔
191
  auto itr = contents_.find( membername );
618✔
192
  if ( itr != contents_.end() )
618✔
193
  {
194
    BObjectRef& oref = ( *itr ).second;
197✔
195
    oref->setimp( target );
197✔
196
    return oref;
197✔
197
  }
198
  BObjectRef ref( new BObject( target ) );
421✔
199
  contents_.emplace( membername, ref );
421✔
200
  return ref;
421✔
201
}
421✔
202

203
// used programmatically
204
const BObjectImp* BStruct::FindMember( const char* name )
50✔
205
{
206
  auto itr = contents_.find( name );
50✔
207
  if ( itr != contents_.end() )
50✔
208
    return ( *itr ).second->impptr();
13✔
209
  return nullptr;
37✔
210
}
211

212
BObjectRef BStruct::get_member( const char* membername )
11,960✔
213
{
214
  auto itr = contents_.find( membername );
11,960✔
215
  if ( itr != contents_.end() )
11,960✔
216
    return ( *itr ).second;
11,904✔
217
  return BObjectRef( UninitObject::create() );
56✔
218
}
219

220
BObjectRef BStruct::OperSubscript( const BObject& obj )
278✔
221
{
222
  if ( obj->isa( OTString ) )
278✔
223
  {
224
    const String* keystr = obj.impptr<String>();
275✔
225

226
    auto itr = contents_.find( keystr->value() );
275✔
227
    if ( itr != contents_.end() )
275✔
228
    {
229
      BObjectRef& oref = ( *itr ).second;
272✔
230
      return oref;
272✔
231
    }
232
    return BObjectRef( UninitObject::create() );
3✔
233
  }
234
  return BObjectRef( new BError( "Struct members can only be accessed by name" ) );
3✔
235
}
236

237
BObjectImp* BStruct::array_assign( BObjectImp* idx, BObjectImp* target, bool copy )
38✔
238
{
239
  if ( auto* key = impptrIf<String>( idx ) )
38✔
240
  {
241
    BObjectImp* new_target = copy ? target->copy() : target;
35✔
242

243
    auto itr = contents_.find( key->value() );
35✔
244
    if ( itr != contents_.end() )
35✔
245
    {
246
      BObjectRef& oref = ( *itr ).second;
15✔
247
      oref->setimp( new_target );
15✔
248
      return new_target;
15✔
249
    }
250
    contents_[key->value()].set( new BObject( new_target ) );
20✔
251
    return new_target;
20✔
252
  }
253
  return new BError( "Struct members can only be accessed by name" );
3✔
254
}
255

256
void BStruct::addMember( const char* name, BObjectRef val )
×
257
{
258
  contents_[name] = std::move( val );
×
259
}
×
260

261
void BStruct::addMember( const char* name, BObjectImp* imp )
9,784✔
262
{
263
  contents_[name] = BObjectRef( imp );
9,784✔
264
}
9,784✔
265

266
BObjectImp* BStruct::call_method_id( const int id, Executor& ex, bool /*forcebuiltin*/ )
670✔
267
{
268
  BObject* keyobj;
269
  BObject* valobj;
270
  switch ( id )
670✔
271
  {
272
  case MTH_SIZE:
27✔
273
    if ( ex.numParams() == 0 )
27✔
274
      return new BLong( static_cast<int>( contents_.size() ) );
27✔
275
    return new BError( "struct.size() doesn't take parameters." );
×
276

277
  case MTH_ERASE:
×
278
    if ( ex.numParams() == 1 && ( keyobj = ex.getParamObj( 0 ) ) != nullptr )
×
279
    {
280
      if ( !keyobj->isa( OTString ) )
×
281
        return new BError( "Struct keys must be strings" );
×
282
      String* strkey = keyobj->impptr<String>();
×
283
      int nremove = static_cast<int>( contents_.erase( strkey->value() ) );
×
284
      return new BLong( nremove );
×
285
    }
286
    return new BError( "struct.erase(key) requires a parameter." );
×
287
    break;
288
  case MTH_INSERT:
15✔
289
    if ( ex.numParams() == 2 && ( keyobj = ex.getParamObj( 0 ) ) != nullptr &&
21✔
290
         ( valobj = ex.getParamObj( 1 ) ) != nullptr )
6✔
291
    {
292
      if ( !keyobj->isa( OTString ) )
6✔
293
        return new BError( "Struct keys must be strings" );
×
294
      String* strkey = keyobj->impptr<String>();
6✔
295
      contents_[strkey->value()] = BObjectRef( new BObject( valobj->impptr()->copy() ) );
6✔
296
      return new BLong( static_cast<int>( contents_.size() ) );
6✔
297
    }
298
    return new BError( "struct.insert(key,value) requires two parameters." );
9✔
299
    break;
300
  case MTH_EXISTS:
625✔
301
    if ( ex.numParams() == 1 && ( keyobj = ex.getParamObj( 0 ) ) != nullptr )
625✔
302
    {
303
      if ( !keyobj->isa( OTString ) )
625✔
304
        return new BError( "Struct keys must be strings" );
×
305
      String* strkey = keyobj->impptr<String>();
625✔
306
      int count = static_cast<int>( contents_.count( strkey->value() ) );
625✔
307
      return new BLong( count );
625✔
308
    }
309
    return new BError( "struct.exists(key) requires a parameter." );
×
310

311
  case MTH_KEYS:
×
312
    if ( ex.numParams() == 0 )
×
313
    {
314
      std::unique_ptr<ObjArray> arr( new ObjArray );
×
315
      for ( const auto& content : contents_ )
×
316
      {
317
        arr->addElement( new String( content.first ) );
×
318
      }
319
      return arr.release();
×
320
    }
×
321
    return new BError( "struct.keys() doesn't take parameters." );
×
322
    break;
323
  default:
3✔
324
    return nullptr;
3✔
325
  }
326
}
327

328
BObjectImp* BStruct::call_method( const char* methodname, Executor& ex )
×
329
{
330
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
331
  if ( objmethod != nullptr )
×
332
    return this->call_method_id( objmethod->id, ex );
×
333
  return nullptr;
×
334
}
335

336
void BStruct::packonto( std::string& str ) const
9✔
337
{
338
  using namespace fmt::literals;
339
  fmt::format_to( std::back_inserter( str ), "{}{}:"_cf, packtype(), contents_.size() );
9✔
340
  for ( const auto& [key, bvalref] : contents_ )
24✔
341
  {
342
    String::packonto( str, key );
15✔
343
    bvalref->impref().packonto( str );
15✔
344
  }
345
}
9✔
346

347
std::string BStruct::getStringRep() const
2,263✔
348
{
349
  std::string rep = fmt::format( "{}{{ ", typetag() );
2,263✔
350
  bool any = false;
2,263✔
351

352
  for ( const auto& [key, bvalref] : contents_ )
5,382✔
353
  {
354
    if ( any )
3,119✔
355
      rep += ", ";
1,306✔
356
    else
357
      any = true;
1,813✔
358

359
    FormatForStringRep( rep, key, bvalref );
3,119✔
360
  }
361

362
  rep += " }";
2,263✔
363
  return rep;
2,263✔
UNCOV
364
}
×
365

366

367
BObjectRef BStruct::operDotPlus( const char* name )
1,951✔
368
{
369
  if ( contents_.count( name ) == 0 )
1,951✔
370
  {
371
    auto pnewobj = new BObject( new UninitObject );
1,945✔
372
    contents_[name] = BObjectRef( pnewobj );
1,945✔
373
    return BObjectRef( pnewobj );
1,945✔
374
  }
375
  return BObjectRef( new BError( "Member already exists" ) );
6✔
376
}
377

378
BObjectRef BStruct::operDotMinus( const char* name )
1✔
379
{
380
  contents_.erase( name );
1✔
381
  return BObjectRef( new BLong( 1 ) );
2✔
382
}
383

384
BObjectRef BStruct::operDotQMark( const char* name )
1,635✔
385
{
386
  int count = static_cast<int>( contents_.count( name ) );
1,635✔
387
  return BObjectRef( new BLong( count ) );
3,270✔
388
}
389

390
const BStruct::Contents& BStruct::contents() const
1,800✔
391
{
392
  return contents_;
1,800✔
393
}
394
}  // 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