Oxygen Basic
Programming => Problems & Solutions => Topic started by: Mike Lobanovsky on October 03, 2014, 06:58:00 PM
-
Hi Charles,
1. Is there any way to express the following two C macros in Oxygen?
#define num_ivalue(p) (isfixnum(p) ? (p)->_object._number._value._ivalue : (__i64)((p)->_object._number._value._rvalue))
#define num_rvalue(p) (isflonum(p) ? (p)->_object._number._value._rvalue : (double)((p)->_object._number._value._ivalue))
Or do I have to recode all occurences to explicit nested If/Then/Else's because the macros can be both lvalues and rvalues of the same C expression, e.g.
if (num_ivalue(a) >= num_ivalue(b))
do_this();
else
do_that();
2. Can I have an Oxygen array of user-defined function pointers and call them efficiently based on their array indices or do I have to turn everything into one huge goto jump table instead to speed things up? The functions are void voids, i.e. arg-less subs in BASIC terms.
Thanks!
-
While we are at it, some more questions:
1. Does the PP understand C-style semicolons if I leave them in place? And also in structs and typedefs?
2. Does O2 need some switch to understand C notation in its PP and elsewhere similar to your #basic or #o2h?
3. Where should I put C-style names for structs and unions in typedef and struct declarations -- before the opening brace or after the closing one? What if I have the same name both before the opening brace and after the closing one?
4. Do Oxygen's user-defined functions fetch their returns in eax and on the FPU stack after inline asm calls to their function pointers in other O2 user-defined functions? Are all O2 functions STDCALL on default?
Thanks again!
-
Hi Mike, I hope this answers your first set of questions. I did not quite understand those C macros.
'SET OF FUNCTIONS
=================
function funA(float f) as string, label
return "called funA: " & f
end function
function funB(float f) as string, label
return "called funB: " & f
end function
'BUILD TABLE OF FUNCTIONS
=========================
sys ftable={&funA,&funB}
'BOOLEAN COMPARATORS INDEXING A FUNCTION
========================================
indexbase 0
float b=1,c=1.1
sys a
a = (b<=c) 'result -1
a=(b<=c) and 1 'result 1
print cast (string) call ftable[a] (1234.5)
a = (b>=c) and 1 'result 0
print cast (string) call ftable[a] (1234.5)
'COMBINED:
==========
print cast (string) call ftable[ (b<=c) and 1 ] (1234.5)
-
1. Does the PP understand C-style semicolons if I leave them in place? And also in structs and typedefs?
By fefault, semicolons are treated as comment markers, so they can be left in most of the time.
However: iterators require the switch:
#semicolon separator
for (i=0 ; i<3 ; i++) {print i} 'o2 now understands
2. Does O2 need some switch to understand C notation in its PP and elsewhere similar to your #basic or #o2h?
There isn't a C switch. but case sensitivity is often important:
#case sensitive
a good compromise is:
#case capital 'sensitive to fully capitalised symbols
O2 understands C notation with some exceptions:
conditional choice expressions: (? ...)
-> arrow notation (o2 pointers are implicit from the type definition)
pointer expressions (implicit pointers)
Line sensitivity : beware split lines in C
Take nothing for granted! :)
3. Where should I put C-style names for structs and unions in typedef and struct declarations -- before the opening brace or after the closing one? What if I have the same name both before the opening brace and after the closing one?
typedef struct _Mytype
{
int a,b
union {
long c
double d
}
} Mytype, *pMytype
4. Do Oxygen's user-defined functions fetch their returns in eax and on the FPU stack after inline asm calls to their function pointers in other O2 user-defined functions? Are all O2 functions STDCALL on default?
Yes, STDcall for 32 bit code, but cdecl also available:
int f cdecl (int a)
{
return 2*a
}
-
(that's in response to your first answer)
Thanks Charles,
Your code answers my question number 2 from the starter message in full.
Other questions from the two messages yet remain unanswered. OK let's start one question at a time:
/* cell structure */
struct cell{
unsigned long _flag;
union {
struct {
char* _svalue;
long _keynum;
} _string;
struct {
union {
__int64 _ivalue;
double _rvalue;
} _value;
} _number;
struct {
struct cell* _car;
struct cell* _cdr;
} _cons;
} _object;
} cell;
typedef struct cell* pointer;
#define type(p) ((p)->_flag)
#define isfixnum(p) ((type(p) & T_FLONUM) == T_NUMBER)
#define isflonum(p) ((type(p) & T_FLONUM) == T_FLONUM)
#define ivalue(p) ((p)->_object._number._value._ivalue)
#define rvalue(p) ((p)->_object._number._value._rvalue)
#define num_ivalue(p) (isfixnum(p) ? ivalue(p) : (__int64)rvalue(p))
#define num_rvalue(p) (isflonum(p) ? rvalue(p) : (double)ivalue(p))
where the argument (p) is of typedef pointer.
In other words, the ternary evaluation of isfixnum(p) or isflonum(p) -- the _flag field of structure cell -- in the last two macros at runtime will put one of the four:
1/2. either the _ivalue field or (__int64)_rvalue field of structure cell; or
3/4. either the _rvalue field or (double)_ivalue field of structure cell
into an expression of the following kind:
if (num_ivalue(a) >= num_ivalue(b))
do_this();
else
do_that();
So, my question is: can Oxygen use these C macros as they are defined above to perform the required substitutions in the above code piece as efficiently, or do I have to abandon these macros altogether and re-write the occurences of num_ivalue(a) >= num_ivalue(b)-style expressions as explicit multiply nested BASIC If/Then/Else blocks (which would be some piece of work, I must admit)?
-
Thanks a lot for the second answer too, but still:
4. Do Oxygen's user-defined functions fetch their returns in eax and on the FPU stack immediately after inline asm calls to their function pointers in other O2 user-defined functions?
-
Mike, I'm falling asleep. It is dawn and I must make haste to my casket. I'll attempt some answers later. But can you show me how those macros are deployed, by way of example pls?
-
Charles,
The above "if (... >= ...) ... else ..." is an example of actual deployment of these macros throughout the code. Never mind though: if you don't grasp their role in the C code at a first glance, it's most probably an indication that O2 wouldn't be able to mimic this functionality one to one anyway either.
I'll just take my time to rewrite the same with explicit If's.
Have a good night's (actually day's) sleep and thanks again for your help! :)
-
Mike,
Conditional Possibilities:
functions are required if you want to use the conditional inside an expression
float aa=1,bb=2,cc=3,dd=4,ee=5
#define conddo(a,b,c) if a then b else c
conddo aa>bb, cc=dd, cc=ee
print cc
float iff(sys a, float b,c) { if a {return b} else {return c} }
sys iff(sys a, sys b,c) { if a {return b} else {return c} }
string iff(sys a, string b,c) { if a {return b} else {return c} }
aa=iff ((bb<=cc),dd,ee)
print aa
-
4. Do Oxygen's user-defined functions fetch their returns in eax and on the FPU stack immediately after inline asm calls to their function pointers in other O2 user-defined functions?
Yes, if you make a call to a function returning a float or a double, then the result will be left on the FPU stack.
In 32 bit mode, quad integers are also returned on the fpu stack
Otherwise, the value will be in the eax register (eax and edx are preserved during epilog operations)
If the function being called uses cdecl then you must restore the stack pointer to its prior position. However, if the function is called in basic syntax: call fun a,b,c,d then the stack pointer adjustment will be automatic.
-
Conditional Possibilities:
Oh yes, FBSL (following VB6) does have a built-in ternary function that would return a simple value choice, which does the same as what you suggest:
d = IIf(a, b, c) (your functions are called iff)
or
If IIf(a, b, c) >= IIf(d, e, f) Then
but this would imply an overhead of two extra function calls in one expression of the if (a <> b) then kind. The comparisons are parts of nanoscheme's jump table and implement its arithmetic comparison procedures <, <=, >=, >. (Arithmetic equality/inequality is expressed via (equal?)/(not (equal?)).)
Therefore I was trying to avoid additional function calls here altogether, and those elegant C macros helped me do just that. Anyway, I'll try to use the functions as you suggest and see if they have significant impact on my benchmarks. If yes then I'll re-write them as explicit If/Then/Else blocks.
Your eax/FPU answer is exhaustive for my purposes. Thanks a lot again for your invaluable help! :)
-
Hi Mike,
If most of your conditional return values are floats/doubles then this float macro should be very efficient. It will work for integers too:
iff ( comparator_expr, true_return_expr, false_return_expr )
deff iff
or eax,eax
(
jnz exit
fxch st1
)
fstp st0
end deff
'TEST:
sys aa=1,bb=2,cc=3,dd=4,ee
ee = iff((aa>bb),cc,dd)
print ee '4
float aa=1,bb=2,cc=3,dd=4,ee
ee = iff((aa<bb),cc,dd)
print ee '3
So I suggest using a macro like this one, wherever it fits your coding pattern. It can be adjusted later, if necessary. Macros and functions both use the same syntax when you call them.
-
Hi Charles,
Values to compare will always be either doubles or quads. There are no more 32-bit integers in nanoscheme.
Will the macro be as efficient for quads? (I think it should since your quads are essentially flints, i.e. 64-bit floats with zero fractional part...)
-
Quads, as 64 bit signed integers, are handled by the FPU when compiled in 32bit mode.
But when RTL64.inc is included, quads are handled directly by the cpu for expression evaluation. However quad variables are loaded directly into the FPU during float macro operations, or when the assignment variable is a float.
I will shortly be tweaking the assembler to facilitate dual 32/64 bit coding. When in 32bit mode, Registers rax..rdi will be automatically down graded to eax..edi
Thus the iff macro should be expressed (with the new compiler) like this:
deff iff
or rax,rax
(
jnz exit
fxch st1
)
fstp st0
end deff
-
Then I'll emit nanoscheme as a 32-bit application with 64-bit calc and then you'll port it to RTL64.inc yourself. It will then be the best, beautifullest, and fastest Scheme interpreter on the net, guaranteed. :D
-
Then I'll emit nanoscheme as a 32-bit application with 64-bit calc and then you'll port it to RTL64.inc yourself. It will then be the best, beautifullest, and fastest Scheme interpreter on the net, guaranteed. :D
The definition of commitment!
-
The definition of commitment!
Let's wait and see Charles' commitment to jump on the bandwagon first. :D
-
Then I will emit guidlines :)
always use sys integers to hold pointers, not int or long !
If you are going ahead with indexed functions, I will need to formulate a safer protocol for compatibility.
rax/eax update:
http://www.oxygenbasic.org/o2zips/Oxygen.zip
-
always use sys integers to hold pointers, not int or long !
Will do.
If you are going ahead with indexed functions, I will need to formulate a safer protocol for compatibility.
If you're talking about
function foo(sys bar) as sys, label
then I'm all ears.
-
The ears attached to your avatar are truly enormous. You can probably hear me muttering two thousan miles away :)
It is safe to work with a fully protyped function:
Indexed Functions
function foo1(quad a) as quad, label
return 10
end function
function foo2(quad a) as quad, label
return 20
end function
function foo3(quad a) as quad, label
return 30
end function
sys fooTable={@foo1,@foo2,@foo3}
!* foo(quad a) as quad 'prototype used for every foo
'TEST
indexbase 1
for i=1 to 3
@foo=fooTable[i] 'assign address
print foo(42) 'make call
next
-
Great!
All of nanoscheme's indexed functions conform to a common proto
! function opexe_N (DWORD operator) as pointer
where DWORD stands for unsigned long, and pointer, for cell* as defined in my C code at the top of this page.
Will that do for our purposes?
-
Sure, I just checked - operator and pointer are not reserved words yet :)
Need a few hours astral. o__/\_
-
o__/\_
(https://c1.staticflickr.com/1/60/201007926_a74c2c11b1_m.jpg)
-
(http://i.guim.co.uk/static/w-700/h--/q-95/sys-images/Guardian/Pix/pictures/2013/10/20/1382290891280/Landscape-Photographer-Of-009.jpg)
View from Afar, Lake District, Cumbria, England
-
(http://truthseekerdaily.com/wp-content/uploads/2014/03/lucid1.jpg)
-
Hi Mike,
My further thought on C equivalents:
struct cell{
unsigned long _flag;
union {
struct {
char* _svalue;
long _keynum;
} _string;
struct {
union {
__int64 _ivalue;
double _rvalue;
} _value;
} _number;
struct {
struct cell* _car;
struct cell* _cdr;
} _cons;
} _object;
} cell;
typedef struct cell* pointer;
#define type(p) ((p)->_flag)
#define isfixnum(p) ((type(p) & T_FLONUM) == T_NUMBER)
#define isflonum(p) ((type(p) & T_FLONUM) == T_FLONUM)
#define ivalue(p) ((p)->_object._number._value._ivalue)
#define rvalue(p) ((p)->_object._number._value._rvalue)
#define num_ivalue(p) (isfixnum(p) ? ivalue(p) : (__int64)rvalue(p))
#define num_rvalue(p) (isflonum(p) ? rvalue(p) : (double)ivalue(p))
'CLARIFYING CELL STRUCTURE
==========================
type cell
sys flag
char* svalue
sys keynum
=
sys flag
quad ivalue
=
sys flag
double rvalue
=
sys flag
cell* car
cell* cdr
end type
'#recordof cell
typedef cell *pointer
enum types { T_NULL, T_NUMBER, T_FLONUM }
'print T_FLONUM
macro isfixnum(p) (p##.flag == T_NUMBER)
macro isflonum(p) (p##.flag == T_FLONUM)
macro ivalue(p) p##.ivalue
macro rvalue(p) p##.rvalue
'C STYLE FUNCTIONS
==================
quad num_ivalue(cell*p) {if isfixnum(p) {return p.ivalue} return p.rvalue }
double num_rvalue(cell*p) {if isfixnum(p) {return p.ivalue} return p.rvalue }
'OPTIMISED ASM FUNCTIONS: 32BIT MODE STDCALL
============================================
quad num_ivalue(cell*p) at num_ivalues_asm
double num_rvalue(cell*p) at num_rvalues_asm
'TEST
=====
double d
quad q
sys n=3
#show cell p at getmemory 100 * sizeof cell
#show q = num_ivalue p[n]
free memory @cell
'ASSEMBLY CODE
==============
jmp fwd over
.num_ivalues_asm
mov eax,[esp+4] 'first param
(
cmp [eax],T_NUMBER
jnz exit
fild qword [eax+8]
ret 4
)
fld qword [eax+8]
frndint 'ROUNDING
ret 4
.num_rvalues_asm
mov eax,[esp+4] 'first param
(
cmp [eax],T_NUMBER
jnz exit
fild qword [eax+8]
ret 4
)
fld qword [eax+8]
ret 4
.over
'USING THE IFF MACRO (DUAL 32/64)
=================================
deff iff
and al,1
(
jnz exit
fxch st1
)
fstp st0
end deff
macro num_ivalue(p) iff(isfixnum(p), p##.ivalue, p##.rvalue)
macro num_rvalue(p) iff(isfixnum(p), p##.ivalue, p##.rvalue)
'ROUNDING?
==========
'it may be desirable to truncate or round when returning num_ivalues
macro num_ivalue(p) iff(isfixnum(p), p##.ivalue, round(p##.rvalue) )
I think the optimised asm functions will give the shortest code stream and best performance:
quad num_ivalue(pointer p) at num_ivalues_asm
...
.num_ivalues_asm
mov eax,[esp+4] 'first param 'pointer'
(
cmp [eax],T_NUMBER
jnz exit
fild qword [eax+8]
ret 4
)
fld qword [eax+8]
frndint 'ROUNDING
ret 4
-
@John:
Thanks for this beautiful picture! I didn't have much chance to enjoy Great Britain's countryside but I remember I really liked what I actually happened to see. And this picture is a perfect match to my recollections. :)
@Charles:
Do you still fly in your dreams?? :o I remember I stopped doing so somewhere at the age of 27 or 28. They say one stops to when one's organism stops to grow and physical maturity sets in. But I still remember that wonderful sense of flight and I would give away much to be able to feel it again. :)
-
Charles,
1. I agree with your vision of cell structure in O2. The C version is an almost exact replica of original author's version with my amendments as to its alignment which used to be really horrible in the original.
Since none of cell's fields are accessed directly throughout the code but rather through the #defines only, your simplifications will not meddle with actual porting. And they also simplify the compiler's part of work since it has fewer offsets to resolve.
2. Your macros isfixnum() and isflonum() won't do because what I presented is only a fraction of possible data types and respective flag combinatins which may be composite. So, bit masking must stay intact. It is used in data type transformations and also in GC where flag overlays are used to mark the cells for recovery and as vacant entities.
3. Your "C style functions" may stay with their returns uncast only if you swear in your mamma's name that Oxygen will do that automatically and won't faulter at that. (but still it leaves me somewhat uneasy...)
4. I'd rather we'd better (hehe...) stick with the asm functions as you suggest.
5. There is absolutely no any transparent rounding of floating-point values in LISP. Everything is always done through explicit (round), (floor), (ceiling), and (truncate) commands. Even if a data type transformation is under way, e.g. (inexact->exact), and the value to be transformed is not a flint, and there is not an explicit command of the four aforementioned ones as to how to round the value in question, an error must be flagged.
And of course there shouldn't be any rounding in case of arithmetic comparisons either, by definition.
-
Dream Flying:
Occasionally. I have a few problems with navigation and maintaining altitude :). A few nights ago, I found myself hanging onto the side of a 6 storey building, - forgot to fly.
It may be helpful to cultivate daydreaming, so you can habitually bring intellect into the dream process.
Apparently, there is a disconnect between waking memory and dream experience. You need to recall your dream experiences and think about them as you wake up. Otherwise the memories fade very quickly.
re: cell
I have stumbled over a few issues with pointer types, which fight O2's implicit referencing. So I advise typing your cell variables as cell *, rather than using pointer.
double d
quad q
sys n=3
'DYNAMIC ARRAY OF 100 CELLS
cell p at getmemory 100 * sizeof cell
'cell *p = getmemory 100 * sizeof cell 'equivalent
q = num_ivalue p[n]
...
free memory @cell
-
Dream Flying:
(https://c1.staticflickr.com/1/60/201007926_a74c2c11b1_m.jpg)
re: cell
Absolutely no problem with that. I'll be keeping on typing pointer everywhere and finally auto-replace all occurences of pointer with cell* throughout the sources. :)
-
I tried def pointer cell* but this macro does not work in prototypes, unfortunately.
PS: cell alignments are a bit wobbly:
In 32bit mode, the offset for string and car is 04 whereas for double and quad, it is 08. It should be okay though.
for bit maskable flags, we have a special form of enumeration: 1 2 4 8 ...
enum bit types { T_NUMBER, T_FLONUM,T_SVALUE,T_CONS }
-
In 32bit mode, the offset for string and car is 04 whereas for double and quad, it is 08.
This isn't so, Charles. In my C structure which was meant for 32 bits only, the offset to char*, __i64, double, and _car is 4 bytes everywhere, since _flag is an unsigned long and not part of a union. Everything that's a multiple of 4 bytes is perfect alignment under 32 bits.
With _flag changed to sys for both 32 and 64 bits, the offset to these fields will be either 4 or 8 bytes, respectively, which means perfect alignment for the respective bitnesses.
we have a special form of enumeration
Thanks, Charles, I'm already aware of it.
-
Mike,
The general C rules for alignment are to align members to their own size. Thus 4 byte members align to the nearest 4 byte step, and 8 bit members to the nearest 8 bytes step. Hence the disparity between svalue and rvalue/ivalue offsets:
I base my info on Wikipedia which I admit is not always the most reliable source:
http://en.wikipedia.org/wiki/Data_structure_alignment
The type of each member of the structure usually has a default alignment, meaning that it will, unless otherwise requested by the programmer, be aligned on a pre-determined boundary. The following typical alignments are valid for compilers from Microsoft (Visual C++), Borland/CodeGear (C++Builder), Digital Mars (DMC) and GNU (GCC) when compiling for 32-bit x86:
A char (one byte) will be 1-byte aligned.
A short (two bytes) will be 2-byte aligned.
An int (four bytes) will be 4-byte aligned.
A long (four bytes) will be 4-byte aligned.
A float (four bytes) will be 4-byte aligned.
A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux (8-byte with -malign-double compile time option).
A long long (eight bytes) will be 8-byte aligned.
A long double (ten bytes with C++Builder and DMC, eight bytes with Visual C++, twelve bytes with GCC) will be 8-byte aligned with C++Builder, 2-byte aligned with DMC, 8-byte aligned with Visual C++ and 4-byte aligned with GCC.
Any pointer (four bytes) will be 4-byte aligned. (e.g.: char*, int*)
The only notable differences in alignment for an LP64 64-bit system when compared to a 32-bit system are:
A long (eight bytes) will be 8-byte aligned.
A double (eight bytes) will be 8-byte aligned.
A long double (eight bytes with Visual C++, sixteen bytes with GCC) will be 8-byte aligned with Visual C++ and 16-byte aligned with GCC.
Any pointer (eight bytes) will be 8-byte aligned.
To get a consistent 4 byte data offset (on a 32bit system) the structure can be packed:
packed type cell
sys flag
char* svalue
sys keynum
=
sys flag
quad ivalue
=
sys flag
double rvalue
=
sys flag
cell* car
cell* cdr
end type
-
Charles,
Then we are simply talking about different alignments. You're talking in terms of C defaults which are exactly as you say, and Wikipedia is perfectly correct here.
But I was talking from the perspective of precessor architecture where perfect alignment is the boundary of machine word, which is 4 and 8 bytes for 32- and 64-bit architectures, respectively, unless more stringent SIMD requirements are to be met. Failure to observe it may lead to complete disfunctioning of Pentium predictors, and the penalty may be as severe as two or three fold drop downs in app speed.
I was always remembering that my final target was OxygenBasic where it would all boil down to asm registers and offsets. :)
-
Yes, a consistent data offset would be useful for asm functions.
If you would like to award cell with an extra flag - this will solidify the structure for all systems.
type flags
int flag,flagx
end type
type cell
flags
char* svalue
sys keynum
=
flags
quad ivalue
=
flags
double rvalue
=
flags
cell* car
cell* cdr
end type
-
The existing 32-bit int will be sufficient to implement the entire "numeric tower" plus chars and vectors. But we can leave the other int in place too for the sake of yet better alignment and call it dwReserved in the best MS Windows traditions. 8) (re: Win32 Programmer's Reference, WinAPI Structures section)
BTW how would you refer to such flag -- cell dot flag or cell dot flags dot flag? The flags structure in cell seems to be anonymous in this notation.
-
One more thing, Charles.
You advocate sys for use as a pointer. But sys is a signed quantity. Now suppose we have a pointer whose numeric value is close to the +/- boundary for a given sys bitness. Now suppose again that we have an overlay to this pointer that we need to increment with, say, p += 1 traversing a string or array in a loop, and sooner or later this incrementation will have to cross that boundary.
What do we do in such a hypothetic case? I'm afraid it would be a latent disaster.
-
(https://fbcdn-sphotos-e-a.akamaihd.net/hphotos-ak-xfp1/v/t1.0-9/984124_548390651931904_8849771911811706588_n.jpg?oh=144782a38a239c445e9b9b265ccd3f5c&oe=54C8D434&__gda__=1420726837_0f8ebc53af06b40a5eee87a6f0ea7edb)
-
Mike,
Good point to consider. In the context of pointers, it makes no difference whether sign-bit 31 is set or not. Inc/Dec/Add/Sub works the same way. It's all twos-complement arithmetic - so, if the OS/Memory supports it, you get the full 4 Gig (2^32) addressing range.
Simple experiment:
sys a
a=0x7fffffff
inc a
print hex a '80000000
inc a
print hex a '80000001
The difference between long and dword becomes significant when multiplying and dividing, however.
John,
At least we have larger screens to gaze at :)
-
At least we have larger screens to gaze at.
Bad news for the cosmetics industry. We all look the same in a Tweet. :)
-
Charles,
I think you're doing what I expected you to do, which was falling into my deliberate trap of simplification. :) In fact, I was expecting you to remind me of multiplication and division. Let's leave out the latter though for the time being.
Now how would you suggest we should mimic the indexing of a matrix in a language that supports only one array dimension? Correct, by way of multiplying the span of matrix width by index height and adding index width if we're talking C-style row-major matrices, or the span of matrix height times index width plus index height, if talking classic BASIC column-major matrices.
Now suppose our matrix is well in excess of 2GB of memory which would not be uncommon for a database application. Unfortunately to us, those 2GB would be exactly where the aforementioned +/- borderline lies. So, our times index height or times index width may easily change the sign of addition to the base pointer value.
If this weren't so then what one would ever need unsigned data types for in the first place? :)
-
At least we have larger screens to gaze at :)
That's simply because we have poorer, aging eyesight. :)
We all look the same in a Tweet. :)
Which of course explains the missing Twitter button. :)
-
(Charles, I'm pushing you gently towards introducing unsigned syses into the language.)
-
Mike,
Generally speaking, the maximum o2 memory allocation size is 2^30, because it uses ole strings. But leaving that aside for a moment..
spanning 4 gig memory
with index literals, which resolve to a [reg+offset], oops!
but using a long index:
With an array of bytes > 0x70000000, we are in trouble
With an array of words, we can do it (base 0 : i=0x7fffffff)
With an array of rgb (a plausible scenario) no problem
Any types larger than 2 bytes, okay :)
I've checked the asm code for these types.
type rgb byte r,g,b
function f(sys p)
=================
word w at p
rgb c at p
word a
byte b
sys i
'#show a=w[0x80000000] ' :(
'#show a=w[i] ' :)
'#show b=c[i].r ' :)
end function
PS: sys variables can be cast where necessary, but I have never had to.
dword a,b
sys i
#show a=b*b
#show (dword) i=b*b
-
Generally speaking, the maximum o2 memory allocation size is 2^30, because it uses ole strings.
I'd call it delusion, Charles, for you can never know what a user has up his sleeve for a complacent developer... :)
I, for one, am using malloc() for nanoscheme allocations. :P And I'm not the naughtiest user among the living. Using malloc(), I can always be sure that my arrays and strings would be aligned on a 4-byte boundary rather than at arbitrary bytes within the memory pools of carelessly written custom memory managers.
That's just one example of the perpendicularity of our visions. OxygenBasic is too good to be squeezed into the Procrustean bed of weird OLE strings. :)
(So what about unsigned syses, Charles? Just to make your users feel themselves safer? mul and div instead of imul and idiv for sys pointers? ;) )
-
Mike, do mallocs carry any length encoding, and are there any performance issues in using them as liberally as olestrings? I would be happy to switch if there were no significant disadvantages.
-
Mike,
I am commited to a dual sized signed integer. One type fits nearly all, and massively simplifies API declarations. Use casting where necessary.
-
do mallocs carry any length encoding
None whatsoever.
are there any performance issues
None whatsoever.
using them as liberally as olestrings?
No liberty. You create them, you manage them, you free them. You are responsible for every little thing that happens to the chunks you malloced.
no significant disadvantages
None whatsoever.
One significant advantage: the addresses that msvcrt.dll mallocs are guaranteed by all the MS might to be aligned on a 4-byte boundary. Noone has ever been able to prove the contrary.
Another significant advantage: no restrictions on allocation sizes within the available memory.
-
Mike,
I am commited to a dual sized signed integer. One type fits nearly all, and massively simplifies API declarations. Use casting where necessary.
Understood.
-
Many thanks Mike,
Must fly now :)
Note the image URL! .../02carpet.jpg
(http://www.how-to-play-piano-by-ear.com/CUST321samples/slides/02carpet.jpg)
-
Have a nice flight, Charles. :)
-
Mike,
Would you recommend s HeapAlloc based system?