nancygold's Journal
 
[Most Recent Entries] [Calendar View] [Friends View]

Sunday, August 4th, 2024

    Time Event
    1:14a
    How my ECS implementation looks
    Still a single macro. Although it does emit the stub getter and setter methods, which the runtime patches with the native code.
    The macro looks simple, but implementing it in C/C++ will require many thousands of error-prone lines of code.
    That is in addtion to all the table related code.
    So ECS is anything but easy to implemnt properly (outside of the basic structure of arrays).
    /*******************************************************************************
    
    Column-oriented Struct (aka CLasSifier)
    
    Usage:
      cls tname.parent(@ParentArgs)! @`prefix` @Params @Args
        :
        @Fields
        =
        @InitCode
    
    !                      - Provide `.tname` method
    
    @`prefix`              - Picks custom prefix for the database columns,
                             associated with this type. Default is `tname_`
                             Can be ``
    
    
    
    @Params:               - Params to the cls
      \nocvt               - Dont init the `cls` column, which allows
                             converting the unknown `id` entities to this type
      \clearable           - Provides the No.cls_clear_tname method,
                             which clears all tables associated with this type
    
    @Args:
      UpperCaseName        - Normal argument name, usable Fields values and Initcode
      lowerCaseName        - Creates a field and initalizes with that arg
      Name!Value           - Keyword argument with a default value
    
    @Fields:
      name                 - Unitialized field, which defaults to No
      name!!Default        - Unitialized field, which defaults to Default
      name!Value           - Initialized field. Value could reference @Args
      'name'!Value         - Creates a column prefix_name, but doesn't generate
                             the cls.name method.
                             Symta's version of C++ private data fields
    
    *******************************************************************************/
    cls Name @Fs =
      OName Name
      NeedsTypePredicate Name(0:['!' &Name]) //wants a type predicate?
      Parent \id
      ParentArgs:
      Name(:['()' &Name @&ParentArgs])
      Name(:['.' &Name &Parent])
      Sink No
      case Parent:
        [`$` Part] =
          Sink = Part
          Parent = \id
          Name(:['.' &Name &Parent])
      Pfx "[Name]_" //part prefix
      case Fs [`@` &Pfx],@R: Fs = R //cls Name@UserPfx @Fs
      Params nocvt!0 clearable!0
      while 1:
        case Fs:
          [`\\` Param],@_ = Params.Param = 1
          [`\\` [`()` Param [@Args]]],@_ = Params.Param = Args
          Else = done
        Fs = Fs.tail
      Body:
      AFs: //auto initialized fields
      case Fs [@FsP [[`|` @L [`=` [] []] @R ]]]: Fs =: @FsP [`=` L.j [`|` @R]]
      case Fs [@FsP [`=` &AFs &Body]]: Fs = FsP
      case Fs [@FsP &Body<[`|` @_]]: Fs = FsP
      //normalize into [Name Value PrefixedName]
      // If Name is `_`, dont produce a database column, only a method
      AFs = AFs{['!' ['@' ['.' PN N]]] V =: N V PN
               ;['!' ['@' PN]] V =: _ V PN
               ;['!' ['!' N]] V =: N ['!' V] "[Pfx][N]"
               ;['!' N] V =: N V "[Pfx][N]"
               ; N =: N No "[Pfx][N]"}
      if NeedsTypePredicate: push [_ 1 Name] AFs //if Object.widget: ...
      //push [_ Name cls]  AFs
      FNs: //field names
      PFNs: //typenanme-prefixed field names
      KVs: //keyworded args default value
      As: //arguments
      FAs: //field arguments
      till Fs.end:
        KV No //keyword value
        case Fs [[`!` _] [`!` _]@_]+[[`!` _]]: Fs =: Fs.head No @Fs.tail
        case Fs [[`!` F] D @R]:
          KV =: D
          Fs =: F @R
        push KV KVs
        AN /Fs
        A AN.title
        push A As
        if AN.is_keyword:
          push AN FNs
          push A FAs
          PAN "[Pfx][AN]"
          Fs(:[`@` &PAN],@&Fs)
          push PAN PFNs
      FNs,FAs,As,KVs,PFNs [FNs FAs As KVs PFNs]{f}
      KAs [As KVs].zip{A,[D] =: ['!' A] D; A,_=:A}.j //args with keywords
      Fields: @[FNs PFNs].zip{?0,?1,No} @AFs.skip(?0><_){?0,?2,?1}
      ParentRig []
      ParentDel []
      Me \Me
      Id form: gid_ Me
      if Parent<>id:
        PR form: Me.$("rig_[Parent]") $@ParentArgs
        push PR ParentRig
        PD form: Me.$("del_[Parent]") 
        push PD ParentDel
      InitedAFs AFs.keep(?1(1:No+['!' V]=0))
      InitCls if Params.nocvt: form (Me = $init_cls_nocvt)
              else form (Me = $init_cls Name)
      Hdr1 form: `|` (cls_set_ Id cls Name)
                    $@([PFNs FAs].zip{PFN,A = form: $rig PFN,A})
                    $@(InitedAFs{N,V,PN = form: $rig PN,V})
      Hdr form: InitCls
                $@ParentRig
                $@([PFNs FAs].zip{PFN,A = form: $rig PFN,A})
                $@(InitedAFs{N,V,PN = form: $rig PN,V})
      Type form: type Name.Parent $@(KAs): = `|` $@Hdr Body
      Rig1 form: id.$("rig1_[Name]") $@(KAs) = $@Hdr1 Body Me
      Rig form: id.$("rig_[Name]") $@(KAs) = `|` $@Hdr Body Me
      IdS "Id".rand
      Del1F form: `|` (IdS Id) $@(Fields{FN,PFN,V = form: $"T_[PFN]_".del IdS})
      Del1 form: id.$("del1_[Name]") = Del1F
      //Del1 form: id.$("del1_[Name]") = $del $@(Fields{?1})
      Del form: id.$("del_[Name]") = `|` $$("del1_[Name]") $@ParentDel
      AsText form: Name.ser_ = "${[\Name] [Me.ub.t.as_text.drop^2]}"
      //`cls`-types don't have the `__` method
      //Instead they explicitly define accessors for the used fields.
      FAs:
      TblNos:
      for [FN PFN V] Fields:
        SetPrologue 0
        GetPrologue 0
        case V:
          ['!' X] =
            case X [['$' SE] @&X]: //user want 
              SetPrologue = SE
              case X [['$' GE] @&X]: GetPrologue = GE
              X = X.~
              V =: '!' X
            if X^is_constant:
              case X ['$' E]: X = E
              push PFN,X TblNos
              V = No
        FG case V: //field getter: replacing missing elements by the default value
            ['!' X] =
              case GetPrologue:
                ['=' [] PBody] =
                  form: Name.FN = `|` PBody (gid_get_ $"T_[PFN]_" Me).@X
                Else = form: Name.FN = (gid_get_ $"T_[PFN]_" Me).@X
            Else = case GetPrologue:
                     ['=' [] PBody] =
                       form: Name.FN = `|` PBody (gid_get_ $"T_[PFN]_" Me)
                     Else = form: Name.FN = cls_get_stub_ Me $"T_[PFN]_"
        push FG FAs
        FSN "=[FN]"
        FS case V: //field setter: assigning default value removes the element
            ['!' V] =
              case SetPrologue:
                ['=' [Var] PBody] =
                  form: Name.FSN Var =
                    PBody
                    if Var><V: ($"T_[PFN]_").del Id
                    else gid_set_ $"T_[PFN]_" Me Var
                Else =
                  form: Name.FSN ~V =
                    if ~V><V: ($"T_[PFN]_").del Id
                    else gid_set_ $"T_[PFN]_" Me ~V
            Else =
              case SetPrologue:
                ['=' [Var] PBody] =
                  form: Name.FSN Var = `|` PBody (gid_set_ $"T_[PFN]_" Me Var)
                Else = form: Name.FSN ~V = cls_set_stub_ Me ~V $"T_[PFN]_"
        push FS FAs
      if got Sink:
        S form: Name.__ ~Method ~Args = |~Args.0 = $(\Me).Sink; ~Args.apply_method ~Method
        push S FAs
      AsType form: id.$("[Name]_") = ref_ (tag_ (_data Name)) Id
      SetCvt form: No.set_cls_cvt_ Name: ~Id => ref_ (tag_ (_data Name)) ~Id
      push AsType FAs
      push SetCvt FAs
      FTbls map [FN PFN V] Fields: //field tables
        form: $"T_[PFN]_" cls_tbl_ PFN
      SetNos map PFN,NoVal TblNos: //set default value for the tables
        form: $"T_[PFN]_".setNo NoVal
      Clearer:
      if Params.clearable:
        CTbls map [FN PFN V] Fields: form: $"T_[PFN]_".clear
        Clear form: no.$("cls_clear_[Name]") = `;` $@CTbls
        Clearer =: Clear
      form @(`|` $@FTbls $@SetNos Type Rig1 Rig Del1 Del AsText $@FAs $@Clearer)


    Current Mood: accomplished
    10:58a
    How ECS solves the null pointer access problem
    https://www.youtube.com/watch?v=jjEsB611kxs

    There are no pointers lol, only the phases.

    Same way in the databases it is rarely an issue.
    Unless your dataset is actually incomplete.
    But ECS allows providing sensible defaults.



    Current Mood: amused
    12:02p
    Patriotism
    Patriotism is when you're a rabbit and there is a forest fire, while the hungry wolves and foxes convince you to stay in the forest instead of running away to the fields and enjoying the burning forest view.

    Патриотизм — это когда ты зайка, а вокруг лесной пожар, и голодные волки и лисы убеждают тебя остаться в лесу, а не убегать в поля и наслаждаться видом горящего леса.

    Current Mood: amused
    1:44p
    ChatGPT is smarter than Anon?
    А теперь можно то же самое, но через чёткую последовательность действий, так чтобы разобрался условный 13-летний школьник?

    https://chatgpt.com/share/6725d89e-1de3-4484-8a23-b3acdd451195

    Current Mood: amused
    5:53p
    Finally this crap got optimized out
    Before fluid and gas code was going through every cell, which was a major CPU cycles eater.
    Now I just do the set lookup.
    Alternately I could have introduced an array of active water cells.
    Or a hashtable.
    But that would have been a partial incomplete ECS implementation.

    Now the bottleneck is in the FFI library I'm using to call C functions.
    It does really inefficient stuff to dynamically generate function calls.
    Open source code is free, but rarely of good quality.



    Current Mood: accomplished

    << Previous Day 2024/08/04
    [Calendar]
    Next Day >>

About LJ.Rossia.org