Compare commits
10 commits
d565640455
...
fd1172ff56
Author | SHA1 | Date | |
---|---|---|---|
fd1172ff56 | |||
468656eee6 | |||
b625655439 | |||
dab666c969 | |||
36413b4dca | |||
1c32e18c74 | |||
2382638005 | |||
38a303da91 | |||
2f76d5b9ae | |||
93c4b6bfc4 |
34 changed files with 1791 additions and 143 deletions
|
@ -317,12 +317,53 @@ ArrayUnique(Array * array, int (*compare) (void *, void *))
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Even though the following operations could be done using only the
|
/* Even though the following operations could be done using only the
|
||||||
* public Array API defined above, I opted for low-level struct
|
* public Array API defined above, I opted for low-level struct
|
||||||
* manipulation because it allows much more efficient copying; we only
|
* manipulation because it allows much more efficient copying; we only
|
||||||
* allocate what we for sure need upfront, and don't have to
|
* allocate what we for sure need upfront, and don't have to
|
||||||
* re-allocate during the operation. */
|
* re-allocate during the operation. */
|
||||||
|
|
||||||
|
Array *
|
||||||
|
ArrayReverse(Array * array)
|
||||||
|
{
|
||||||
|
Array *ret;
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (!array)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!array->size)
|
||||||
|
{
|
||||||
|
return ArrayCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = Malloc(sizeof(Array));
|
||||||
|
|
||||||
|
size = array->size;
|
||||||
|
|
||||||
|
ret->size = size;
|
||||||
|
ret->allocated = size;
|
||||||
|
ret->entries = Malloc(sizeof(void *) * size);
|
||||||
|
|
||||||
|
if (!ret->entries)
|
||||||
|
{
|
||||||
|
Free(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
ret->entries[i] = array->entries[size - i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Array *
|
Array *
|
||||||
ArrayFromVarArgs(size_t n, va_list ap)
|
ArrayFromVarArgs(size_t n, va_list ap)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
#include <Cron.h>
|
#include <Cron.h>
|
||||||
|
|
||||||
|
#include <UInt64.h>
|
||||||
#include <Array.h>
|
#include <Array.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
|
|
||||||
struct Cron
|
struct Cron
|
||||||
{
|
{
|
||||||
unsigned long tick;
|
UInt64 tick;
|
||||||
Array *jobs;
|
Array *jobs;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
volatile unsigned int stop:1;
|
volatile unsigned int stop:1;
|
||||||
|
@ -40,14 +41,14 @@ struct Cron
|
||||||
|
|
||||||
typedef struct Job
|
typedef struct Job
|
||||||
{
|
{
|
||||||
unsigned long interval;
|
UInt64 interval;
|
||||||
unsigned long lastExec;
|
UInt64 lastExec;
|
||||||
JobFunc *func;
|
JobFunc *func;
|
||||||
void *args;
|
void *args;
|
||||||
} Job;
|
} Job;
|
||||||
|
|
||||||
static Job *
|
static Job *
|
||||||
JobCreate(long interval, JobFunc * func, void *args)
|
JobCreate(UInt32 interval, JobFunc * func, void *args)
|
||||||
{
|
{
|
||||||
Job *job;
|
Job *job;
|
||||||
|
|
||||||
|
@ -62,8 +63,8 @@ JobCreate(long interval, JobFunc * func, void *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
job->interval = interval;
|
job->interval = UInt64Create(0, interval);
|
||||||
job->lastExec = 0;
|
job->lastExec = UInt64Create(0, 0);
|
||||||
job->func = func;
|
job->func = func;
|
||||||
job->args = args;
|
job->args = args;
|
||||||
|
|
||||||
|
@ -78,8 +79,8 @@ CronThread(void *args)
|
||||||
while (!cron->stop)
|
while (!cron->stop)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
unsigned long ts; /* tick start */
|
UInt64 ts; /* tick start */
|
||||||
unsigned long te; /* tick end */
|
UInt64 te; /* tick end */
|
||||||
|
|
||||||
pthread_mutex_lock(&cron->lock);
|
pthread_mutex_lock(&cron->lock);
|
||||||
|
|
||||||
|
@ -89,13 +90,13 @@ CronThread(void *args)
|
||||||
{
|
{
|
||||||
Job *job = ArrayGet(cron->jobs, i);
|
Job *job = ArrayGet(cron->jobs, i);
|
||||||
|
|
||||||
if (ts - job->lastExec > job->interval)
|
if (UInt64Gt(UInt64Sub(ts, job->lastExec), job->interval))
|
||||||
{
|
{
|
||||||
job->func(job->args);
|
job->func(job->args);
|
||||||
job->lastExec = ts;
|
job->lastExec = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!job->interval)
|
if (UInt64Eq(job->interval, UInt64Create(0, 0)))
|
||||||
{
|
{
|
||||||
ArrayDelete(cron->jobs, i);
|
ArrayDelete(cron->jobs, i);
|
||||||
Free(job);
|
Free(job);
|
||||||
|
@ -106,21 +107,23 @@ CronThread(void *args)
|
||||||
pthread_mutex_unlock(&cron->lock);
|
pthread_mutex_unlock(&cron->lock);
|
||||||
|
|
||||||
/* Only sleep if the jobs didn't overrun the tick */
|
/* Only sleep if the jobs didn't overrun the tick */
|
||||||
if (cron->tick > (te - ts))
|
if (UInt64Gt(cron->tick, UInt64Sub(te, ts)))
|
||||||
{
|
{
|
||||||
const unsigned long microTick = 100;
|
const UInt64 microTick = UInt64Create(0, 100);
|
||||||
unsigned long remainingTick = cron->tick - (te - ts);
|
|
||||||
|
UInt64 remainingTick = UInt64Sub(cron->tick, UInt64Sub(te, ts));
|
||||||
|
|
||||||
/* Only sleep for microTick ms at a time because if the job
|
/* Only sleep for microTick ms at a time because if the job
|
||||||
* scheduler is supposed to stop before the tick is up, we
|
* scheduler is supposed to stop before the tick is up, we
|
||||||
* don't want to be stuck in a long sleep */
|
* don't want to be stuck in a long sleep */
|
||||||
while (remainingTick >= microTick && !cron->stop)
|
while (UInt64Geq(remainingTick, microTick) && !cron->stop)
|
||||||
{
|
{
|
||||||
UtilSleepMillis(microTick);
|
UtilSleepMillis(microTick);
|
||||||
remainingTick -= microTick;
|
|
||||||
|
remainingTick = UInt64Sub(remainingTick, microTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainingTick && !cron->stop)
|
if (UInt64Neq(remainingTick, UInt64Create(0, 0)) && !cron->stop)
|
||||||
{
|
{
|
||||||
UtilSleepMillis(remainingTick);
|
UtilSleepMillis(remainingTick);
|
||||||
}
|
}
|
||||||
|
@ -131,7 +134,7 @@ CronThread(void *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
Cron *
|
Cron *
|
||||||
CronCreate(unsigned long tick)
|
CronCreate(UInt32 tick)
|
||||||
{
|
{
|
||||||
Cron *cron = Malloc(sizeof(Cron));
|
Cron *cron = Malloc(sizeof(Cron));
|
||||||
|
|
||||||
|
@ -147,7 +150,7 @@ CronCreate(unsigned long tick)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cron->tick = tick;
|
cron->tick = UInt64Create(0, tick);
|
||||||
cron->stop = 1;
|
cron->stop = 1;
|
||||||
|
|
||||||
pthread_mutex_init(&cron->lock, NULL);
|
pthread_mutex_init(&cron->lock, NULL);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
#include <Db.h>
|
#include <Db.h>
|
||||||
|
|
||||||
|
#include <UInt64.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
|
@ -76,7 +77,7 @@ struct DbRef
|
||||||
{
|
{
|
||||||
HashMap *json;
|
HashMap *json;
|
||||||
|
|
||||||
unsigned long ts;
|
UInt64 ts;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
Array *name;
|
Array *name;
|
||||||
|
@ -494,12 +495,12 @@ DbLockFromArr(Db * db, Array * args)
|
||||||
|
|
||||||
if (ref) /* In cache */
|
if (ref) /* In cache */
|
||||||
{
|
{
|
||||||
unsigned long diskTs = UtilLastModified(file);
|
UInt64 diskTs = UtilLastModified(file);
|
||||||
|
|
||||||
ref->fd = fd;
|
ref->fd = fd;
|
||||||
ref->stream = stream;
|
ref->stream = stream;
|
||||||
|
|
||||||
if (diskTs > ref->ts)
|
if (UInt64Gt(diskTs, ref->ts))
|
||||||
{
|
{
|
||||||
/* File was modified on disk since it was cached */
|
/* File was modified on disk since it was cached */
|
||||||
HashMap *json = JsonDecode(ref->stream);
|
HashMap *json = JsonDecode(ref->stream);
|
||||||
|
@ -651,7 +652,7 @@ DbCreate(Db * db, size_t nArgs,...)
|
||||||
|
|
||||||
file = DbFileName(db, args);
|
file = DbFileName(db, args);
|
||||||
|
|
||||||
if (UtilLastModified(file))
|
if (UInt64Neq(UtilLastModified(file), UInt64Create(0, 0)))
|
||||||
{
|
{
|
||||||
Free(file);
|
Free(file);
|
||||||
ArrayFree(args);
|
ArrayFree(args);
|
||||||
|
@ -754,7 +755,7 @@ DbDelete(Db * db, size_t nArgs,...)
|
||||||
|
|
||||||
Free(hash);
|
Free(hash);
|
||||||
|
|
||||||
if (UtilLastModified(file))
|
if (UInt64Neq(UtilLastModified(file), UInt64Create(0, 0)))
|
||||||
{
|
{
|
||||||
ret = remove(file) == 0;
|
ret = remove(file) == 0;
|
||||||
}
|
}
|
||||||
|
@ -872,7 +873,7 @@ DbExists(Db * db, size_t nArgs,...)
|
||||||
pthread_mutex_lock(&db->lock);
|
pthread_mutex_lock(&db->lock);
|
||||||
|
|
||||||
file = DbFileName(db, args);
|
file = DbFileName(db, args);
|
||||||
ret = UtilLastModified(file);
|
ret = UInt64Neq(UtilLastModified(file), UInt64Create(0, 0));
|
||||||
|
|
||||||
pthread_mutex_unlock(&db->lock);
|
pthread_mutex_unlock(&db->lock);
|
||||||
|
|
||||||
|
|
|
@ -465,7 +465,7 @@ HttpServerWorkerThread(void *args)
|
||||||
ssize_t i = 0;
|
ssize_t i = 0;
|
||||||
HttpRequestMethod requestMethod;
|
HttpRequestMethod requestMethod;
|
||||||
|
|
||||||
long firstRead;
|
UInt64 firstRead;
|
||||||
|
|
||||||
fp = DequeueConnection(server);
|
fp = DequeueConnection(server);
|
||||||
|
|
||||||
|
@ -473,7 +473,7 @@ HttpServerWorkerThread(void *args)
|
||||||
{
|
{
|
||||||
/* Block for 1 millisecond before continuing so we don't
|
/* Block for 1 millisecond before continuing so we don't
|
||||||
* murder the CPU if the queue is empty. */
|
* murder the CPU if the queue is empty. */
|
||||||
UtilSleepMillis(1);
|
UtilSleepMillis(UInt64Create(0, 1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,12 +492,12 @@ HttpServerWorkerThread(void *args)
|
||||||
|
|
||||||
/* If the server is stopped, or it's been a while, just
|
/* If the server is stopped, or it's been a while, just
|
||||||
* give up so we aren't wasting a thread on this client. */
|
* give up so we aren't wasting a thread on this client. */
|
||||||
if (server->stop || (UtilServerTs() - firstRead) > 1000 * 30)
|
if (server->stop || UInt64Gt(UInt64Sub(UtilServerTs(), firstRead), UInt64Create(0, 1000 * 30)))
|
||||||
{
|
{
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
UtilSleepMillis(5);
|
UtilSleepMillis(UInt64Create(0, 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lineLen == -1)
|
if (lineLen == -1)
|
||||||
|
|
399
Cytoplasm/src/Int64.c
Normal file
399
Cytoplasm/src/Int64.c
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <Log.h>
|
||||||
|
|
||||||
|
#ifdef INT64_NATIVE
|
||||||
|
#define Int64Sign(x) ((int) (((UInt64) (x)) >> 63))
|
||||||
|
#else
|
||||||
|
#define Int64Sign(x) ((int) ((x).i[1] >> 31))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t
|
||||||
|
Int64Str(Int64 x, int base, char *out, size_t len)
|
||||||
|
{
|
||||||
|
static const char symbols[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
size_t i = len - 1;
|
||||||
|
size_t j = 0;
|
||||||
|
|
||||||
|
int neg = Int64Sign(x);
|
||||||
|
|
||||||
|
Int64 base64 = Int64Create(0, base);
|
||||||
|
|
||||||
|
/* We only have symbols up to base 16 */
|
||||||
|
if (base < 2 || base > 16)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This algorithm doesn't work on INT64_MIN.
|
||||||
|
*
|
||||||
|
* But it works on all other integers in the range, so we
|
||||||
|
* just scoot the range in by one for now. It's a hack and
|
||||||
|
* I'm not a huge fan of it, but this function is mostly
|
||||||
|
* used in Json, which shouldn't have a range this large
|
||||||
|
* anyway (Json is limited to -2^53 -> 2^53-1).
|
||||||
|
*
|
||||||
|
* Proper fixes are always welcome.
|
||||||
|
*/
|
||||||
|
if (Int64Eq(x, Int64Create(0x80000000, 0x00000000)))
|
||||||
|
{
|
||||||
|
x = Int64Add(x, Int64Create(0, 1));
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
else if (Int64Eq(x, Int64Create(0x7FFFFFFF, 0xFFFFFFFF)))
|
||||||
|
{
|
||||||
|
x = Int64Sub(x, Int64Create(0, 1));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (base != 2 && base != 8 && base != 16 && neg)
|
||||||
|
{
|
||||||
|
x = Int64Neg(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Int64 mod = Int64Rem(x, base64);
|
||||||
|
Int32 low = Int64Low(mod);
|
||||||
|
|
||||||
|
out[i] = symbols[low];
|
||||||
|
i--;
|
||||||
|
x = Int64Div(x, base64);
|
||||||
|
} while (Int64Gt(x, Int64Create(0, 0)));
|
||||||
|
|
||||||
|
if (base != 2 && base != 8 && base != 16)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Binary, octal, and hexadecimal are known to
|
||||||
|
* be bit representations. Everything else (notably
|
||||||
|
* decimal) should include the negative sign.
|
||||||
|
*/
|
||||||
|
if (neg)
|
||||||
|
{
|
||||||
|
out[i] = '-';
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (++i < len)
|
||||||
|
{
|
||||||
|
out[j++] = out[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
out[j] = '\0';
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef INT64_NATIVE
|
||||||
|
|
||||||
|
/* No native 64-bit support, add our own */
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Create(UInt32 high, UInt32 low)
|
||||||
|
{
|
||||||
|
Int64 x;
|
||||||
|
|
||||||
|
x.i[0] = low;
|
||||||
|
x.i[1] = high;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Add(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
Int64 z = Int64Create(0, 0);
|
||||||
|
int carry;
|
||||||
|
|
||||||
|
z.i[0] = x.i[0] + y.i[0];
|
||||||
|
carry = z.i[0] < x.i[0];
|
||||||
|
z.i[1] = x.i[1] + y.i[1] + carry;
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Sub(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
return Int64Add(x, Int64Neg(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Mul(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
Int64 z = Int64Create(0, 0);
|
||||||
|
|
||||||
|
int xneg = Int64Sign(x);
|
||||||
|
int yneg = Int64Sign(y);
|
||||||
|
|
||||||
|
if (xneg)
|
||||||
|
{
|
||||||
|
x = Int64Neg(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yneg)
|
||||||
|
{
|
||||||
|
y = Int64Neg(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* while (y > 0) */
|
||||||
|
while (Int64Gt(y, Int64Create(0, 0)))
|
||||||
|
{
|
||||||
|
/* if (y & 1 != 0) */
|
||||||
|
if (Int64Neq(Int64And(y, Int64Create(0, 1)), Int64Create(0, 0)))
|
||||||
|
{
|
||||||
|
z = Int64Add(z, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = Int64Sll(x, 1);
|
||||||
|
y = Int64Sra(y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xneg != yneg)
|
||||||
|
{
|
||||||
|
z = Int64Neg(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Int64 q;
|
||||||
|
Int64 r;
|
||||||
|
} Int64Ldiv;
|
||||||
|
|
||||||
|
static Int64Ldiv
|
||||||
|
Int64LongDivision(Int64 n, Int64 d)
|
||||||
|
{
|
||||||
|
Int64Ldiv o;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
int nneg = Int64Sign(n);
|
||||||
|
int dneg = Int64Sign(d);
|
||||||
|
|
||||||
|
o.q = Int64Create(0, 0);
|
||||||
|
o.r = Int64Create(0, 0);
|
||||||
|
|
||||||
|
if (Int64Eq(d, Int64Create(0, 0)))
|
||||||
|
{
|
||||||
|
raise(SIGFPE);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nneg)
|
||||||
|
{
|
||||||
|
n = Int64Neg(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dneg)
|
||||||
|
{
|
||||||
|
d = Int64Neg(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 63; i >= 0; i--)
|
||||||
|
{
|
||||||
|
Int64 bit = Int64And(Int64Sra(n, i), Int64Create(0, 1));
|
||||||
|
|
||||||
|
o.r = Int64Sll(o.r, 1);
|
||||||
|
o.r = Int64Or(o.r, bit);
|
||||||
|
|
||||||
|
if (Int64Geq(o.r, d))
|
||||||
|
{
|
||||||
|
o.r = Int64Sub(o.r, d);
|
||||||
|
o.q = Int64Or(o.q, Int64Sll(Int64Create(0, 1), i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nneg != dneg)
|
||||||
|
{
|
||||||
|
o.r = Int64Neg(o.r);
|
||||||
|
o.q = Int64Neg(o.q);
|
||||||
|
}
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Div(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
return Int64LongDivision(x, y).q;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Rem(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
return Int64LongDivision(x, y).r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Sll(Int64 x, int y)
|
||||||
|
{
|
||||||
|
Int64 z;
|
||||||
|
|
||||||
|
if (!y)
|
||||||
|
{
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
z = Int64Create(0, 0);
|
||||||
|
|
||||||
|
if (y < 32)
|
||||||
|
{
|
||||||
|
z.i[1] = (x.i[0] >> (32 - y)) | (x.i[1] << y);
|
||||||
|
z.i[0] = x.i[0] << y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
z.i[1] = x.i[0] << (y - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Sra(Int64 x, int y)
|
||||||
|
{
|
||||||
|
Int64 z;
|
||||||
|
|
||||||
|
int neg = Int64Sign(x);
|
||||||
|
|
||||||
|
if (!y)
|
||||||
|
{
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
z = Int64Create(0, 0);
|
||||||
|
|
||||||
|
if (y < 32)
|
||||||
|
{
|
||||||
|
z.i[0] = (x.i[1] << (32 - y)) | (x.i[0] >> y);
|
||||||
|
z.i[1] = x.i[1] >> y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
z.i[0] = x.i[1] >> (y - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (neg)
|
||||||
|
{
|
||||||
|
Int64 mask = Int64Create(0xFFFFFFFF, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
z = Int64Or(Int64Sll(mask, (64 - y)), z);
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64And(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
return Int64Create(x.i[1] & y.i[1], x.i[0] & y.i[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Or(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
return Int64Create(x.i[1] | y.i[1], x.i[0] | y.i[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Xor(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
return Int64Create(x.i[1] ^ y.i[1], x.i[0] ^ y.i[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64
|
||||||
|
Int64Not(Int64 x)
|
||||||
|
{
|
||||||
|
return Int64Create(~(x.i[1]), ~(x.i[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Int64Eq(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
return x.i[0] == y.i[0] && x.i[1] == y.i[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Int64Lt(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
int xneg = Int64Sign(x);
|
||||||
|
int yneg = Int64Sign(y);
|
||||||
|
|
||||||
|
if (xneg != yneg)
|
||||||
|
{
|
||||||
|
return xneg > yneg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (xneg)
|
||||||
|
{
|
||||||
|
/* Both negative */
|
||||||
|
return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Both positive */
|
||||||
|
return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Int64Gt(Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
int xneg = Int64Sign(x);
|
||||||
|
int yneg = Int64Sign(y);
|
||||||
|
|
||||||
|
if (xneg != yneg)
|
||||||
|
{
|
||||||
|
return xneg < yneg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (xneg)
|
||||||
|
{
|
||||||
|
/* Both negative */
|
||||||
|
return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Both positive */
|
||||||
|
return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -27,6 +27,7 @@
|
||||||
#include <Str.h>
|
#include <Str.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
#include <Int.h>
|
#include <Int.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -43,7 +44,7 @@ struct JsonValue
|
||||||
HashMap *object;
|
HashMap *object;
|
||||||
Array *array;
|
Array *array;
|
||||||
char *string;
|
char *string;
|
||||||
long integer;
|
Int64 integer;
|
||||||
double floating;
|
double floating;
|
||||||
int boolean:1;
|
int boolean:1;
|
||||||
} as;
|
} as;
|
||||||
|
@ -200,7 +201,7 @@ JsonValueAsString(JsonValue * value)
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonValue *
|
JsonValue *
|
||||||
JsonValueInteger(long integer)
|
JsonValueInteger(Int64 integer)
|
||||||
{
|
{
|
||||||
JsonValue *value;
|
JsonValue *value;
|
||||||
|
|
||||||
|
@ -216,12 +217,12 @@ JsonValueInteger(long integer)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
long
|
Int64
|
||||||
JsonValueAsInteger(JsonValue * value)
|
JsonValueAsInteger(JsonValue * value)
|
||||||
{
|
{
|
||||||
if (!value || value->type != JSON_INTEGER)
|
if (!value || value->type != JSON_INTEGER)
|
||||||
{
|
{
|
||||||
return 0;
|
return Int64Create(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value->as.integer;
|
return value->as.integer;
|
||||||
|
@ -605,6 +606,8 @@ JsonEncodeValue(JsonValue * value, Stream * out, int level)
|
||||||
Array *arr;
|
Array *arr;
|
||||||
int length = 0;
|
int length = 0;
|
||||||
|
|
||||||
|
char ibuf[INT64_STRBUF];
|
||||||
|
|
||||||
switch (value->type)
|
switch (value->type)
|
||||||
{
|
{
|
||||||
case JSON_OBJECT:
|
case JSON_OBJECT:
|
||||||
|
@ -641,7 +644,8 @@ JsonEncodeValue(JsonValue * value, Stream * out, int level)
|
||||||
length += JsonEncodeString(value->as.string, out);
|
length += JsonEncodeString(value->as.string, out);
|
||||||
break;
|
break;
|
||||||
case JSON_INTEGER:
|
case JSON_INTEGER:
|
||||||
length += StreamPrintf(out, "%ld", value->as.integer);
|
Int64Str(value->as.integer, 10, ibuf, INT64_STRBUF);
|
||||||
|
length += StreamPrintf(out, "%s", ibuf);
|
||||||
break;
|
break;
|
||||||
case JSON_FLOAT:
|
case JSON_FLOAT:
|
||||||
length += StreamPrintf(out, "%f", value->as.floating);
|
length += StreamPrintf(out, "%f", value->as.floating);
|
||||||
|
@ -872,7 +876,7 @@ JsonConsumeWhitespace(JsonParserState * state)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UtilSleepMillis(delay);
|
UtilSleepMillis(UInt64Create(0, delay));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -979,7 +983,7 @@ JsonTokenSeek(JsonParserState * state)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->tokenLen >= allocated)
|
if (state->tokenLen + 1 >= allocated)
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
|
@ -1119,6 +1123,10 @@ JsonDecodeValue(JsonParserState * state)
|
||||||
JsonValue *value;
|
JsonValue *value;
|
||||||
char *strValue;
|
char *strValue;
|
||||||
|
|
||||||
|
Int64 iValue;
|
||||||
|
size_t i;
|
||||||
|
int neg;
|
||||||
|
|
||||||
switch (state->tokenType)
|
switch (state->tokenType)
|
||||||
{
|
{
|
||||||
case TOKEN_OBJECT_OPEN:
|
case TOKEN_OBJECT_OPEN:
|
||||||
|
@ -1138,7 +1146,32 @@ JsonDecodeValue(JsonParserState * state)
|
||||||
Free(strValue);
|
Free(strValue);
|
||||||
break;
|
break;
|
||||||
case TOKEN_INTEGER:
|
case TOKEN_INTEGER:
|
||||||
value = JsonValueInteger(atol(state->token));
|
iValue = Int64Create(0, 0);
|
||||||
|
i = 0;
|
||||||
|
neg = 0;
|
||||||
|
|
||||||
|
while (state->token[i])
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
|
||||||
|
if (i == 0 && !neg && state->token[i] == '-')
|
||||||
|
{
|
||||||
|
neg = 1;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = state->token[i] - '0';
|
||||||
|
iValue = Int64Mul(iValue, Int64Create(0, 10));
|
||||||
|
iValue = Int64Add(iValue, Int64Create(0, d));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (neg)
|
||||||
|
{
|
||||||
|
iValue = Int64Neg(iValue);
|
||||||
|
}
|
||||||
|
value = JsonValueInteger(iValue);
|
||||||
break;
|
break;
|
||||||
case TOKEN_FLOAT:
|
case TOKEN_FLOAT:
|
||||||
value = JsonValueFloat(atof(state->token));
|
value = JsonValueFloat(atof(state->token));
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <Rand.h>
|
#include <Rand.h>
|
||||||
|
|
||||||
#include <Int.h>
|
#include <Int.h>
|
||||||
|
#include <UInt64.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
|
||||||
|
@ -140,7 +141,8 @@ RandIntN(int *buf, size_t size, unsigned int max)
|
||||||
if (!state)
|
if (!state)
|
||||||
{
|
{
|
||||||
/* Generate a seed from the system time, PID, and TID */
|
/* Generate a seed from the system time, PID, and TID */
|
||||||
UInt32 seed = UtilServerTs() ^ getpid() ^ (unsigned long) pthread_self();
|
UInt64 ts = UtilServerTs();
|
||||||
|
UInt32 seed = UInt64Low(ts) ^ getpid() ^ (unsigned long) pthread_self();
|
||||||
|
|
||||||
state = Malloc(sizeof(RandState));
|
state = Malloc(sizeof(RandState));
|
||||||
RandSeed(state, seed);
|
RandSeed(state, seed);
|
||||||
|
|
|
@ -626,7 +626,7 @@ StreamCopy(Stream * in, Stream * out)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UtilSleepMillis(STREAM_DELAY);
|
UtilSleepMillis(UInt64Create(0, STREAM_DELAY));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
265
Cytoplasm/src/UInt64.c
Normal file
265
Cytoplasm/src/UInt64.c
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <UInt64.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
size_t
|
||||||
|
UInt64Str(UInt64 x, int base, char *out, size_t len)
|
||||||
|
{
|
||||||
|
static const char symbols[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
size_t i = len - 1;
|
||||||
|
size_t j = 0;
|
||||||
|
|
||||||
|
UInt64 base64 = UInt64Create(0, base);
|
||||||
|
|
||||||
|
/* We only have symbols up to base 16 */
|
||||||
|
if (base < 2 || base > 16)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
UInt64 mod = UInt64Rem(x, base64);
|
||||||
|
UInt32 low = UInt64Low(mod);
|
||||||
|
|
||||||
|
out[i] = symbols[low];
|
||||||
|
i--;
|
||||||
|
x = UInt64Div(x, base64);
|
||||||
|
} while (UInt64Gt(x, UInt64Create(0, 0)));
|
||||||
|
|
||||||
|
while (++i < len)
|
||||||
|
{
|
||||||
|
out[j++] = out[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
out[j] = '\0';
|
||||||
|
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef UINT64_NATIVE
|
||||||
|
|
||||||
|
/* No native 64-bit support, add our own */
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Create(UInt32 high, UInt32 low)
|
||||||
|
{
|
||||||
|
UInt64 x;
|
||||||
|
|
||||||
|
x.i[0] = low;
|
||||||
|
x.i[1] = high;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Add(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
UInt64 z = UInt64Create(0, 0);
|
||||||
|
int carry;
|
||||||
|
|
||||||
|
z.i[0] = x.i[0] + y.i[0];
|
||||||
|
carry = z.i[0] < x.i[0];
|
||||||
|
z.i[1] = x.i[1] + y.i[1] + carry;
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Sub(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
UInt64 twosCompl = UInt64Add(UInt64Not(y), UInt64Create(0, 1));
|
||||||
|
|
||||||
|
return UInt64Add(x, twosCompl);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Mul(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
UInt64 z = UInt64Create(0, 0);
|
||||||
|
|
||||||
|
/* while (y > 0) */
|
||||||
|
while (UInt64Gt(y, UInt64Create(0, 0)))
|
||||||
|
{
|
||||||
|
/* if (y & 1 != 0) */
|
||||||
|
if (UInt64Neq(UInt64And(y, UInt64Create(0, 1)), UInt64Create(0, 0)))
|
||||||
|
{
|
||||||
|
z = UInt64Add(z, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = UInt64Sll(x, 1);
|
||||||
|
y = UInt64Srl(y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt64 q;
|
||||||
|
UInt64 r;
|
||||||
|
} UInt64Ldiv;
|
||||||
|
|
||||||
|
static UInt64Ldiv
|
||||||
|
UInt64LongDivision(UInt64 n, UInt64 d)
|
||||||
|
{
|
||||||
|
UInt64Ldiv o;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
o.q = UInt64Create(0, 0);
|
||||||
|
o.r = UInt64Create(0, 0);
|
||||||
|
|
||||||
|
if (UInt64Eq(d, UInt64Create(0, 0)))
|
||||||
|
{
|
||||||
|
raise(SIGFPE);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 63; i >= 0; i--)
|
||||||
|
{
|
||||||
|
UInt64 bit = UInt64And(UInt64Srl(n, i), UInt64Create(0, 1));
|
||||||
|
|
||||||
|
o.r = UInt64Sll(o.r, 1);
|
||||||
|
o.r = UInt64Or(o.r, bit);
|
||||||
|
|
||||||
|
if (UInt64Geq(o.r, d))
|
||||||
|
{
|
||||||
|
o.r = UInt64Sub(o.r, d);
|
||||||
|
o.q = UInt64Or(o.q, UInt64Sll(UInt64Create(0, 1), i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Div(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
return UInt64LongDivision(x, y).q;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Rem(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
return UInt64LongDivision(x, y).r;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Sll(UInt64 x, int y)
|
||||||
|
{
|
||||||
|
UInt64 z;
|
||||||
|
|
||||||
|
if (!y)
|
||||||
|
{
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
z = UInt64Create(0, 0);
|
||||||
|
|
||||||
|
if (y < 32)
|
||||||
|
{
|
||||||
|
z.i[1] = (x.i[0] >> (32 - y)) | (x.i[1] << y);
|
||||||
|
z.i[0] = x.i[0] << y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
z.i[1] = x.i[0] << (y - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Srl(UInt64 x, int y)
|
||||||
|
{
|
||||||
|
UInt64 z;
|
||||||
|
|
||||||
|
if (!y)
|
||||||
|
{
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
z = UInt64Create(0, 0);
|
||||||
|
|
||||||
|
if (y < 32)
|
||||||
|
{
|
||||||
|
z.i[0] = (x.i[1] << (32 - y)) | (x.i[0] >> y);
|
||||||
|
z.i[1] = x.i[1] >> y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
z.i[0] = x.i[1] >> (y - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64And(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
return UInt64Create(x.i[1] & y.i[1], x.i[0] & y.i[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Or(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
return UInt64Create(x.i[1] | y.i[1], x.i[0] | y.i[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Xor(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
return UInt64Create(x.i[1] ^ y.i[1], x.i[0] ^ y.i[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64
|
||||||
|
UInt64Not(UInt64 x)
|
||||||
|
{
|
||||||
|
return UInt64Create(~(x.i[1]), ~(x.i[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
UInt64Eq(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
return x.i[0] == y.i[0] && x.i[1] == y.i[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
UInt64Lt(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
UInt64Gt(UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -40,6 +40,8 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <UInt64.h>
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
#define PATH_MAX 256
|
#define PATH_MAX 256
|
||||||
#endif
|
#endif
|
||||||
|
@ -48,33 +50,84 @@
|
||||||
#define SSIZE_MAX LONG_MAX
|
#define SSIZE_MAX LONG_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned long
|
UInt64
|
||||||
UtilServerTs(void)
|
UtilServerTs(void)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
unsigned long ts;
|
|
||||||
|
UInt64 ts;
|
||||||
|
UInt64 sec;
|
||||||
|
UInt64 usec;
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
ts = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
|
||||||
|
/*
|
||||||
|
* POSIX defines struct timeval to be:
|
||||||
|
*
|
||||||
|
* struct timeval {
|
||||||
|
* time_t tv_sec;
|
||||||
|
* suseconds_t tv_usec;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Note: Although the C standard does not require that
|
||||||
|
* time_t be an integer type (it may be floating point),
|
||||||
|
* according to POSIX, time_t shall be an integer type.
|
||||||
|
* As we are targeting POSIX, not ANSI/ISO C, we can
|
||||||
|
* rely on this.
|
||||||
|
*
|
||||||
|
* The same goes for suseconds_t.
|
||||||
|
*/
|
||||||
|
if (sizeof(time_t) == sizeof(UInt64))
|
||||||
|
{
|
||||||
|
/* 64 bit time_t: convert it to a 64 bit integer */
|
||||||
|
time_t ms = tv.tv_sec * 1000;
|
||||||
|
UInt32 high = (UInt32) (ms >> 32);
|
||||||
|
UInt32 low = (UInt32) ms;
|
||||||
|
|
||||||
|
sec = UInt64Create(high, low);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Assume 32 bit time_t: promote to 64 bit, then multiply, in
|
||||||
|
* case multiplication overflows 32 bits. */
|
||||||
|
sec = UInt64Create(0, tv.tv_sec);
|
||||||
|
sec = UInt64Mul(sec, UInt64Create(0, 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
usec = UInt64Create(0, tv.tv_usec / 1000);
|
||||||
|
ts = UInt64Add(sec, usec);
|
||||||
|
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
UInt64
|
||||||
UtilLastModified(char *path)
|
UtilLastModified(char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
unsigned long ts;
|
UInt64 ts = UInt64Create(0, 0);
|
||||||
|
|
||||||
if (stat(path, &st) == 0)
|
if (stat(path, &st) == 0)
|
||||||
{
|
{
|
||||||
ts = (st.st_mtim.tv_sec * 1000) + (st.st_mtim.tv_nsec / 1000000);
|
if (sizeof(time_t) == sizeof(UInt64))
|
||||||
return ts;
|
{
|
||||||
|
/* 64 bit time_t: convert it to a 64 bit integer */
|
||||||
|
time_t ms = st.st_mtim.tv_sec * 1000;
|
||||||
|
UInt32 high = (UInt32) (ms >> 32);
|
||||||
|
UInt32 low = (UInt32) ms;
|
||||||
|
|
||||||
|
ts = UInt64Create(high, low);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0;
|
ts = UInt64Create(0, st.st_mtim.tv_sec);
|
||||||
|
ts = UInt64Mul(ts, UInt64Create(0, 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* nsec gauanteed to fit in 32 bits */
|
||||||
|
ts = UInt64Add(ts, UInt64Create(0, st.st_mtim.tv_nsec / 1000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -149,13 +202,21 @@ UtilMkdir(const char *dir, const mode_t mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
UtilSleepMillis(long ms)
|
UtilSleepMillis(UInt64 ms)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
ts.tv_sec = ms / 1000;
|
if (sizeof(time_t) == sizeof(UInt64))
|
||||||
ts.tv_nsec = (ms % 1000) * 1000000;
|
{
|
||||||
|
ts.tv_sec = ((time_t) UInt64High(ms) << 32 | UInt64Low(ms)) / 1000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ts.tv_sec = UInt64Low(ms) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.tv_nsec = UInt64Low(UInt64Rem(ms, UInt64Create(0, 1000))) * 1000000;
|
||||||
|
|
||||||
res = nanosleep(&ts, &ts);
|
res = nanosleep(&ts, &ts);
|
||||||
|
|
||||||
|
@ -251,14 +312,14 @@ ThreadNoDestructor(void *p)
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long
|
UInt32
|
||||||
UtilThreadNo(void)
|
UtilThreadNo(void)
|
||||||
{
|
{
|
||||||
static pthread_key_t key;
|
static pthread_key_t key;
|
||||||
static int createdKey = 0;
|
static int createdKey = 0;
|
||||||
static unsigned long count = 0;
|
static unsigned long count = 0;
|
||||||
|
|
||||||
unsigned long *no;
|
UInt32 *no;
|
||||||
|
|
||||||
if (!createdKey)
|
if (!createdKey)
|
||||||
{
|
{
|
||||||
|
@ -269,7 +330,7 @@ UtilThreadNo(void)
|
||||||
no = pthread_getspecific(key);
|
no = pthread_getspecific(key);
|
||||||
if (!no)
|
if (!no)
|
||||||
{
|
{
|
||||||
no = malloc(sizeof(unsigned long));
|
no = malloc(sizeof(UInt32));
|
||||||
*no = count++;
|
*no = count++;
|
||||||
pthread_setspecific(key, no);
|
pthread_setspecific(key, no);
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,6 +151,14 @@ extern void ArraySort(Array *, int (*) (void *, void *));
|
||||||
*/
|
*/
|
||||||
extern Array *ArrayUnique(Array *, int (*) (void *, void *));
|
extern Array *ArrayUnique(Array *, int (*) (void *, void *));
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverses the order of all elements in the array into a new array on
|
||||||
|
* the heap, to be freed using
|
||||||
|
* .Fn ArrayFree .
|
||||||
|
*/
|
||||||
|
extern Array *ArrayReverse(Array *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If possible, reduce the amount of memory allocated to this array
|
* If possible, reduce the amount of memory allocated to this array
|
||||||
* by calling
|
* by calling
|
||||||
|
|
|
@ -56,6 +56,8 @@
|
||||||
* by any means.
|
* by any means.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <Int.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All functions defined here operate on a structure opaque to the
|
* All functions defined here operate on a structure opaque to the
|
||||||
* caller.
|
* caller.
|
||||||
|
@ -80,8 +82,7 @@ typedef void (JobFunc) (void *);
|
||||||
* .Pp
|
* .Pp
|
||||||
* This function takes the tick interval in milliseconds.
|
* This function takes the tick interval in milliseconds.
|
||||||
*/
|
*/
|
||||||
extern Cron *
|
extern Cron * CronCreate(UInt32);
|
||||||
CronCreate(unsigned long);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule a one-off job to be executed only at the next tick, and
|
* Schedule a one-off job to be executed only at the next tick, and
|
||||||
|
|
|
@ -55,10 +55,9 @@
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#define BIT64_MAX 18446744073709551615
|
#define BIT32_MAX 4294967295UL
|
||||||
#define BIT32_MAX 4294967295
|
#define BIT16_MAX 65535UL
|
||||||
#define BIT16_MAX 65535
|
#define BIT8_MAX 255UL
|
||||||
#define BIT8_MAX 255
|
|
||||||
|
|
||||||
#ifndef UCHAR_MAX
|
#ifndef UCHAR_MAX
|
||||||
#error Size of char data type is unknown. Define UCHAR_MAX.
|
#error Size of char data type is unknown. Define UCHAR_MAX.
|
||||||
|
@ -120,6 +119,4 @@ typedef unsigned char UInt32;
|
||||||
#error Unable to determine suitable data type for 32-bit integers.
|
#error Unable to determine suitable data type for 32-bit integers.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The ANSI C standard only guarantees a data size of up to 32 bits. */
|
#endif /* CYTOPLASM_INT_H */
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
252
Cytoplasm/src/include/Int64.h
Normal file
252
Cytoplasm/src/include/Int64.h
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CYTOPLASM_INT64_H
|
||||||
|
#define CYTOPLASM_INT64_H
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @Nm Int64
|
||||||
|
* @Nd Fixed-width 64 bit integers.
|
||||||
|
* @Dd August 11, 2023
|
||||||
|
*
|
||||||
|
* .Pp
|
||||||
|
* ANSI C89 (or C99 for that matter) provides no required mechanism
|
||||||
|
* for 64 bit integers. Nevertheless, many compilers provide them as
|
||||||
|
* extensions. However, since it is not a gaurantee, and to be fully
|
||||||
|
* standards-compliant and thus portable, a platform-agnostic interface
|
||||||
|
* is required. This header provides such an interface. If the platform
|
||||||
|
* has a 64 bit integer type, that is used, and native operations are
|
||||||
|
* performed by C preprocessor macro expansion. Otherwise, a
|
||||||
|
* compatibility layer is provided, which implements 64-bit
|
||||||
|
* arithmetic on an array of 2 32-bit numbers which are provided by
|
||||||
|
* .Xr Int 3 .
|
||||||
|
* .Pp
|
||||||
|
* Note that 64-bit emulation is certainly not as performant as using
|
||||||
|
* native 64-bit operations, so whenever possible, the native
|
||||||
|
* operations should be preferred. However, since C provides no required
|
||||||
|
* 64 bit integer on 32-bit and less platforms, this API can be used as
|
||||||
|
* a "good enough" fallback mechanism.
|
||||||
|
* .Pp
|
||||||
|
* Also note that this implementation, both in the native and
|
||||||
|
* non-native forms, makes some assumptions:
|
||||||
|
* .Bl -bullet -width Ds
|
||||||
|
* .It
|
||||||
|
* When a cast from a larger integer to a smaller integer is performed,
|
||||||
|
* the upper bits are truncated, not the lower bits.
|
||||||
|
* .It
|
||||||
|
* Negative numbers are represented in memory and in registers in two's
|
||||||
|
* compliment form.
|
||||||
|
* .El
|
||||||
|
* .Pp
|
||||||
|
* This API may provide unexpected output if these assumptions are
|
||||||
|
* false for a given platform.
|
||||||
|
*
|
||||||
|
* @ignore-typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Int.h>
|
||||||
|
#include <UInt64.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef INT64_FORCE_EMULATED
|
||||||
|
|
||||||
|
#define BIT64_MAX 18446744073709551615UL
|
||||||
|
|
||||||
|
#if UINT_MAX == BIT64_MAX
|
||||||
|
typedef signed int Int64;
|
||||||
|
|
||||||
|
#define INT64_NATIVE
|
||||||
|
|
||||||
|
#elif ULONG_MAX == BIT64_MAX
|
||||||
|
typedef signed long Int64;
|
||||||
|
|
||||||
|
#define INT64_NATIVE
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ifndef INT64_FORCE_EMULATED */
|
||||||
|
|
||||||
|
#ifdef INT64_NATIVE
|
||||||
|
|
||||||
|
#define Int64Create(high, low) ((Int64) (((UInt64) (high) << 32) | (low)))
|
||||||
|
#define Int64Neg(x) (-(x))
|
||||||
|
|
||||||
|
#define Int64Low(a) ((UInt32) (a))
|
||||||
|
#define Int64High(a) ((UInt32) ((a) >> 32))
|
||||||
|
|
||||||
|
#define Int64Add(a, b) ((a) + (b))
|
||||||
|
#define Int64Sub(a, b) ((a) - (b))
|
||||||
|
#define Int64Mul(a, b) ((a) * (b))
|
||||||
|
#define Int64Div(a, b) ((a) / (b))
|
||||||
|
#define Int64Rem(a, b) ((a) % (b))
|
||||||
|
|
||||||
|
#define Int64Sll(a, b) ((a) << (b))
|
||||||
|
#define Int64Sra(a, b) ((a) >> (b))
|
||||||
|
|
||||||
|
#define Int64And(a, b) ((a) & (b))
|
||||||
|
#define Int64Or(a, b) ((a) | (b))
|
||||||
|
#define Int64Xor(a, b) ((a) ^ (b))
|
||||||
|
#define Int64Not(a) (~(a))
|
||||||
|
|
||||||
|
#define Int64Eq(a, b) ((a) == (b))
|
||||||
|
#define Int64Lt(a, b) ((a) < (b))
|
||||||
|
#define Int64Gt(a, b) ((a) > (b))
|
||||||
|
|
||||||
|
#define Int64Neq(a, b) ((a) != (b))
|
||||||
|
#define Int64Leq(a, b) ((a) <= (b))
|
||||||
|
#define Int64Geq(a, b) ((a) >= (b))
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define Int64Neg(x) (Int64Add(Int64Not(x), Int64Create(0, 1)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal bit representation of a signed integer is identical
|
||||||
|
* to an unsigned integer, the difference is in the algorithms and
|
||||||
|
* the way the bits are interpreted.
|
||||||
|
*/
|
||||||
|
typedef UInt64 Int64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new signed 64 bit integer using the given high and low
|
||||||
|
* bits.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Create(UInt32, UInt32);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two signed 64 bit integers together.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Add(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract the second 64 bit integer from the first.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Sub(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply two 64 bit integers together. The non-native version of
|
||||||
|
* this function uses the Russian Peasant method of multiplication,
|
||||||
|
* which should afford more performance than a naive multiplication by
|
||||||
|
* addition, but it is still rather slow and depends on the size of
|
||||||
|
* the integers being multiplied.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Mul(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Divide the first 64 bit integer by the second and return the
|
||||||
|
* quotient. The non-native version of this function uses naive binary
|
||||||
|
* long division, which is slow, but gauranteed to finish in constant
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Div(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Divide the first 64 bit integer by the second and return the
|
||||||
|
* remainder. The non-native version of this function uses naive binary
|
||||||
|
* long division, which is slow, but gauranteed to finish in constant
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Rem(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a left logical bit shift of a 64 bit integer. The second
|
||||||
|
* parameter is how many places to shift, and is declared as a regular
|
||||||
|
* integer because anything more than 64 does not make sense.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Sll(Int64, int);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a right arithmetic bit shift of a 64 bit integer. The second
|
||||||
|
* parameter is how many places to shift, and is declared as a regular
|
||||||
|
* integer because anything more than 64 does not make sense.
|
||||||
|
* .Pp
|
||||||
|
* Note that on platforms that use the native 64-bit implementation,
|
||||||
|
* this is technically implementation-defined, and may in fact be a
|
||||||
|
* logical shift instead of an arithmetic shift. Note that typically
|
||||||
|
* this operation is not performed on signed integers.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Sra(Int64, int);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise AND (&) of the provided 64 bit integers.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64And(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise OR (|) of the provided 64 bit integers.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Or(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise XOR (^) of the provided 64 bit integers.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Xor(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise NOT (~) of the provided 64 bit integer.
|
||||||
|
*/
|
||||||
|
extern Int64 Int64Not(Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a comparison of the provided 64 bit integers and return a C
|
||||||
|
* boolean that is true if and only if they are equal.
|
||||||
|
*/
|
||||||
|
extern int Int64Eq(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a comparison of the provided 64 bit integers and return a C
|
||||||
|
* boolean that is true if and only if the second operand is strictly
|
||||||
|
* less than the first.
|
||||||
|
*/
|
||||||
|
extern int Int64Lt(Int64, Int64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a comparison of the provided 64 bit integers and return a C
|
||||||
|
* boolean that is true if and only if the second operand is strictly
|
||||||
|
* greater than the first.
|
||||||
|
*/
|
||||||
|
extern int Int64Gt(Int64, Int64);
|
||||||
|
|
||||||
|
#define Int64Low(a) ((a).i[0])
|
||||||
|
#define Int64High(a) ((a).i[1])
|
||||||
|
|
||||||
|
#define Int64Neq(a, b) (!Int64Eq(a, b))
|
||||||
|
#define Int64Leq(a, b) (Int64Eq(a, b) || Int64Lt(a, b))
|
||||||
|
#define Int64Geq(a, b) (Int64Eq(a, b) || Int64Gt(a, b))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INT64_STRBUF 65 /* Base 2 representation with '\0' */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a 64 bit integer to a string in an arbitrary base
|
||||||
|
* representation specified by the second parameter, using the provided
|
||||||
|
* buffer and length specified by the third and fourth parameters. To
|
||||||
|
* guarantee that the string will fit in the buffer, allocate it of
|
||||||
|
* size INT64_STRBUF or larger. Note that a buffer size smaller than
|
||||||
|
* INT64_STRBUF will invoke undefined behavior.
|
||||||
|
*/
|
||||||
|
extern size_t Int64Str(Int64, int, char *, size_t);
|
||||||
|
|
||||||
|
#endif /* CYTOPLASM_INT64_H */
|
|
@ -71,6 +71,7 @@
|
||||||
#include <HashMap.h>
|
#include <HashMap.h>
|
||||||
#include <Array.h>
|
#include <Array.h>
|
||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -101,7 +102,7 @@ typedef enum JsonType
|
||||||
JSON_OBJECT, /* Maps to a HashMap of JsonValues */
|
JSON_OBJECT, /* Maps to a HashMap of JsonValues */
|
||||||
JSON_ARRAY, /* Maps to an Array of JsonValues */
|
JSON_ARRAY, /* Maps to an Array of JsonValues */
|
||||||
JSON_STRING, /* Maps to a null-terminated C string */
|
JSON_STRING, /* Maps to a null-terminated C string */
|
||||||
JSON_INTEGER, /* Maps to a C long */
|
JSON_INTEGER, /* Maps to an Int64 */
|
||||||
JSON_FLOAT, /* Maps to a C double */
|
JSON_FLOAT, /* Maps to a C double */
|
||||||
JSON_BOOLEAN /* Maps to a C integer of either 0 or 1 */
|
JSON_BOOLEAN /* Maps to a C integer of either 0 or 1 */
|
||||||
} JsonType;
|
} JsonType;
|
||||||
|
@ -151,7 +152,7 @@ extern char * JsonValueAsString(JsonValue *);
|
||||||
* Encode a number as a JSON value that can be added to an object or
|
* Encode a number as a JSON value that can be added to an object or
|
||||||
* an array.
|
* an array.
|
||||||
*/
|
*/
|
||||||
extern JsonValue * JsonValueInteger(long);
|
extern JsonValue * JsonValueInteger(Int64);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unwrap a JSON value that represents a number. This function will
|
* Unwrap a JSON value that represents a number. This function will
|
||||||
|
@ -159,7 +160,7 @@ extern JsonValue * JsonValueInteger(long);
|
||||||
* misleading. Check the type of the value before making assumptions
|
* misleading. Check the type of the value before making assumptions
|
||||||
* about its value.
|
* about its value.
|
||||||
*/
|
*/
|
||||||
extern long JsonValueAsInteger(JsonValue *);
|
extern Int64 JsonValueAsInteger(JsonValue *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode a floating point number as a JSON value that can be added
|
* Encode a floating point number as a JSON value that can be added
|
||||||
|
|
252
Cytoplasm/src/include/UInt64.h
Normal file
252
Cytoplasm/src/include/UInt64.h
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef CYTOPLASM_UINT64_H
|
||||||
|
#define CYTOPLASM_UINT64_H
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @Nm UInt64
|
||||||
|
* @Nd Fixed-width 64 bit integers.
|
||||||
|
* @Dd August 11, 2023
|
||||||
|
*
|
||||||
|
* .Pp
|
||||||
|
* ANSI C89 (or C99 for that matter) provides no required mechanism
|
||||||
|
* for 64 bit integers. Nevertheless, many compilers provide them as
|
||||||
|
* extensions. However, since it is not a gaurantee, and to be fully
|
||||||
|
* standards-compliant and thus portable, a platform-agnostic interface
|
||||||
|
* is required. This header provides such an interface. If the platform
|
||||||
|
* has a 64 bit integer type, that is used, and native operations are
|
||||||
|
* performed by C preprocessor macro expansion. Otherwise, a
|
||||||
|
* compatibility layer is provided, which implements 64-bit
|
||||||
|
* arithmetic on an array of 2 32-bit numbers which are provided by
|
||||||
|
* .Xr Int 3 .
|
||||||
|
* .Pp
|
||||||
|
* Note that 64-bit emulation is certainly not as performant as using
|
||||||
|
* native 64-bit operations, so whenever possible, the native
|
||||||
|
* operations should be preferred. However, since C provides no required
|
||||||
|
* 64 bit integer on 32-bit and less platforms, this API can be used as
|
||||||
|
* a "good enough" fallback mechanism.
|
||||||
|
* .Pp
|
||||||
|
* Also note that this implementation, both in the native and
|
||||||
|
* non-native forms, makes some assumptions:
|
||||||
|
* .Bl -bullet -width Ds
|
||||||
|
* .It
|
||||||
|
* When a cast from a larger integer to a smaller integer is performed,
|
||||||
|
* the upper bits are truncated, not the lower bits.
|
||||||
|
* .It
|
||||||
|
* Negative numbers are represented in memory and in registers in two's
|
||||||
|
* compliment form.
|
||||||
|
* .El
|
||||||
|
* .Pp
|
||||||
|
* This API may provide unexpected output if these assumptions are
|
||||||
|
* false for a given platform.
|
||||||
|
*
|
||||||
|
* @ignore-typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Int.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef INT64_FORCE_EMULATED
|
||||||
|
|
||||||
|
#define BIT64_MAX 18446744073709551615UL
|
||||||
|
|
||||||
|
#if UINT_MAX == BIT64_MAX
|
||||||
|
/* typedef signed int Int64; */
|
||||||
|
typedef unsigned int UInt64;
|
||||||
|
|
||||||
|
#define UINT64_NATIVE
|
||||||
|
|
||||||
|
#elif ULONG_MAX == BIT64_MAX
|
||||||
|
/* typedef signed int Int64; */
|
||||||
|
typedef unsigned long UInt64;
|
||||||
|
|
||||||
|
#define UINT64_NATIVE
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ifndef INT64_FORCE_EMULATED */
|
||||||
|
|
||||||
|
#ifdef UINT64_NATIVE
|
||||||
|
|
||||||
|
#define UInt64Create(high, low) (((UInt64) (high) << 32) | (low))
|
||||||
|
#define UInt64Low(a) ((UInt32) ((a) & 0x00000000FFFFFFFF))
|
||||||
|
#define UInt64High(a) ((UInt32) ((a) >> 32))
|
||||||
|
|
||||||
|
#define UInt64Add(a, b) ((a) + (b))
|
||||||
|
#define UInt64Sub(a, b) ((a) - (b))
|
||||||
|
#define UInt64Mul(a, b) ((a) * (b))
|
||||||
|
#define UInt64Div(a, b) ((a) / (b))
|
||||||
|
#define UInt64Rem(a, b) ((a) % (b))
|
||||||
|
|
||||||
|
#define UInt64Sll(a, b) ((a) << (b))
|
||||||
|
#define UInt64Srl(a, b) ((a) >> (b))
|
||||||
|
|
||||||
|
#define UInt64And(a, b) ((a) & (b))
|
||||||
|
#define UInt64Or(a, b) ((a) | (b))
|
||||||
|
#define UInt64Xor(a, b) ((a) ^ (b))
|
||||||
|
#define UInt64Not(a) (~(a))
|
||||||
|
|
||||||
|
#define UInt64Eq(a, b) ((a) == (b))
|
||||||
|
#define UInt64Lt(a, b) ((a) < (b))
|
||||||
|
#define UInt64Gt(a, b) ((a) > (b))
|
||||||
|
|
||||||
|
#define UInt64Neq(a, b) ((a) != (b))
|
||||||
|
#define UInt64Leq(a, b) ((a) <= (b))
|
||||||
|
#define UInt64Geq(a, b) ((a) >= (b))
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For platforms that do not have a native integer large enough to
|
||||||
|
* store a 64 bit integer, this struct is used. i[0] contains the low
|
||||||
|
* bits of integer, and i[1] contains the high bits of the integer.
|
||||||
|
* .Pp
|
||||||
|
* This struct should not be accessed directly, because UInt64 may not
|
||||||
|
* actually be this struct, it might be an actual integer type. For
|
||||||
|
* maximum portability, only use the functions defined here to
|
||||||
|
* manipulate 64 bit integers.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UInt32 i[2];
|
||||||
|
} UInt64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new unsigned 64 bit integer using the given high and low
|
||||||
|
* bits.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Create(UInt32, UInt32);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add two unsigned 64 bit integers together.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Add(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtract the second 64 bit integer from the first.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Sub(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply two 64 bit integers together. The non-native version of
|
||||||
|
* this function uses the Russian Peasant method of multiplication,
|
||||||
|
* which should afford more performance than a naive multiplication by
|
||||||
|
* addition, but it is still rather slow and depends on the size of
|
||||||
|
* the integers being multiplied.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Mul(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Divide the first 64 bit integer by the second and return the
|
||||||
|
* quotient. The non-native version of this function uses naive binary
|
||||||
|
* long division, which is slow, but gauranteed to finish in constant
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Div(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Divide the first 64 bit integer by the second and return the
|
||||||
|
* remainder. The non-native version of this function uses naive binary
|
||||||
|
* long division, which is slow, but gauranteed to finish in constant
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Rem(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a left logical bit shift of a 64 bit integer. The second
|
||||||
|
* parameter is how many places to shift, and is declared as a regular
|
||||||
|
* integer because anything more than 64 does not make sense.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Sll(UInt64, int);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a right logical bit shift of a 64 bit integer. The second
|
||||||
|
* parameter is how many places to shift, and is declared as a regular
|
||||||
|
* integer because anything more than 64 does not make sense.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Srl(UInt64, int);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise AND (&) of the provided 64 bit integers.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64And(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise OR (|) of the provided 64 bit integers.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Or(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise XOR (^) of the provided 64 bit integers.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Xor(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a bitwise NOT (~) of the provided 64 bit integer.
|
||||||
|
*/
|
||||||
|
extern UInt64 UInt64Not(UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a comparison of the provided 64 bit integers and return a C
|
||||||
|
* boolean that is true if and only if they are equal.
|
||||||
|
*/
|
||||||
|
extern int UInt64Eq(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a comparison of the provided 64 bit integers and return a C
|
||||||
|
* boolean that is true if and only if the second operand is strictly
|
||||||
|
* less than the first.
|
||||||
|
*/
|
||||||
|
extern int UInt64Lt(UInt64, UInt64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a comparison of the provided 64 bit integers and return a C
|
||||||
|
* boolean that is true if and only if the second operand is strictly
|
||||||
|
* greater than the first.
|
||||||
|
*/
|
||||||
|
extern int UInt64Gt(UInt64, UInt64);
|
||||||
|
|
||||||
|
#define UInt64Low(a) ((a).i[0])
|
||||||
|
#define UInt64High(a) ((a).i[1])
|
||||||
|
|
||||||
|
#define UInt64Neq(a, b) (!UInt64Eq(a, b))
|
||||||
|
#define UInt64Leq(a, b) (UInt64Eq(a, b) || UInt64Lt(a, b))
|
||||||
|
#define UInt64Geq(a, b) (UInt64Eq(a, b) || UInt64Gt(a, b))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UINT64_STRBUF 65 /* Base 2 representation with '\0' */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a 64 bit integer to a string in an arbitrary base
|
||||||
|
* representation specified by the second parameter, using the provided
|
||||||
|
* buffer and length specified by the third and fourth parameters. To
|
||||||
|
* guarantee that the string will fit in the buffer, allocate it of
|
||||||
|
* size UINT64_STRBUF or larger. Note that a buffer size smaller than
|
||||||
|
* UINT64_STRBUF will invoke undefined behavior.
|
||||||
|
*/
|
||||||
|
extern size_t UInt64Str(UInt64, int, char *, size_t);
|
||||||
|
|
||||||
|
#endif /* CYTOPLASM_UINT64_H */
|
|
@ -43,6 +43,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
|
#include <UInt64.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current timestamp in milliseconds since the Unix epoch. This
|
* Get the current timestamp in milliseconds since the Unix epoch. This
|
||||||
|
@ -51,16 +52,16 @@
|
||||||
* and time_t, and converts it to a single number, which is then
|
* and time_t, and converts it to a single number, which is then
|
||||||
* returned to the caller.
|
* returned to the caller.
|
||||||
* .Pp
|
* .Pp
|
||||||
* A note on the 2038 problem: as long as sizeof(long) >= 8, that is,
|
* A note on the 2038 problem: as long as sizeof(time_t) >= 8, that is,
|
||||||
* as long as the long data type is 64 bits or more, then everything
|
* as long as the time_t type is 64 bits or more, then everything
|
||||||
* should be fine. On most, if not, all, 64-bit systems, long is 64
|
* should be fine. On most, if not, all, 64-bit systems, time_t is 64
|
||||||
* bits. I would expect Cytoplasm to break for 32 bit systems
|
* bits. time_t is promoted to a 64-bit integer before it is converted
|
||||||
* eventually, but we should have a ways to go before that happens.
|
* to milliseconds, so there is no risk of overflue due to the
|
||||||
* I didn't want to try to hack together some system to store larger
|
* multiplication by 1000. However, if time_t is only 32 bits, it will
|
||||||
* numbers than the architecture supports. But we can always
|
* overflow before it even gets to this function, which will cause this
|
||||||
* re-evaluate over the next few years.
|
* function to produce unexpected results.
|
||||||
*/
|
*/
|
||||||
extern unsigned long UtilServerTs(void);
|
extern UInt64 UtilServerTs(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use
|
* Use
|
||||||
|
@ -69,7 +70,7 @@ extern unsigned long UtilServerTs(void);
|
||||||
* was an error getting the last modified time of a file. This is
|
* was an error getting the last modified time of a file. This is
|
||||||
* primarily useful for caching file data.
|
* primarily useful for caching file data.
|
||||||
*/
|
*/
|
||||||
extern unsigned long UtilLastModified(char *);
|
extern UInt64 UtilLastModified(char *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function behaves just like the system call
|
* This function behaves just like the system call
|
||||||
|
@ -85,7 +86,7 @@ extern int UtilMkdir(const char *, const mode_t);
|
||||||
* .Xr nanosleep 2
|
* .Xr nanosleep 2
|
||||||
* to make its usage much, much simpler.
|
* to make its usage much, much simpler.
|
||||||
*/
|
*/
|
||||||
extern int UtilSleepMillis(long);
|
extern int UtilSleepMillis(UInt64);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function works identically to the POSIX
|
* This function works identically to the POSIX
|
||||||
|
@ -111,6 +112,6 @@ extern ssize_t UtilGetLine(char **, size_t *, Stream *);
|
||||||
* .Fn pthread_self
|
* .Fn pthread_self
|
||||||
* to a number.
|
* to a number.
|
||||||
*/
|
*/
|
||||||
extern unsigned long UtilThreadNo(void);
|
extern UInt32 UtilThreadNo(void);
|
||||||
|
|
||||||
#endif /* CYTOPLASM_UTIL_H */
|
#endif /* CYTOPLASM_UTIL_H */
|
||||||
|
|
145
Cytoplasm/tools/int64.c
Normal file
145
Cytoplasm/tools/int64.c
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
|
#include <Log.h>
|
||||||
|
|
||||||
|
/* AssertEquals(actual, expected) */
|
||||||
|
int
|
||||||
|
AssertEquals(char *msg, Int64 x, Int64 y)
|
||||||
|
{
|
||||||
|
if (!Int64Eq(x, y))
|
||||||
|
{
|
||||||
|
Log(LOG_ERR, "%s: Expected 0x%X 0x%X, got 0x%X 0x%X", msg,
|
||||||
|
Int64High(y), Int64Low(y),
|
||||||
|
Int64High(x), Int64Low(x));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Main(void)
|
||||||
|
{
|
||||||
|
Int64 x, y;
|
||||||
|
|
||||||
|
Log(LOG_INFO, "sizeof(Int64) = %lu", sizeof(Int64));
|
||||||
|
|
||||||
|
#ifdef INT64_NATIVE
|
||||||
|
Log(LOG_INFO, "Using native 64-bit integers.");
|
||||||
|
#else
|
||||||
|
Log(LOG_INFO, "Using emulated 64-bit integers.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* BSR Tests */
|
||||||
|
|
||||||
|
x = Int64Create(0x000000FF, 0x00000000);
|
||||||
|
|
||||||
|
y = Int64Sra(x, 4);
|
||||||
|
AssertEquals("x >> 4", y, Int64Create(0x0000000F, 0xF0000000));
|
||||||
|
|
||||||
|
y = Int64Sra(x, 8);
|
||||||
|
AssertEquals("x >> 8", y, Int64Create(0x00000000, 0xFF000000));
|
||||||
|
|
||||||
|
y = Int64Sra(x, 36);
|
||||||
|
AssertEquals("x >> 36", y, Int64Create(0x00000000, 0x0000000F));
|
||||||
|
|
||||||
|
x = Int64Create(0xFF000000, 0x00000000);
|
||||||
|
|
||||||
|
y = Int64Sra(x, 4);
|
||||||
|
AssertEquals("x >> 4", y, Int64Create(0xFFF00000, 0x00000000));
|
||||||
|
|
||||||
|
y = Int64Sra(x, 8);
|
||||||
|
AssertEquals("x >> 8", y, Int64Create(0xFFFF0000, 0x00000000));
|
||||||
|
|
||||||
|
y = Int64Sra(x, 63);
|
||||||
|
AssertEquals("x >> 63", y, Int64Create(0xFFFFFFFF, 0xFFFFFFFF));
|
||||||
|
|
||||||
|
/* BSL Tests */
|
||||||
|
|
||||||
|
x = Int64Create(0x00000000, 0xFF000000);
|
||||||
|
|
||||||
|
y = Int64Sll(x, 4);
|
||||||
|
AssertEquals("x << 4", y, Int64Create(0x0000000F, 0xF0000000));
|
||||||
|
|
||||||
|
y = Int64Sll(x, 8);
|
||||||
|
AssertEquals("x << 8", y, Int64Create(0x000000FF, 0x00000000));
|
||||||
|
|
||||||
|
y = Int64Sll(x, 36);
|
||||||
|
AssertEquals("x << 36", y, Int64Create(0xF0000000, 0x00000000));
|
||||||
|
|
||||||
|
/* ADD Tests */
|
||||||
|
|
||||||
|
x = Int64Create(0x00000000, 0xF0000001);
|
||||||
|
y = Int64Create(0x00000000, 0x00000002);
|
||||||
|
AssertEquals("0xF0000001 + 0x00000002", Int64Add(x, y), Int64Create(0x00000000, 0xF0000003));
|
||||||
|
|
||||||
|
x = Int64Create(0x00000000, 0xF0000000);
|
||||||
|
y = Int64Create(0x00000000, 0x10000000);
|
||||||
|
AssertEquals("0xF0000000 + 0x10000000", Int64Add(x, y), Int64Create(0x00000001, 0x00000000));
|
||||||
|
|
||||||
|
x = Int64Create(0, 5);
|
||||||
|
y = Int64Neg(Int64Create(0, 10));
|
||||||
|
AssertEquals("5 + (-10)", Int64Add(x, y), Int64Neg(Int64Create(0, 5)));
|
||||||
|
|
||||||
|
/* SUB Tests */
|
||||||
|
x = Int64Create(0x00000000, 0x00000005);
|
||||||
|
y = Int64Create(0x00000000, 0x00000002);
|
||||||
|
AssertEquals("0x00000005 - 0x00000002", Int64Sub(x, y), Int64Create(0x00000000, 0x00000003));
|
||||||
|
|
||||||
|
x = Int64Create(0x00000001, 0x00000000);
|
||||||
|
y = Int64Create(0x00000000, 0x00000001);
|
||||||
|
AssertEquals("0x00000001 0x00000000 - 0x00000001", Int64Sub(x, y), Int64Create(0x00000000, 0xFFFFFFFF));
|
||||||
|
|
||||||
|
x = Int64Create(0, 5);
|
||||||
|
y = Int64Create(0, 10);
|
||||||
|
AssertEquals("5 - 10", Int64Sub(x, y), Int64Neg(Int64Create(0, 5)));
|
||||||
|
|
||||||
|
x = Int64Create(0, 5);
|
||||||
|
y = Int64Neg(Int64Create(0, 10));
|
||||||
|
AssertEquals("5 - (-10)", Int64Sub(x, y), Int64Create(0, 15));
|
||||||
|
|
||||||
|
/* MUL Tests */
|
||||||
|
x = Int64Create(0, 18);
|
||||||
|
y = Int64Create(0, 1);
|
||||||
|
AssertEquals("18 * 1", Int64Mul(x, y), Int64Create(0, 18));
|
||||||
|
|
||||||
|
x = Int64Create(0, 20);
|
||||||
|
y = Int64Create(0, 12);
|
||||||
|
AssertEquals("20 * 12", Int64Mul(x, y), Int64Create(0, 240));
|
||||||
|
|
||||||
|
x = Int64Create(0x00000000, 0x00000005);
|
||||||
|
y = Int64Create(0x00000000, 0x00000005);
|
||||||
|
AssertEquals("0x00000005 * 0x00000005", Int64Mul(x, y), Int64Create(0x00000000, 0x00000019));
|
||||||
|
|
||||||
|
x = Int64Create(0x00000001, 0x00000000);
|
||||||
|
y = Int64Create(0x00000000, 0x00000005);
|
||||||
|
AssertEquals("0x00000001 0x00000000 * 0x00000005", Int64Mul(x, y), Int64Create(0x00000005, 0x00000000));
|
||||||
|
|
||||||
|
/* DIV Tests */
|
||||||
|
x = Int64Create(0, 12);
|
||||||
|
y = Int64Create(0, 4);
|
||||||
|
AssertEquals("12 / 4", Int64Div(x, y), Int64Create(0, 3));
|
||||||
|
|
||||||
|
/* MOD Tests */
|
||||||
|
x = Int64Create(0x000000FF, 0x00000000);
|
||||||
|
y = Int64Create(0x00000000, 0x00000010);
|
||||||
|
AssertEquals("0x000000FF 0x00000000 mod 0x00000010", Int64Rem(x, y), Int64Create(0, 0));
|
||||||
|
|
||||||
|
x = Int64Create(0x00000000, 0xFF000000);
|
||||||
|
y = Int64Create(0x00000000, 0x00000010);
|
||||||
|
AssertEquals("0x00000000 0xFF000000 mod 0x00000010", Int64Rem(x, y), Int64Create(0, 0));
|
||||||
|
|
||||||
|
x = Int64Create(0xFF000000, 0x00000000);
|
||||||
|
y = Int64Create(0x00000000, 0x00000010);
|
||||||
|
AssertEquals("0xFF000000 0x00000000 mod 0x00000010", Int64Rem(x, y), Int64Create(0, 0));
|
||||||
|
|
||||||
|
x = Int64Create(0x00000000, 0x000000F0);
|
||||||
|
y = Int64Create(0x00000000, 0x00000010);
|
||||||
|
AssertEquals("0x00000000 0x000000F0 mod 0x00000010", Int64Rem(x, y), Int64Create(0, 0));
|
||||||
|
|
||||||
|
/* TODO: Add more tests for negative multiplication, division, and
|
||||||
|
* mod */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -40,7 +40,8 @@
|
||||||
static char *
|
static char *
|
||||||
Trim(char c, char *str)
|
Trim(char c, char *str)
|
||||||
{
|
{
|
||||||
while (*str == c) str++;
|
while (*str == c)
|
||||||
|
str++;
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,6 +356,7 @@ Main(Array * args)
|
||||||
!StrEquals(fieldType, "boolean"))
|
!StrEquals(fieldType, "boolean"))
|
||||||
{
|
{
|
||||||
Node *node = HashMapGet(typeToNode, fieldType);
|
Node *node = HashMapGet(typeToNode, fieldType);
|
||||||
|
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
{
|
||||||
node = Malloc(sizeof(Node));
|
node = Malloc(sizeof(Node));
|
||||||
|
@ -441,6 +443,7 @@ Main(Array * args)
|
||||||
|
|
||||||
StreamPrintf(headerFile, "#include <Array.h>\n");
|
StreamPrintf(headerFile, "#include <Array.h>\n");
|
||||||
StreamPrintf(headerFile, "#include <HashMap.h>\n");
|
StreamPrintf(headerFile, "#include <HashMap.h>\n");
|
||||||
|
StreamPrintf(headerFile, "#include <Int64.h>\n");
|
||||||
|
|
||||||
StreamPutc(headerFile, '\n');
|
StreamPutc(headerFile, '\n');
|
||||||
|
|
||||||
|
@ -489,7 +492,7 @@ Main(Array * args)
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "integer"))
|
else if (StrEquals(fieldType, "integer"))
|
||||||
{
|
{
|
||||||
cType = "long";
|
cType = "Int64";
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "boolean"))
|
else if (StrEquals(fieldType, "boolean"))
|
||||||
{
|
{
|
||||||
|
@ -607,7 +610,7 @@ Main(Array * args)
|
||||||
" *errp = \"Invalid pointers passed to %sFromJson()\";\n"
|
" *errp = \"Invalid pointers passed to %sFromJson()\";\n"
|
||||||
" return 0;\n"
|
" return 0;\n"
|
||||||
" }\n\n"
|
" }\n\n"
|
||||||
, type);
|
,type);
|
||||||
for (i = 0; i < ArraySize(keys); i++)
|
for (i = 0; i < ArraySize(keys); i++)
|
||||||
{
|
{
|
||||||
char *key = ArrayGet(keys, i);
|
char *key = ArrayGet(keys, i);
|
||||||
|
@ -662,7 +665,7 @@ Main(Array * args)
|
||||||
|
|
||||||
if (StrEquals(fieldType, "integer"))
|
if (StrEquals(fieldType, "integer"))
|
||||||
{
|
{
|
||||||
cType = "long";
|
cType = "Int64";
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "float"))
|
else if (StrEquals(fieldType, "float"))
|
||||||
{
|
{
|
||||||
|
@ -905,7 +908,7 @@ Main(Array * args)
|
||||||
|
|
||||||
if (StrEquals(fieldType, "integer"))
|
if (StrEquals(fieldType, "integer"))
|
||||||
{
|
{
|
||||||
cType = "long";
|
cType = "Int64";
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "float"))
|
else if (StrEquals(fieldType, "float"))
|
||||||
{
|
{
|
||||||
|
@ -1006,6 +1009,10 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " for (i = 0; i < ArraySize(val->%s); i++)\n", key);
|
StreamPrintf(implFile, " for (i = 0; i < ArraySize(val->%s); i++)\n", key);
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " %sFree(ArrayGet(val->%s, i));\n", (!isEnum && !isPrimitive) ? fieldType : "", key);
|
StreamPrintf(implFile, " %sFree(ArrayGet(val->%s, i));\n", (!isEnum && !isPrimitive) ? fieldType : "", key);
|
||||||
|
if (!isEnum && !isPrimitive)
|
||||||
|
{
|
||||||
|
StreamPrintf(implFile, " Free(ArrayGet(val->%s, i));\n", key);
|
||||||
|
}
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " ArrayFree(val->%s);\n", key);
|
StreamPrintf(implFile, " ArrayFree(val->%s);\n", key);
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
|
@ -1014,7 +1021,8 @@ Main(Array * args)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Ignore primitives but call the appropriate free method on declared types */
|
/* Ignore primitives but call the appropriate free
|
||||||
|
* method on declared types */
|
||||||
if (!isEnum && HashMapGet(types, fieldType))
|
if (!isEnum && HashMapGet(types, fieldType))
|
||||||
{
|
{
|
||||||
StreamPrintf(implFile, " %sFree(&val->%s);\n", fieldType, key);
|
StreamPrintf(implFile, " %sFree(&val->%s);\n", fieldType, key);
|
||||||
|
|
119
Cytoplasm/tools/uint64.c
Normal file
119
Cytoplasm/tools/uint64.c
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#include <UInt64.h>
|
||||||
|
|
||||||
|
#include <Log.h>
|
||||||
|
|
||||||
|
/* AssertEquals(actual, expected) */
|
||||||
|
int
|
||||||
|
AssertEquals(char *msg, UInt64 x, UInt64 y)
|
||||||
|
{
|
||||||
|
if (!UInt64Eq(x, y))
|
||||||
|
{
|
||||||
|
Log(LOG_ERR, "%s: Expected 0x%X 0x%X, got 0x%X 0x%X", msg,
|
||||||
|
UInt64High(y), UInt64Low(y),
|
||||||
|
UInt64High(x), UInt64Low(x));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Main(void)
|
||||||
|
{
|
||||||
|
UInt64 x, y;
|
||||||
|
|
||||||
|
Log(LOG_INFO, "sizeof(UInt64) = %lu", sizeof(UInt64));
|
||||||
|
|
||||||
|
#ifdef UINT64_NATIVE
|
||||||
|
Log(LOG_INFO, "Using native 64-bit integers.");
|
||||||
|
#else
|
||||||
|
Log(LOG_INFO, "Using emulated 64-bit integers.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* BSR Tests */
|
||||||
|
|
||||||
|
x = UInt64Create(0x000000FF, 0x00000000);
|
||||||
|
|
||||||
|
y = UInt64Srl(x, 4);
|
||||||
|
AssertEquals("x >> 4", y, UInt64Create(0x0000000F, 0xF0000000));
|
||||||
|
|
||||||
|
y = UInt64Srl(x, 8);
|
||||||
|
AssertEquals("x >> 8", y, UInt64Create(0x00000000, 0xFF000000));
|
||||||
|
|
||||||
|
y = UInt64Srl(x, 36);
|
||||||
|
AssertEquals("x >> 36", y, UInt64Create(0x00000000, 0x0000000F));
|
||||||
|
|
||||||
|
/* BSL Tests */
|
||||||
|
|
||||||
|
x = UInt64Create(0x00000000, 0xFF000000);
|
||||||
|
|
||||||
|
y = UInt64Sll(x, 4);
|
||||||
|
AssertEquals("x << 4", y, UInt64Create(0x0000000F, 0xF0000000));
|
||||||
|
|
||||||
|
y = UInt64Sll(x, 8);
|
||||||
|
AssertEquals("x << 8", y, UInt64Create(0x000000FF, 0x00000000));
|
||||||
|
|
||||||
|
y = UInt64Sll(x, 36);
|
||||||
|
AssertEquals("x << 36", y, UInt64Create(0xF0000000, 0x00000000));
|
||||||
|
|
||||||
|
/* ADD Tests */
|
||||||
|
|
||||||
|
x = UInt64Create(0x00000000, 0xF0000001);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000002);
|
||||||
|
AssertEquals("0xF0000001 + 0x00000002", UInt64Add(x, y), UInt64Create(0x00000000, 0xF0000003));
|
||||||
|
|
||||||
|
x = UInt64Create(0x00000000, 0xF0000000);
|
||||||
|
y = UInt64Create(0x00000000, 0x10000000);
|
||||||
|
AssertEquals("0xF0000000 + 0x10000000", UInt64Add(x, y), UInt64Create(0x00000001, 0x00000000));
|
||||||
|
|
||||||
|
/* SUB Tests */
|
||||||
|
x = UInt64Create(0x00000000, 0x00000005);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000002);
|
||||||
|
AssertEquals("0x00000005 - 0x00000002", UInt64Sub(x, y), UInt64Create(0x00000000, 0x00000003));
|
||||||
|
|
||||||
|
x = UInt64Create(0x00000001, 0x00000000);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000001);
|
||||||
|
AssertEquals("0x00000001 0x00000000 - 0x00000001", UInt64Sub(x, y), UInt64Create(0x00000000, 0xFFFFFFFF));
|
||||||
|
|
||||||
|
/* MUL Tests */
|
||||||
|
x = UInt64Create(0, 18);
|
||||||
|
y = UInt64Create(0, 1);
|
||||||
|
AssertEquals("18 * 1", UInt64Mul(x, y), UInt64Create(0, 18));
|
||||||
|
|
||||||
|
x = UInt64Create(0, 20);
|
||||||
|
y = UInt64Create(0, 12);
|
||||||
|
AssertEquals("20 * 12", UInt64Mul(x, y), UInt64Create(0, 240));
|
||||||
|
|
||||||
|
x = UInt64Create(0x00000000, 0x00000005);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000005);
|
||||||
|
AssertEquals("0x00000005 * 0x00000005", UInt64Mul(x, y), UInt64Create(0x00000000, 0x00000019));
|
||||||
|
|
||||||
|
x = UInt64Create(0x00000001, 0x00000000);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000005);
|
||||||
|
AssertEquals("0x00000001 0x00000000 * 0x00000005", UInt64Mul(x, y), UInt64Create(0x00000005, 0x00000000));
|
||||||
|
|
||||||
|
/* DIV Tests */
|
||||||
|
x = UInt64Create(0, 12);
|
||||||
|
y = UInt64Create(0, 4);
|
||||||
|
AssertEquals("12 / 4", UInt64Div(x, y), UInt64Create(0, 3));
|
||||||
|
|
||||||
|
/* MOD Tests */
|
||||||
|
x = UInt64Create(0x000000FF, 0x00000000);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000010);
|
||||||
|
AssertEquals("0x000000FF 0x00000000 mod 0x00000010", UInt64Rem(x, y), UInt64Create(0, 0));
|
||||||
|
|
||||||
|
x = UInt64Create(0x00000000, 0xFF000000);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000010);
|
||||||
|
AssertEquals("0x00000000 0xFF000000 mod 0x00000010", UInt64Rem(x, y), UInt64Create(0, 0));
|
||||||
|
|
||||||
|
x = UInt64Create(0xFF000000, 0x00000000);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000010);
|
||||||
|
AssertEquals("0xFF000000 0x00000000 mod 0x00000010", UInt64Rem(x, y), UInt64Create(0, 0));
|
||||||
|
|
||||||
|
x = UInt64Create(0x00000000, 0x000000F0);
|
||||||
|
y = UInt64Create(0x00000000, 0x00000010);
|
||||||
|
AssertEquals("0x00000000 0x000000F0 mod 0x00000010", UInt64Rem(x, y), UInt64Create(0, 0));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
5
TODO.txt
5
TODO.txt
|
@ -34,7 +34,11 @@ Milestone: v0.4.0
|
||||||
[~] Debug OpenSSL
|
[~] Debug OpenSSL
|
||||||
[x] Database corruption
|
[x] Database corruption
|
||||||
[ ] File descriptor exhaustion
|
[ ] File descriptor exhaustion
|
||||||
|
[ ] Fix tp on NetBSD
|
||||||
[ ] Random memory corruption after many requests.
|
[ ] Random memory corruption after many requests.
|
||||||
|
[ ] HOST_NAME_MAX not defined on some systems?
|
||||||
|
- Check if POSIX
|
||||||
|
- Might be enough to #define it when it doesn't exist.
|
||||||
[~] j2s
|
[~] j2s
|
||||||
[x] Properly support arrays of primitives.
|
[x] Properly support arrays of primitives.
|
||||||
[ ] How to set default value of true on boolean?
|
[ ] How to set default value of true on boolean?
|
||||||
|
@ -62,6 +66,7 @@ Milestone: v0.4.0
|
||||||
[ ] Add "id" objects when putting aliases
|
[ ] Add "id" objects when putting aliases
|
||||||
[ ] Delete from "id" when deleting alias
|
[ ] Delete from "id" when deleting alias
|
||||||
[x] Add alias admin privilege to allow admins to manage aliases
|
[x] Add alias admin privilege to allow admins to manage aliases
|
||||||
|
[ ] Fix note link on website main page.
|
||||||
|
|
||||||
Milestone: v0.5.0
|
Milestone: v0.5.0
|
||||||
-----------------
|
-----------------
|
||||||
|
|
11
src/Config.c
11
src/Config.c
|
@ -30,6 +30,7 @@
|
||||||
#include <Db.h>
|
#include <Db.h>
|
||||||
#include <HttpServer.h>
|
#include <HttpServer.h>
|
||||||
#include <Log.h>
|
#include <Log.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
@ -82,7 +83,7 @@
|
||||||
tConfig->err = "Expected " key " to be of type JSON_INTEGER"; \
|
tConfig->err = "Expected " key " to be of type JSON_INTEGER"; \
|
||||||
goto error; \
|
goto error; \
|
||||||
} \
|
} \
|
||||||
into = JsonValueAsInteger(value); \
|
into = Int64Low(JsonValueAsInteger(value)); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
|
@ -146,9 +147,9 @@ ConfigParseListen(Config * tConfig, Array * listen)
|
||||||
|
|
||||||
obj = JsonValueAsObject(val);
|
obj = JsonValueAsObject(val);
|
||||||
|
|
||||||
serverCfg->port = JsonValueAsInteger(HashMapGet(obj, "port"));
|
serverCfg->port = Int64Low(JsonValueAsInteger(HashMapGet(obj, "port")));
|
||||||
serverCfg->threads = JsonValueAsInteger(HashMapGet(obj, "threads"));
|
serverCfg->threads = Int64Low(JsonValueAsInteger(HashMapGet(obj, "threads")));
|
||||||
serverCfg->maxConnections = JsonValueAsInteger(HashMapGet(obj, "maxConnections"));
|
serverCfg->maxConnections = Int64Low(JsonValueAsInteger(HashMapGet(obj, "maxConnections")));
|
||||||
|
|
||||||
if (!serverCfg->port)
|
if (!serverCfg->port)
|
||||||
{
|
{
|
||||||
|
@ -450,7 +451,7 @@ ConfigCreateDefault(Db * db)
|
||||||
|
|
||||||
listeners = ArrayCreate();
|
listeners = ArrayCreate();
|
||||||
listen = HashMapCreate();
|
listen = HashMapCreate();
|
||||||
HashMapSet(listen, "port", JsonValueInteger(8008));
|
HashMapSet(listen, "port", JsonValueInteger(Int64Create(0, 8008)));
|
||||||
HashMapSet(listen, "tls", JsonValueBoolean(0));
|
HashMapSet(listen, "tls", JsonValueBoolean(0));
|
||||||
ArrayAdd(listeners, JsonValueObject(listen));
|
ArrayAdd(listeners, JsonValueObject(listen));
|
||||||
HashMapSet(json, "listen", JsonValueArray(listeners));
|
HashMapSet(json, "listen", JsonValueArray(listeners));
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include <Schema/Filter.h>
|
#include <Schema/Filter.h>
|
||||||
|
|
||||||
HashMap *
|
HashMap *
|
||||||
FilterApply(Filter *filter, HashMap *event)
|
FilterApply(Filter * filter, HashMap * event)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
13
src/Main.c
13
src/Main.c
|
@ -247,7 +247,7 @@ start:
|
||||||
}
|
}
|
||||||
|
|
||||||
token = StrRandom(32);
|
token = StrRandom(32);
|
||||||
info = RegTokenCreate(matrixArgs.db, token, NULL, 0, 1, USER_ALL);
|
info = RegTokenCreate(matrixArgs.db, token, NULL, UInt64Create(0, 0), Int64Create(0, 1), USER_ALL);
|
||||||
if (!info)
|
if (!info)
|
||||||
{
|
{
|
||||||
Free(token);
|
Free(token);
|
||||||
|
@ -259,8 +259,8 @@ start:
|
||||||
RegTokenClose(info);
|
RegTokenClose(info);
|
||||||
RegTokenFree(info);
|
RegTokenFree(info);
|
||||||
|
|
||||||
/* Don't free token, because we need to print it when logging is
|
/* Don't free token, because we need to print it when logging
|
||||||
* set up. */
|
* is set up. */
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(LOG_NOTICE, "Loading configuration...");
|
Log(LOG_NOTICE, "Loading configuration...");
|
||||||
|
@ -339,7 +339,8 @@ start:
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If a token was created with a default config, print it to the log */
|
/* If a token was created with a default config, print it to the
|
||||||
|
* log */
|
||||||
if (token)
|
if (token)
|
||||||
{
|
{
|
||||||
Log(LOG_NOTICE, "Admin Registration token: %s", token);
|
Log(LOG_NOTICE, "Admin Registration token: %s", token);
|
||||||
|
@ -384,14 +385,14 @@ start:
|
||||||
|
|
||||||
if (serverCfg->flags & HTTP_FLAG_TLS)
|
if (serverCfg->flags & HTTP_FLAG_TLS)
|
||||||
{
|
{
|
||||||
if (!UtilLastModified(serverCfg->tlsCert))
|
if (UInt64Eq(UtilLastModified(serverCfg->tlsCert), UInt64Create(0, 0)))
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsCert);
|
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsCert);
|
||||||
exit = EXIT_FAILURE;
|
exit = EXIT_FAILURE;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UtilLastModified(serverCfg->tlsKey))
|
if (UInt64Eq(UtilLastModified(serverCfg->tlsKey), UInt64Create(0, 0)))
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsKey);
|
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsKey);
|
||||||
exit = EXIT_FAILURE;
|
exit = EXIT_FAILURE;
|
||||||
|
|
|
@ -31,14 +31,15 @@
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
#include <Str.h>
|
#include <Str.h>
|
||||||
#include <User.h>
|
#include <User.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
int
|
int
|
||||||
RegTokenValid(RegTokenInfo * token)
|
RegTokenValid(RegTokenInfo * token)
|
||||||
{
|
{
|
||||||
HashMap *tokenJson;
|
HashMap *tokenJson;
|
||||||
int uses, used;
|
Int64 uses, used;
|
||||||
|
|
||||||
unsigned long expiration;
|
UInt64 expiration;
|
||||||
|
|
||||||
if (!token || !RegTokenExists(token->db, token->name))
|
if (!token || !RegTokenExists(token->db, token->name))
|
||||||
{
|
{
|
||||||
|
@ -50,8 +51,9 @@ RegTokenValid(RegTokenInfo * token)
|
||||||
used = JsonValueAsInteger(HashMapGet(tokenJson, "used"));
|
used = JsonValueAsInteger(HashMapGet(tokenJson, "used"));
|
||||||
expiration = JsonValueAsInteger(HashMapGet(tokenJson, "expires_on"));
|
expiration = JsonValueAsInteger(HashMapGet(tokenJson, "expires_on"));
|
||||||
|
|
||||||
return (!expiration || (UtilServerTs() <= expiration)) &&
|
return (UInt64Eq(expiration, UInt64Create(0, 0)) ||
|
||||||
(uses == -1 || used < uses);
|
UInt64Geq(UtilServerTs(), expiration)) &&
|
||||||
|
(Int64Eq(uses, Int64Neg(Int64Create(0, 1))) || Int64Lt(used, uses));
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
RegTokenUse(RegTokenInfo * token)
|
RegTokenUse(RegTokenInfo * token)
|
||||||
|
@ -63,12 +65,13 @@ RegTokenUse(RegTokenInfo * token)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token->uses >= 0 && token->used >= token->uses)
|
if (Int64Geq(token->uses, Int64Create(0, 0)) &&
|
||||||
|
Int64Geq(token->used, token->uses))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
token->used++;
|
token->used = Int64Add(token->used, Int64Create(0, 1));
|
||||||
|
|
||||||
/* Write the information to the hashmap */
|
/* Write the information to the hashmap */
|
||||||
tokenJson = DbJson(token->ref);
|
tokenJson = DbJson(token->ref);
|
||||||
|
@ -196,12 +199,12 @@ RegTokenVerify(char *token)
|
||||||
}
|
}
|
||||||
|
|
||||||
RegTokenInfo *
|
RegTokenInfo *
|
||||||
RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses, int privileges)
|
RegTokenCreate(Db * db, char *name, char *owner, UInt64 expires, Int64 uses, int privileges)
|
||||||
{
|
{
|
||||||
RegTokenInfo *ret;
|
RegTokenInfo *ret;
|
||||||
HashMap *tokenJson;
|
HashMap *tokenJson;
|
||||||
|
|
||||||
unsigned long timestamp = UtilServerTs();
|
UInt64 timestamp = UtilServerTs();
|
||||||
|
|
||||||
if (!db || !name)
|
if (!db || !name)
|
||||||
{
|
{
|
||||||
|
@ -211,13 +214,13 @@ RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses
|
||||||
/* -1 indicates infinite uses; zero and all positive values are a
|
/* -1 indicates infinite uses; zero and all positive values are a
|
||||||
* valid number of uses; althought zero would be rather useless.
|
* valid number of uses; althought zero would be rather useless.
|
||||||
* Anything less than -1 doesn't make sense. */
|
* Anything less than -1 doesn't make sense. */
|
||||||
if (uses < -1)
|
if (Int64Lt(uses, Int64Neg(Int64Create(0, 1))))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify the token */
|
/* Verify the token */
|
||||||
if (!RegTokenVerify(name) || (expires > 0 && expires < timestamp))
|
if (!RegTokenVerify(name) || (UInt64Gt(expires, UInt64Create(0, 0)) && UInt64Lt(expires, timestamp)))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -233,7 +236,7 @@ RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses
|
||||||
}
|
}
|
||||||
ret->name = StrDuplicate(name);
|
ret->name = StrDuplicate(name);
|
||||||
ret->owner = StrDuplicate(owner);
|
ret->owner = StrDuplicate(owner);
|
||||||
ret->used = 0;
|
ret->used = Int64Create(0, 0);
|
||||||
ret->uses = uses;
|
ret->uses = uses;
|
||||||
ret->created = timestamp;
|
ret->created = timestamp;
|
||||||
ret->expires = expires;
|
ret->expires = expires;
|
||||||
|
|
|
@ -40,7 +40,7 @@ struct Room
|
||||||
};
|
};
|
||||||
|
|
||||||
Room *
|
Room *
|
||||||
RoomCreate(Db * db, RoomCreateRequest *req)
|
RoomCreate(Db * db, RoomCreateRequest * req)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ ROUTE_IMPL(RouteAliasDirectory, path, argp)
|
||||||
HashMap *newAlias;
|
HashMap *newAlias;
|
||||||
|
|
||||||
/* TODO: Validate alias domain and make sure it matches
|
/* TODO: Validate alias domain and make sure it matches
|
||||||
server name and is well formed. */
|
* server name and is well formed. */
|
||||||
|
|
||||||
if (JsonGet(aliases, 2, "alias", alias))
|
if (JsonGet(aliases, 2, "alias", alias))
|
||||||
{
|
{
|
||||||
|
@ -117,7 +117,8 @@ ROUTE_IMPL(RouteAliasDirectory, path, argp)
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Validate room ID to make sure it is well formed. */
|
/* TODO: Validate room ID to make sure it is well
|
||||||
|
* formed. */
|
||||||
|
|
||||||
newAlias = HashMapCreate();
|
newAlias = HashMapCreate();
|
||||||
HashMapSet(newAlias, "createdBy", JsonValueString(UserGetName(user)));
|
HashMapSet(newAlias, "createdBy", JsonValueString(UserGetName(user)));
|
||||||
|
|
|
@ -139,7 +139,7 @@ ROUTE_IMPL(RouteFilter, path, argp)
|
||||||
DbRef *ref;
|
DbRef *ref;
|
||||||
char *filterId;
|
char *filterId;
|
||||||
|
|
||||||
Filter filter = { 0 };
|
Filter filter = {0};
|
||||||
char *parseErr;
|
char *parseErr;
|
||||||
HashMap *filterJson;
|
HashMap *filterJson;
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
#include <Routes.h>
|
#include <Routes.h>
|
||||||
|
|
||||||
|
#include <Int64.h>
|
||||||
#include <User.h>
|
#include <User.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Str.h>
|
#include <Str.h>
|
||||||
|
@ -80,10 +81,25 @@ ROUTE_IMPL(RouteProcControl, path, argp)
|
||||||
case HTTP_GET:
|
case HTTP_GET:
|
||||||
if (StrEquals(op, "stats"))
|
if (StrEquals(op, "stats"))
|
||||||
{
|
{
|
||||||
|
size_t allocated = MemoryAllocated();
|
||||||
|
Int64 a;
|
||||||
|
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
|
|
||||||
|
if (sizeof(size_t) == sizeof(Int64))
|
||||||
|
{
|
||||||
|
UInt32 high = (UInt32) (allocated >> 32);
|
||||||
|
UInt32 low = (UInt32) (allocated);
|
||||||
|
|
||||||
|
a = Int64Create(high, low);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a = Int64Create(0, allocated);
|
||||||
|
}
|
||||||
|
|
||||||
HashMapSet(response, "version", JsonValueString(TELODENDRIA_VERSION));
|
HashMapSet(response, "version", JsonValueString(TELODENDRIA_VERSION));
|
||||||
HashMapSet(response, "memory_allocated", JsonValueInteger(MemoryAllocated()));
|
HashMapSet(response, "memory_allocated", JsonValueInteger(a));
|
||||||
|
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
|
@ -491,7 +491,7 @@ UiaCleanup(MatrixHttpHandlerArgs * args)
|
||||||
char *session = ArrayGet(sessions, i);
|
char *session = ArrayGet(sessions, i);
|
||||||
DbRef *ref = DbLock(args->db, 2, "user_interactive", session);
|
DbRef *ref = DbLock(args->db, 2, "user_interactive", session);
|
||||||
|
|
||||||
unsigned long lastAccess;
|
UInt64 lastAccess;
|
||||||
|
|
||||||
if (!ref)
|
if (!ref)
|
||||||
{
|
{
|
||||||
|
@ -506,7 +506,7 @@ UiaCleanup(MatrixHttpHandlerArgs * args)
|
||||||
|
|
||||||
/* If last access was greater than 15 minutes ago, remove this
|
/* If last access was greater than 15 minutes ago, remove this
|
||||||
* session */
|
* session */
|
||||||
if (UtilServerTs() - lastAccess > 1000 * 60 * 15)
|
if (UInt64Gt(UInt64Sub(UtilServerTs(), lastAccess), UInt64Create(0, 1000 * 60 * 15)))
|
||||||
{
|
{
|
||||||
DbDelete(args->db, 2, "user_interactive", session);
|
DbDelete(args->db, 2, "user_interactive", session);
|
||||||
Log(LOG_DEBUG, "Deleted session %s", session);
|
Log(LOG_DEBUG, "Deleted session %s", session);
|
||||||
|
|
17
src/User.c
17
src/User.c
|
@ -27,6 +27,8 @@
|
||||||
#include <Str.h>
|
#include <Str.h>
|
||||||
#include <Sha.h>
|
#include <Sha.h>
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
#include <UInt64.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -128,7 +130,7 @@ UserAuthenticate(Db * db, char *accessToken)
|
||||||
|
|
||||||
char *userName;
|
char *userName;
|
||||||
char *deviceId;
|
char *deviceId;
|
||||||
long expires;
|
UInt64 expires;
|
||||||
|
|
||||||
if (!db || !accessToken)
|
if (!db || !accessToken)
|
||||||
{
|
{
|
||||||
|
@ -152,7 +154,8 @@ UserAuthenticate(Db * db, char *accessToken)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expires && UtilServerTs() >= (unsigned long) expires)
|
if (UInt64Neq(expires, UInt64Create(0, 0)) &&
|
||||||
|
UInt64Geq(UtilServerTs(), expires))
|
||||||
{
|
{
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
DbUnlock(db, atRef);
|
DbUnlock(db, atRef);
|
||||||
|
@ -190,7 +193,7 @@ UserCreate(Db * db, char *name, char *password)
|
||||||
User *user = NULL;
|
User *user = NULL;
|
||||||
HashMap *json = NULL;
|
HashMap *json = NULL;
|
||||||
|
|
||||||
unsigned long ts = UtilServerTs();
|
UInt64 ts = UtilServerTs();
|
||||||
|
|
||||||
/* TODO: Put some sort of password policy(like for example at least
|
/* TODO: Put some sort of password policy(like for example at least
|
||||||
* 8 chars, or maybe check it's entropy)? */
|
* 8 chars, or maybe check it's entropy)? */
|
||||||
|
@ -495,11 +498,11 @@ UserAccessTokenGenerate(User * user, char *deviceId, int withRefresh)
|
||||||
|
|
||||||
if (withRefresh)
|
if (withRefresh)
|
||||||
{
|
{
|
||||||
token->lifetime = 1000 * 60 * 60 * 24 * 7; /* 1 Week */
|
token->lifetime = Int64Create(0, 1000 * 60 * 60 * 24 * 7); /* 1 Week */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
token->lifetime = 0;
|
token->lifetime = Int64Create(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
|
@ -528,9 +531,9 @@ UserAccessTokenSave(Db * db, UserAccessToken * token)
|
||||||
HashMapSet(json, "user", JsonValueString(token->user));
|
HashMapSet(json, "user", JsonValueString(token->user));
|
||||||
HashMapSet(json, "device", JsonValueString(token->deviceId));
|
HashMapSet(json, "device", JsonValueString(token->deviceId));
|
||||||
|
|
||||||
if (token->lifetime)
|
if (Int64Neq(token->lifetime, Int64Create(0, 0)))
|
||||||
{
|
{
|
||||||
HashMapSet(json, "expires", JsonValueInteger(UtilServerTs() + token->lifetime));
|
HashMapSet(json, "expires", JsonValueInteger(UInt64Add(UtilServerTs(), token->lifetime)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return DbUnlock(db, ref);
|
return DbUnlock(db, ref);
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Db.h>
|
#include <Db.h>
|
||||||
|
#include <Int64.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This structure describes a registration token that is in the
|
* This structure describes a registration token that is in the
|
||||||
|
@ -64,23 +65,23 @@ typedef struct RegTokenInfo
|
||||||
/*
|
/*
|
||||||
* How many times the token was used.
|
* How many times the token was used.
|
||||||
*/
|
*/
|
||||||
int used;
|
Int64 used;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* How many uses are allowed.
|
* How many uses are allowed.
|
||||||
*/
|
*/
|
||||||
int uses;
|
Int64 uses;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Timestamp when this token was created.
|
* Timestamp when this token was created.
|
||||||
*/
|
*/
|
||||||
unsigned long created;
|
UInt64 created;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Timestamp when this token expires, or 0 if it does not
|
* Timestamp when this token expires, or 0 if it does not
|
||||||
* expire.
|
* expire.
|
||||||
*/
|
*/
|
||||||
unsigned long expires;
|
UInt64 expires;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A bit field describing the privileges this token grants. See
|
* A bit field describing the privileges this token grants. See
|
||||||
|
@ -123,7 +124,7 @@ extern RegTokenInfo * RegTokenGetInfo(Db *, char *);
|
||||||
* structure will be returned. Otherwise, NULL will be returned.
|
* structure will be returned. Otherwise, NULL will be returned.
|
||||||
*/
|
*/
|
||||||
extern RegTokenInfo *
|
extern RegTokenInfo *
|
||||||
RegTokenCreate(Db *, char *, char *, unsigned long, int, int);
|
RegTokenCreate(Db *, char *, char *, UInt64, Int64, int);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free the memory associated with the registration token. This should
|
* Free the memory associated with the registration token. This should
|
||||||
|
|
|
@ -38,8 +38,8 @@
|
||||||
* users, among many other tasks.
|
* users, among many other tasks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <Int64.h>
|
||||||
#include <Db.h>
|
#include <Db.h>
|
||||||
|
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +74,7 @@ typedef struct UserAccessToken
|
||||||
char *user;
|
char *user;
|
||||||
char *string;
|
char *string;
|
||||||
char *deviceId;
|
char *deviceId;
|
||||||
long lifetime;
|
Int64 lifetime;
|
||||||
} UserAccessToken;
|
} UserAccessToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -69,14 +69,42 @@ query(char *select, HashMap * json, int canonical)
|
||||||
{
|
{
|
||||||
if (StrEquals(keyName + 1, "length"))
|
if (StrEquals(keyName + 1, "length"))
|
||||||
{
|
{
|
||||||
|
UInt64 len;
|
||||||
|
|
||||||
switch (JsonValueType(val))
|
switch (JsonValueType(val))
|
||||||
{
|
{
|
||||||
case JSON_ARRAY:
|
case JSON_ARRAY:
|
||||||
val = JsonValueInteger(ArraySize(JsonValueAsArray(val)));
|
if (sizeof(size_t) == sizeof(UInt64))
|
||||||
|
{
|
||||||
|
size_t slen = ArraySize(JsonValueAsArray(val));
|
||||||
|
UInt32 high = slen >> 32;
|
||||||
|
UInt32 low = slen;
|
||||||
|
|
||||||
|
len = UInt64Create(high, low);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len = UInt64Create(0, ArraySize(JsonValueAsArray(val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = JsonValueInteger(len);
|
||||||
ArrayAdd(cleanUp, val);
|
ArrayAdd(cleanUp, val);
|
||||||
break;
|
break;
|
||||||
case JSON_STRING:
|
case JSON_STRING:
|
||||||
val = JsonValueInteger(strlen(JsonValueAsString(val)));
|
if (sizeof(size_t) == sizeof(UInt64))
|
||||||
|
{
|
||||||
|
size_t slen = strlen(JsonValueAsString(val));
|
||||||
|
UInt32 high = slen >> 32;
|
||||||
|
UInt32 low = slen;
|
||||||
|
|
||||||
|
len = UInt64Create(high, low);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
len = UInt64Create(0, strlen(JsonValueAsString(val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
val = JsonValueInteger(len);
|
||||||
ArrayAdd(cleanUp, val);
|
ArrayAdd(cleanUp, val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in a new issue