diff options
| author | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-01-20 10:51:11 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-01-20 10:51:11 +0100 |
| commit | cf9b09ff352611fb8cee3679127f3655cbe73ae7 (patch) | |
| tree | 011ae091b0bff2d10a9e8dd0fd564ab2b6365f86 /src | |
| parent | 1843a0add00186eee129b0b0a2ee605866acbb61 (diff) | |
| download | lanes-cf9b09ff352611fb8cee3679127f3655cbe73ae7.tar.gz lanes-cf9b09ff352611fb8cee3679127f3655cbe73ae7.tar.bz2 lanes-cf9b09ff352611fb8cee3679127f3655cbe73ae7.zip | |
get()/set() improvements
* bumped version to 3.8.0
* linda:set() accepts multiple values to set in the specified slot
* linda:get() accepts an optional count to peek several values at once
* nil values are now converted just as in send()/receive()
Diffstat (limited to 'src')
| -rw-r--r-- | src/keeper.c | 102 | ||||
| -rw-r--r-- | src/keeper.h | 2 | ||||
| -rw-r--r-- | src/lanes.c | 44 | ||||
| -rw-r--r-- | src/lanes.lua | 2 |
4 files changed, 80 insertions, 70 deletions
diff --git a/src/keeper.c b/src/keeper.c index 6d5ecbf..b0db8b4 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
| @@ -115,11 +115,11 @@ static void fifo_push( lua_State* L, keeper_fifo* fifo, int _count) | |||
| 115 | // expects exactly 1 value on the stack! | 115 | // expects exactly 1 value on the stack! |
| 116 | // currently only called with a count of 1, but this may change in the future | 116 | // currently only called with a count of 1, but this may change in the future |
| 117 | // function assumes that there is enough data in the fifo to satisfy the request | 117 | // function assumes that there is enough data in the fifo to satisfy the request |
| 118 | static void fifo_peek( lua_State* L, keeper_fifo* fifo, int _count) | 118 | static void fifo_peek( lua_State* L, keeper_fifo* fifo, int count_) |
| 119 | { | 119 | { |
| 120 | int i; | 120 | int i; |
| 121 | STACK_GROW( L, _count); | 121 | STACK_GROW( L, count_); |
| 122 | for( i = 0; i < _count; ++ i) | 122 | for( i = 0; i < count_; ++ i) |
| 123 | { | 123 | { |
| 124 | lua_rawgeti( L, 1, fifo->first + i); | 124 | lua_rawgeti( L, 1, fifo->first + i); |
| 125 | } | 125 | } |
| @@ -384,54 +384,21 @@ int keepercall_limit( lua_State* L) | |||
| 384 | return lua_gettop( L); | 384 | return lua_gettop( L); |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | //in: linda_ud key [val] | 387 | //in: linda_ud key [[val] ...] |
| 388 | //out: true or nil | 388 | //out: true or nil |
| 389 | int keepercall_set( lua_State* L) | 389 | int keepercall_set( lua_State* L) |
| 390 | { | 390 | { |
| 391 | bool_t should_wake_writers = FALSE; | 391 | bool_t should_wake_writers = FALSE; |
| 392 | STACK_GROW( L, 6); | 392 | STACK_GROW( L, 6); |
| 393 | // make sure we have a value on the stack | ||
| 394 | if( lua_gettop( L) == 2) // ud key val? | ||
| 395 | { | ||
| 396 | lua_pushnil( L); // ud key nil | ||
| 397 | } | ||
| 398 | 393 | ||
| 399 | // retrieve fifos associated with the linda | 394 | // retrieve fifos associated with the linda |
| 400 | push_table( L, 1); // ud key val fifos | 395 | push_table( L, 1); // ud key [val [, ...]] fifos |
| 401 | lua_replace( L, 1); // fifos key val | 396 | lua_replace( L, 1); // fifos key [val [, ...]] |
| 402 | 397 | ||
| 403 | if( !lua_isnil( L, 3)) // set/replace contents stored at the specified key? | 398 | // make sure we have a value on the stack |
| 399 | if( lua_gettop( L) == 2) // fifos key | ||
| 404 | { | 400 | { |
| 405 | keeper_fifo* fifo; | 401 | keeper_fifo* fifo; |
| 406 | lua_pushvalue( L, -2); // fifos key val key | ||
| 407 | lua_rawget( L, 1); // fifos key val fifo|nil | ||
| 408 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | ||
| 409 | if( fifo == NULL) // can be NULL if we store a value at a new key | ||
| 410 | { // fifos key val nil | ||
| 411 | lua_pop( L, 1); // fifos key val | ||
| 412 | fifo_new( L); // fifos key val fifo | ||
| 413 | lua_pushvalue( L, 2); // fifos key val fifo key | ||
| 414 | lua_pushvalue( L, -2); // fifos key val fifo key fifo | ||
| 415 | lua_rawset( L, 1); // fifos key val fifo | ||
| 416 | } | ||
| 417 | else // the fifo exists, we just want to update its contents | ||
| 418 | { // fifos key val fifo | ||
| 419 | // we create room if the fifo was full but it is no longer the case | ||
| 420 | should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit); | ||
| 421 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | ||
| 422 | lua_newtable( L); // fifos key val fifo {} | ||
| 423 | lua_setuservalue( L, -2); // fifos key val fifo | ||
| 424 | fifo->first = 1; | ||
| 425 | fifo->count = 0; | ||
| 426 | } | ||
| 427 | fifo = prepare_fifo_access( L, -1); | ||
| 428 | lua_insert( L, -2); // fifos key fifo val | ||
| 429 | fifo_push( L, fifo, 1); // fifos key fifo | ||
| 430 | } | ||
| 431 | else // val == nil: we clear the key contents | ||
| 432 | { // fifos key nil | ||
| 433 | keeper_fifo* fifo; | ||
| 434 | lua_pop( L, 1); // fifos key | ||
| 435 | lua_pushvalue( L, -1); // fifos key key | 402 | lua_pushvalue( L, -1); // fifos key key |
| 436 | lua_rawget( L, 1); // fifos key fifo|nil | 403 | lua_rawget( L, 1); // fifos key fifo|nil |
| 437 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | 404 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! |
| @@ -456,13 +423,51 @@ int keepercall_set( lua_State* L) | |||
| 456 | } | 423 | } |
| 457 | } | 424 | } |
| 458 | } | 425 | } |
| 426 | else // set/replace contents stored at the specified key? | ||
| 427 | { | ||
| 428 | int count = lua_gettop( L) - 2; // number of items we want to store | ||
| 429 | keeper_fifo* fifo; // fifos key [val [, ...]] | ||
| 430 | lua_pushvalue( L, 2); // fifos key [val [, ...]] key | ||
| 431 | lua_rawget( L, 1); // fifos key [val [, ...]] fifo|nil | ||
| 432 | fifo = (keeper_fifo*) lua_touserdata( L, -1); | ||
| 433 | if( fifo == NULL) // can be NULL if we store a value at a new key | ||
| 434 | { // fifos key [val [, ...]] nil | ||
| 435 | // no need to wake writers in that case, because a writer can't wait on an inexistent key | ||
| 436 | lua_pop( L, 1); // fifos key [val [, ...]] | ||
| 437 | fifo_new( L); // fifos key [val [, ...]] fifo | ||
| 438 | lua_pushvalue( L, 2); // fifos key [val [, ...]] fifo key | ||
| 439 | lua_pushvalue( L, -2); // fifos key [val [, ...]] fifo key fifo | ||
| 440 | lua_rawset( L, 1); // fifos key [val [, ...]] fifo | ||
| 441 | } | ||
| 442 | else // the fifo exists, we just want to update its contents | ||
| 443 | { // fifos key [val [, ...]] fifo | ||
| 444 | // we create room if the fifo was full but it is no longer the case | ||
| 445 | should_wake_writers = (fifo->limit > 0) && (fifo->count >= fifo->limit) && (count < fifo->limit); | ||
| 446 | // empty the fifo for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! | ||
| 447 | lua_newtable( L); // fifos key [val [, ...]] fifo {} | ||
| 448 | lua_setuservalue( L, -2); // fifos key [val [, ...]] fifo | ||
| 449 | fifo->first = 1; | ||
| 450 | fifo->count = 0; | ||
| 451 | } | ||
| 452 | fifo = prepare_fifo_access( L, -1); | ||
| 453 | // move the fifo below the values we want to store | ||
| 454 | lua_insert( L, 3); // fifos key fifo [val [, ...]] | ||
| 455 | fifo_push( L, fifo, count); // fifos key fifo | ||
| 456 | } | ||
| 459 | return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0; | 457 | return should_wake_writers ? (lua_pushboolean( L, 1), 1) : 0; |
| 460 | } | 458 | } |
| 461 | 459 | ||
| 462 | // in: linda_ud key | 460 | // in: linda_ud key [count] |
| 461 | // out: at most <count> values | ||
| 463 | int keepercall_get( lua_State* L) | 462 | int keepercall_get( lua_State* L) |
| 464 | { | 463 | { |
| 465 | keeper_fifo* fifo; | 464 | keeper_fifo* fifo; |
| 465 | int count = 1; | ||
| 466 | if( lua_gettop( L) == 3) // ud key count | ||
| 467 | { | ||
| 468 | count = lua_tointeger( L, 3); | ||
| 469 | lua_pop( L, 1); // ud key | ||
| 470 | } | ||
| 466 | push_table( L, 1); // ud key fifos | 471 | push_table( L, 1); // ud key fifos |
| 467 | lua_replace( L, 1); // fifos key | 472 | lua_replace( L, 1); // fifos key |
| 468 | lua_rawget( L, 1); // fifos fifo | 473 | lua_rawget( L, 1); // fifos fifo |
| @@ -470,9 +475,10 @@ int keepercall_get( lua_State* L) | |||
| 470 | if( fifo != NULL && fifo->count > 0) | 475 | if( fifo != NULL && fifo->count > 0) |
| 471 | { | 476 | { |
| 472 | lua_remove( L, 1); // fifo | 477 | lua_remove( L, 1); // fifo |
| 473 | // read one value off the fifo | 478 | count = __min( count, fifo->count); |
| 474 | fifo_peek( L, fifo, 1); // fifo ... | 479 | // read <count> value off the fifo |
| 475 | return 1; | 480 | fifo_peek( L, fifo, count); // fifo ... |
| 481 | return count; | ||
| 476 | } | 482 | } |
| 477 | // no fifo was ever registered for this key, or it is empty | 483 | // no fifo was ever registered for this key, or it is empty |
| 478 | return 0; | 484 | return 0; |
| @@ -682,16 +688,16 @@ void keeper_release( struct s_Keeper* K) | |||
| 682 | if( K) MUTEX_UNLOCK( &K->lock_); | 688 | if( K) MUTEX_UNLOCK( &K->lock_); |
| 683 | } | 689 | } |
| 684 | 690 | ||
| 685 | void keeper_toggle_nil_sentinels( lua_State* L, int _val_i, int _nil_to_sentinel) | 691 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, enum eLookupMode mode_) |
| 686 | { | 692 | { |
| 687 | int i, n = lua_gettop( L); | 693 | int i, n = lua_gettop( L); |
| 688 | /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe | 694 | /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe |
| 689 | * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global of ours) | 695 | * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global of ours) |
| 690 | */ | 696 | */ |
| 691 | void* nil_sentinel = &GNbKeepers; | 697 | void* nil_sentinel = &GNbKeepers; |
| 692 | for( i = _val_i; i <= n; ++ i) | 698 | for( i = val_i_; i <= n; ++ i) |
| 693 | { | 699 | { |
| 694 | if( _nil_to_sentinel) | 700 | if( mode_ == eLM_ToKeeper) |
| 695 | { | 701 | { |
| 696 | if( lua_isnil( L, i)) | 702 | if( lua_isnil( L, i)) |
| 697 | { | 703 | { |
diff --git a/src/keeper.h b/src/keeper.h index 2ef443d..c0fd5d0 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
| @@ -20,7 +20,7 @@ void close_keepers( void); | |||
| 20 | 20 | ||
| 21 | struct s_Keeper *keeper_acquire( const void *ptr); | 21 | struct s_Keeper *keeper_acquire( const void *ptr); |
| 22 | void keeper_release( struct s_Keeper *K); | 22 | void keeper_release( struct s_Keeper *K); |
| 23 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); | 23 | void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, enum eLookupMode const mode_); |
| 24 | int keeper_push_linda_storage( lua_State* L, void* ptr); | 24 | int keeper_push_linda_storage( lua_State* L, void* ptr); |
| 25 | 25 | ||
| 26 | typedef lua_CFunction keeper_api_t; | 26 | typedef lua_CFunction keeper_api_t; |
diff --git a/src/lanes.c b/src/lanes.c index cad8fb1..f62c39f 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -52,7 +52,7 @@ | |||
| 52 | * ... | 52 | * ... |
| 53 | */ | 53 | */ |
| 54 | 54 | ||
| 55 | char const* VERSION = "3.7.8"; | 55 | char const* VERSION = "3.8.0"; |
| 56 | 56 | ||
| 57 | /* | 57 | /* |
| 58 | =============================================================================== | 58 | =============================================================================== |
| @@ -464,7 +464,7 @@ LUAG_FUNC( linda_send) | |||
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | // convert nils to some special non-nil sentinel in sent values | 466 | // convert nils to some special non-nil sentinel in sent values |
| 467 | keeper_toggle_nil_sentinels( L, key_i + 1, 1); | 467 | keeper_toggle_nil_sentinels( L, key_i + 1, eLM_ToKeeper); |
| 468 | 468 | ||
| 469 | STACK_GROW( L, 1); | 469 | STACK_GROW( L, 1); |
| 470 | { | 470 | { |
| @@ -649,7 +649,7 @@ LUAG_FUNC( linda_receive) | |||
| 649 | { | 649 | { |
| 650 | ASSERT_L( pushed >= expected_pushed_min && pushed <= expected_pushed_max); | 650 | ASSERT_L( pushed >= expected_pushed_min && pushed <= expected_pushed_max); |
| 651 | // replace sentinels with real nils | 651 | // replace sentinels with real nils |
| 652 | keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); | 652 | keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper); |
| 653 | // To be done from within the 'K' locking area | 653 | // To be done from within the 'K' locking area |
| 654 | // | 654 | // |
| 655 | SIGNAL_ALL( &linda->read_happened); | 655 | SIGNAL_ALL( &linda->read_happened); |
| @@ -725,28 +725,31 @@ LUAG_FUNC( linda_receive) | |||
| 725 | 725 | ||
| 726 | 726 | ||
| 727 | /* | 727 | /* |
| 728 | * [true] = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] ) | 728 | * [true] = linda_set( linda_ud, key_num|str|bool|lightuserdata [, value [, ...]]) |
| 729 | * | 729 | * |
| 730 | * Set a value to Linda. | 730 | * Set one or more value to Linda. |
| 731 | * TODO: what do we do if we set to non-nil and limit is 0? | 731 | * TODO: what do we do if we set to non-nil and limit is 0? |
| 732 | * | 732 | * |
| 733 | * Existing slot value is replaced, and possible queue entries removed. | 733 | * Existing slot value is replaced, and possible queued entries removed. |
| 734 | */ | 734 | */ |
| 735 | LUAG_FUNC( linda_set) | 735 | LUAG_FUNC( linda_set) |
| 736 | { | 736 | { |
| 737 | struct s_Linda *linda = lua_toLinda( L, 1); | 737 | struct s_Linda* const linda = lua_toLinda( L, 1); |
| 738 | int pushed; | 738 | int pushed; |
| 739 | bool_t has_value = !lua_isnil( L, 3); | 739 | bool_t has_value = lua_gettop( L) > 2; |
| 740 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 740 | luaL_argcheck( L, linda, 1, "expected a linda object!"); |
| 741 | luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); | ||
| 742 | 741 | ||
| 743 | // make sure the key is of a valid type | 742 | // make sure the key is of a valid type (throws an error if not the case) |
| 744 | check_key_types( L, 2, 2); | 743 | check_key_types( L, 2, 2); |
| 745 | 744 | ||
| 746 | { | 745 | { |
| 747 | struct s_Keeper* K = keeper_acquire( linda); | 746 | struct s_Keeper* K = keeper_acquire( linda); |
| 748 | if( K == NULL) return 0; | 747 | if( K == NULL) return 0; |
| 749 | // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() | 748 | if( has_value) |
| 749 | { | ||
| 750 | // convert nils to some special non-nil sentinel in sent values | ||
| 751 | keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper); | ||
| 752 | } | ||
| 750 | pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); | 753 | pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); |
| 751 | if( pushed >= 0) // no error? | 754 | if( pushed >= 0) // no error? |
| 752 | { | 755 | { |
| @@ -801,31 +804,32 @@ LUAG_FUNC( linda_count) | |||
| 801 | 804 | ||
| 802 | 805 | ||
| 803 | /* | 806 | /* |
| 804 | * [val]= linda_get( linda_ud, key_num|str|bool|lightuserdata ) | 807 | * [val [, ...]] = linda_get( linda_ud, key_num|str|bool|lightuserdata [, count = 1]) |
| 805 | * | 808 | * |
| 806 | * Get a value from Linda. | 809 | * Get one or more values from Linda. |
| 807 | * TODO: add support to get multiple values? | ||
| 808 | */ | 810 | */ |
| 809 | LUAG_FUNC( linda_get) | 811 | LUAG_FUNC( linda_get) |
| 810 | { | 812 | { |
| 811 | struct s_Linda *linda= lua_toLinda( L, 1); | 813 | struct s_Linda* const linda = lua_toLinda( L, 1); |
| 812 | int pushed; | 814 | int pushed; |
| 815 | int count = luaL_optint( L, 3, 1); | ||
| 816 | luaL_argcheck( L, count >= 1, 3, "count should be >= 1"); | ||
| 817 | luaL_argcheck( L, linda, 1, "expected a linda object"); | ||
| 818 | luaL_argcheck( L, lua_gettop( L) <= 3, 4, "too many arguments"); | ||
| 813 | 819 | ||
| 814 | luaL_argcheck( L, linda, 1, "expected a linda object!"); | 820 | // make sure the key is of a valid type (throws an error if not the case) |
| 815 | // make sure the key is of a valid type | ||
| 816 | check_key_types( L, 2, 2); | 821 | check_key_types( L, 2, 2); |
| 817 | |||
| 818 | { | 822 | { |
| 819 | struct s_Keeper* K = keeper_acquire( linda); | 823 | struct s_Keeper* K = keeper_acquire( linda); |
| 820 | if( K == NULL) return 0; | 824 | if( K == NULL) return 0; |
| 821 | pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); | 825 | pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); |
| 822 | ASSERT_L( pushed == 0 || pushed == 1); | ||
| 823 | if( pushed > 0) | 826 | if( pushed > 0) |
| 824 | { | 827 | { |
| 825 | keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); | 828 | keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper); |
| 826 | } | 829 | } |
| 827 | keeper_release( K); | 830 | keeper_release( K); |
| 828 | // must trigger error after keeper state has been released | 831 | // must trigger error after keeper state has been released |
| 832 | // (an error can be raised if we attempt to read an unregistered function) | ||
| 829 | if( pushed < 0) | 833 | if( pushed < 0) |
| 830 | { | 834 | { |
| 831 | return luaL_error( L, "tried to copy unsupported types"); | 835 | return luaL_error( L, "tried to copy unsupported types"); |
diff --git a/src/lanes.lua b/src/lanes.lua index e7b9715..9a0287d 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
| @@ -596,8 +596,8 @@ end -- settings.with_timers | |||
| 596 | -- | 596 | -- |
| 597 | -- PUBLIC LANES API | 597 | -- PUBLIC LANES API |
| 598 | local genlock = function( linda, key, N) | 598 | local genlock = function( linda, key, N) |
| 599 | linda:set( key) -- clears existing data | ||
| 599 | linda:limit( key, N) | 600 | linda:limit( key, N) |
| 600 | linda:set( key, nil) -- clears existing data | ||
| 601 | 601 | ||
| 602 | -- | 602 | -- |
| 603 | -- [true [, ...]= trues(uint) | 603 | -- [true [, ...]= trues(uint) |
