Τρίτη, 17 Μαΐου 2016

Αναθεώρηση 17 νέο αντικείμενο Buffer ή Διάρθρωση

Ετοίμασα νέο αντικείμενο (είχα σκοπό να το κάνω, αλλά τώρα ήταν η ώρα επειδή είχα έτοιμη την υποδομή, δηλαδή το mHandler class το οποίο χειρίζεται αντικείμενα με αναφορά (δεν αντιγράφονται, μόνο η αναφορά αντιγράφεται και αυτή έμμεσα, δηλαδή το mHandler είναι κλάση που δείχνει σε άλλη κλάση. Μέσα σε αυτήν έχουμε το FastCollection.cls που είναι το Inventory ή Κατάσταση (Κατάσταση ειδών) και τώρα το MemBlock.cls που είναι το Buffer ή Διάρθρωση (Διάρθρωση μνήμης).

Η Διάρθρωση ή Buffer είναι μια "έκταση" μνήμης που δύναται να μεγαλώνει ή να μικραίνει και αν δεν πειράζουμε το μέγεθος είναι non movable μνήμη, δηλαδή μνήμη που καταλαμβάνει σταθερό σημείο, η αρχή του δηλαδή είναι σε σταθερό σημείο. Η διάρθρωση είναι χρήσιμη γιατί μπορούμε να σώνουμε πολλά στοιχεία μαζί, με δυαδική μορφή και να τα εξάγουμε σε αρχείο ή να τα εισάγουμε (δουλεύει και με random/τυχαία προσπέλαση) καθώς επίσης για να δίνουμε διευθύνσεις και να καλούμε ρουτίνες (από dll, εξωτερικές βιβλιοθήκες). Θα δούμε παράδειγμα παρακάτω.

Μπορούμε να καταχωρήσουμε ένα Buffer, σε Κατάσταση, σε Πίνακα, σε Ομάδα, σε άλλη μεταβλητή. Μπορούμε να φτιάξουμε συναρτήσεις που να μας γυρνούν ένα Buffer. Μπορούμε να ορίσουμε γενικό ή να χρησιμοποιούμε τοπικό. Η επιστροφή της μνήμης γίνεται αυτόματα ή αν θέλουμε το επιλέγουμε με την εντολή Καθαρό και το όνομα του Buffer.

H Διάρθρωση μοιάζει με τη Κατάσταση, ως προς την χρήση της Επιστροφής (βάζουμε στη Διάρθρωση δεδομένα) και τα Εκφρ() και Εκφρ$() για να πάρουμε αριθμητικά ή αλφαριθμητικά δεδομένα.

Οι αριθμητικές τιμές Byte, Integer, Long είναι χωρίς πρόσημο Unsign (Ψηφίο, Ακέραιος, Μακρύς). Τα μήκη τους είναι 2 Βyte ο Ακέραιος, 4 Byte ο Μακρύς. Έχουμε και τον Double ή Διπλό που πιάνει 8 byte. Μπορούμε να γράφουμε αλφαριθμητικά με δυο byte ο χαρακτήρας ή με ένα.

Ορίζουμε κενή Διάρθρωση ή μη κενή. Κενή σημαίνει ότι θα μηδενιστεί η νέα μνήμη. Αν ορίσουμε ξανά τη Διάρθρωση αλλά δεν αλλάξουμε το μέγεθός της τότε δεν χάνονται τα στοιχεία της. Εσωτερικά χρησιμοποιεί το HeapAlloc.
Στο παράδειγμα παρακάτω καλώ την PathAddBackslashW που βρίσκεται στο Shlwapi.dll με δυο τρόπους. Ο ένας είναι ο παλιός, με χρήση αλφαριθμητικού με αναφορά. Στην ουσία το αλφαριθμητικό δουλεύει σαν Buffer, όμως δεν γνωρίζω που είναι! Δεν με ενδιαφέρει αφού παίρνω το αποτέλεσμα. Αλλά η πληροφορία του Α μου είναι άχρηστη επειδή δεν έχω τον δείκτη που δείχνει τον πρώτο χαρακτήρα του αλφαριθμητικού (τα αλφαριθμητικά αλλάζουν θέσεις πολύ γρήγορα, και την ώρα που το Path$ θα δοθεί στην ρουτίνα, θα γίνει το λεγόμενο copy in copy out, οπότε η διεύθυνση που τελικά θα πάει θα είναι γνωστή "στο βάθος" που δεν δίνει πληροφορίες ο διερμηνευτής.

Με την χρήση του Buffer έχουμε σταθερή θέση μνήμης, και ο δείκτης θα δείχνει το ίδιο στοιχείο (αν δεν αλλάξουμε μέγεθος στο Buffer). Φτιάχνουμε έναν καθαρό Buffer με 250  ακέραιους. Ορίζουμε την  PathAddBackslash2() να δέχεται unsign LPWSTR που είναι ένας δείκτης σε αλφαριθμητικό (αυτό το ρόλο παίζει τώρα ο Buffer). To mypath(0) είναι η διεύθυνση της αρχής του Buffer.To mypath(1) θα είναι 2 Byte πιο μεγάλο, γιατί πάει ανά μέγεθος "διάρθρωσης". Εδώ η Διάρθρωση έχει διάρθρωση σε ακέραιους. Μπορούμε όμως να γράψουμε και ότι άλλο θέλουμε, χρησιμοποιώντας έναν τρόπο cast, παραλλαγής.

\\ we can pass LPWSTR from a string
Declare PathAddBackslash Lib "Shlwapi.PathAddBackslashW" { &Path$ }


P$ = "C:"+String$(Chr$(0), 250)
A= PathAddBackslash( &P$ )
\\ but we can't find the string pointer so we get string until 0
Print LeftPart$(P$, 0)


\\ we get C:\


\\ using buffer we have non movable memory
Declare PathAddBackslash2 Lib "Shlwapi.PathAddBackslashW" { Long LPWSTR }


Buffer Clear mypath As Integer*250
Return mypath, 0 := "C:"
A= PathAddBackslash2(mypath(0))
If A<>0 Then Print eval$(mypath, 0, A-mypath(0))
Clear mypath ' remove buffer



Παρακάτω θα δούμε 4 μικρά προγράμματα με διάρθρωση του Buffer με 1, 2, 4 και 8 byte και σε κάθε περίπτωση θα γράψουμε byte, integer, long, double, Ansi αλφαριθμητικό και UTF-16LE

buffer clear alfa as byte *100
Return alfa, 40 :=-1.232e+45 as double
Return alfa, 30 :=uint(-2000) as long
Return alfa, 28 :=uint(-2001) as integer
Return alfa, 27 :=uint(-21)
Return alfa, 0:="Hello There"  \\22 bytes
Return alfa, 60:=str$("AnsiChars"+chr$(0)) \\ 10 bytes


Print eval(alfa, 40 as double)
Print sint(eval(alfa, 30 as long))
Print sint(eval(alfa, 28 as integer),2)
Print sint(alfa,27)
Print eval$(alfa, 0,22)+"!"
Print chr$(eval$(alfa, 60, 10))


Print "Pointers, can be used with dll"
\\ using item offset (unsing values)
\\ a long in a Declare Lib...is an unsign also
Print alfa(40), alfa(30), alfa(28), alfa(27), alfa(0), alfa(60)
Print alfa(20!)=alfa(20) \\ we can provide byte but here identical


Τώρα με ακέραιο:

buffer clear alfa as integer *100
Return alfa, 40 :=-1.232e+45 as double
Return alfa, 30 :=uint(-2000) as long
Return alfa, 28 :=uint(-2001) as integer
Return alfa, 27 :=uint(-21) as byte
Return alfa, 0:="Hello There"  \\22 bytes
Return alfa, 60:=str$("AnsiChars"+chr$(0)) \\ 10 bytes


\\ using cast we have to multiply by length of item
Print eval(alfa, 40*2 as double)
Print sint(eval(alfa, 30*2 as Long),4)
Print sint(alfa,28)
Print sint(eval(alfa, 27*2 as byte),1)
Print eval$(alfa, 0,22)+"!"
Print chr$(eval$(alfa, 60, 10))


Print "Pointers, can be used with dll"
\\ using item offset (unsing values)
\\ a long in a Declare Lib...is an unsign also
Print alfa(40), alfa(30), alfa(28), alfa(27), alfa(0), alfa(60)
Print alfa(20!)=alfa(10) \\ we can provide byte offset also


Τώρα με Μακρύ
buffer clear alfa as Long *100
\\ we align any value at 4 bytes
Return alfa, 40 :=-1.232e+45 as double
Return alfa, 30 :=uint(-2000) as long
Return alfa, 28 :=uint(-2001) as integer
Return alfa, 27 :=uint(-21) as byte
Return alfa, 0:="Hello There"  \\22 bytes
Return alfa, 60:=str$("AnsiChars"+chr$(0)) \\ 10 bytes


\\ using cast we have to multiply by length of item
Print eval(alfa, 40*4 as double)
Print sint(alfa, 30)
Print sint(eval(alfa, 28*4 as integer),2)
Print sint(eval(alfa, 27*4 as byte),1)
Print eval$(alfa, 0,22)+"!"
Print chr$(eval$(alfa, 60, 10))


Print "Pointers, can be used with dll"
\\ using item offset (unsing values)
\\ a long in a Declare Lib...is an unsign also
Print alfa(40), alfa(30), alfa(28), alfa(27), alfa(0), alfa(60)
Print alfa(20!)=alfa(5) \\ we can provide byte offset also



Τώρα με διπλό (εδώ δεν υπάρχει είδος unsign)

buffer clear alfa as double *100
\\ using align to 8 bytes
Return alfa, 40 :=-1.232e+45 as double
Return alfa, 30 :=uint(-2000) as long
Return alfa, 28 :=uint(-2001) as integer
Return alfa, 27 :=uint(-21) as byte
Return alfa, 0:="Hello There"  \\22 bytes
Return alfa, 60:=str$("AnsiChars"+chr$(0)) \\ 10 bytes


\\ using cast we have to multiply by length of item
Print eval(alfa, 40)
Print sint(eval(alfa, 30*8 as Long),4)
Print sint(eval(alfa, 28*8 as Long),2)
Print sint(eval(alfa, 27*8 as byte),1)
Print eval$(alfa, 0,22)+"!"
Print chr$(eval$(alfa, 60, 10))


Print "Pointers, can be used with dll"
\\ using item offset (unsing values)
\\ a long in a Declare Lib...is an unsign also
Print alfa(40), alfa(30), alfa(28), alfa(27), alfa(0), alfa(60)
Print alfa(24!)=alfa(6) \\ we can provide byte offset also



Και εδώ χρησιμοποιούμε την Structure (με αλφαριθμητικό κάνει κάτι άλλο, δίνει τη δομή μιας βάσης δεδομένων, αλλά εδώ την χρησιμοποιώ με απλό αναγνωριστικό)
Τώρα η Διάρθρωση έχει στρωμένες Δομές διαφόρων μεγεθών!

structure stringA {
      str as integer*20
}
structure beta {
      Alfa as byte
      align1 as byte*3
      Kappa as long*20
      Name as stringA*10
      kappa2 as double
}
Buffer clear alfa as beta*100
Print Len(alfa), len.disp(alfa)
Print 5*len(beta)+ beta("kappa"), beta("kappa")
Return alfa, 50!kappa!10:=50
\\ sLong=4
\\ Return alfa, 5*len(beta)+ beta("kappa")+10*sLong! :=50 as long
\\ Print eval(alfa, 5*len(beta)+ beta("kappa")+40  as long)


Print eval(alfa, 50!kappa!10)
return alfa, 50!name!5:="George", 50!name!6:="Hello"
Print eval$(alfa, 50!name!5, 20)
Print eval$(alfa, 50!name!6, 20)
Print Len(alfa), type$(beta)
Print len(beta), len.disp(beta)
Print beta("Alfa"), beta("Name")




Εισαγωγή από αρχείο (το φτιάχνουμε κιόλας)

dir user
document A$={hello there
            Something Else
            third line
            }
Save.Doc A$, "here.txt", 0 ' Utf-16
   
If exist("here.txt") then {
      ALFA.items=filelen("here.txt")
      buffer clear ALFA as integer * ALFA.items
      f=1
      open "here.txt" for random as f Len=Len(ALFA) \\Len(ALFA) bytes
      get #f, ALFA
      close #f
} else print "can't find" : exit
Report eval$(ALFA)


Με άλλο τρόπο:

dir user
document A$={hello there
            Something Else
            third line
            }
Save.Doc A$, "here.txt", 0 ' Utf-16
   
If exist("here.txt") then {
      ALFA.items=filelen("here.txt")/2
      buffer clear ALFA as integer * ALFA.items
      open "here.txt" for wide input as f
      Return Alfa, 0:=Input$(#f, ALFA.items)
      close #f
} else print "can't find" : exit
Report eval$(ALFA)
document B$=eval$(ALFA)
Report B$



Εισαγωγή από ANSI αρχείο

dir user
document A$={hello there
            second line
            }
Save.Doc A$, "here.txt", 3 ' Ansi


If exist("here.txt") then {
      buffer alfa as byte * filelen("here.txt")
      f=1
      open "here.txt" for random as f Len=Len(alfa) \\Len=filelen("here.txt")
      get #f, alfa
      close #f
} else print "can't find"


Report chr$(eval$(alfa))


Βάζουμε σε ένα "δυαδικό" αρχείο, εγγραφές κάθε 50 χαρακτήρες (100 bytes). έχουμε ένα Buffer για 50 εγγραφές και ένα για μια. Μαζί με το όνομα βάζουμε σε 40 byte μετά την αρχή (στο 0 είναι το πρώτο Byte) έναν Διπλό (θέλει 8 bytes). Δεν έχουμε δηλώσει ότι θα βάζουμε διπλούς, αλλά χρησιμοποιούμε την θέση σε Bytes με το ! αμέσως μετά τον αριθμό και το as double.

structure record1 {
      all as integer*50
}
Buffer Clear alfa as record1*50
Buffer clear beta as record1
Return alfa, 30:="George", 3040 ! := -343.434 as double
Open "M1.klm" for wide random as f Len=50
      Put #f, eval$(alfa,30),1
      Get #f, beta(0),1
close f
Print eval$(beta, 0,12), eval(beta, 40 as double)


με μια μικρή παραλλαγή βάζουμε το George σε 6 bytes (ANSI μορφή)

structure record1 {
      all as integer*50
}
Buffer Clear alfa as record1*50
Buffer clear beta as record1
Return alfa, 30:=str$("George"), 3040 ! := -343.434 as double
Open "M134.klm" for wide random as f Len=50
      Put #f, eval$(alfa,30),1
      Get #f, beta(0),1
close f
Print chr$(eval$(beta, 0,6)), eval(beta, 40 as double)


Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου