7#include "../../contracts/eosio/action.hpp"
8#include "../../core/eosio/name.hpp"
9#include "../../core/eosio/serialize.hpp"
10#include "../../core/eosio/fixed_bytes.hpp"
12#include <bluegrass/meta/for_each.hpp>
30 namespace internal_use_do_not_use {
39 void db_remove_i64(int32_t);
42 int32_t db_get_i64(int32_t, const
void*,
uint32_t);
45 int32_t db_next_i64(int32_t,
uint64_t*);
48 int32_t db_previous_i64(int32_t,
uint64_t*);
69 void db_idx64_remove(int32_t);
72 int32_t db_idx64_next(int32_t,
uint64_t*);
75 int32_t db_idx64_previous(int32_t,
uint64_t*);
96 void db_idx128_update(int32_t,
uint64_t, const uint128_t*);
99 void db_idx128_remove(int32_t);
102 int32_t db_idx128_next(int32_t,
uint64_t*);
105 int32_t db_idx128_previous(int32_t,
uint64_t*);
129 void db_idx256_remove(int32_t);
132 int32_t db_idx256_next(int32_t,
uint64_t*);
135 int32_t db_idx256_previous(int32_t,
uint64_t*);
156 void db_idx_double_update(int32_t,
uint64_t, const
double*);
159 void db_idx_double_remove(int32_t);
162 int32_t db_idx_double_next(int32_t,
uint64_t*);
165 int32_t db_idx_double_previous(int32_t,
uint64_t*);
186 void db_idx_long_double_update(int32_t,
uint64_t, const
long double*);
189 void db_idx_long_double_remove(int32_t);
192 int32_t db_idx_long_double_next(int32_t,
uint64_t*);
195 int32_t db_idx_long_double_previous(int32_t,
uint64_t*);
214constexpr static inline
name same_payer{};
216template<
class Class,
typename Type,Type (Class::*PtrToMemberFunction)()const>
221 template<
typename ChainedPtr>
223 auto operator()(
const ChainedPtr& x)
const -> std::enable_if_t<!std::is_convertible<const ChainedPtr&, const Class&>::value, Type>
225 return operator()(*x);
230 return (x.*PtrToMemberFunction)();
233 Type
operator()(
const std::reference_wrapper<const Class>& x)
const
235 return operator()(x.get());
240 return operator()(x.get());
244#define WRAP_SECONDARY_SIMPLE_TYPE(IDX, TYPE)\
246struct secondary_index_db_functions<TYPE> {\
247 static int32_t db_idx_next( int32_t iterator, uint64_t* primary ) { return internal_use_do_not_use::db_##IDX##_next( iterator, primary ); } \
248 static int32_t db_idx_previous( int32_t iterator, uint64_t* primary ) { return internal_use_do_not_use::db_##IDX##_previous( iterator, primary ); } \
249 static void db_idx_remove( int32_t iterator ) { internal_use_do_not_use::db_##IDX##_remove( iterator ); } \
250 static int32_t db_idx_end( uint64_t code, uint64_t scope, uint64_t table ) { return internal_use_do_not_use::db_##IDX##_end( code, scope, table ); } \
251 static int32_t db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\
252 return internal_use_do_not_use::db_##IDX##_store( scope, table, payer, id, &secondary ); \
254 static void db_idx_update( int32_t iterator, uint64_t payer, const TYPE& secondary ) {\
255 internal_use_do_not_use::db_##IDX##_update( iterator, payer, &secondary ); \
257 static int32_t db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, TYPE& secondary ) {\
258 return internal_use_do_not_use::db_##IDX##_find_primary( code, scope, table, &secondary, primary ); \
260 static int32_t db_idx_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\
261 return internal_use_do_not_use::db_##IDX##_find_secondary( code, scope, table, &secondary, &primary ); \
263 static int32_t db_idx_lowerbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\
264 return internal_use_do_not_use::db_##IDX##_lowerbound( code, scope, table, &secondary, &primary ); \
266 static int32_t db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\
267 return internal_use_do_not_use::db_##IDX##_upperbound( code, scope, table, &secondary, &primary ); \
271#define WRAP_SECONDARY_ARRAY_TYPE(IDX, TYPE)\
273struct secondary_index_db_functions<TYPE> {\
274 static int32_t db_idx_next( int32_t iterator, uint64_t* primary ) { return internal_use_do_not_use::db_##IDX##_next( iterator, primary ); } \
275 static int32_t db_idx_previous( int32_t iterator, uint64_t* primary ) { return internal_use_do_not_use::db_##IDX##_previous( iterator, primary ); } \
276 static void db_idx_remove( int32_t iterator ) { internal_use_do_not_use::db_##IDX##_remove( iterator ); } \
277 static int32_t db_idx_end( uint64_t code, uint64_t scope, uint64_t table ) { return internal_use_do_not_use::db_##IDX##_end( code, scope, table ); } \
278 static int32_t db_idx_store( uint64_t scope, uint64_t table, uint64_t payer, uint64_t id, const TYPE& secondary ) {\
279 return internal_use_do_not_use::db_##IDX##_store( scope, table, payer, id, secondary.data(), TYPE::num_words() ); \
281 static void db_idx_update( int32_t iterator, uint64_t payer, const TYPE& secondary ) {\
282 internal_use_do_not_use::db_##IDX##_update( iterator, payer, secondary.data(), TYPE::num_words() ); \
284 static int32_t db_idx_find_primary( uint64_t code, uint64_t scope, uint64_t table, uint64_t primary, TYPE& secondary ) {\
285 return internal_use_do_not_use::db_##IDX##_find_primary( code, scope, table, secondary.data(), TYPE::num_words(), primary ); \
287 static int32_t db_idx_find_secondary( uint64_t code, uint64_t scope, uint64_t table, const TYPE& secondary, uint64_t& primary ) {\
288 return internal_use_do_not_use::db_##IDX##_find_secondary( code, scope, table, secondary.data(), TYPE::num_words(), &primary ); \
290 static int32_t db_idx_lowerbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\
291 return internal_use_do_not_use::db_##IDX##_lowerbound( code, scope, table, secondary.data(), TYPE::num_words(), &primary ); \
293 static int32_t db_idx_upperbound( uint64_t code, uint64_t scope, uint64_t table, TYPE& secondary, uint64_t& primary ) {\
294 return internal_use_do_not_use::db_##IDX##_upperbound( code, scope, table, secondary.data(), TYPE::num_words(), &primary ); \
298#define MAKE_TRAITS_FOR_ARITHMETIC_SECONDARY_KEY(TYPE)\
300struct secondary_key_traits<TYPE> {\
301 static_assert( std::numeric_limits<TYPE>::is_specialized, "TYPE does not have specialized numeric_limits" );\
302 static constexpr TYPE true_lowest() { return std::numeric_limits<TYPE>::lowest(); }\
305namespace _multi_index_detail {
322 static constexpr double true_lowest() {
return -std::numeric_limits<double>::infinity(); }
328 static constexpr long double true_lowest() {
return -std::numeric_limits<long double>::infinity(); }
337 template<
typename PK>
375template<name::raw IndexName,
typename Extractor>
437template<
name::raw TableName,
typename T,
typename... Indices>
442 static_assert( std::is_same_v<decltype(_multi_index_detail::to_raw_key(std::declval<T>().primary_key())),
uint64_t>,
443 "Primary key must be uint64_t or name" );
444 static_assert(
sizeof...(Indices) <= 16,
"multi_index only supports a maximum of 16 secondary indices" );
446 constexpr static bool validate_table_name(
name n ) {
451 constexpr static size_t max_stack_buffer_size = 512;
453 static_assert( validate_table_name(
name(TableName) ),
"multi_index does not support table names with a length greater than 12");
460 enum next_primary_key_tags :
uint64_t {
461 no_available_primary_key =
static_cast<uint64_t>(-2),
462 unset_next_primary_key =
static_cast<uint64_t>(-1)
465 struct item :
public T
467 template<
typename Constructor>
474 int32_t __primary_itr;
475 int32_t __iters[
sizeof...(Indices)+(
sizeof...(Indices)==0)];
480 item_ptr(std::unique_ptr<item>&& i,
uint64_t pk, int32_t pitr)
481 : _item(std::move(i)), _primary_key(pk), _primary_itr(pitr) {}
483 std::unique_ptr<item> _item;
485 int32_t _primary_itr;
488 mutable std::vector<item_ptr> _items_vector;
490 template<name::raw IndexName,
typename Extractor, u
int64_t Number,
bool IsConst>
493 typedef Extractor secondary_extractor_type;
494 typedef typename std::decay<
decltype( Extractor()(
nullptr) )>::type secondary_key_type;
496 constexpr static bool validate_index_name(
eosio::name n ) {
500 static_assert( validate_index_name(
name(IndexName) ),
"invalid index name used in multi_index" );
503 table_name =
static_cast<uint64_t>(TableName),
504 index_name =
static_cast<uint64_t>(IndexName),
505 index_number = Number,
506 index_table_name = (
static_cast<uint64_t>(TableName) & 0xFFFFFFFFFFFFFFF0ULL)
507 | (Number & 0x000000000000000FULL)
510 constexpr static uint64_t name() {
return index_table_name; }
511 constexpr static uint64_t number() {
return Number; }
513 struct const_iterator :
public std::iterator<std::bidirectional_iterator_tag, const T> {
516 return a._item == b._item;
519 return a._item != b._item;
522 const T&
operator*()
const {
return *
static_cast<const T*
>(_item); }
523 const T*
operator->()
const {
return static_cast<const T*
>(_item); }
538 using namespace _multi_index_detail;
540 eosio::check( _item !=
nullptr,
"cannot increment end iterator" );
542 if( _item->__iters[Number] == -1 ) {
543 secondary_key_type temp_secondary_key;
544 auto idxitr = secondary_index_db_functions<secondary_key_type>::db_idx_find_primary(_idx->get_code().value, _idx->get_scope(), _idx->name(), _item->primary_key(), temp_secondary_key);
545 auto& mi =
const_cast<item&
>( *_item );
546 mi.__iters[Number] = idxitr;
550 auto next_itr = secondary_index_db_functions<secondary_key_type>::db_idx_next( _item->__iters[Number], &next_pk );
556 const T& obj = *_idx->_multidx->find( next_pk );
557 auto& mi =
const_cast<item&
>(
static_cast<const item&
>(obj) );
558 mi.__iters[Number] = next_itr;
565 using namespace _multi_index_detail;
568 int32_t prev_itr = -1;
571 auto ei = secondary_index_db_functions<secondary_key_type>::db_idx_end(_idx->get_code().value, _idx->get_scope(), _idx->name());
572 eosio::check( ei != -1,
"cannot decrement end iterator when the index is empty" );
573 prev_itr = secondary_index_db_functions<secondary_key_type>::db_idx_previous( ei , &prev_pk );
574 eosio::check( prev_itr >= 0,
"cannot decrement end iterator when the index is empty" );
576 if( _item->__iters[Number] == -1 ) {
577 secondary_key_type temp_secondary_key;
578 auto idxitr = secondary_index_db_functions<secondary_key_type>::db_idx_find_primary(_idx->get_code().value, _idx->get_scope(), _idx->name(), _item->primary_key(), temp_secondary_key);
579 auto& mi =
const_cast<item&
>( *_item );
580 mi.__iters[Number] = idxitr;
582 prev_itr = secondary_index_db_functions<secondary_key_type>::db_idx_previous( _item->__iters[Number], &prev_pk );
583 eosio::check( prev_itr >= 0,
"cannot decrement iterator at beginning of index" );
586 const T& obj = *_idx->_multidx->find( prev_pk );
587 auto& mi =
const_cast<item&
>(
static_cast<const item&
>(obj) );
588 mi.__iters[Number] = prev_itr;
598 : _idx(idx), _item(i) {}
607 using namespace _multi_index_detail;
608 return lower_bound( secondary_key_traits<secondary_key_type>::true_lowest() );
610 const_iterator begin()
const {
return cbegin(); }
612 const_iterator cend()
const {
return const_iterator(
this ); }
613 const_iterator end()
const {
return cend(); }
615 const_reverse_iterator crbegin()
const {
return std::make_reverse_iterator(cend()); }
616 const_reverse_iterator rbegin()
const {
return crbegin(); }
618 const_reverse_iterator crend()
const {
return std::make_reverse_iterator(cbegin()); }
619 const_reverse_iterator rend()
const {
return crend(); }
621 const_iterator find( secondary_key_type&& secondary )
const {
622 return find( secondary );
625 const_iterator find(
const secondary_key_type& secondary )
const {
626 auto lb = lower_bound( secondary );
628 if( lb == e )
return e;
630 if( secondary != secondary_extractor_type()(*lb) )
635 const_iterator require_find( secondary_key_type&& secondary,
const char* error_msg =
"unable to find secondary key" )
const {
636 return require_find( secondary, error_msg );
639 const_iterator require_find(
const secondary_key_type& secondary,
const char* error_msg =
"unable to find secondary key" )
const {
640 auto lb = lower_bound( secondary );
642 eosio::check( secondary == secondary_extractor_type()(*lb), error_msg );
654 const T& get( secondary_key_type&& secondary,
const char* error_msg =
"unable to find secondary key" )
const {
655 return get( secondary, error_msg );
666 const T& get(
const secondary_key_type& secondary,
const char* error_msg =
"unable to find secondary key" )
const {
667 auto result = find( secondary );
672 const_iterator lower_bound( secondary_key_type&& secondary )
const {
673 return lower_bound( secondary );
675 const_iterator lower_bound(
const secondary_key_type& secondary )
const {
676 using namespace _multi_index_detail;
679 secondary_key_type secondary_copy(secondary);
680 auto itr = secondary_index_db_functions<secondary_key_type>::db_idx_lowerbound( get_code().value, get_scope(), name(), secondary_copy, primary );
681 if( itr < 0 )
return cend();
683 const T& obj = *_multidx->find( primary );
684 auto& mi =
const_cast<item&
>(
static_cast<const item&
>(obj) );
685 mi.__iters[Number] = itr;
690 const_iterator upper_bound( secondary_key_type&& secondary )
const {
691 return upper_bound( secondary );
693 const_iterator upper_bound(
const secondary_key_type& secondary )
const {
694 using namespace _multi_index_detail;
697 secondary_key_type secondary_copy(secondary);
698 auto itr = secondary_index_db_functions<secondary_key_type>::db_idx_upperbound( get_code().value, get_scope(), name(), secondary_copy, primary );
699 if( itr < 0 )
return cend();
701 const T& obj = *_multidx->find( primary );
702 auto& mi =
const_cast<item&
>(
static_cast<const item&
>(obj) );
703 mi.__iters[Number] = itr;
712 const_iterator iterator_to(
const T& obj ) {
713 using namespace _multi_index_detail;
715 const auto& objitem =
static_cast<const item&
>(obj);
716 eosio::check( objitem.__idx == _multidx,
"object passed to iterator_to is not in multi_index" );
718 if( objitem.__iters[Number] == -1 ) {
719 secondary_key_type temp_secondary_key;
720 auto idxitr = secondary_index_db_functions<secondary_key_type>::db_idx_find_primary(get_code().value, get_scope(), name(), objitem.primary_key(), temp_secondary_key);
721 auto& mi =
const_cast<item&
>( objitem );
722 mi.__iters[Number] = idxitr;
725 return {
this, &objitem};
728 template<
typename Lambda>
729 void modify( const_iterator itr,
eosio::name payer, Lambda&& updater ) {
730 eosio::check( itr != cend(),
"cannot pass end iterator to modify" );
732 _multidx->modify( *itr, payer, std::forward<Lambda&&>(updater) );
735 template<
typename Lambda>
736 void modify(
const T& obj,
eosio::name payer, Lambda&& updater ) {
737 _multidx->modify( obj, payer, std::forward<Lambda&&>(updater) );
740 const_iterator erase( const_iterator itr ) {
741 eosio::check( itr != cend(),
"cannot pass end iterator to erase" );
743 const auto& obj = *itr;
746 _multidx->erase(obj);
751 eosio::name get_code()
const {
return _multidx->get_code(); }
752 uint64_t get_scope()
const {
return _multidx->get_scope(); }
754 static auto extract_secondary_key(
const T& obj) {
return secondary_extractor_type()(obj); }
757 constexpr index() : _multidx(nullptr) { }
759 friend class multi_index;
761 index(
typename std::conditional<IsConst, const multi_index*, multi_index*>::type midx )
764 typename std::conditional<IsConst, const multi_index*, multi_index*>::type _multidx;
768 struct intc {
enum e{ value = I };
operator uint64_t()
const{
return I; } };
769 enum index_cv { const_index = 0, mutable_index = 1 };
772 class make_index_tuple {
775 static constexpr auto get_type(std::index_sequence<Seq...>) {
777 typename Values::secondary_extractor_type,
778 intc<Seq>::e::value, const_index>{},
779 index<eosio::name::raw(static_cast<uint64_t>(Values::index_name)),
780 typename Values::secondary_extractor_type,
781 intc<Seq>::e::value, mutable_index>{})...);
784 using type =
decltype( get_type(std::make_index_sequence<Num>{}) );
787 using indices_type =
typename make_index_tuple<
sizeof... (Indices), Indices...>::type;
789 class make_extractor_tuple {
790 template <typename Obj, typename IndicesType, std::size_t... Seq>
791 static constexpr auto extractor_tuple(IndicesType,
const Obj& obj, std::index_sequence<Seq...>) {
792 return std::make_tuple(std::tuple_element_t<const_index, std::tuple_element_t<Seq, IndicesType>>::extract_secondary_key(obj)...);
795 template <
typename Obj,
typename IndicesType>
796 static constexpr auto get_extractor_tuple(IndicesType,
const Obj& obj) {
797 return extractor_tuple(IndicesType{}, obj, std::make_index_sequence<std::tuple_size_v<IndicesType>>{});
801 const item& load_object_by_primary_iterator( int32_t itr )
const {
802 using namespace _multi_index_detail;
804 auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](
const item_ptr& ptr) {
805 return ptr._primary_itr == itr;
807 if( itr2 != _items_vector.rend() )
810 auto size = internal_use_do_not_use::db_get_i64( itr,
nullptr, 0 );
816 internal_use_do_not_use::db_get_i64( itr, buffer,
uint32_t(
size) );
818 datastream<const char*> ds( (
char*)buffer,
uint32_t(
size) );
820 auto itm = std::make_unique<item>(
this, [&](
auto& i ) {
821 T& val =
static_cast<T&
>(i);
824 i.__primary_itr = itr;
825 bluegrass::meta::for_each(indices_type{}, [&](
auto idx){
826 typedef std::tuple_element_t<const_index,
decltype(idx)> index_type;
827 i.__iters[ index_type::number() ] = -1;
831 const item* ptr = itm.get();
833 auto pitr = itm->__primary_itr;
835 _items_vector.emplace_back( std::move(itm), pk, pitr );
837 if ( max_stack_buffer_size <
size_t(
size) ) {
893 :_code(
code),_scope(scope),_next_primary_key(unset_next_primary_key)
938 struct const_iterator :
public std::iterator<std::bidirectional_iterator_tag, const T> {
940 return a._item == b._item;
943 return a._item != b._item;
946 const T&
operator*()
const {
return *
static_cast<const T*
>(_item); }
947 const T*
operator->()
const {
return static_cast<const T*
>(_item); }
962 eosio::check( _item !=
nullptr,
"cannot increment end iterator" );
965 auto next_itr = internal_use_do_not_use::db_next_i64( _item->__primary_itr, &next_pk );
969 _item = &_multidx->load_object_by_primary_iterator( next_itr );
974 int32_t prev_itr = -1;
977 auto ei = internal_use_do_not_use::db_end_i64(_multidx->get_code().value, _multidx->get_scope(),
static_cast<uint64_t>(TableName));
978 eosio::check( ei != -1,
"cannot decrement end iterator when the table is empty" );
979 prev_itr = internal_use_do_not_use::db_previous_i64( ei , &prev_pk );
980 eosio::check( prev_itr >= 0,
"cannot decrement end iterator when the table is empty" );
982 prev_itr = internal_use_do_not_use::db_previous_i64( _item->__primary_itr, &prev_pk );
983 eosio::check( prev_itr >= 0,
"cannot decrement iterator at beginning of table" );
986 _item = &_multidx->load_object_by_primary_iterator( prev_itr );
992 :_multidx(mi),_item(i){}
1024 return lower_bound(std::numeric_limits<uint64_t>::lowest());
1280 template<
typename PK>
1283 auto itr = internal_use_do_not_use::db_lowerbound_i64( _code.
value, _scope,
static_cast<uint64_t>(TableName), primary_int );
1284 if( itr < 0 )
return end();
1285 const auto& obj = load_object_by_primary_iterator( itr );
1286 return {
this, &obj};
1326 template<
typename PK>
1329 auto itr = internal_use_do_not_use::db_upperbound_i64( _code.
value, _scope,
static_cast<uint64_t>(TableName), primary_int );
1330 if( itr < 0 )
return end();
1331 const auto& obj = load_object_by_primary_iterator( itr );
1332 return {
this, &obj};
1367 if( _next_primary_key == unset_next_primary_key ) {
1369 if( begin() == end() ) {
1370 _next_primary_key = 0;
1373 auto pk = itr->primary_key();
1374 if( pk >= no_available_primary_key )
1375 _next_primary_key = no_available_primary_key;
1377 _next_primary_key = pk + 1;
1381 eosio::check( _next_primary_key < no_available_primary_key,
"next primary key in table is at autoincrement limit");
1382 return _next_primary_key;
1426 template<name::raw IndexName>
1428 using namespace _multi_index_detail;
1430 constexpr uint64_t index_num = bluegrass::meta::for_each(indices_type{}, [](
auto idx){
1431 return std::tuple_element_t<const_index,
decltype(idx)>::index_name ==
static_cast<uint64_t>(IndexName);
1434 static_assert( index_num <
sizeof...(Indices),
"name provided is not the name of any secondary index within multi_index" );
1436 return std::tuple_element_t<const_index, std::tuple_element_t<index_num, indices_type>>(
this);
1477 template<name::raw IndexName>
1479 using namespace _multi_index_detail;
1481 constexpr uint64_t index_num = bluegrass::meta::for_each(indices_type{}, [](
auto idx){
1482 return std::tuple_element_t<mutable_index,
decltype(idx)>::index_name ==
static_cast<uint64_t>(IndexName);
1485 static_assert( index_num <
sizeof...(Indices),
"name provided is not the name of any secondary index within multi_index" );
1487 return std::tuple_element_t<mutable_index, std::tuple_element_t<index_num, indices_type>>(
this);
1530 const auto& objitem =
static_cast<const item&
>(obj);
1531 eosio::check( objitem.__idx ==
this,
"object passed to iterator_to is not in multi_index" );
1532 return {
this, &objitem};
1571 template<
typename Lambda>
1573 using namespace _multi_index_detail;
1577 auto itm = std::make_unique<item>(
this, [&](
auto& i ){
1578 T& obj =
static_cast<T&
>(i);
1584 void* buffer = max_stack_buffer_size <
size ? malloc(
size) : alloca(
size);
1591 i.__primary_itr = internal_use_do_not_use::db_store_i64( _scope,
static_cast<uint64_t>(TableName), payer.
value, pk, buffer,
size );
1593 if ( max_stack_buffer_size <
size ) {
1597 if( pk >= _next_primary_key )
1598 _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1);
1600 bluegrass::meta::for_each(indices_type{}, [&](
auto idx){
1601 typedef std::tuple_element_t<const_index,
decltype(idx)> index_type;
1603 i.__iters[index_type::number()] = secondary_index_db_functions<typename index_type::secondary_key_type>::db_idx_store( _scope, index_type::name(), payer.
value, obj.primary_key(), index_type::extract_secondary_key(obj) );
1607 const item* ptr = itm.get();
1609 auto pitr = itm->__primary_itr;
1611 _items_vector.emplace_back( std::move(itm), pk, pitr );
1656 template<
typename Lambda>
1658 eosio::check( itr != end(),
"cannot pass end iterator to modify" );
1660 modify( *itr, payer, std::forward<Lambda&&>(updater) );
1704 template<
typename Lambda>
1706 using namespace _multi_index_detail;
1708 const auto& objitem =
static_cast<const item&
>(obj);
1709 eosio::check( objitem.__idx ==
this,
"object passed to modify is not in multi_index" );
1710 auto& mutableitem =
const_cast<item&
>(objitem);
1713 auto secondary_keys = make_extractor_tuple::get_extractor_tuple(indices_type{}, obj);
1717 auto& mutableobj =
const_cast<T&
>(obj);
1718 updater( mutableobj );
1724 void* buffer = max_stack_buffer_size <
size ? malloc(
size) : alloca(
size);
1729 internal_use_do_not_use::db_update_i64( objitem.__primary_itr, payer.
value, buffer,
size );
1731 if ( max_stack_buffer_size <
size ) {
1735 if( pk >= _next_primary_key )
1736 _next_primary_key = (pk >= no_available_primary_key) ? no_available_primary_key : (pk + 1);
1738 bluegrass::meta::for_each(indices_type{}, [&](
auto idx){
1739 typedef std::tuple_element_t<const_index,
decltype(idx)> index_type;
1740 auto secondary = index_type::extract_secondary_key( obj );
1741 if( memcmp( &std::get<index_type::index_number>(secondary_keys), &secondary,
sizeof(secondary) ) != 0 ) {
1742 auto indexitr = mutableitem.__iters[index_type::number()];
1744 if( indexitr < 0 ) {
1745 typename index_type::secondary_key_type temp_secondary_key;
1746 indexitr = mutableitem.__iters[index_type::number()]
1747 = secondary_index_db_functions<typename index_type::secondary_key_type>::db_idx_find_primary( _code.
value, _scope, index_type::name(), pk, temp_secondary_key );
1750 secondary_index_db_functions<typename index_type::secondary_key_type>::db_idx_update( indexitr, payer.
value, secondary );
1787 template<
typename PK>
1788 const T&
get( PK primary,
const char* error_msg =
"unable to find key" )
const {
1789 auto result = find( primary );
1817 template<
typename PK>
1819 auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](
const item_ptr& ptr) {
1820 return ptr._item->primary_key() == primary;
1822 if( itr2 != _items_vector.rend() )
1823 return iterator_to(*(itr2->_item));
1826 auto itr = internal_use_do_not_use::db_find_i64( _code.
value, _scope,
static_cast<uint64_t>(TableName), primary_int );
1827 if( itr < 0 )
return end();
1829 const item& i = load_object_by_primary_iterator( itr );
1830 return iterator_to(
static_cast<const T&
>(i));
1842 template<
typename PK>
1844 auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](
const item_ptr& ptr) {
1845 return ptr._item->primary_key() == primary;
1847 if( itr2 != _items_vector.rend() )
1848 return iterator_to(*(itr2->_item));
1851 auto itr = internal_use_do_not_use::db_find_i64( _code.
value, _scope,
static_cast<uint64_t>(TableName), primary_int );
1854 const item& i = load_object_by_primary_iterator( itr );
1855 return iterator_to(
static_cast<const T&
>(i));
1895 eosio::check( itr != end(),
"cannot pass end iterator to erase" );
1897 const auto& obj = *itr;
1938 using namespace _multi_index_detail;
1940 const auto& objitem =
static_cast<const item&
>(obj);
1941 eosio::check( objitem.__idx ==
this,
"object passed to erase is not in multi_index" );
1944 auto pk = objitem.primary_key();
1945 auto itr2 = std::find_if(_items_vector.rbegin(), _items_vector.rend(), [&](
const item_ptr& ptr) {
1946 return ptr._item->primary_key() == pk;
1949 eosio::check( itr2 != _items_vector.rend(),
"attempt to remove object that was not in multi_index" );
1951 internal_use_do_not_use::db_remove_i64( objitem.__primary_itr );
1953 bluegrass::meta::for_each(indices_type{}, [&](
auto idx){
1954 typedef std::tuple_element_t<const_index,
decltype(idx)> index_type;
1956 auto i = objitem.__iters[index_type::number()];
1958 typename index_type::secondary_key_type secondary;
1959 i = secondary_index_db_functions<typename index_type::secondary_key_type>::db_idx_find_primary( _code.
value, _scope, index_type::name(), objitem.primary_key(), secondary );
1962 secondary_index_db_functions<typename index_type::secondary_key_type>::db_idx_remove( i );
1965 _items_vector.erase(--(itr2.base()));