Code conventions ================ Language dialect ---------------- For greater portability, the code should be ANSI C compatible where possible. We note the following exceptions: - Inlined functions, inlined assembly. We define alternative keywords __asm__ and __inline__ in flint.h so that gcc allows compiling with the flags "-ansi -pendatic" nonetheless. Build system ------------ Each module should go in Makefile.in and in CMakeLists.txt under BUILD_DIRS. Each module should have a non-empty test directory. The file names in a module should friendly to case-insensitivity, i.e. it is not a good idea to have both fmpz/FOO.c and fmpz/foo.c. Primitive types --------------- Depending on the main interpretation of the value of a variable, where possible the following primitive datatype should be used: | bit counts up to a single limb | ulong | | bit counts, multiprecision | mp_bitcnt_t | | byte counts (strings) | size_t | | limb counts in multiprecision integers | mp_size_t | | limbs (unsigned/signed) | mp_limb_t/ mp_limb_signed_t | | mp_limb_t arrays | mp_ptr/ mp_srcptr | | ui/ si function constants | ulong/ slong | | exponents (unsigned/signed) | ulong/ slong | | polynomial lengths | slong | | number of indeterminates | slong | | row/ column indices | slong | | precision for mpfr types | mpfr_prec_t | The typical definitions of these in terms of primitive types are: | mp_bitcnt_t | ulong, or ulong long | | mp_size_t | long, or long long | | mp_limb_t | ulong, or ulong long | | mp_ptr | mp_limb_t * | | mp_srcptr | const mp_limb_t * | | slong | long or long long | | ulong | ulong or ulong long | Constant integers ----------------- Because the ulong/slong types can be (unsigned) long on Linux and (unsigned) long long on Windows, we cannot use the usual 123456789UL to declare them. Instead, we provide two macros: WORD(123456789) /* slong constant */ UWORD(123456789) /* ulong constant */ Format specifiers ----------------- Again, because a ulong/slong use different types on Windows and Linux, we cannot use the format specifers %lu/%ld in printf. For this purpose we provide the flint_printf functions, which is the same as printf, except that it supports: flint_printf("%wu", d); /* print ulong */ flint_printf("%wd", d); /* print slong */ Use of const ------------ Input parameters to functions should be marked const in the following cases: * complex types that are passed by reference, e.g. fmpz_poly_t They should not be used on output parameters or for simple types or simple structs which are passed by value and not reference, e.g. nmod_t. Random functions ---------------- When writing functions which produce random values the order of operands should follow one of the following: if the function returns its random value, the state comes first, e.g: a = n_randint(state, n) if the function sets its first argument to a random value, the state comes second, e.g. nmod_poly_randtest(poly, state, len, bits) Conversion functions -------------------- When naming functions which convert between objects of different modules, use the convention module1_get_module2 and module1_set_module2, where module1 is notionally the more complex of the two modules. E.g. fmpz_poly_get_nmod_poly. The set function should set an object of module1 to the value of an object of module2, and the get function should do the opposite. Function prototypes ------------------- All function prototypes in .h files in FLINT require a FLINT_DLL declaration in front of them. Please keep the initial part of the prototype all on a single line, rather than placing the FLINT_DLL and/or return type on a different line, e.g. prototypes should look like this: FLINT_DLL void myfunc(blah, .... ...., blah, blah) Note that dll import/export is handled differently for inlines. Please don't add FLINT_DLL to inline functions. Rather, add a single FLINT_DLL to the non-inline branch inside the relevant BLAH_INLINES_C #define at the top of the .h file. Underscores in function names ----------------------------- Generally, underscores should not be used in function names to "hide" them. Instead, append _internal or _helper or just make the function static in the file in which it is used and give it a very descriptive name. Underscores at the beginning of function names have a special meaning in Flint. Functions without underscores generally are user facing in the sense that they handle aliasing (if appropriate), memory management and deal with objects that have structs associated to them. Functions with underscores are lower level and may have restrictions, such as not handling aliasing, assuming all objects have already been resized to have enough space for the output to be written and typically take many more arguments, corresponding to the various entries of higher level structs, e.g. an array of coefficients and a length instead of a polynomial struct. Threading --------- Flint uses a custom thread pool for threading. This involves creating a worker function, requesting threads from the thread pool, starting the threads, waiting for them to finish, then giving the threads back to the pool. Simple examples of this include fmpz_mod_mat_mul_classical_threaded and fmpz_poly_taylor_shift_multi_mod. The user should not have to run specialised versions of functions to get threading. This means that user facing functions should generally not have _threaded appended to their name. Either there is a single function that does the job, and it happens to be threaded, or there is a best-of-breed function that calls the appropriate threaded function when this is the best strategy. There are some instances where it may be desirable (e.g. for testing purposes, or because naming proves difficult) where one wants a _threaded in the name. But these cases should be rare. In some cases, one does not want functions to request threads from the pool themselves, but to accept threads from another function which has already obtained them. Such functions will accept an array of thread pool handles and a number of threads. The naming convention for such functions is to append _threaded_pool to the end of their name. However, the usual distinctions between underscore and non-underscore functions should still apply. Functions should request flint_get_num_threads() threads from the thread pool. The function should not exceed this number of threads in total. In general a thread that is woken should start zero additional workers. However, if this is not the desired behaviour, an option exists to the function for waking worker threads to alter how many threads it can start. In some cases it is also necessary to temporarily restrict the number of worker threads a given function can start. This is accomplished by calling flint_set_num_workers() and then once the function is called, calling flint_reset_num_workers(). Any function threaded function which calls flint_get_num_threads() to determine how many threads to request from the thread pool will be appropriately restricted by such calls. Note that if flint_get_num_threads() returns n then the number of workers that can be started is n - 1 (in addition to the thread the function is already running in). For this reason our documentation often distinguishes number of workers and number of threads. Please refer to the thread pool interface and Flint threading interface documentation to see the exact specification. Code formatting --------------- The C code should follow the style produced by the following call to "indent", indent -bap -blf -bli0 -cbi0 -cdw -cli4 -cs -i4 -l79 -nbad -nbc -nce -npcs -nprs -nut -pmt -psl -saf -sai -saw -sbi0 -ss -ts4 which is explained as follows: -bap Force blank lines after procedure bodies -blf Put braces on line following function definition line -bli0 Indent braces 0 spaces -cbi0 Indent braces after a case label 0 spaces -cdw Cuddle while of do {} while -cli4 Case label indent of 4 spaces -cs Put a space after a cast operator -i4 Set indentation level to 4 spaces -l79 Set maximum line length for non-comment lines to 79 -nbad Do not force blank lines after declarations -nbc Do not force newlines after commas in declarations -nce Do not cuddle else -npcs Do not put a space after the function in function calls -nprs Do not put a space after every ( and before every ) -nut Use spaces instead of tabs -pmt Preserve access and modificaion times on output files -psl Put the type of a procedure on the line before its name -saf Put a space before each for -sai Space after each for -saw Space after every while -sbi0 Indent braces of a struct, union or enum 0 spaces -ss On one-line for and while statements, for a blank before ; -ts4 Set tab size to 4 spaces