#define EURYDICE_ASSERT(test, msg) \ do { \ if (!(test)) { \
fprintf(stderr, "assertion \"%s\" failed: file \"%s\", line %d\n", msg, \
__FILE__, __LINE__); \ exit(255); \
} \
} while (0)
// SLICES, ARRAYS, ETC.
// We represent a slice as a pair of an (untyped) pointer, along with the length // of the slice, i.e. the number of elements in the slice (this is NOT the // number of bytes). This design choice has two important consequences. // - if you need to use `ptr`, you MUST cast it to a proper type *before* // performing pointer arithmetic on it (remember that C desugars pointer // arithmetic based on the type of the address) // - if you need to use `len` for a C style function (e.g. memcpy, memcmp), you // need to multiply it by sizeof t, where t is the type of the elements. // // Empty slices have `len == 0` and `ptr` always needs to be a valid pointer // that is not NULL (otherwise the construction in EURYDICE_SLICE computes `NULL // + start`). typedefstruct { void *ptr;
size_t len;
} Eurydice_slice;
#ifdefined(__cplusplus) #define KRML_CLITERAL(type) type #else #define KRML_CLITERAL(type) (type) #endif
// Helper macro to create a slice out of a pointer x, a start index in x // (included), and an end index in x (excluded). The argument x must be suitably // cast to something that can decay (see remark above about how pointer // arithmetic works in C), meaning either pointer or array type. #define EURYDICE_SLICE(x, start, end) \
(KRML_CLITERAL(Eurydice_slice){ (void *)(x + start), end - start })
// This macro is a pain because in case the dereferenced element type is an // array, you cannot simply write `t x` as it would yield `int[4] x` instead, // which is NOT correct C syntax, so we add a dedicated phase in Eurydice that // adds an extra argument to this macro at the last minute so that we have the // correct type of *pointers* to elements. #define Eurydice_slice_index(s, i, t, t_ptr_t) (((t_ptr_t)s.ptr)[i])
// The following functions get sub slices from a slice.
// Variant for when the start and end indices are statically known (i.e., the // range argument `r` is a literal). #define Eurydice_slice_subslice2(s, start, end, t) \
EURYDICE_SLICE((t *)s.ptr, (start), (end))
#define Eurydice_array_to_slice(end, x, t) \
EURYDICE_SLICE(x, 0, \
end) /* x is already at an array type, no need for cast */ #define Eurydice_array_to_subslice(_arraylen, x, r, t, _0, _1) \
EURYDICE_SLICE((t *)x, r.start, r.end)
// Same as above, variant for when start and end are statically known #define Eurydice_array_to_subslice2(x, start, end, t) \
EURYDICE_SLICE((t *)x, (start), (end))
// Same as above, variant for when start and end are statically known #define Eurydice_array_to_subslice3(x, start, end, t_ptr) \
EURYDICE_SLICE((t_ptr)x, (start), (end))
#define Eurydice_array_repeat(dst, len, init, t) \
ERROR "should've been desugared"
// The following functions convert an array into a slice.
// Conversion of slice to an array, rewritten (by Eurydice) to name the // destination array, since arrays are not values in C. // N.B.: see note in karamel/lib/Inlining.ml if you change this. #define Eurydice_slice_to_array2(dst, src, _0, t_arr, _1) \
Eurydice_slice_to_array3(&(dst)->tag, (char *)&(dst)->val.case_Ok, src, \ sizeof(t_arr))
// A DST is a fat pointer that keeps tracks of the size of it flexible array // member. Slices are a specific case of DSTs, where [T; N] implements // Unsize<[T]>, meaning an array of statically known size can be converted to a // fat pointer, i.e. a slice. // // Unlike slices, DSTs have a built-in definition that gets monomorphized, of // the form: // // typedef struct { // T *ptr; // size_t len; // number of elements // } Eurydice_dst; // // Furthermore, T = T0<[U0]> where `struct T0<U: ?Sized>`, where the `U` is the // last field. This means that there are two monomorphizations of T0 in the // program. One is `T0<[V; N]>` // -- this is directly converted to a Eurydice_dst via suitable codegen (no // macro). The other is `T = T0<[U]>`, where `[U]` gets emitted to // `Eurydice_derefed_slice`, a type that only appears in that precise situation // and is thus defined to give rise to a flexible array member.
// We slap extern "C" on declarations that intend to implement a prototype // generated by Eurydice, because Eurydice prototypes are always emitted within // an extern "C" block, UNLESS you use -fcxx17-compat, in which case, you must // pass -DKRML_CXX17_COMPAT="" to your C++ compiler. #ifdefined(__cplusplus) && !defined(KRML_CXX17_COMPAT) extern"C" { #endif
staticinlinevoid
core_num__u32__to_be_bytes(uint32_t src, uint8_t dst[4])
{ // TODO: why not store32_be?
uint32_t x = htobe32(src);
memcpy(dst, &x, 4);
}
// See note in karamel/lib/Inlining.ml if you change this #define Eurydice_into_iter(x, t, _ret_t, _) (x) #define core_iter_traits_collect___core__iter__traits__collect__IntoIterator_Clause1_Item__I__for_I__1__into_iter \
Eurydice_into_iter
// Can't use macros Eurydice_slice_subslice_{to,from} because they require a // type, and this static inline function cannot receive a type as an argument. // Instead, we receive the element size and use it to peform manual offset // computations rather than going through the macros. staticinline Eurydice_slice
chunk_next(Eurydice_chunks *chunks,
size_t element_size)
{
size_t chunk_size = chunks->slice.len >= chunks->chunk_size
? chunks->chunk_size
: chunks->slice.len;
Eurydice_slice curr_chunk;
curr_chunk.ptr = chunks->slice.ptr;
curr_chunk.len = chunk_size;
chunks->slice.ptr = (char *)(chunks->slice.ptr) + chunk_size * element_size;
chunks->slice.len = chunks->slice.len - chunk_size; return curr_chunk;
}
// using it anyway?? #define Eurydice_slice_subslice3(s, start, end, t_ptr) \
EURYDICE_SLICE((t_ptr)s.ptr, (start), (end))
/* For now these are passed by value -- three words. We could conceivably change *therepresentationtoheap-allocatethisstructandonlypassaroundthe
* pointer (one word). */ typedefstruct { void *ptr;
size_t len; /* the number of elements */
size_t alloc_size; /* the size of the allocation, in number of BYTES */
} Eurydice_vec_s, *Eurydice_vec;
/* Here, we set everything to zero rather than use a non-standard GCC *statement-expression--thissuitablyinitializesptrtoNULLandlenand
* size to 0. */ #define EURYDICE_VEC_NEW(_) calloc(1, sizeof(Eurydice_vec_s)) #define EURYDICE_VEC_PUSH(v, x, t) \ do { \ /* Grow the vector if capacity has been reached. */ \ if (v->len == v->alloc_size / sizeof(t)) { \ /* Assuming that this does not exceed SIZE_MAX, because code proven \
* correct by Aeneas. Would this even happen in practice? */ \
size_t new_size; \ if (v->alloc_size == 0) \
new_size = 8 * sizeof(t); \ elseif (v->alloc_size <= SIZE_MAX / 2) \ /* TODO: discuss growth policy */ \
new_size = 2 * v->alloc_size; \ else \
new_size = (SIZE_MAX / sizeof(t)) * sizeof(t); \
v->ptr = realloc(v->ptr, new_size); \
v->alloc_size = new_size; \
} \
((t *)v->ptr)[v->len] = x; \
v->len++; \
} while (0)
#define EURYDICE_VEC_DROP(v, t) \ do { \
free(v->ptr); \
free(v); \
} while (0)
#define EURYDICE_VEC_INDEX(v, i, t) &((t *)v->ptr)[i] #define EURYDICE_VEC_LEN(v, t) (v)->len
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.