iodine 0.7.2 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9304bf27335fe19b9c7d7ca9442fe994772c5489a70aa598cc045bda313c755
4
- data.tar.gz: 8acee18f9da3f77a763fb7c93ac2c4328788c79298c5b792597e6b40ee1b14c5
3
+ metadata.gz: bf89fce9c0e4b457fb88d8871bc61e81517fdb9bfe227627394f8c06753829c1
4
+ data.tar.gz: 20f66f4a8fe102b9c9e59ee2eda6ed27e0f65e880a42c953554df8b3ead6ca11
5
5
  SHA512:
6
- metadata.gz: aef5181c233342793d2c74a8d4ca6c398a357c36bc399dd133f796aa0c2e67ed881d99514b45c2e85da880e0a2b49844fa869afc28be696dc63675558b7dba2c
7
- data.tar.gz: 6e6f11fd287cafbcc9eae4ef3df92fe4b4c543e9d930344745725c59cc4be587d24e8c226416ae65208516bd995afa90c210847f0e8faf9873dfe3913c4ef7dc
6
+ metadata.gz: 4967888c32c01259d933576876d07d66612ac71689dfb93ae8dad8e08675a4908e654d76ebb9e44cf4f9fb87b657a068fb97520648b89df6daae2bfe4a191f55
7
+ data.tar.gz: 11170c43eece7c6a6627408e40c5f5751abde9b5e330ba97c8f19c6643e0cf842d70c7a3dfaaf2b18b6fb30894cf48563d2d56ffc9cc70fa58809eb5e30c2983
@@ -6,6 +6,12 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ #### Change log v.0.7.3
10
+
11
+ **Fix**: (facil.io) updating facil.io fixes a channel name memory leak fixed in facil.io's edge version.
12
+
13
+ **Updated**: Improved logging for server data, allowing for log silencing.
14
+
9
15
  #### Change log v.0.7.2
10
16
 
11
17
  **Updated**: updated the logging for HTTP services startup, to minimize log clutter.
data/exe/iodine CHANGED
@@ -32,6 +32,7 @@ Available options:
32
32
  -maxbd Maximum Mb per HTTP message (max body size). Default: 50Mb.
33
33
  -maxms Maximum Bytes per Websocket message. Default: 250Kb.
34
34
  -ping WebSocket / SSE ping interval in seconds. Default: 40 seconds.
35
+ -logging Server level logging (not HTTP), values between 0..5. Defaults to 4.
35
36
  <filename> Defaults to: config.ru
36
37
 
37
38
  Example:
@@ -29,7 +29,7 @@ else
29
29
  puts 'using an unknown (old?) compiler... who knows if this will work out... we hope.'
30
30
  end
31
31
 
32
- $CFLAGS = "-std=c11 -O2 -Wall #{ENV['CFLAGS']}"
32
+ $CFLAGS = "-std=c11 -O2 -Wall -DFIO_PRINT_STATE=0 #{ENV['CFLAGS']}"
33
33
  RbConfig::MAKEFILE_CONFIG['CC'] = $CC = ENV['CC'] if ENV['CC']
34
34
  RbConfig::MAKEFILE_CONFIG['CPP'] = $CPP = ENV['CPP'] if ENV['CPP']
35
35
 
@@ -467,7 +467,8 @@ void fio_uuid_link(intptr_t uuid, void *obj, void (*on_close)(void *obj)) {
467
467
  fio_lock(&uuid_data(uuid).sock_lock);
468
468
  if (!uuid_is_valid(uuid))
469
469
  goto locked_invalid;
470
- fio_uuid_links_overwrite(&uuid_data(uuid).links, (uintptr_t)obj, on_close);
470
+ fio_uuid_links_overwrite(&uuid_data(uuid).links, (uintptr_t)obj, on_close,
471
+ NULL);
471
472
  fio_unlock(&uuid_data(uuid).sock_lock);
472
473
  return;
473
474
  locked_invalid:
@@ -485,7 +486,8 @@ int fio_uuid_unlink(intptr_t uuid, void *obj) {
485
486
  if (!uuid_is_valid(uuid))
486
487
  goto locked_invalid;
487
488
  /* default object comparison is always true */
488
- int ret = fio_uuid_links_remove(&uuid_data(uuid).links, (uintptr_t)obj, NULL);
489
+ int ret =
490
+ fio_uuid_links_remove(&uuid_data(uuid).links, (uintptr_t)obj, NULL, NULL);
489
491
  if (ret)
490
492
  errno = ENOTCONN;
491
493
  fio_unlock(&uuid_data(uuid).sock_lock);
@@ -3071,6 +3073,7 @@ static void fio_pubsub_on_fork(void);
3071
3073
 
3072
3074
  static void fio_mem_destroy(void);
3073
3075
  static void __attribute__((destructor)) fio_lib_destroy(void) {
3076
+ uint8_t add_eol = fio_is_master();
3074
3077
  fio_data->active = 0;
3075
3078
  fio_state_callback_force(FIO_CALL_AT_EXIT);
3076
3079
  fio_state_callback_clear_all();
@@ -3081,7 +3084,8 @@ static void __attribute__((destructor)) fio_lib_destroy(void) {
3081
3084
  /* memory library destruction must be last */
3082
3085
  fio_mem_destroy();
3083
3086
  FIO_LOG_DEBUG("(%d) facil.io resources released, exit complete.", getpid());
3084
- fprintf(stderr, "\n"); /* add EOL to logs (logging adds EOL before text */
3087
+ if (add_eol)
3088
+ fprintf(stderr, "\n"); /* add EOL to logs (logging adds EOL before text */
3085
3089
  }
3086
3090
 
3087
3091
  /* Called within a child process after it starts. */
@@ -3477,6 +3481,7 @@ void fio_start FIO_IGNORE_MACRO(struct fio_start_args args) {
3477
3481
  fio_data->workers = (uint16_t)args.workers;
3478
3482
  fio_data->threads = (uint16_t)args.threads;
3479
3483
  fio_data->active = 1;
3484
+ fio_data->is_worker = 0;
3480
3485
 
3481
3486
  fio_state_callback_force(FIO_CALL_PRE_START);
3482
3487
 
@@ -3899,10 +3904,10 @@ static void fio_listen_on_startup(void *pr_) {
3899
3904
  fio_listen_protocol_s *pr = pr_;
3900
3905
  fio_attach(pr->uuid, &pr->pr);
3901
3906
  if (pr->port_len)
3902
- FIO_LOG_INFO("(%d) started listening on port %s", getpid(), pr->port);
3907
+ FIO_LOG_DEBUG("(%d) started listening on port %s", getpid(), pr->port);
3903
3908
  else
3904
- FIO_LOG_INFO("(%d) started listening on Unix Socket at %s", getpid(),
3905
- pr->addr);
3909
+ FIO_LOG_DEBUG("(%d) started listening on Unix Socket at %s", getpid(),
3910
+ pr->addr);
3906
3911
  }
3907
3912
 
3908
3913
  static void fio_listen_on_close(intptr_t uuid, fio_protocol_s *pr_) {
@@ -4303,7 +4308,7 @@ static inline channel_s *fio_filter_dup_lock_internal(channel_s *ch,
4303
4308
  uint64_t hashed,
4304
4309
  fio_collection_s *c) {
4305
4310
  fio_lock(&c->lock);
4306
- ch = *fio_ch_set_insert(&c->channels, hashed, ch);
4311
+ ch = fio_ch_set_insert(&c->channels, hashed, ch);
4307
4312
  fio_str_dup(&ch->id);
4308
4313
  fio_lock(&ch->lock);
4309
4314
  fio_unlock(&c->lock);
@@ -4440,7 +4445,7 @@ void fio_unsubscribe(subscription_s *s) {
4440
4445
  fio_lock(&c->lock);
4441
4446
  /* test again within lock */
4442
4447
  if (fio_ls_embd_is_empty(&ch->subscriptions)) {
4443
- fio_ch_set_remove(&c->channels, hashed, ch);
4448
+ fio_ch_set_remove(&c->channels, hashed, ch, NULL);
4444
4449
  removed = 1;
4445
4450
  }
4446
4451
  fio_unlock(&c->lock);
@@ -4520,13 +4525,14 @@ void fio_pubsub_attach(fio_pubsub_engine_s *engine) {
4520
4525
  /** Detaches an engine, so it could be safely destroyed. */
4521
4526
  void fio_pubsub_detach(fio_pubsub_engine_s *engine) {
4522
4527
  fio_lock(&fio_postoffice.engines.lock);
4523
- fio_engine_set_remove(&fio_postoffice.engines.set, (uintptr_t)engine, engine);
4528
+ fio_engine_set_remove(&fio_postoffice.engines.set, (uintptr_t)engine, engine,
4529
+ NULL);
4524
4530
  fio_unlock(&fio_postoffice.engines.lock);
4525
4531
  }
4526
4532
 
4527
4533
  /** Returns true (1) if the engine is attached to the system. */
4528
4534
  int fio_pubsub_is_attached(fio_pubsub_engine_s *engine) {
4529
- fio_pubsub_engine_s **addr;
4535
+ fio_pubsub_engine_s *addr;
4530
4536
  fio_lock(&fio_postoffice.engines.lock);
4531
4537
  addr = fio_engine_set_find(&fio_postoffice.engines.set, (uintptr_t)engine,
4532
4538
  engine);
@@ -4612,8 +4618,8 @@ void fio_message_metadata_callback_set(fio_msg_metadata_fn callback,
4612
4618
  fio_meta_set_insert(&fio_postoffice.meta.set, (uintptr_t)callback,
4613
4619
  callback);
4614
4620
  else
4615
- fio_meta_set_remove(&fio_postoffice.meta.set, (uintptr_t)callback,
4616
- callback);
4621
+ fio_meta_set_remove(&fio_postoffice.meta.set, (uintptr_t)callback, callback,
4622
+ NULL);
4617
4623
  fio_unlock(&fio_postoffice.meta.lock);
4618
4624
  }
4619
4625
 
@@ -4637,12 +4643,11 @@ void *fio_message_metadata(fio_msg_s *msg, intptr_t type_id) {
4637
4643
  static channel_s *fio_channel_find_dup_internal(fio_str_s *s, uint64_t hashed,
4638
4644
  fio_collection_s *c) {
4639
4645
  fio_lock(&c->lock);
4640
- channel_s **pch = fio_ch_set_find(&c->channels, hashed, (channel_s *)s);
4641
- if (!pch) {
4646
+ channel_s *ch = fio_ch_set_find(&c->channels, hashed, (channel_s *)s);
4647
+ if (!ch) {
4642
4648
  fio_unlock(&c->lock);
4643
4649
  return NULL;
4644
4650
  }
4645
- channel_s *ch = *pch;
4646
4651
  fio_str_dup((fio_str_s *)ch);
4647
4652
  fio_unlock(&c->lock);
4648
4653
  return ch;
@@ -4778,8 +4783,7 @@ static void fio_publish2process(fio_msg_internal_s *m) {
4778
4783
  }
4779
4784
  /* exact match */
4780
4785
  if (ch) {
4781
- fio_defer(fio_publish2channel_task, fio_str_dup(&ch->id),
4782
- fio_msg_internal_dup(m));
4786
+ fio_defer(fio_publish2channel_task, &ch->id, fio_msg_internal_dup(m));
4783
4787
  }
4784
4788
  if (m->filter == 0) {
4785
4789
  /* pattern matching match */
@@ -5128,7 +5132,7 @@ static void fio_cluster_server_handler(struct cluster_pr_s *pr) {
5128
5132
  fio_str_s tmp = FIO_STR_INIT_EXISTING(
5129
5133
  pr->msg->channel.data, pr->msg->channel.len, 0); // don't free
5130
5134
  fio_lock(&pr->lock);
5131
- fio_sub_hash_insert(&pr->pubsub, fio_str_hash(&tmp), tmp, s);
5135
+ fio_sub_hash_insert(&pr->pubsub, fio_str_hash(&tmp), tmp, s, NULL);
5132
5136
  fio_unlock(&pr->lock);
5133
5137
  break;
5134
5138
  }
@@ -5136,7 +5140,7 @@ static void fio_cluster_server_handler(struct cluster_pr_s *pr) {
5136
5140
  fio_str_s tmp = FIO_STR_INIT_EXISTING(
5137
5141
  pr->msg->channel.data, pr->msg->channel.len, 0); // don't free
5138
5142
  fio_lock(&pr->lock);
5139
- fio_sub_hash_remove(&pr->pubsub, fio_str_hash(&tmp), tmp);
5143
+ fio_sub_hash_remove(&pr->pubsub, fio_str_hash(&tmp), tmp, NULL);
5140
5144
  fio_unlock(&pr->lock);
5141
5145
  break;
5142
5146
  }
@@ -5149,7 +5153,7 @@ static void fio_cluster_server_handler(struct cluster_pr_s *pr) {
5149
5153
  fio_str_s tmp = FIO_STR_INIT_EXISTING(
5150
5154
  pr->msg->channel.data, pr->msg->channel.len, 0); // don't free
5151
5155
  fio_lock(&pr->lock);
5152
- fio_sub_hash_insert(&pr->patterns, fio_str_hash(&tmp), tmp, s);
5156
+ fio_sub_hash_insert(&pr->patterns, fio_str_hash(&tmp), tmp, s, NULL);
5153
5157
  fio_unlock(&pr->lock);
5154
5158
  break;
5155
5159
  }
@@ -5158,7 +5162,7 @@ static void fio_cluster_server_handler(struct cluster_pr_s *pr) {
5158
5162
  fio_str_s tmp = FIO_STR_INIT_EXISTING(
5159
5163
  pr->msg->channel.data, pr->msg->channel.len, 0); // don't free
5160
5164
  fio_lock(&pr->lock);
5161
- fio_sub_hash_remove(&pr->patterns, fio_str_hash(&tmp), tmp);
5165
+ fio_sub_hash_remove(&pr->patterns, fio_str_hash(&tmp), tmp, NULL);
5162
5166
  fio_unlock(&pr->lock);
5163
5167
  break;
5164
5168
  }
@@ -5412,7 +5416,7 @@ static void fio_cluster_at_exit(void *ignore) {
5412
5416
  fio_pubsub_on_fork();
5413
5417
  /* clear subscriptions of all types */
5414
5418
  while (fio_ch_set_count(&fio_postoffice.patterns.channels)) {
5415
- channel_s *ch = *fio_ch_set_last(&fio_postoffice.patterns.channels);
5419
+ channel_s *ch = fio_ch_set_last(&fio_postoffice.patterns.channels);
5416
5420
  while (fio_ls_embd_any(&ch->subscriptions)) {
5417
5421
  subscription_s *sub =
5418
5422
  FIO_LS_EMBD_OBJ(subscription_s, node, ch->subscriptions.next);
@@ -5422,7 +5426,7 @@ static void fio_cluster_at_exit(void *ignore) {
5422
5426
  }
5423
5427
 
5424
5428
  while (fio_ch_set_count(&fio_postoffice.pubsub.channels)) {
5425
- channel_s *ch = *fio_ch_set_last(&fio_postoffice.pubsub.channels);
5429
+ channel_s *ch = fio_ch_set_last(&fio_postoffice.pubsub.channels);
5426
5430
  while (fio_ls_embd_any(&ch->subscriptions)) {
5427
5431
  subscription_s *sub =
5428
5432
  FIO_LS_EMBD_OBJ(subscription_s, node, ch->subscriptions.next);
@@ -5432,7 +5436,7 @@ static void fio_cluster_at_exit(void *ignore) {
5432
5436
  }
5433
5437
 
5434
5438
  while (fio_ch_set_count(&fio_postoffice.filters.channels)) {
5435
- channel_s *ch = *fio_ch_set_last(&fio_postoffice.filters.channels);
5439
+ channel_s *ch = fio_ch_set_last(&fio_postoffice.filters.channels);
5436
5440
  while (fio_ls_embd_any(&ch->subscriptions)) {
5437
5441
  subscription_s *sub =
5438
5442
  FIO_LS_EMBD_OBJ(subscription_s, node, ch->subscriptions.next);
@@ -5447,7 +5451,7 @@ static void fio_cluster_at_exit(void *ignore) {
5447
5451
  /* clear engines */
5448
5452
  FIO_PUBSUB_DEFAULT = FIO_PUBSUB_CLUSTER;
5449
5453
  while (fio_engine_set_count(&fio_postoffice.engines.set)) {
5450
- fio_pubsub_detach(*fio_engine_set_last(&fio_postoffice.engines.set));
5454
+ fio_pubsub_detach(fio_engine_set_last(&fio_postoffice.engines.set));
5451
5455
  fio_engine_set_last(&fio_postoffice.engines.set);
5452
5456
  }
5453
5457
  fio_engine_set_free(&fio_postoffice.engines.set);
@@ -8434,23 +8438,22 @@ FIO_FUNC void fio_set_test(void) {
8434
8438
  FIO_ASSERT(!fio_hash_test_is_fragmented(&h),
8435
8439
  "empty hash shouldn't be considered fragmented");
8436
8440
  FIO_ASSERT(!fio_set_test_last(&s), "empty set shouldn't have a last object");
8437
- FIO_ASSERT(!fio_hash_test_last(&h),
8441
+ FIO_ASSERT(!fio_hash_test_last(&h).key && !fio_hash_test_last(&h).obj,
8438
8442
  "empty hash shouldn't have a last object");
8439
8443
 
8440
8444
  for (uintptr_t i = 1; i < FIO_SET_TEXT_COUNT; ++i) {
8441
8445
  fio_set_test_insert(&s, i, i);
8442
- fio_hash_test_insert(&h, i, i, i + 1);
8446
+ fio_hash_test_insert(&h, i, i, i + 1, NULL);
8443
8447
  FIO_ASSERT(fio_set_test_find(&s, i, i), "set find failed after insert");
8444
8448
  FIO_ASSERT(fio_hash_test_find(&h, i, i), "hash find failed after insert");
8445
- FIO_ASSERT(i == *fio_set_test_find(&s, i, i), "set insertion != find");
8446
- FIO_ASSERT(i + 1 == *fio_hash_test_find(&h, i, i),
8447
- "hash insertion != find");
8449
+ FIO_ASSERT(i == fio_set_test_find(&s, i, i), "set insertion != find");
8450
+ FIO_ASSERT(i + 1 == fio_hash_test_find(&h, i, i), "hash insertion != find");
8448
8451
  }
8449
8452
  fprintf(stderr, "* Seeking %lu items\n", FIO_SET_TEXT_COUNT);
8450
8453
  for (unsigned long i = 1; i < FIO_SET_TEXT_COUNT; ++i) {
8451
- FIO_ASSERT((i == *fio_set_test_find(&s, i, i)),
8454
+ FIO_ASSERT((i == fio_set_test_find(&s, i, i)),
8452
8455
  "set insertion != find (seek)");
8453
- FIO_ASSERT((i + 1 == *fio_hash_test_find(&h, i, i)),
8456
+ FIO_ASSERT((i + 1 == fio_hash_test_find(&h, i, i)),
8454
8457
  "hash insertion != find (seek)");
8455
8458
  }
8456
8459
  {
@@ -8477,8 +8480,8 @@ FIO_FUNC void fio_set_test(void) {
8477
8480
 
8478
8481
  fprintf(stderr, "* Removing odd items from %lu items\n", FIO_SET_TEXT_COUNT);
8479
8482
  for (unsigned long i = 1; i < FIO_SET_TEXT_COUNT; i += 2) {
8480
- fio_set_test_remove(&s, i, i);
8481
- fio_hash_test_remove(&h, i, i);
8483
+ fio_set_test_remove(&s, i, i, NULL);
8484
+ fio_hash_test_remove(&h, i, i, NULL);
8482
8485
  FIO_ASSERT(!(fio_set_test_find(&s, i, i)),
8483
8486
  "Removal failed in set (still exists).");
8484
8487
  FIO_ASSERT(!(fio_hash_test_find(&h, i, i)),
@@ -8510,49 +8513,49 @@ FIO_FUNC void fio_set_test(void) {
8510
8513
  {
8511
8514
  fprintf(stderr, "* Poping two elements (testing pop through holes)\n");
8512
8515
  FIO_ASSERT(fio_set_test_last(&s), "Pop `last` 1 failed - no last object");
8513
- uintptr_t tmp = *fio_set_test_last(&s);
8516
+ uintptr_t tmp = fio_set_test_last(&s);
8514
8517
  FIO_ASSERT(tmp, "Pop set `last` 1 failed to collect object");
8515
8518
  fio_set_test_pop(&s);
8516
8519
  FIO_ASSERT(
8517
- *fio_set_test_last(&s) != tmp,
8520
+ fio_set_test_last(&s) != tmp,
8518
8521
  "Pop `last` 2 in set same as `last` 1 - failed to collect object");
8519
- tmp = fio_hash_test_last(&h)->key;
8522
+ tmp = fio_hash_test_last(&h).key;
8520
8523
  FIO_ASSERT(tmp, "Pop hash `last` 1 failed to collect object");
8521
8524
  fio_hash_test_pop(&h);
8522
8525
  FIO_ASSERT(
8523
- fio_hash_test_last(&h)->key != tmp,
8526
+ fio_hash_test_last(&h).key != tmp,
8524
8527
  "Pop `last` 2 in hash same as `last` 1 - failed to collect object");
8525
8528
  FIO_ASSERT(fio_set_test_last(&s), "Pop `last` 2 failed - no last object");
8526
- FIO_ASSERT(fio_hash_test_last(&h),
8529
+ FIO_ASSERT(fio_hash_test_last(&h).obj,
8527
8530
  "Pop `last` 2 failed in hash - no last object");
8528
8531
  fio_set_test_pop(&s);
8529
8532
  fio_hash_test_pop(&h);
8530
8533
  }
8531
8534
  if (1) {
8532
8535
  uintptr_t tmp = 1;
8533
- fio_set_test_remove(&s, tmp, tmp);
8534
- fio_hash_test_remove(&h, tmp, tmp);
8536
+ fio_set_test_remove(&s, tmp, tmp, NULL);
8537
+ fio_hash_test_remove(&h, tmp, tmp, NULL);
8535
8538
  size_t count = s.count;
8536
- fio_set_test_overwrite(&s, tmp, tmp);
8539
+ fio_set_test_overwrite(&s, tmp, tmp, NULL);
8537
8540
  FIO_ASSERT(
8538
8541
  count + 1 == s.count,
8539
8542
  "Re-adding a removed item in set should increase count by 1 (%zu + "
8540
8543
  "1 != %zu).",
8541
8544
  count, (size_t)s.count);
8542
8545
  count = h.count;
8543
- fio_hash_test_insert(&h, tmp, tmp, tmp);
8546
+ fio_hash_test_insert(&h, tmp, tmp, tmp, NULL);
8544
8547
  FIO_ASSERT(
8545
8548
  count + 1 == h.count,
8546
8549
  "Re-adding a removed item in hash should increase count by 1 (%zu + "
8547
8550
  "1 != %zu).",
8548
8551
  count, (size_t)s.count);
8549
- tmp = *fio_set_test_find(&s, tmp, tmp);
8552
+ tmp = fio_set_test_find(&s, tmp, tmp);
8550
8553
  FIO_ASSERT(tmp == 1,
8551
8554
  "Re-adding a removed item should update the item in the set "
8552
8555
  "(%lu != 1)!",
8553
- (unsigned long)*fio_set_test_find(&s, tmp, tmp));
8554
- fio_set_test_remove(&s, tmp, tmp);
8555
- fio_hash_test_remove(&h, tmp, tmp);
8556
+ (unsigned long)fio_set_test_find(&s, tmp, tmp));
8557
+ fio_set_test_remove(&s, tmp, tmp, NULL);
8558
+ fio_hash_test_remove(&h, tmp, tmp, NULL);
8556
8559
  FIO_ASSERT(count == h.count,
8557
8560
  "Re-removing an item should decrease count (%zu != %zu).",
8558
8561
  count, (size_t)s.count);
@@ -8589,14 +8592,13 @@ FIO_FUNC void fio_set_test(void) {
8589
8592
  fio_set_test_insert(&s, i, i);
8590
8593
  FIO_ASSERT(fio_set_test_find(&s, i, i),
8591
8594
  "find failed after insert (2nd round)");
8592
- FIO_ASSERT(i == *fio_set_test_find(&s, i, i),
8595
+ FIO_ASSERT(i == fio_set_test_find(&s, i, i),
8593
8596
  "insertion (2nd round) != find");
8594
8597
  FIO_ASSERT(i == s.count, "count error (%lu != %lu) post insertion.", i,
8595
8598
  s.count);
8596
8599
  }
8597
8600
  fio_set_test_free(&s);
8598
8601
  }
8599
- #undef FIO_SET_NAME
8600
8602
 
8601
8603
  /* *****************************************************************************
8602
8604
  SipHash tests
@@ -402,10 +402,8 @@ extern size_t FIO_LOG_LEVEL;
402
402
  /** Tests for an allocation failure. The behavior can be overridden. */
403
403
  #define FIO_ASSERT_ALLOC(ptr) \
404
404
  if (!(ptr)) { \
405
- fprintf(stderr, \
406
- "FATAL ERROR: memory allocation error "__FILE__ \
407
- ":%d\n", \
408
- __LINE__); \
405
+ fprintf(stderr, "\nFATAL ERROR: memory allocation error "__FILE__ \
406
+ ":" FIO_MACRO2STR(__LINE__) "\n"); \
409
407
  perror(" Error details (errno)"); \
410
408
  kill(0, SIGINT); \
411
409
  exit(errno); \
@@ -2738,11 +2736,11 @@ FIO_FUNC inline int fio_ls_embd_any(fio_ls_embd_s *list);
2738
2736
  Independent Linked List API
2739
2737
  ***************************************************************************** */
2740
2738
 
2741
- /** Adds an object to the list's head. */
2742
- FIO_FUNC inline void fio_ls_push(fio_ls_s *pos, const void *obj);
2739
+ /** Adds an object to the list's head, returnin's the object's location. */
2740
+ FIO_FUNC inline fio_ls_s *fio_ls_push(fio_ls_s *pos, const void *obj);
2743
2741
 
2744
- /** Adds an object to the list's tail. */
2745
- FIO_FUNC inline void fio_ls_unshift(fio_ls_s *pos, const void *obj);
2742
+ /** Adds an object to the list's tail, returnin's the object's location. */
2743
+ FIO_FUNC inline fio_ls_s *fio_ls_unshift(fio_ls_s *pos, const void *obj);
2746
2744
 
2747
2745
  /** Removes an object from the list's head. */
2748
2746
  FIO_FUNC inline void *fio_ls_pop(fio_ls_s *list);
@@ -2848,7 +2846,7 @@ FIO_FUNC inline void *fio_ls_remove(fio_ls_s *node) {
2848
2846
  }
2849
2847
 
2850
2848
  /** Adds an object to the list's head. */
2851
- FIO_FUNC inline void fio_ls_push(fio_ls_s *pos, const void *obj) {
2849
+ FIO_FUNC inline fio_ls_s *fio_ls_push(fio_ls_s *pos, const void *obj) {
2852
2850
  /* prepare item */
2853
2851
  fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
2854
2852
  if (!item) {
@@ -2859,11 +2857,12 @@ FIO_FUNC inline void fio_ls_push(fio_ls_s *pos, const void *obj) {
2859
2857
  /* inject item */
2860
2858
  pos->prev->next = item;
2861
2859
  pos->prev = item;
2860
+ return item;
2862
2861
  }
2863
2862
 
2864
2863
  /** Adds an object to the list's tail. */
2865
- FIO_FUNC inline void fio_ls_unshift(fio_ls_s *pos, const void *obj) {
2866
- fio_ls_push(pos->next, obj);
2864
+ FIO_FUNC inline fio_ls_s *fio_ls_unshift(fio_ls_s *pos, const void *obj) {
2865
+ return fio_ls_push(pos->next, obj);
2867
2866
  }
2868
2867
 
2869
2868
  /** Removes an object from the list's head. */
@@ -4207,9 +4206,9 @@ inline FIO_FUNC ssize_t fio_str_send_free2(const intptr_t uuid,
4207
4206
  typedef struct {
4208
4207
  FIO_SET_KEY_TYPE key;
4209
4208
  FIO_SET_OBJ_TYPE obj;
4210
- } FIO_NAME(_couplet_s);
4209
+ } FIO_NAME(couplet_s);
4211
4210
 
4212
- #define FIO_SET_TYPE FIO_NAME(_couplet_s)
4211
+ #define FIO_SET_TYPE FIO_NAME(couplet_s)
4213
4212
 
4214
4213
  /** key copy required? */
4215
4214
  #ifndef FIO_SET_KEY_COPY
@@ -4270,26 +4269,10 @@ FIO_FUNC void FIO_NAME(free)(FIO_NAME(s) * set);
4270
4269
  *
4271
4270
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4272
4271
  */
4273
- FIO_FUNC inline FIO_SET_OBJ_TYPE *
4272
+ FIO_FUNC inline FIO_SET_OBJ_TYPE
4274
4273
  FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4275
4274
  FIO_SET_KEY_TYPE key);
4276
4275
 
4277
- /**
4278
- * Inserts an object to the Hash Map, rehashing if required, returning the new
4279
- * object's location using a pointer.
4280
- *
4281
- * If an object already exists in the Hash Map with the same key, it will be
4282
- * destroyed.
4283
- *
4284
- * NOTE 1: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4285
- *
4286
- * NOTE 2: This is equivelant to calling the `insert2` with `old` set to NULL.
4287
- */
4288
- FIO_FUNC inline void FIO_NAME(insert)(FIO_NAME(s) * set,
4289
- const FIO_SET_HASH_TYPE hash_value,
4290
- FIO_SET_KEY_TYPE key,
4291
- FIO_SET_OBJ_TYPE obj);
4292
-
4293
4276
  /**
4294
4277
  * Inserts an object to the Hash Map, rehashing if required, returning the new
4295
4278
  * object's location using a pointer.
@@ -4301,22 +4284,11 @@ FIO_FUNC inline void FIO_NAME(insert)(FIO_NAME(s) * set,
4301
4284
  *
4302
4285
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4303
4286
  */
4304
- FIO_FUNC inline void FIO_NAME(insert2)(FIO_NAME(s) * set,
4305
- const FIO_SET_HASH_TYPE hash_value,
4306
- FIO_SET_KEY_TYPE key,
4307
- FIO_SET_OBJ_TYPE obj,
4308
- FIO_SET_OBJ_TYPE *old);
4309
-
4310
- /**
4311
- * Removes an object from the Hash Map, rehashing if required.
4312
- *
4313
- * Returns 0 on success and -1 if the object wasn't found.
4314
- *
4315
- * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4316
- */
4317
- FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4318
- const FIO_SET_HASH_TYPE hash_value,
4319
- FIO_SET_KEY_TYPE key);
4287
+ FIO_FUNC inline void FIO_NAME(insert)(FIO_NAME(s) * set,
4288
+ const FIO_SET_HASH_TYPE hash_value,
4289
+ FIO_SET_KEY_TYPE key,
4290
+ FIO_SET_OBJ_TYPE obj,
4291
+ FIO_SET_OBJ_TYPE *old);
4320
4292
 
4321
4293
  /**
4322
4294
  * Removes an object from the Hash Map, rehashing if required.
@@ -4328,10 +4300,10 @@ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4328
4300
  *
4329
4301
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4330
4302
  */
4331
- FIO_FUNC inline int FIO_NAME(remove2)(FIO_NAME(s) * set,
4332
- const FIO_SET_HASH_TYPE hash_value,
4333
- FIO_SET_KEY_TYPE key,
4334
- FIO_SET_OBJ_TYPE *old);
4303
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4304
+ const FIO_SET_HASH_TYPE hash_value,
4305
+ FIO_SET_KEY_TYPE key,
4306
+ FIO_SET_OBJ_TYPE *old);
4335
4307
 
4336
4308
  #else
4337
4309
 
@@ -4340,47 +4312,35 @@ FIO_FUNC inline int FIO_NAME(remove2)(FIO_NAME(s) * set,
4340
4312
  *
4341
4313
  * NOTE: This is the function's pure Set variant (no FIO_SET_KEY_TYPE).
4342
4314
  */
4343
- FIO_FUNC inline FIO_SET_OBJ_TYPE *
4315
+ FIO_FUNC inline FIO_SET_OBJ_TYPE
4344
4316
  FIO_NAME(find)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4345
4317
  FIO_SET_OBJ_TYPE obj);
4346
4318
 
4347
4319
  /**
4348
4320
  * Inserts an object to the Set only if it's missing, rehashing if required,
4349
- * returning the new (or old) object's pointer.
4350
- *
4321
+ * returning the new (or old) object.
4351
4322
  *
4352
4323
  * If the object already exists in the set, than the new object will be
4353
- * destroyed and the old object's address will be returned.
4324
+ * destroyed and the old object will be returned.
4354
4325
  *
4355
4326
  * NOTE: This is the function's pure Set variant (no FIO_SET_KEY_TYPE).
4356
4327
  */
4357
- FIO_FUNC inline FIO_SET_OBJ_TYPE *
4328
+ FIO_FUNC inline FIO_SET_OBJ_TYPE
4358
4329
  FIO_NAME(insert)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4359
4330
  FIO_SET_OBJ_TYPE obj);
4360
4331
 
4361
4332
  /**
4362
4333
  * Inserts an object to the Set, rehashing if required, returning the new
4363
- * object's pointer.
4334
+ * object.
4364
4335
  *
4365
4336
  * If the object already exists in the set, it will be destroyed and
4366
4337
  * overwritten.
4367
4338
  *
4368
- * NOTE: This function doesn't exist when FIO_SET_KEY_TYPE is defined.
4369
- */
4370
- FIO_FUNC inline FIO_SET_OBJ_TYPE *
4371
- FIO_NAME(overwrite)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4372
- FIO_SET_OBJ_TYPE obj);
4373
-
4374
- /**
4375
- * The same as `overwrite`, only it copies the old object (if any) to the
4376
- * location pointed to by `old`.
4377
- *
4378
4339
  * When setting `old` to NULL, the function behaves the same as `overwrite`.
4379
4340
  */
4380
- FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(replace)(FIO_NAME(s) * set,
4381
- const FIO_SET_HASH_TYPE hash_value,
4382
- FIO_SET_OBJ_TYPE obj,
4383
- FIO_SET_OBJ_TYPE *old);
4341
+ FIO_FUNC FIO_SET_OBJ_TYPE
4342
+ FIO_NAME(overwrite)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4343
+ FIO_SET_OBJ_TYPE obj, FIO_SET_OBJ_TYPE *old);
4384
4344
 
4385
4345
  /**
4386
4346
  * Removes an object from the Set, rehashing if required.
@@ -4391,7 +4351,8 @@ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(replace)(FIO_NAME(s) * set,
4391
4351
  */
4392
4352
  FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4393
4353
  const FIO_SET_HASH_TYPE hash_value,
4394
- FIO_SET_OBJ_TYPE obj);
4354
+ FIO_SET_OBJ_TYPE obj,
4355
+ FIO_SET_OBJ_TYPE *old);
4395
4356
 
4396
4357
  #endif
4397
4358
  /**
@@ -4400,7 +4361,7 @@ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4400
4361
  * Remember that objects might be destroyed if the Set is altered
4401
4362
  * (`FIO_SET_OBJ_DESTROY` / `FIO_SET_KEY_DESTROY`).
4402
4363
  */
4403
- FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(last)(FIO_NAME(s) * set);
4364
+ FIO_FUNC inline FIO_SET_TYPE FIO_NAME(last)(FIO_NAME(s) * set);
4404
4365
 
4405
4366
  /**
4406
4367
  * Allows the Hash to be momentarily used as a stack, destroying the last
@@ -4579,11 +4540,14 @@ FIO_FUNC inline void FIO_NAME(_reallocate_set_mem_)(FIO_NAME(s) * set) {
4579
4540
  * If the object already exists in the set, it will be destroyed and
4580
4541
  * overwritten.
4581
4542
  */
4582
- FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(_insert_or_overwrite_)(
4543
+ FIO_FUNC inline FIO_SET_TYPE FIO_NAME(_insert_or_overwrite_)(
4583
4544
  FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value, FIO_SET_TYPE obj,
4584
4545
  int overwrite, FIO_SET_OBJ_TYPE *old) {
4585
- if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID))
4586
- return NULL;
4546
+ if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID)) {
4547
+ FIO_SET_TYPE empty;
4548
+ memset(&empty, 0, sizeof(empty));
4549
+ return empty;
4550
+ }
4587
4551
 
4588
4552
  /* automatic fragmentation protection */
4589
4553
  if (FIO_NAME(is_fragmented)(set))
@@ -4603,7 +4567,7 @@ FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(_insert_or_overwrite_)(
4603
4567
  /* overwrite existing object */
4604
4568
  if (!overwrite) {
4605
4569
  FIO_SET_DESTROY(obj);
4606
- return &pos->pos->obj;
4570
+ return pos->pos->obj;
4607
4571
  }
4608
4572
  #ifdef FIO_SET_KEY_TYPE
4609
4573
  if (old) {
@@ -4612,7 +4576,7 @@ FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(_insert_or_overwrite_)(
4612
4576
  /* no need to recreate the key object, just the value object */
4613
4577
  FIO_SET_OBJ_DESTROY(pos->pos->obj.obj);
4614
4578
  FIO_SET_OBJ_COPY(pos->pos->obj.obj, obj.obj);
4615
- return &pos->pos->obj;
4579
+ return pos->pos->obj;
4616
4580
  #else
4617
4581
  if (old) {
4618
4582
  FIO_SET_COPY((*old), pos->pos->obj);
@@ -4630,7 +4594,7 @@ FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(_insert_or_overwrite_)(
4630
4594
  pos->pos->hash = hash_value;
4631
4595
  FIO_SET_COPY(pos->pos->obj, obj);
4632
4596
 
4633
- return &pos->pos->obj;
4597
+ return pos->pos->obj;
4634
4598
  }
4635
4599
 
4636
4600
  /* *****************************************************************************
@@ -4661,29 +4625,17 @@ FIO_FUNC void FIO_NAME(free)(FIO_NAME(s) * s) {
4661
4625
  *
4662
4626
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4663
4627
  */
4664
- FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(find)(FIO_NAME(s) * set,
4665
- const FIO_SET_HASH_TYPE hash_value,
4666
- FIO_SET_KEY_TYPE key) {
4628
+ FIO_FUNC FIO_SET_OBJ_TYPE FIO_NAME(find)(FIO_NAME(s) * set,
4629
+ const FIO_SET_HASH_TYPE hash_value,
4630
+ FIO_SET_KEY_TYPE key) {
4667
4631
  FIO_NAME(_map_s_) *pos =
4668
4632
  FIO_NAME(_find_map_pos_)(set, hash_value, (FIO_SET_TYPE){.key = key});
4669
- if (!pos || !pos->pos)
4670
- return NULL;
4671
- return &pos->pos->obj.obj;
4672
- }
4673
-
4674
- /**
4675
- * Inserts an object to the Hash Map, rehashing if required, returning the new
4676
- * object's location using a pointer.
4677
- *
4678
- * If the object already exists in the set, it will be destroyed.
4679
- *
4680
- * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4681
- */
4682
- FIO_FUNC void FIO_NAME(insert)(FIO_NAME(s) * set,
4683
- const FIO_SET_HASH_TYPE hash_value,
4684
- FIO_SET_KEY_TYPE key, FIO_SET_OBJ_TYPE obj) {
4685
- FIO_NAME(_insert_or_overwrite_)
4686
- (set, hash_value, (FIO_SET_TYPE){.key = key, .obj = obj}, 1, NULL);
4633
+ if (!pos || !pos->pos) {
4634
+ FIO_SET_OBJ_TYPE empty;
4635
+ memset(&empty, 0, sizeof(empty));
4636
+ return empty;
4637
+ }
4638
+ return pos->pos->obj.obj;
4687
4639
  }
4688
4640
 
4689
4641
  /**
@@ -4697,10 +4649,10 @@ FIO_FUNC void FIO_NAME(insert)(FIO_NAME(s) * set,
4697
4649
  *
4698
4650
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4699
4651
  */
4700
- FIO_FUNC void FIO_NAME(insert2)(FIO_NAME(s) * set,
4701
- const FIO_SET_HASH_TYPE hash_value,
4702
- FIO_SET_KEY_TYPE key, FIO_SET_OBJ_TYPE obj,
4703
- FIO_SET_OBJ_TYPE *old) {
4652
+ FIO_FUNC void FIO_NAME(insert)(FIO_NAME(s) * set,
4653
+ const FIO_SET_HASH_TYPE hash_value,
4654
+ FIO_SET_KEY_TYPE key, FIO_SET_OBJ_TYPE obj,
4655
+ FIO_SET_OBJ_TYPE *old) {
4704
4656
  FIO_NAME(_insert_or_overwrite_)
4705
4657
  (set, hash_value, (FIO_SET_TYPE){.key = key, .obj = obj}, 1, old);
4706
4658
  }
@@ -4715,10 +4667,10 @@ FIO_FUNC void FIO_NAME(insert2)(FIO_NAME(s) * set,
4715
4667
  *
4716
4668
  * NOTE: This is the function's Hash Map variant. See FIO_SET_KEY_TYPE.
4717
4669
  */
4718
- FIO_FUNC inline int FIO_NAME(remove2)(FIO_NAME(s) * set,
4719
- const FIO_SET_HASH_TYPE hash_value,
4720
- FIO_SET_KEY_TYPE key,
4721
- FIO_SET_OBJ_TYPE *old) {
4670
+ FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4671
+ const FIO_SET_HASH_TYPE hash_value,
4672
+ FIO_SET_KEY_TYPE key,
4673
+ FIO_SET_OBJ_TYPE *old) {
4722
4674
  if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID))
4723
4675
  return -1;
4724
4676
  FIO_NAME(_map_s_) *pos =
@@ -4740,22 +4692,19 @@ FIO_FUNC inline int FIO_NAME(remove2)(FIO_NAME(s) * set,
4740
4692
  return 0;
4741
4693
  }
4742
4694
 
4743
- FIO_FUNC inline int FIO_NAME(remove)(FIO_NAME(s) * set,
4744
- const FIO_SET_HASH_TYPE hash_value,
4745
- FIO_SET_KEY_TYPE key) {
4746
- return FIO_NAME(remove2)(set, hash_value, key, NULL);
4747
- }
4748
-
4749
4695
  #else
4750
4696
 
4751
4697
  /** Locates an object in the Set, if it exists. */
4752
- FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(find)(FIO_NAME(s) * set,
4753
- const FIO_SET_HASH_TYPE hash_value,
4754
- FIO_SET_OBJ_TYPE obj) {
4698
+ FIO_FUNC FIO_SET_OBJ_TYPE FIO_NAME(find)(FIO_NAME(s) * set,
4699
+ const FIO_SET_HASH_TYPE hash_value,
4700
+ FIO_SET_OBJ_TYPE obj) {
4755
4701
  FIO_NAME(_map_s_) *pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4756
- if (!pos || !pos->pos)
4757
- return NULL;
4758
- return &pos->pos->obj;
4702
+ if (!pos || !pos->pos) {
4703
+ FIO_SET_OBJ_TYPE empty;
4704
+ memset(&empty, 0, sizeof(empty));
4705
+ return empty;
4706
+ }
4707
+ return pos->pos->obj;
4759
4708
  }
4760
4709
 
4761
4710
  /**
@@ -4765,9 +4714,9 @@ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(find)(FIO_NAME(s) * set,
4765
4714
  * If the object already exists in the set, than the new object will be
4766
4715
  * destroyed and the old object's address will be returned.
4767
4716
  */
4768
- FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(insert)(FIO_NAME(s) * set,
4769
- const FIO_SET_HASH_TYPE hash_value,
4770
- FIO_SET_OBJ_TYPE obj) {
4717
+ FIO_FUNC FIO_SET_OBJ_TYPE FIO_NAME(insert)(FIO_NAME(s) * set,
4718
+ const FIO_SET_HASH_TYPE hash_value,
4719
+ FIO_SET_OBJ_TYPE obj) {
4771
4720
  return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 0, NULL);
4772
4721
  }
4773
4722
 
@@ -4777,23 +4726,12 @@ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(insert)(FIO_NAME(s) * set,
4777
4726
  *
4778
4727
  * If the object already exists in the set, it will be destroyed and
4779
4728
  * overwritten.
4780
- */
4781
- FIO_FUNC FIO_SET_OBJ_TYPE *
4782
- FIO_NAME(overwrite)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4783
- FIO_SET_OBJ_TYPE obj) {
4784
- return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 1, NULL);
4785
- }
4786
-
4787
- /**
4788
- * The same as `overwrite`, only it copies the old object (if any) to the
4789
- * location pointed to by `old`.
4790
4729
  *
4791
4730
  * When setting `old` to NULL, the function behaves the same as `overwrite`.
4792
4731
  */
4793
- FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(replace)(FIO_NAME(s) * set,
4794
- const FIO_SET_HASH_TYPE hash_value,
4795
- FIO_SET_OBJ_TYPE obj,
4796
- FIO_SET_OBJ_TYPE *old) {
4732
+ FIO_FUNC FIO_SET_OBJ_TYPE
4733
+ FIO_NAME(overwrite)(FIO_NAME(s) * set, const FIO_SET_HASH_TYPE hash_value,
4734
+ FIO_SET_OBJ_TYPE obj, FIO_SET_OBJ_TYPE *old) {
4797
4735
  return FIO_NAME(_insert_or_overwrite_)(set, hash_value, obj, 1, old);
4798
4736
  }
4799
4737
 
@@ -4802,12 +4740,14 @@ FIO_FUNC FIO_SET_OBJ_TYPE *FIO_NAME(replace)(FIO_NAME(s) * set,
4802
4740
  */
4803
4741
  FIO_FUNC int FIO_NAME(remove)(FIO_NAME(s) * set,
4804
4742
  const FIO_SET_HASH_TYPE hash_value,
4805
- FIO_SET_OBJ_TYPE obj) {
4743
+ FIO_SET_OBJ_TYPE obj, FIO_SET_OBJ_TYPE *old) {
4806
4744
  if (FIO_SET_HASH_COMPARE(hash_value, FIO_SET_HASH_INVALID))
4807
4745
  return -1;
4808
4746
  FIO_NAME(_map_s_) *pos = FIO_NAME(_find_map_pos_)(set, hash_value, obj);
4809
4747
  if (!pos || !pos->pos)
4810
4748
  return -1;
4749
+ if (old)
4750
+ FIO_SET_COPY((*old), pos->pos->obj);
4811
4751
  FIO_SET_DESTROY(pos->pos->obj);
4812
4752
  --set->count;
4813
4753
  pos->pos->hash = FIO_SET_HASH_INVALID;
@@ -4829,10 +4769,13 @@ FIO_FUNC int FIO_NAME(remove)(FIO_NAME(s) * set,
4829
4769
  * Remember that objects might be destroyed if the Set is altered
4830
4770
  * (`FIO_SET_OBJ_DESTROY` / `FIO_SET_KEY_DESTROY`).
4831
4771
  */
4832
- FIO_FUNC inline FIO_SET_TYPE *FIO_NAME(last)(FIO_NAME(s) * set) {
4833
- if (!set->ordered || !set->pos)
4834
- return NULL;
4835
- return &set->ordered[set->pos - 1].obj;
4772
+ FIO_FUNC inline FIO_SET_TYPE FIO_NAME(last)(FIO_NAME(s) * set) {
4773
+ if (!set->ordered || !set->pos) {
4774
+ FIO_SET_TYPE empty;
4775
+ memset(&empty, 0, sizeof(empty));
4776
+ return empty;
4777
+ }
4778
+ return set->ordered[set->pos - 1].obj;
4836
4779
  }
4837
4780
 
4838
4781
  /**