Idris2/support/refc/stringOps.c
Hattori, Hiroki 1dc7b74e4e
[RefC] Suppress arglist wrapper (#3177)
* [RefC] Suppress code generation for unnecessary arglist wrappers.

* [RefC] cleanup dead code of arglist.

* Removed Value_Arglist to reduce Closure's allocation overhead.

* fix linter error

* [RefC] make trampoline() safety.

* [RefC] cleanup cStatementsFromANF to keep code simple.

* fix linter error

* fix linter error

* In another time, another galaxy. THE LINTER INVADORS conquaer the all humanity and make them slaves. Under 2024, a only leaved job for every humans is adjusting spaces of source code, or just type gg0vG$== in vim.

* [ test ] update golden value

* added supports 32 params on closure.

* [RefC] [Cleanup] removing duplicate codes.

* [RefC] Switch calling conventions based on the number of arguments to avoid limits on the number of arguments and to reduce stack usage.

* [RefC] Argument that are too large are placed on the heap, as are closures.

* [RefC] use idris2_malloc instead of malloc.

* [RefC] [Cleanup] Keep pure things pure.

* [RefC] Mapped some special constructors to NULL. This reduces malloc cost and generates simpler code in ConCase. But not work yet.

* [RefC] fix merge failure.

* [RefC] stringOps.c replace  NULL for NIL.

* [RefC] cleanup

* [RefC] ConstCase now generate simple if-then statements instead of using helpers. This reduces malloc/free costs.

* fix indentation

* fix whitespaces

* [RefC] The name field in Value_Constructor was restored for tycon. But changed to static const*. Hopefully the C compiler will remove the common string constants. The smartest thing to do would be to create a dummy global variable and use its address as a tag, but that would depend on the C compiler to resolve conflicts.

* [refc] a big changes of the space

* [RefC] Little tricks to reduce temporary variables

* spaces

* [RefC] fix compiler warnings

* [RefC] [test]  Perform memory leak analysis, if valgrind is installed.

* [RefC] Fix invalid memory read. Fix C compiler warnings.

* [RefC] Fix invalid memory read of strSubstr. [test] Perform memory leak analysis, if valgrind is installed.

* [test] fix junk line

* linter

* linter

* linter

* linter

* [RefC] merge with erase_trivial_constuctors

* merge w/ erase_trivial_constructors

* Revert "merge w/ erase_trivial_constructors"

This reverts commit be593a3715.

* Revert "[RefC] merge with erase_trivial_constuctors"

This reverts commit 3c21eb45d8.

* merge w/ upstream/main

* fix merge failure

* rename

* fix renaming

* [RefC] fix merge fail

* [RefC] renamed C functions for safty.

* [RefC] cleanup

* [RefC] Fix constructor tag of UnconsResult.CHARACTER.

---------

Co-authored-by: Mathew Polzin <matt.polzin@gmail.com>
Co-authored-by: Guillaume Allais <guillaume.allais@ens-lyon.org>
2024-04-17 15:48:43 +01:00

205 lines
5.4 KiB
C

#include "stringOps.h"
#include "refc_util.h"
Value *tail(Value *input) {
Value_String *tailStr = IDRIS2_NEW_VALUE(Value_String);
tailStr->header.tag = STRING_TAG;
Value_String *s = (Value_String *)input;
int l = strlen(s->str);
if (l != 0) {
tailStr->str = malloc(l);
IDRIS2_REFC_VERIFY(tailStr->str, "malloc failed");
memset(tailStr->str, 0, l);
memcpy(tailStr->str, s->str + 1, l - 1);
return (Value *)tailStr;
} else {
tailStr->str = malloc(1);
IDRIS2_REFC_VERIFY(tailStr->str, "malloc failed");
tailStr->str[0] = '\0';
return (Value *)tailStr;
}
}
Value *reverse(Value *str) {
Value_String *retVal = IDRIS2_NEW_VALUE(Value_String);
retVal->header.tag = STRING_TAG;
Value_String *input = (Value_String *)str;
int l = strlen(input->str);
retVal->str = malloc(l + 1);
IDRIS2_REFC_VERIFY(retVal->str, "malloc failed");
memset(retVal->str, 0, l + 1);
char *p = retVal->str;
char *q = input->str + (l - 1);
for (int i = 0; i < l; i++) {
*p++ = *q--;
}
return (Value *)retVal;
}
Value *strIndex(Value *str, Value *i) {
char *s = ((Value_String *)str)->str;
int idx = idris2_vp_to_Int64(i);
return (Value *)idris2_mkChar(s[idx]);
}
Value *strCons(Value *c, Value *str) {
int l = strlen(((Value_String *)str)->str);
Value_String *retVal = idris2_mkEmptyString(l + 2);
retVal->str[0] = idris2_vp_to_Char(c);
memcpy(retVal->str + 1, ((Value_String *)str)->str, l);
return (Value *)retVal;
}
Value *strAppend(Value *a, Value *b) {
int la = strlen(((Value_String *)a)->str);
int lb = strlen(((Value_String *)b)->str);
Value_String *retVal = idris2_mkEmptyString(la + lb + 1);
memcpy(retVal->str, ((Value_String *)a)->str, la);
memcpy(retVal->str + la, ((Value_String *)b)->str, lb);
return (Value *)retVal;
}
Value *strSubstr(Value *start, Value *len, Value *s) {
char *input = ((Value_String *)s)->str;
int offset = idris2_vp_to_Int64(start); /* start and len was come from Nat. */
int l = idris2_vp_to_Int64(len);
int tailLen = strlen(input) - offset;
if (tailLen < l) {
l = tailLen;
}
Value_String *retVal = idris2_mkEmptyString(l + 1);
memcpy(retVal->str, input + offset, l);
return (Value *)retVal;
}
char *fastPack(Value *charList) {
Value_Constructor *current;
int l = 0;
current = (Value_Constructor *)charList;
while (current != NULL) {
l++;
current = (Value_Constructor *)current->args[1];
}
char *retVal = malloc(l + 1);
retVal[l] = 0;
int i = 0;
current = (Value_Constructor *)charList;
while (current != NULL) {
retVal[i++] = idris2_vp_to_Char(current->args[0]);
current = (Value_Constructor *)current->args[1];
}
return retVal;
}
Value *fastUnpack(char *str) {
if (str[0] == '\0') {
return NULL;
}
Value_Constructor *retVal = idris2_newConstructor(2, 1);
retVal->args[0] = idris2_mkChar(str[0]);
int i = 1;
Value_Constructor *current = (Value_Constructor *)retVal;
Value_Constructor *next;
while (str[i] != '\0') {
next = idris2_newConstructor(2, 1);
next->args[0] = idris2_mkChar(str[i]);
current->args[1] = (Value *)next;
i++;
current = next;
}
current->args[1] = NULL;
return (Value *)retVal;
}
char *fastConcat(Value *strList) {
Value_Constructor *current;
int totalLength = 0;
current = (Value_Constructor *)strList;
while (current != NULL) {
totalLength += strlen(((Value_String *)current->args[0])->str);
current = (Value_Constructor *)current->args[1];
}
char *retVal = malloc(totalLength + 1);
retVal[totalLength] = '\0';
char *currentStr;
int currentStrLen;
int offset = 0;
current = (Value_Constructor *)strList;
while (current != NULL) {
currentStr = ((Value_String *)current->args[0])->str;
currentStrLen = strlen(currentStr);
memcpy(retVal + offset, currentStr, currentStrLen);
offset += currentStrLen;
current = (Value_Constructor *)current->args[1];
}
return retVal;
}
typedef struct {
char *str;
int pos;
} String_Iterator;
Value *stringIteratorNew(char *str) {
int l = strlen(str);
String_Iterator *it = (String_Iterator *)malloc(sizeof(String_Iterator));
IDRIS2_REFC_VERIFY(it, "malloc failed");
it->str = (char *)malloc(l + 1);
it->pos = 0;
memcpy(it->str, str, l + 1); // Take a copy of str, in case it gets GCed
return (Value *)idris2_makeGCPointer(
it, (Value_Closure *)idris2_mkClosure(
(Value * (*)()) onCollectStringIterator, 2, 0));
}
Value *onCollectStringIterator(Value_Pointer *ptr, void *null) {
String_Iterator *it = (String_Iterator *)ptr->p;
free(it->str);
free(it);
return NULL;
}
Value *stringIteratorToString(void *a, char *str, Value *it_p,
Value_Closure *f) {
String_Iterator *it = ((Value_GCPointer *)it_p)->p->p;
Value *strVal = (Value *)idris2_mkString(it->str + it->pos);
return idris2_apply_closure(idris2_newReference((Value *)f), strVal);
}
// contrib/Data.String.Iterator.uncons :
// (str : String) -> (1 it : StringIterator str) -> UnconsResult str
Value *stringIteratorNext(char *s, Value *it_p) {
String_Iterator *it = (String_Iterator *)((Value_GCPointer *)it_p)->p->p;
char c = it->str[it->pos];
if (c == '\0')
return NULL; // EOF [nil]
it->pos++; // Ok to do this as StringIterator linear
// Character [cons]
Value_Constructor *retVal = (Value_Constructor *)idris2_newConstructor(2, 1);
retVal->args[0] = idris2_mkChar(c);
retVal->args[1] = idris2_newReference(it_p);
return (Value *)retVal;
}