본문으로 건너뛰기

FunC 표준 라이브러리

정보

이 섹션에서는 FunC에서 사용되는 표준 함수들이 포함된 stdlib.fc 라이브러리에 대해 설명합니다.

현재 이 라이브러리는 내장되지 않은 가장 일반적인 TVM 어셈블러 명령어들의 래퍼일 뿐입니다. 라이브러리에서 사용되는 각 TVM 명령어에 대한 설명은 TVM 문서 섹션에서 확인할 수 있습니다. 일부 설명은 이 문서에서 인용되었습니다.

파일에서 일부 함수들은 주석 처리되어 있습니다. 이는 최적화를 위해 이미 내장 함수가 되었다는 것을 의미합니다. 하지만 타입 시그니처와 의미는 동일하게 유지됩니다.

일부 덜 일반적인 명령어들은 stdlib에 포함되어 있지 않습니다. 언젠가는 이들도 추가될 것입니다.

튜플 조작 프리미티브

이름과 타입은 대부분 자명합니다. 다형성 함수에 대한 자세한 내용은 forall을 사용한 다형성을 참조하세요.

현재 원자적 타입 tuple의 값은 복합 튜플 타입(예: [int, cell])으로 캐스팅될 수 없으며, 그 반대도 마찬가지입니다.

Lisp 스타일 리스트

리스트는 중첩된 2-요소 튜플로 표현될 수 있습니다. 빈 리스트는 일반적으로 TVM null 값으로 표현됩니다(null()을 호출하여 얻을 수 있음). 예를 들어, 튜플 (1, (2, (3, null)))은 리스트 [1, 2, 3]을 나타냅니다. 리스트의 요소들은 서로 다른 타입일 수 있습니다.

cons

forall X -> tuple cons(X head, tuple tail) asm "CONS";

Lisp 스타일 리스트의 시작 부분에 요소를 추가합니다.

uncons

forall X -> (X, tuple) uncons(tuple list) asm "UNCONS";

Lisp 스타일 리스트에서 head와 tail을 추출합니다.

list_next

forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS";

Lisp 스타일 리스트에서 head와 tail을 추출합니다. (비)수정 메서드로 사용될 수 있습니다.

() foo(tuple xs) {
(_, int x) = xs.list_next(); ;; get the first element, `_` means do not use tail list
int y = xs~list_next(); ;; pop the first element
int z = xs~list_next(); ;; pop the second element
}

car

forall X -> X car(tuple list) asm "CAR";

Lisp 스타일 리스트의 head를 반환합니다.

cdr

tuple cdr(tuple list) asm "CDR";

Lisp 스타일 리스트의 tail을 반환합니다.

기타 튜플 프리미티브

empty_tuple

tuple empty_tuple() asm "NIL";

0-요소 튜플을 생성합니다.

tpush

forall X -> tuple tpush(tuple t, X value) asm "TPUSH";
forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH";

x를 튜플 t = (x1, ..., xn)에 추가하지만, 결과 튜플 t' = (x1, ..., xn, x)가 255자를 초과하지 않는 경우에만 가능합니다. 그렇지 않으면 타입 체크 예외가 발생합니다.

single

forall X -> [X] single(X x) asm "SINGLE";

싱글톤(길이가 1인 튜플)을 생성합니다.

unsingle

forall X -> X unsingle([X] t) asm "UNSINGLE";

싱글톤을 언패킹합니다.

pair

forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR";

쌍을 생성합니다.

unpair

forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR";

쌍을 언패킹합니다.

triple

forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE";

트리플을 생성합니다.

untriple

forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE";

트리플을 언패킹합니다.

tuple4

forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE";

4-요소 튜플을 생성합니다.

untuple4

forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE";

4-요소 튜플을 언패킹합니다.

first

forall X -> X first(tuple t) asm "FIRST";

튜플의 첫 번째 요소를 반환합니다.

second

forall X -> X second(tuple t) asm "SECOND";

튜플의 두 번째 요소를 반환합니다.

third

forall X -> X third(tuple t) asm "THIRD";

튜플의 세 번째 요소를 반환합니다.

fourth

forall X -> X fourth(tuple t) asm "3 INDEX";

튜플의 네 번째 요소를 반환합니다.

pair_first

forall X, Y -> X pair_first([X, Y] p) asm "FIRST";

쌍의 첫 번째 요소를 반환합니다.

pair_second

forall X, Y -> Y pair_second([X, Y] p) asm "SECOND";

쌍의 두 번째 요소를 반환합니다.

triple_first

forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST";

트리플의 첫 번째 요소를 반환합니다.

triple_second

forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND";

트리플의 두 번째 요소를 반환합니다.

triple_third

forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD";

트리플의 세 번째 요소를 반환합니다.

도메인 특화 프리미티브

c7에서 정보 추출하기

스마트 컨트랙트 호출과 관련된 유용한 정보는 c7 특수 레지스터에서 찾을 수 있습니다. 이러한 프리미티브들은 편리한 데이터 추출을 위해 존재합니다.

now

int now() asm "NOW";

현재 Unix 시간을 정수로 반환합니다.

my_address

slice my_address() asm "MYADDR";

현재 스마트 컨트랙트의 내부 주소를 MsgAddressInt가 포함된 Slice로 반환합니다. 필요한 경우 parse_std_addr와 같은 프리미티브를 사용하여 추가 파싱할 수 있습니다.

get_balance

[int, cell] get_balance() asm "BALANCE";

스마트 컨트랙트의 남은 잔액을 tuple로 반환합니다. 이 tuple은 nanotoncoins 단위의 남은 잔액을 나타내는 int와 "추가 통화"의 잔액을 나타내는 32비트 키를 가진 딕셔너리인 cell로 구성됩니다. RAW 프리미티브(예: send_raw_message)는 이 필드를 업데이트하지 않습니다.

cur_lt

int cur_lt() asm "LTIME";

현재 트랜잭션의 논리적 시간을 반환합니다.

block_lt

int block_lt() asm "BLOCKLT";

현재 블록의 시작 논리적 시간을 반환합니다.

config_param

cell config_param(int x) asm "CONFIGOPTPARAM";

정수 인덱스 i를 가진 전역 설정 매개변수의 값을 cell 또는 null 값으로 반환합니다.

해시

cell_hash

int cell_hash(cell c) asm "HASHCU";

cell c의 표현 해시를 계산하여 256비트 부호 없는 정수 x로 반환합니다. 셀 트리로 표현된 임의의 엔티티의 서명 및 서명 확인에 유용합니다.

slice_hash

int slice_hash(slice s) asm "HASHSU";

slice s의 해시를 계산하여 256비트 부호 없는 정수 x로 반환합니다. 결과는 s의 데이터와 참조만을 포함하는 일반 셀이 생성되고 그 해시가 cell_hash로 계산된 것과 동일합니다.

string_hash

int string_hash(slice s) asm "SHA256U";

slice s의 데이터 비트의 sha256을 계산합니다. s의 비트 길이가 8로 나누어 떨어지지 않으면 셀 언더플로우 예외가 발생합니다. 해시 값은 256비트 부호 없는 정수 x로 반환됩니다.

서명 확인

check_signature

int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU";

hash(일반적으로 일부 데이터의 해시로 계산된 256비트 부호 없는 정수)의 Ed25519 signaturepublic_key(256비트 부호 없는 정수로 표현됨)를 사용하여 확인합니다. 서명은 최소 512 데이터 비트를 포함해야 합니다; 처음 512비트만 사용됩니다. 서명이 유효하면 결과는 -1이고, 그렇지 않으면 0입니다. CHKSIGNU는 해시를 포함하는 256비트 슬라이스를 생성하고 CHKSIGNS를 호출합니다. 즉, hash가 일부 데이터의 해시로 계산된 경우, 이 데이터는 두 번 해시되며, 두 번째 해시는 CHKSIGNS 내부에서 발생합니다.

check_data_signature

int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS";

signaturecheck_signature와 유사하게 public_key를 사용하여 slice data의 데이터 부분의 유효한 Ed25519 서명인지 확인합니다. data의 비트 길이가 8로 나누어 떨어지지 않으면 셀 언더플로우 예외가 발생합니다. Ed25519 서명의 검증은 표준적이며, sha256을 사용하여 data를 실제로 서명되는 256비트 숫자로 줄입니다.

boc 크기 계산

아래의 프리미티브들은 사용자가 제공한 데이터의 저장 수수료를 계산하는 데 유용할 수 있습니다.

compute_data_size?

(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";

(x, y, z, -1) 또는 (null, null, null, 0)을 반환합니다. cell c를 루트로 하는 DAG에서 고유한 셀 개수 x, 데이터 비트 y, 셀 참조 z를 재귀적으로 계산합니다. 동일한 셀의 식별을 고려하여 이 DAG가 사용하는 총 저장 공간을 효과적으로 반환합니다. x, y, z의 값은 이미 방문한 셀의 재방문을 방지하기 위해 방문한 셀 해시의 해시 테이블을 사용하여 이 DAG를 깊이 우선 순회하여 계산됩니다. 방문한 총 셀 수 x는 음이 아닌 max_cells를 초과할 수 없습니다; 그렇지 않으면 (max_cells + 1)번째 셀을 방문하기 전에 계산이 중단되고 실패를 나타내는 0 플래그가 반환됩니다. cnull이면 x = y = z = 0을 반환합니다.

slice_compute_data_size?

(int, int, int, int) slice_compute_data_size?(slice s, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";

compute_data_size?와 유사하지만 slice s를 입력으로 받습니다. 반환되는 x 값은 slice s 자체를 포함하는 셀을 고려하지 않습니다; 하지만, s의 데이터 비트와 셀 참조는 yz에서 고려됩니다.

compute_data_size

(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";

실패 시 셀 오버플로우 예외(8)를 발생시키는 compute_data_size?의 non-quiet 버전입니다.

slice_compute_data_size

(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE";

실패 시 셀 오버플로우 예외(8)를 발생시키는 slice_compute_data_size?의 non-quiet 버전입니다.

영구 저장소 저장 및 로드

get_data

cell get_data() asm "c4 PUSH";

영구 컨트랙트 저장소 셀을 반환합니다. 나중에 slice와 builder 프리미티브를 사용하여 파싱하거나 수정할 수 있습니다.

set_data

() set_data(cell c) impure asm "c4 POP";

c를 영구 컨트랙트 데이터로 설정합니다. 이 프리미티브를 사용하여 영구 컨트랙트 저장소를 업데이트할 수 있습니다.

연속체(Continuation) 프리미티브

get_c3

cont get_c3() impure asm "c3 PUSH";

일반적으로 c3는 컨트랙트의 전체 코드로 초기화된 연속체를 가집니다. 함수 호출에 사용됩니다. 이 프리미티브는 c3의 현재 값을 반환합니다.

set_c3

() set_c3(cont c) impure asm "c3 POP";

c3의 현재 값을 업데이트합니다. 일반적으로 런타임에서 스마트 컨트랙트 코드를 업데이트하는 데 사용됩니다. 이 프리미티브를 실행한 후에도 현재 코드(및 재귀 함수 호출 스택)는 변경되지 않지만, 다른 모든 함수 호출은 새 코드의 함수를 사용할 것입니다.

bless

cont bless(slice s) impure asm "BLESS";

slice sc.code = s인 단순 일반 연속체 c로 변환하며, 빈 스택과 저장 리스트를 가집니다.

가스 관련 프리미티브

accept_message

() accept_message() impure asm "ACCEPT";

현재 가스 한도 gl을 허용된 최대값 gm으로 설정하고 가스 크레딧 gc를 0으로 재설정하며, 이 과정에서 gr 값을 gc만큼 감소시킵니다. 다시 말해, 현재 스마트 컨트랙트가 현재 트랜잭션을 완료하기 위해 가스를 구매하는 것에 동의합니다. 이 작업은 값(따라서 가스)을 전달하지 않는 외부 메시지를 처리하는 데 필요합니다.

자세한 내용은 accept_message effects를 확인하세요.

set_gas_limit

() set_gas_limit(int limit) impure asm "SETGASLIMIT";

현재 가스 한도 gllimitgm 중 더 작은 값으로 설정하고 가스 크레딧 gc를 0으로 재설정합니다. 이 시점에서 소비된 가스량(현재 명령어 포함)이 결과 gl 값을 초과하면 새 가스 한도를 설정하기 전에 (처리되지 않은) 가스 부족 예외가 발생합니다. limit ≥ 2^63 − 1인 인자를 가진 set_gas_limitaccept_message와 동등합니다.

자세한 내용은 accept_message effects를 확인하세요.

commit

() commit() impure asm "COMMIT";

레지스터 c4("영구 데이터")와 c5("액션")의 현재 상태를 커밋하여 나중에 예외가 발생하더라도 현재 실행이 저장된 값으로 "성공"으로 간주되도록 합니다.

buy_gas

() buy_gas(int gram) impure asm "BUYGAS";
주의

BUYGAS 옵코드는 현재 구현되지 않았습니다

gram nanotoncoins로 구매할 수 있는 가스량을 계산하고 set_gas_limit과 동일한 방식으로 gl을 설정합니다.

액션 프리미티브

raw_reserve

() raw_reserve(int amount, int mode) impure asm "RAWRESERVE";

계정의 남은 잔액에서 정확히 amount nanotoncoins(mode = 0인 경우), 최대 amount nanotoncoins(mode = 2인 경우), 또는 amount를 제외한 모든 nanotoncoins(mode = 1 또는 mode = 3인 경우)를 예약하는 출력 액션을 생성합니다. 이는 대략적으로 자신에게 amount nanotoncoins(또는 남은 잔액 b에서 amount nanotoncoins를 뺀 값)을 전달하는 아웃바운드 메시지를 생성하는 것과 동등하여, 이후 출력 액션이 나머지보다 더 많은 돈을 사용할 수 없게 됩니다. mode에서 비트 +2는 지정된 금액을 예약할 수 없는 경우 외부 액션이 실패하지 않고 대신 남은 잔액 전체가 예약됨을 의미합니다. mode에서 비트 +8은 다른 액션을 수행하기 전에 amount <- -amount를 의미합니다. mode에서 비트 +4는 다른 검사와 액션을 수행하기 전에 amount가 모든 추가 통화를 포함하여 현재 계정의 원래 잔액(계산 단계 이전)만큼 증가함을 의미합니다. 현재, amount는 음이 아닌 정수여야 하며, mode0..15 범위에 있어야 합니다.

raw_reserve_extra

() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX";

raw_reserve와 유사하지만 추가 통화를 가진 딕셔너리 extra_amount(cell 또는 null로 표현됨)도 받습니다. 이 방식으로 Toncoin 이외의 통화도 예약할 수 있습니다.

send_raw_message

() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG";

msg에 포함된 원시 메시지를 전송합니다. msg는 객체 Message X를 올바르게 직렬화한 것이어야 하며, 소스 주소가 더미 값 addr_none을 가질 수 있다는 점(현재 스마트 컨트랙트 주소로 자동 대체됨)과 ihr_fee, fwd_fee, created_lt, created_at 필드가 임의의 값을 가질 수 있다는 점(현재 트랜잭션의 액션 단계에서 올바른 값으로 재작성됨)만이 예외입니다. 정수 매개변수 mode는 플래그를 포함합니다.

현재 메시지에 대해 3가지 모드와 4가지 플래그가 있습니다. 단일 모드와 여러(또는 없는) 플래그를 조합하여 필요한 mode를 얻을 수 있습니다. 조합은 단순히 값들의 합을 의미합니다. 모드와 플래그에 대한 설명은 아래 표에 제공됩니다.

모드설명
0일반 메시지
64새 메시지에 처음 표시된 값 외에도 인바운드 메시지의 남은 값 전체를 전달
128메시지에 원래 표시된 값 대신 현재 스마트 컨트랙트의 남은 잔액 전체를 전달
플래그설명
+1전송 수수료를 메시지 값과 별도로 지불
+2액션 단계에서 이 메시지를 처리하는 동안 발생하는 일부 오류 무시(아래 참고 확인)
+16액션 실패 시 - 트랜잭션 반송. +2가 사용되는 경우 효과 없음
+32결과 잔액이 0인 경우 현재 계정이 파괴되어야 함(종종 모드 128과 함께 사용됨)
+2 플래그
  1. Toncoin이 부족한 경우:
    • 메시지와 함께 전송할 값이 부족함(인바운드 메시지 값이 모두 소비됨).
    • 메시지를 처리할 자금이 부족함.
    • 전달 수수료를 지불할 메시지에 첨부된 값이 부족함.
    • 메시지와 함께 보낼 추가 통화가 부족함.
    • 아웃바운드 외부 메시지에 대한 지불 자금이 부족함.
  2. 메시지가 너무 큼(Message size 참고).
  3. 메시지의 머클 깊이가 너무 큼.

하지만 다음 시나리오의 오류는 무시하지 않습니다:

  1. 메시지 형식이 잘못됨.
  2. 메시지 모드가 64와 128 모드를 모두 포함함.
  3. 아웃바운드 메시지가 StateInit에 잘못된 라이브러리를 포함함.
  4. 외부 메시지가 일반적이지 않거나 +16 또는 +32 플래그를 포함하거나 둘 다 포함함.
경고
  1. +16 플래그 - 외부 메시지(예: 지갑으로)에서 사용하지 마세요. 반송된 메시지를 받을 발신자가 없기 때문입니다.
  2. +2 플래그 - 외부 메시지(예: 지갑으로)에서 중요합니다.

use case 예제를 여기에서 볼 수 있습니다.

set_code

() set_code(cell new_code) impure asm "SETCODE";

이 스마트 컨트랙트 코드를 셀 new_code가 제공하는 코드로 변경하는 출력 액션을 생성합니다. 이 변경은 현재 스마트 컨트랙트 실행이 성공적으로 종료된 후에만 효과가 있습니다. (set_c3와 비교)

난수 생성기 프리미티브

의사 난수 생성기는 부호 없는 256비트 정수인 난수 시드와 (때때로) c7에 보관된 다른 데이터를 사용합니다. TON 블록체인에서 스마트 컨트랙트가 실행되기 전의 초기 난수 시드 값은 스마트 컨트랙트 주소와 전역 블록 난수 시드의 해시입니다. 한 블록 내에서 같은 스마트 컨트랙트의 여러 실행이 있는 경우, 이 모든 실행은 동일한 난수 시드를 가지게 됩니다. 이는 의사 난수 생성기를 처음 사용하기 전에 randomize_lt를 실행하여 해결할 수 있습니다.

주의

Keep in mind that random numbers generated by the functions below can be predicted if you do not use additional tricks.

random

int random() impure asm "RANDU256";

새로운 의사 난수 부호 없는 256비트 정수 x를 생성합니다. 알고리즘은 다음과 같습니다: 난수 시드의 이전 값 r을 32바이트 배열로 간주하면(부호 없는 256비트 정수의 빅엔디안 표현을 구성하여), sha512(r)이 계산됩니다; 이 해시의 첫 32바이트는 새로운 값 r'으로 난수 시드에 저장되고, 나머지 32바이트는 다음 난수 값 x로 반환됩니다.

rand

int rand(int range) impure asm "RAND";

범위 0..range−1(또는 range < 0인 경우 range..−1) 내의 새로운 의사 난수 정수 z를 생성합니다. 더 정확히는, random에서처럼 부호 없는 난수 값 x가 생성됩니다; 그런 다음 z := x * range / 2^256이 계산됩니다.

get_seed

int get_seed() impure asm "RANDSEED";

현재 난수 시드를 부호 없는 256비트 정수로 반환합니다.

set_seed

int set_seed(int seed) impure asm "SETRAND";

난수 시드를 부호 없는 256비트 seed로 설정합니다.

randomize

() randomize(int x) impure asm "ADDRAND";

부호 없는 256비트 정수 x를 난수 시드 r에 혼합합니다. 두 개의 32바이트 문자열의 연결의 sha256을 계산하여 난수 시드를 설정합니다: 첫 번째는 이전 시드 r의 빅엔디안 표현이고, 두 번째는 x의 빅엔디안 표현입니다.

randomize_lt

() randomize_lt() impure asm "LTIME" "ADDRAND";

randomize(cur_lt());와 동일합니다.

주소 조작 프리미티브

아래 나열된 주소 조작 프리미티브들은 다음 TL-B 스키마에 따라 값을 직렬화하고 역직렬화합니다.

addr_none$00 = MsgAddressExt;

addr_extern$01 len:(## 8) external_address:(bits len)
= MsgAddressExt;

anycast_info$_ depth:(#<= 30) { depth >= 1 }
rewrite_pfx:(bits depth) = Anycast;

addr_std$10 anycast:(Maybe Anycast)
workchain_id:int8 address:bits256 = MsgAddressInt;

addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
_ _:MsgAddressInt = MsgAddress;
_ _:MsgAddressExt = MsgAddress;

int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddress dest:MsgAddressInt
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;

ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;

역직렬화된 MsgAddress는 다음과 같이 튜플 t로 표현됩니다:

  • addr_nonet = (0)로 표현됩니다. 즉, 정확히 하나의 0인 정수를 포함하는 튜플입니다
  • addr_externt = (1, s)로 표현됩니다. 여기서 slice sexternal_address 필드를 포함합니다. 다시 말해, t는 1과 slice s를 포함하는 쌍(두 개의 항목으로 구성된 튜플)입니다
  • addr_stdt = (2, u, x, s)로 표현됩니다. 여기서 uanycast가 없는 경우 null이거나 anycast가 있는 경우 rewrite_pfx를 포함하는 slice s'입니다. xworkchain_id이고 slice s는 주소를 포함합니다
  • addr_vart = (3, u, x, s)로 표현됩니다. 여기서 u, x, saddr_std와 동일한 의미를 가집니다

load_msg_addr

(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR";

slice s에서 유효한 MsgAddress인 유일한 접두사를 로드하고 이 접두사 s's의 나머지 s''를 slice로 반환합니다.

parse_addr

tuple parse_addr(slice s) asm "PARSEMSGADDR";

유효한 MsgAddress를 포함하는 slice s를 이 MsgAddress의 개별 필드를 가진 tuple t로 분해합니다. s가 유효한 MsgAddress가 아닌 경우 셀 역직렬화 예외가 발생합니다.

parse_std_addr

(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR";

유효한 MsgAddressInt(일반적으로 msg_addr_std)를 포함하는 slice s를 파싱하고, anycast(있는 경우)의 재작성을 주소의 같은 길이 접두사에 적용하며, workchain과 256비트 주소를 모두 정수로 반환합니다. 주소가 256비트가 아니거나 sMsgAddressInt의 유효한 직렬화가 아닌 경우 셀 역직렬화 예외가 발생합니다.

parse_var_addr

(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR";

parse_std_addr의 변형으로, 정확히 256비트가 아닌 경우에도(msg_addr_var로 표현됨) (재작성된) 주소를 slice s로 반환합니다.

디버그 프리미티브

디버그 프리미티브는 테스트나 콘솔 스크립트를 실행하는 동안 다양한 변수의 상태를 검사하는 데 사용될 수 있습니다.

~dump

forall X -> () ~dump(X value) impure asm "s0 DUMP";

값을 출력합니다. 여러 값을 튜플로 덤프할 수 있습니다. 예: ~dump([v1, v2, v3]).

~strdump

() ~strdump(slice str) impure asm "STRDUMP";

문자열을 덤프합니다. Slice 매개변수의 비트 길이는 8로 나누어 떨어져야 합니다.

dump_stack

() dump_stack() impure asm "DUMPSTK";

스택을 덤프합니다(최대 상위 255개 값)하고 총 스택 깊이를 보여줍니다.

Slice 프리미티브

프리미티브가 데이터와 slice의 나머지를 반환하는 경우 그것은 데이터를 _로드_한다고 합니다(따라서 수정 메서드로도 사용될 수 있습니다).

프리미티브가 데이터만 반환하는 경우 그것은 데이터를 _미리 로드_한다고 합니다(비수정 메서드로 사용될 수 있습니다).

달리 명시되지 않는 한, 로딩과 미리 로딩 프리미티브는 slice의 접두사에서 데이터를 읽습니다.

begin_parse

slice begin_parse(cell c) asm "CTOS";

cellslice로 변환합니다. c는 일반 셀이거나 자동으로 로드되어 나중에 slice로 변환되는 일반 셀 c'를 생성하는 특수 셀(TVM.pdf, 3.1.2 참조)이어야 합니다.

end_parse

() end_parse(slice s) impure asm "ENDS";

s가 비어 있는지 확인합니다. 그렇지 않으면 예외를 발생시킵니다.

load_ref

(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF";

slice에서 첫 번째 참조를 로드합니다.

preload_ref

cell preload_ref(slice s) asm "PLDREF";

slice에서 첫 번째 참조를 미리 로드합니다.

load_int

;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX";

slice에서 부호 있는 len비트 정수를 로드합니다.

load_uint

;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX";

slice에서 부호 없는 len비트 정수를 로드합니다.

preload_int

;; int preload_int(slice s, int len) asm "PLDIX";

slice에서 부호 있는 len비트 정수를 미리 로드합니다.

preload_uint

;; int preload_uint(slice s, int len) asm "PLDUX";

slice에서 부호 없는 len비트 정수를 미리 로드합니다.

load_bits

;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX";

slice s에서 첫 0 ≤ len ≤ 1023 비트를 별도의 slice s''로 로드합니다.

preload_bits

;; slice preload_bits(slice s, int len) asm "PLDSLICEX";

slice s에서 첫 0 ≤ len ≤ 1023 비트를 별도의 slice s''로 미리 로드합니다.

load_coins

(slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS";

직렬화된 Toncoin 금액을 로드합니다(최대 2^120 - 1까지의 부호 없는 정수).

skip_bits

slice skip_bits(slice s, int len) asm "SDSKIPFIRST";
(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST";

s의 첫 0 ≤ len ≤ 1023 비트를 제외한 모든 비트를 반환합니다.

first_bits

slice first_bits(slice s, int len) asm "SDCUTFIRST";

s의 첫 0 ≤ len ≤ 1023 비트를 반환합니다.

skip_last_bits

slice skip_last_bits(slice s, int len) asm "SDSKIPLAST";
(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST";

s의 마지막 0 ≤ len ≤ 1023 비트를 제외한 모든 비트를 반환합니다.

slice_last

slice slice_last(slice s, int len) asm "SDCUTLAST";

s의 마지막 0 ≤ len ≤ 1023 비트를 반환합니다.

load_dict

(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT";

slice s에서 딕셔너리 D를 로드합니다. 딕셔너리나 임의의 Maybe ^Y 타입의 값에 적용될 수 있습니다(nothing 생성자가 사용되는 경우 null을 반환).

preload_dict

cell preload_dict(slice s) asm "PLDDICT";

slice s에서 딕셔너리 D를 미리 로드합니다.

skip_dict

slice skip_dict(slice s) asm "SKIPDICT";

load_dict처럼 딕셔너리를 로드하지만 slice의 나머지만 반환합니다.

Slice 크기 프리미티브

slice_refs

int slice_refs(slice s) asm "SREFS";

slice s의 참조 수를 반환합니다.

slice_bits

int slice_bits(slice s) asm "SBITS";

slice s의 데이터 비트 수를 반환합니다.

slice_bits_refs

(int, int) slice_bits_refs(slice s) asm "SBITREFS";

s의 데이터 비트 수와 참조 수를 모두 반환합니다.

slice_empty?

int slice_empty?(slice s) asm "SEMPTY";

slice s가 비어 있는지(즉, 데이터 비트나 셀 참조가 없는지) 확인합니다.

slice_data_empty?

int slice_data_empty?(slice s) asm "SDEMPTY";

slice s에 데이터 비트가 없는지 확인합니다.

slice_refs_empty?

int slice_refs_empty?(slice s) asm "SREMPTY";

slice s에 참조가 없는지 확인합니다.

slice_depth

int slice_depth(slice s) asm "SDEPTH";

slice s의 깊이를 반환합니다. s에 참조가 없으면 0을 반환합니다; 그렇지 않으면 반환되는 값은 s에서 참조된 셀들의 깊이의 최댓값에 1을 더한 값입니다.

Builder 프리미티브

프리미티브가 builder b에 값 x를 _저장_한다고 하면, 그것은 값 x가 끝에 저장된 builder b의 수정된 버전 b'를 반환합니다. 비수정 메서드로 사용될 수 있습니다.

아래 나열된 모든 프리미티브는 먼저 builder에 충분한 공간이 있는지 확인한 다음, 직렬화되는 값의 범위를 확인합니다.

begin_cell

builder begin_cell() asm "NEWC";

새로운 빈 builder를 생성합니다.

end_cell

cell end_cell(builder b) asm "ENDC";

builder를 일반 cell로 변환합니다.

store_ref

builder store_ref(builder b, cell c) asm(c b) "STREF";

builder b에 cell c에 대한 참조를 저장합니다.

store_uint

builder store_uint(builder b, int x, int len) asm(x b len) "STUX";

builder b에 부호 없는 len비트 정수 x를 저장합니다(0 ≤ len ≤ 256).

store_int

builder store_int(builder b, int x, int len) asm(x b len) "STIX";

builder b에 부호 있는 len비트 정수 x를 저장합니다(0 ≤ len ≤ 257).

store_slice

builder store_slice(builder b, slice s) asm "STSLICER";

builder b에 slice s를 저장합니다.

store_grams

builder store_grams(builder b, int x) asm "STGRAMS";

store_coins

builder store_coins(builder b, int x) asm "STGRAMS";

범위 0..2^120 − 1의 정수 x를 builder b에 저장(직렬화)합니다. x의 직렬화는 4비트 부호 없는 빅엔디안 정수 l로 구성되며, 이는 x < 2^8l를 만족하는 가장 작은 정수 l ≥ 0이고, 그 뒤에 x8l비트 부호 없는 빅엔디안 표현이 따릅니다. x가 지원되는 범위에 속하지 않으면 범위 체크 예외가 발생합니다.

이것은 Toncoin을 저장하는 가장 일반적인 방법입니다.

store_dict

builder store_dict(builder b, cell c) asm(c b) "STDICT";

cell c 또는 null로 표현되는 딕셔너리 D를 builder b에 저장합니다. 다시 말해, cnull이 아닌 경우 1비트와 c에 대한 참조를, 그렇지 않은 경우 0비트를 저장합니다.

store_maybe_ref

builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";

store_dict와 동일합니다.

Builder 크기 프리미티브

builder_refs

int builder_refs(builder b) asm "BREFS";

builder b에 이미 저장된 셀 참조의 수를 반환합니다.

builder_bits

int builder_bits(builder b) asm "BBITS";

builder b에 이미 저장된 데이터 비트의 수를 반환합니다.

builder_depth

int builder_depth(builder b) asm "BDEPTH";

builder b의 깊이를 반환합니다. b에 셀 참조가 저장되어 있지 않으면 0을 반환합니다; 그렇지 않으면 반환되는 값은 b에서 참조된 셀들의 깊이의 최댓값에 1을 더한 값입니다.

Cell 프리미티브

cell_depth

int cell_depth(cell c) asm "CDEPTH";

cell c의 깊이를 반환합니다. c에 참조가 없으면 0을 반환합니다; 그렇지 않으면 반환되는 값은 c에서 참조된 셀들의 깊이의 최댓값에 1을 더한 값입니다. c가 cell 대신 null인 경우 0을 반환합니다.

cell_null?

int cell_null?(cell c) asm "ISNULL";

cnull인지 확인합니다. 일반적으로 null-cell은 빈 딕셔너리를 나타냅니다. FunC는 또한 다형성 null? 내장 함수를 가지고 있습니다. (내장 함수 참조.)

딕셔너리 프리미티브

주의

아래의 딕셔너리 프리미티브들은 저수준이며 적용되는 셀의 구조가 연산 시그니처와 일치하는지 확인하지 않습니다. 예를 들어, "비딕셔너리"에 딕셔너리 연산을 적용하거나 하나의 딕셔너리에 8비트 부호 있는 키와 7비트 부호 없는 키로 동시에 키-값을 쓰는 것과 같이 다른 종류의 키를 가진 딕셔너리에 해당하는 연산을 적용하는 것은 정의되지 않은 동작입니다. 이러한 경우 종종 예외가 발생하지만, 드문 경우에는 잘못된 값이 쓰이거나 읽힐 수 있습니다. 개발자들은 이러한 코드를 강력히 피하는 것이 좋습니다.

TVM.pdf에서 언급된 바와 같이:

딕셔너리는 TVM 스택 값으로 두 가지 다른 표현을 가질 수 있습니다:

  • HashmapE(n, X) 타입의 TL-B 값의 직렬화를 포함하는 slice s. 다시 말해, s는 딕셔너리가 비어 있는 경우 0과 같은 하나의 비트로 구성되거나, 1과 같은 하나의 비트와 이진 트리의 루트를 포함하는 셀에 대한 참조(즉, Hashmap(n, X) 타입의 직렬화된 값)로 구성됩니다.
  • "Maybe cell" c^?, 즉 (이전과 같이 Hashmap(n, X) 타입의 직렬화된 값을 포함하는) 셀이거나 (빈 딕셔너리에 해당하는) null인 값입니다(참조: null 값). "Maybe cell" c^?가 딕셔너리를 나타내는 데 사용될 때, 우리는 일반적으로 이를 D로 표시합니다.

아래 나열된 대부분의 딕셔너리 프리미티브는 스택 조작에 더 편리한 두 번째 형태로 딕셔너리를 받고 반환합니다. 하지만 더 큰 TL-B 객체 내의 직렬화된 딕셔너리는 첫 번째 표현을 사용합니다.

FunC에서 딕셔너리도 cell 타입으로 표현되며 null 값일 수 있다는 암시적 가정이 있습니다. 서로 다른 키 길이나 값 타입을 가진 딕셔너리에 대한 별도의 타입은 없습니다(결국, 이건 FunC++가 아닌 FunC입니다).

분류 참고

딕셔너리 프리미티브는 딕셔너리의 키를 부호 없는 l비트 정수, 부호 있는 l비트 정수, 또는 l비트 slice로 해석할 수 있습니다. 아래 나열된 프리미티브들은 이름에서 "dict" 단어 앞의 접두사로 구분됩니다. i는 부호 있는 정수 키, u는 부호 없는 정수 키, 빈 접두사는 slice 키를 나타냅니다.

예를 들어, udict_set은 부호 없는 정수 키를 가진 딕셔너리의 키별 설정 함수입니다; idict_set은 부호 있는 정수 키에 대한 해당 함수입니다; dict_set은 slice 키에 대한 함수입니다.

제목에는 빈 접두사가 사용됩니다.

또한 일부 프리미티브들은 ~가 접두사로 붙은 대응물을 가지고 있습니다. 이를 통해 수정 메서드로 사용할 수 있습니다.

딕셔너리의 값

딕셔너리 내의 값들은 내부 딕셔너리 셀의 하위 슬라이스로 저장되거나 별도의 셀에 대한 참조를 통해 저장될 수 있습니다. 전자의 경우, 셀에 들어갈 만큼 작은 값이 딕셔너리에도 맞을 것이라고 보장할 수 없습니다. 내부 셀의 공간 중 일부가 이미 해당 키의 일부로 차지되어 있을 수 있기 때문입니다. 반대로, 후자의 저장 방법은 가스 사용 면에서 덜 효율적입니다. 두 번째 방법을 사용하여 값을 저장하는 것은 첫 번째 방법에서 데이터 비트가 없고 값에 대한 단일 참조만 있는 슬라이스를 삽입하는 것과 같습니다.

dict_set

cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET";
cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET";
(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET";
(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET";

딕셔너리 dict에서 key_len비트 키 index와 연관된 값을 value(slice)로 설정하고 결과 딕셔너리를 반환합니다.

dict_set_ref

cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";
cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";
(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";

dict_set과 유사하지만 값을 cell value에 대한 참조로 설정합니다.

dict_get?

(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT";
(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT";

key_len 비트의 키를 사용하는 dict 딕셔너리 내에서 키 index를 검색합니다. 성공하면 연관된 값을 slice로 검색하고 성공을 나타내는 플래그 값 -1을 반환합니다. 검색이 실패하면 (null, 0)을 반환합니다.

dict_get_ref?

(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF";
(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF";

dict_get?와 유사하지만 찾은 값의 첫 번째 참조를 반환합니다.

dict_get_ref

cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF";

dict_get_ref?의 변형으로, 키 index가 딕셔너리 dict에 없는 경우 값 대신 null을 반환합니다.

dict_set_get_ref

(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF";
(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF";

index와 연관된 값을 value로 설정하고(valuenull인 경우 대신 키가 삭제됨) 이전 값을 반환합니다(또는 값이 없었던 경우 null을 반환).

dict_delete?

(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL";
(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL";

딕셔너리 dict에서 key_len비트 키 index를 삭제합니다. 키가 있으면 수정된 딕셔너리 dict'와 성공 플래그 −1을 반환합니다. 그렇지 않으면 원래 딕셔너리 dict0을 반환합니다.

dict_delete_get?

(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT";
(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT";
(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT";
(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT";

딕셔너리 dict에서 key_len비트 키 index를 삭제합니다. 키가 있으면 수정된 딕셔너리 dict', 키 k와 연관된 원래 값 x(Slice로 표현), 성공 플래그 −1을 반환합니다. 그렇지 않으면 (dict, null, 0)을 반환합니다.

dict_add?

(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD";
(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD";

dict_setadd 대응물로, 딕셔너리 dict에서 키 index와 연관된 값을 value로 설정하지만 D에 이미 있는 경우에만 가능합니다. 딕셔너리의 수정된 버전과 -1 플래그를 반환하거나 (dict, 0)을 반환합니다.

dict_replace?

(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE";
(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE";

dict_set과 유사한 replace 연산이지만 키가 dict에 이미 있는 경우에만 딕셔너리 dict에서 키 index의 값을 value로 설정합니다. 딕셔너리의 수정된 버전과 -1 플래그를 반환하거나 (dict, 0)을 반환합니다.

Builder 대응물

다음 프리미티브들은 새 값을 slice 대신 builder로 받습니다. 이는 값을 스택에서 계산된 여러 컴포넌트로부터 직렬화해야 하는 경우에 더 편리한 경우가 많습니다. 순효과는 대략적으로 b를 slice로 변환하고 위에 나열된 해당 프리미티브를 실행하는 것과 동등합니다.

dict_set_builder

cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB";
cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB";
cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB";
(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB";
(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB";
(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB";

dict_set과 유사하지만 builder를 받습니다.

dict_add_builder?

(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB";
(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB";

dict_add?와 유사하지만 builder를 받습니다.

dict_replace_builder?

(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB";
(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB";

dict_replace?와 유사하지만 builder를 받습니다.

dict_delete_get_min

(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";

딕셔너리 dict에서 최소 키 k를 계산하고, 이를 제거한 후 (dict', k, x, -1)을 반환합니다. 여기서 dict'dict의 수정된 버전이고 xk와 연관된 값입니다. dict가 비어 있으면 (dict, null, null, 0)을 반환합니다.

idict_delete_get_min이 반환하는 키는 dict_delete_get_minudict_delete_get_min이 반환하는 키와 다를 수 있습니다.

dict_delete_get_max

(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";

딕셔너리 dict에서 최대 키 k를 계산하고, 이를 제거한 후 (dict', k, x, -1)을 반환합니다. 여기서 dict'dict의 수정된 버전이고 xk와 연관된 값입니다. dict가 비어 있으면 (dict, null, null, 0)을 반환합니다.

dict_get_min?

(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2";
(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";

딕셔너리 dict에서 최소 키 k, 연관된 값 x를 계산하고 (k, x, -1)을 반환합니다. 딕셔너리가 비어 있으면 (null, null, 0)을 반환합니다.

dict_get_max?

(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2";
(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2";

딕셔너리 dict에서 최대 키 k, 연관된 값 x를 계산하고 (k, x, -1)을 반환합니다. 딕셔너리가 비어 있으면 (null, null, 0)을 반환합니다.

dict_get_min_ref?

(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2";
(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2";

dict_get_min?과 유사하지만 값의 유일한 참조를 참조로 반환합니다.

dict_get_max_ref?

(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2";
(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2";

dict_get_max?와 유사하지만 값의 유일한 참조를 참조로 반환합니다.

dict_get_next?

(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2";
(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2";

딕셔너리 dict에서 pivot보다 큰 최소 키 k를 계산합니다; k, 연관된 값, 성공을 나타내는 플래그를 반환합니다. 딕셔너리가 비어 있으면 (null, null, 0)을 반환합니다.

dict_get_nexteq?

(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2";
(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2";

dict_get_next?와 유사하지만 pivot보다 크거나 같은 최소 키 k를 계산합니다.

dict_get_prev?

(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2";
(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2";

dict_get_next?와 유사하지만 pivot보다 작은 최대 키 k를 계산합니다.

dict_get_preveq?

(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2";
(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2";

dict_get_prev?와 유사하지만 pivot보다 작거나 같은 최대 키 k를 계산합니다.

new_dict

cell new_dict() asm "NEWDICT";

빈 딕셔너리를 생성합니다. 실제로는 null 값입니다. null()의 특별한 경우입니다.

dict_empty?

int dict_empty?(cell c) asm "DICTEMPTY";

딕셔너리가 비어 있는지 확인합니다. cell_null?와 동일합니다.

접두사 딕셔너리 프리미티브

TVM은 고정되지 않은 길이의 키를 가진 딕셔너리도 지원합니다. 이 키들은 접두사 코드를 형성합니다(즉, 다른 키의 접두사인 키는 없습니다). TVM 명령어 섹션에서 자세히 알아보세요.

pfxdict_get?

(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2";

(s', x, s'', -1) 또는 (null, null, s, 0)을 반환합니다. 접두사 코드 딕셔너리 dict에 있는 slice key의 유일한 접두사를 찾습니다. 찾으면 s의 접두사를 s'로, 해당 값(역시 slice)을 x로 반환합니다. s의 나머지는 slice s''로 반환됩니다. s의 어떤 접두사도 접두사 코드 딕셔너리 dict의 키가 아닌 경우, 변경되지 않은 s와 실패를 나타내는 0 플래그를 반환합니다.

pfxdict_set?

(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET";

dict_set과 유사하지만 키가 딕셔너리에 이미 있는 다른 키의 접두사인 경우 실패할 수 있습니다. 성공을 나타내는 플래그를 반환합니다.

pfxdict_delete?

(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL";

dict_delete?와 유사합니다.

특수 프리미티브

null

forall X -> X null() asm "PUSHNULL";

TVM 타입 Null로, FunC는 일부 원자적 타입 값의 부재를 나타냅니다. 따라서 null은 실제로 어떤 원자적 타입도 가질 수 있습니다.

~impure_touch

forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP";

변수를 사용된 것으로 표시하여, 그것을 생성한 코드가 impure가 아니더라도 삭제되지 않도록 합니다. (impure 지정자 참조)

기타 프리미티브

min

int min(int x, int y) asm "MIN";

두 정수 xy 중 더 작은 값을 계산합니다.

max

int max(int x, int y) asm "MAX";

두 정수 xy 중 더 큰 값을 계산합니다.

minmax

(int, int) minmax(int x, int y) asm "MINMAX";

두 정수를 정렬합니다.

abs

int abs(int x) asm "ABS";

정수 x의 절댓값을 계산합니다.