Results 1 to 5 of 5

Thread: All about using pointers in Lape

  1. #1
    Join Date
    May 2012
    Location
    Moscow, Russia
    Posts
    661
    Mentioned
    35 Post(s)
    Quoted
    102 Post(s)

    Default A lot about using pointers in Lape

    Hey. Today I will try to explain how how to using a pointers in Lape. I hope - this article may be helpful for your scripting.
    Part1:
    Pointers in the World of Object Orientation:
    In the past, especially in languages, pointers were a critical aspect of the language. They allowed direct access to memory, enabling complex data structures to be built and navigated. However, with the advent of Object Orientation, things have changed somewhat. For example, the TStringList class allows a list of strings to be built without the user needing to manage the storage. And hence, removing the need to use pointers to do this.Additionally, the Pascal language has also evolved to avoid dynamic storage management by coders - for example with the advent of dynamic arrays. You can now simply code a SetLength call to set or increase the size of such an array as your program runs. However, there are still some situations where pointers are valid in Lape.
    What are pointers?
    Simply put, a pointer is a variable that holds the address of anything in memory.
    To concrete this definition, keep in mind the following: everything used in an application is stored somewhere in the computer's memory. Because a pointer holds the address of another variable, it is said to point to that variable.
    Most of the time pointers in Lape point to a specific type:

    Simba Code:
    var
      iValue, j : integer;
      pIntValue : ^integer;
     begin
       iValue := 2001;
       pIntValue := @iValue;
       ...
       j:= pIntValue^;
     end;

    The syntax to declare a pointer data type uses a caret (^) . In the code above iValue is an integer type variable and pIntValue is an integer type pointer. Since a pointer is nothing more than an address in memory, we must assign to it the location (address) of value stored in iValue integer variable. The @ operator returns the address of a variable (or a function or procedure as will be seen later in this article). Equivalent to the @ operator is the Addr function . Note that pIntValue's value is not 2001.
    In the code above the pIntValue is a typed integer pointer. Good programming style is to use typed pointers as much as you can. The Pointer data type is a generic pointer type - represents a pointer to any data.
    Types of pointers:
    Lape provides a number of typed pointer types, such as PChar, along with a generic, 'point to anything' type - the Pointer type. The nice thing about the typed pointers is that they work sensibly with the Inc and Dec functions. Incrementing an Pinteger pointer will add SizeOf(Integer) bytes to the pointer address so that it points to the next Integer variable in memory.The Pointer type is a dangerous one - it falls foul of Lape's normally tight type handling. Use it with care, or you will end up addressing the wrong memory.
    Last edited by CynicRus; 02-16-2015 at 08:24 AM.
    Per aspera ad Astra!
    ----------------------------------------
    Slow and steady wins the race.

  2. #2
    Join Date
    May 2012
    Location
    Moscow, Russia
    Posts
    661
    Mentioned
    35 Post(s)
    Quoted
    102 Post(s)

    Default

    A simple example using PChar:
    The PChar type can be used to scan along a string :
    Simba Code:
    program new;

    var
      myString: string;
      myCharPtr: PChar;
      i: Integer;
    begin
      myString := 'Hello World';
      i := 1;
      myCharPtr := @ myString[i];
      while i <= Length(myString) do
      begin
        WriteLn(myCharPtr^);
        Inc(i);
        Inc(myCharPtr);
      end;
    end;

    There are two things to note here. First the use of @ to get the address of the string. Pointers always work with addresses - the address of a variable here, or a block of acquired memory. Here we point the PChar value to the first character in the string.

    Secondly, now that we have a pointer, we use the ^ character at the end of the pointer name to refer to what the pointer points to. In this case, a character.

    A PChar^ will always give us a character. A PInteger^, for example, will give us an Integer value. This is where the typing comes in.

    Record pointers:

    You can define a pointer to any data type using a different technique:
    Simba Code:
    var
       myRecordPtr : ^TMyRecord;
    Here, the ^ symbol is used to dereference the type - we are saying that we do not have a TMyRecord type, but a pointer to one. Note that this is a prefix use of ^.

    Let us create a full record example :
    Simba Code:
    program new;

    type
      TMyRecord = record
        name: string [20];
        age: Integer;
      end;

    var
      myRecord: TMyRecord;
      myRecordPtr: ^ TMyRecord;
    begin
      myRecord.name := 'John Doe';
      myRecord.age := 23;
      myRecordPtr := @myRecord;
      WriteLn(myRecordptr^.name);
    end;
    When we simpy refer to the record field name, without a ^, Lape is in fact adding one for us - it recognises what we are doing, and helps us make for more readable code.
    A full memory handling example:
    In this example, we'll build a new class that is a limited number list equivalent to the TStringList class. This class will allow you to keep adding numbers to a list of numbers.
    The class uses pointers to help store the numbers in a block of memory, reallocating this block when it is all used up.
    First off, we will look at the constructor :
    Simba Code:
    const
       ALLOCATE_SIZE = 20;   // How many numbers to store in first memory block
     type
     PInt = ^Integer;
     type
       TNumberList = record
          msCount  : Integer;   // Count of numbers in the list
          maxCount : Integer;   // Maximum numbers that can fit into current storage
          memStart : Pointer;   // Start of the memory holding the list
          nextSlot : PInt;    // Points to the next free slot in memory
       end;

    procedure TNumberList.Init;
    begin
      msCount  := 0;    // No numbers in the list yet

       // Allocate space for a limited number of numbers
      memStart:=GetMem(ALLOCATE_SIZE * SizeOf(Integer));

       // Indicate how many numbers that we can add before acquiring more memory
      maxCount := ALLOCATE_SIZE;

       // And point to the next free memory slot - the first!
      nextSlot := memStart;
    end;

    The role of the constructor is to initialise the class(record). The key part of this is to allocate a block of memory that can hold 20 numbers.
    The GetMem call allocates storage of the desired size, setting the memStart generalised Pointer variable to the starting address of the memory allocated. Note that GetMem insists on a Pointer variable.
    We'll add a routine to add a value to the memory :
    Simba Code:
    // Add a number to the list
     procedure TNumberList.Add(number : Integer);
     begin
       // Store the number at the next slot in our memory block
       nextSlot^ := number;
     
       // And update things to suit
       Inc(msCount);
       Inc(nextSlot);
     end;
    The passed number is stored in the next Int64 slot in our memory block, and this nextSlot pointer incremented. Note that this adds SizeOf(Int64) bytes to the address value in this pointer, because the Inc call knows the type of this pointer.
    And here is a routine for retrieving a value :
    Simba Code:
    // Get the number at the index position (starting at 0)
     function TNumberList.GetValue(index : Integer): Integer;
     var
       numberPtr : PInt;
     begin
       // Simply get the value at the given Integer index position
       numberPtr := memStart;
       Inc(numberPtr, index);   // Point to the index'th Integer number in storage
       Result := numberPtr^;    // And get the Integer number it points to
     end;
    Here we use Inc to add index Integer size bytes to the start of memory to get to the slot of the required memory.
    However, we have not yet covered the situation where the memory we allocate is all used up.
    We will extend the Add routine to do just this :
    Simba Code:
    // Add a number to the list
    procedure TNumberList.Add(const number : Int64);
     var
       newMemoryStart : Pointer;
       oldPtr, newPtr : PInt;
       i : Integer;
     begin
       // if we do not have enough space to add the number, then get more space!
       if msCount = maxCount then
       begin
         // First allocate a bigger memory space
         newMemoryStart:=GetMem((maxCount + ALLOCATE_SIZE) * SizeOf(Integer));

         // Copy the data from the old memory here
         oldPtr := memStart;
         newPtr := newMemoryStart;
         for i := 1 to maxCount do
         begin
           // Copy one number at a time
           newPtr^ := oldPtr^;
           Inc(oldPtr);
           Inc(newPtr);
         end;

         // Free the old memory
         FreeMem(memStart);

         // And now refer to the new memory
         memStart := newMemoryStart;
         nextSlot := memStart;
         Inc(nextSlot, maxCount);
         Inc(maxCount, ALLOCATE_SIZE);
       end;

       // Now we can safely add the number to the list
       nextSlot^ := number;

       // And update things to suit
       Inc(msCount);
       Inc(nextSlot);
     end;
    Here we abandon our old memory block , and create a bigger one. Having allocated it, we must copy the old memory contents to it. Here we see a new concept - assigning the value referred by one pointer to the contents of memory pointed to by another. Delphi knows to copy the whole Integer value rather than just one byte because these are PInt pointers.
    Below is the full code of the class :
    Simba Code:
    program new;
    const
      ALLOCATE_SIZE = 20;

    type
      PInt = ^Integer;

    type
      TNumberList = record
        msCount: Integer;
        maxCount: Integer;
        memStart: Pointer;
        nextSlot: PInt;
      end;

    procedure TNumberList.Init;
    begin
      msCount := 0;
      memStart := GetMem(ALLOCATE_SIZE * SizeOf(Integer));
      maxCount := ALLOCATE_SIZE;
      nextSlot := memStart;
    end;

    procedure TNumberList.Destroy;
    begin
      FreeMem(memStart)
    end;

    procedure TNumberList.Add(const number: Int64);
    var
      newMemoryStart: Pointer;
      oldPtr, newPtr: PInt;
      i: Integer;
    begin
      if msCount = maxCount then
      begin
        newMemoryStart := GetMem((maxCount + ALLOCATE_SIZE) * SizeOf(Integer));
        oldPtr := memStart;
        newPtr := newMemoryStart;
        for i := 1 to maxCount do
        begin
          newPtr ^ := oldPtr ^;
          Inc(oldPtr);
          Inc(newPtr);
        end;
        FreeMem(memStart);
        memStart := newMemoryStart;
        nextSlot := memStart;
        Inc(nextSlot, maxCount);
        Inc(maxCount, ALLOCATE_SIZE);
      end;
      nextSlot ^ := number;
      Inc(msCount);
      Inc(nextSlot);
    end;

    function TNumberList.GetValue(index: Integer): Integer;
    var
      numberPtr: PInt;
    begin
      numberPtr := memStart;
      Inc(numberPtr, index);
      Result := numberPtr ^;
    end;
    And here is how the code could be used :
    Simba Code:
    var
      list: TNumberList;
      value: Integer;
      i: Integer;
    begin
      list.Init;
      try
        for i := 0 to 29 do
          list.Add(i * 2);
        value := list.GetValue(22);
        WriteLn('22nd value = ' + IntToStr(value));
      finally
        List.Destroy;
      end;
    end;

    The end.

    Well, this original article I was found in Google a many years ago, and that is very helpful for me. I was reworked that for simba's lape, and all examples is work as it is written in the article.

    Happy scripting!

    Cheers,
    Cynic.
    Per aspera ad Astra!
    ----------------------------------------
    Slow and steady wins the race.

  3. #3
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Simba Code:
    // First allocate a bigger memory space
    newMemoryStart:=GetMem((maxCount + ALLOCATE_SIZE) * SizeOf(Integer));

    // Copy the data from the old memory here
    ...

    // Free the old memory

    can and should be replaced with:

    Simba Code:
    ReallocMem(ptr, newsize);


    Example:

    Simba Code:
    procedure memcpy(dst, src: pointer; size: Int32);
    begin
      memmove(src^, dst^, size);
    end;

    var
      ptr: PChar;
    begin
      Ptr := AllocMem(10);
      memcpy(Ptr, PChar('hello world'), 11);


      //ptr now contains 'hello world'..

      ReallocMem(Ptr, 100);  //resize it..

      writeln(Ptr); //it still contains the same content. No need to copy.

      FreeMem(Ptr);
    end.

    Personally, I'd avoid allocations like this unless passing it to a native function.. but meh, it's a tutorial. Good job!
    Last edited by Brandon; 02-16-2015 at 08:58 AM.
    I am Ggzz..
    Hackintosher

  4. #4
    Join Date
    Feb 2006
    Location
    Amsterdam
    Posts
    13,691
    Mentioned
    146 Post(s)
    Quoted
    130 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    Simba Code:
    // First allocate a bigger memory space
    newMemoryStart:=GetMem((maxCount + ALLOCATE_SIZE) * SizeOf(Integer));

    // Copy the data from the old memory here
    ...

    // Free the old memory

    can and should be replaced with:

    Simba Code:
    ReallocMem(ptr, newsize);
    Unless you're trying to explain the basics - then it may make more sense.



    The best way to contact me is by email, which you can find on my website: http://wizzup.org
    I also get email notifications of private messages, though.

    Simba (on Twitter | Group on Villavu | Website | Stable/Unstable releases
    Documentation | Source | Simba Bug Tracker on Github and Villavu )


    My (Blog | Website)

  5. #5
    Join Date
    Feb 2006
    Location
    Helsinki, Finland
    Posts
    1,395
    Mentioned
    30 Post(s)
    Quoted
    107 Post(s)

    Default

    Quote Originally Posted by CynicRus View Post
    Hey. Today I will try to explain how how to using a pointers in Lape.*SNIP*
    Good effort for great tutorial Cynic, thanks for this!

    I would hit you with some reputation+ points, but...
    "You must spread some Reputation around before giving it to CynicRus again." :\ In the future then.

    -Jani

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •