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

polserver / polserver / 25918451630

15 May 2026 12:43PM UTC coverage: 60.929% (+2.1%) from 58.859%
25918451630

push

github

turleypol
added dynamic property which returns a pointer of the object instead of
a copy like the current imp.
needed to be able to eg store a vector

43 of 61 new or added lines in 2 files covered. (70.49%)

14455 existing lines in 345 files now uncovered.

44695 of 73356 relevant lines covered (60.93%)

449621.59 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,089✔
30

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

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

40
    contents_[key] = BObjectRef( new BObject( bvalref->impref().copy() ) );
7,811✔
41
  }
42
}
2,710✔
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 )
×
UNCOV
62
        BObject objv( valimp );
×
63
    }
64
  }
65
}
3✔
66

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

77
const char* BStruct::typetag() const
1,623✔
78
{
79
  return "struct";
1,623✔
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

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

112
void BStruct::FormatForStringRep( std::string& rep, const std::string& key,
3,115✔
113
                                  const BObjectRef& bvalref ) const
114
{
115
  fmt::format_to( std::back_inserter( rep ), "{} = {}", key,
3,115✔
116
                  bvalref->impref().getFormattedStringRep() );
6,230✔
117
}
3,115✔
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✔
UNCOV
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✔
UNCOV
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,982✔
213
{
214
  auto itr = contents_.find( membername );
11,982✔
215
  if ( itr != contents_.end() )
11,982✔
216
    return ( *itr ).second;
11,926✔
217
  return BObjectRef( UninitObject::create() );
56✔
218
}
219

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

226
    auto itr = contents_.find( keystr->value() );
273✔
227
    if ( itr != contents_.end() )
273✔
228
    {
229
      BObjectRef& oref = ( *itr ).second;
270✔
230
      return oref;
270✔
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

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

261
void BStruct::addMember( const char* name, BObjectImp* imp )
9,776✔
262
{
263
  contents_[name] = BObjectRef( imp );
9,776✔
264
}
9,776✔
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✔
UNCOV
275
    return new BError( "struct.size() doesn't take parameters." );
×
276

UNCOV
277
  case MTH_ERASE:
×
UNCOV
278
    if ( ex.numParams() == 1 && ( keyobj = ex.getParamObj( 0 ) ) != nullptr )
×
279
    {
UNCOV
280
      if ( !keyobj->isa( OTString ) )
×
UNCOV
281
        return new BError( "Struct keys must be strings" );
×
UNCOV
282
      String* strkey = keyobj->impptr<String>();
×
UNCOV
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✔
UNCOV
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✔
UNCOV
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
    }
UNCOV
309
    return new BError( "struct.exists(key) requires a parameter." );
×
310

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

UNCOV
328
BObjectImp* BStruct::call_method( const char* methodname, Executor& ex )
×
329
{
330
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
UNCOV
331
  if ( objmethod != nullptr )
×
UNCOV
332
    return this->call_method_id( objmethod->id, ex );
×
UNCOV
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,261✔
348
{
349
  std::string rep = fmt::format( "{}{{ ", typetag() );
2,261✔
350
  bool any = false;
2,261✔
351

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

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

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

366

367
BObjectRef BStruct::operDotPlus( const char* name )
1,973✔
368
{
369
  if ( contents_.count( name ) == 0 )
1,973✔
370
  {
371
    auto pnewobj = new BObject( new UninitObject );
1,967✔
372
    contents_[name] = BObjectRef( pnewobj );
1,967✔
373
    return BObjectRef( pnewobj );
1,967✔
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,629✔
385
{
386
  int count = static_cast<int>( contents_.count( name ) );
1,629✔
387
  return BObjectRef( new BLong( count ) );
3,258✔
388
}
389

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