Page 1 of 1

Small tricks with JSON

Posted: Sun Sep 21, 2014 12:16 pm
by Little John
Here are tricks that make use of the JSON library, which is built into PB versions 5.30+.
Better do not use them in parts of your code where speed is crucial.
If you also have got JSON tricks, please post them here. :-)

Create an array
I originally posted the code in this thread.
The macro allows to quickly write concise and good readable code for creating and initializing an array at the same time.
It can create arrays of any standard type, with one or more dimensions.

//edit 2015-01-24
Changed
  • CreateArray()
    In order to make creation of string arrays easy, normally the character ' is used as quote, e.g.
    CreateArray(a$, "['dog', 'cat', 'mouse']").
    However, sometimes the character ' is part of the strings themselves. For handling this case, I've added the optional parameter _ersatzQuote_, which allows to use another character as quote (see 2nd example).
New
  • ComposeArray()
  • DebugArray()

Code: Select all

; <https://www.purebasic.fr/english/viewtopic.php?t=60589>
; by Little John

; Version 1.00
; successfully tested with
; [x] PB 5.30        (x86 and x64) on Windows
; [v] PB 6.03 beta 4 (x86 and x64) on Windows 11 – both ASM and C backend
; [v] PB 6.03 beta 4 (x64) on Linux Mint 20.3    – both ASM and C backend

; == Reusable macros

Macro CreateArray (_array_, _content_, _dimensions_=1, _ersatzQuote_="'")
   ; in : _array_      : name and type of array (without trailing brackets!),
   ;                     e.g. a.i
   ;      _content_    : content of array as string, e.g. "[1,2,3]"
   ;      _dimensions_ : number of array dimensions (1 or 2)
   ;      _ersatzQuote_: character used as quote in _content_, when _array_ is a string array
   ; out: _array_ (first index = 0)
   CompilerIf Not Defined(m_jArray,  #PB_Variable)
      Define m_jArray.i
   CompilerEndIf
   If Asc(_ersatzQuote_) <> 0
      ReplaceString(_content_, _ersatzQuote_, #DQUOTE$, #PB_String_InPlace)
   EndIf
   m_jArray = ParseJSON(#PB_Any, _content_)
   If m_jArray
      CompilerIf _dimensions_ = 1
         Dim _array_(0)
      CompilerElseIf _dimensions_ = 2
         Dim _array_(0, 0)
         ; If necessary, add code for more dimensions here.
      CompilerEndIf
      ExtractJSONArray(JSONValue(m_jArray), _array_())
      FreeJSON(m_jArray)
   EndIf
EndMacro

Macro ComposeArray (_array_, _content_, _ersatzQuote_="")
   ; in : _array_      : name of array (without trailing brackets!),
   ;                     e.g. a
   ;      _ersatzQuote_: character used as quote in _content_, when _array_ is a string array
   ; out: _content_: content of _array_ as string
   Define.i m_jArray = CreateJSON(#PB_Any)
   If m_jArray
      InsertJSONArray(JSONValue(m_jArray), _array_())
      _content_ = ComposeJSON(m_jArray)
      FreeJSON(m_jArray)
      If Asc(_ersatzQuote_) <> 0
         ReplaceString(_content_, #DQUOTE$, _ersatzQuote_, #PB_String_InPlace)
      EndIf
   EndIf
EndMacro

Macro DebugArray (_array_, _before_="", _after_="", _level_=0)
   ; in : _array_: name of array (without trailing brackets!),
   ;               e.g. a
   ;     _before_: text shown before array content
   ;     _after_ : text shown after  array content
   ;     _level_ : DebugLevel
   Define.i m_jArray = CreateJSON(#PB_Any)
   If m_jArray
      InsertJSONArray(JSONValue(m_jArray), _array_())
      Debug _before_ + ComposeJSON(m_jArray) + _after_, _level_
      FreeJSON(m_jArray)
   EndIf
EndMacro


; == Demo
EnableExplicit
Define i.i, k.i, ret$

CreateArray(a$, "['dog', 'cat', 'mouse']")

For i = 0 To ArraySize(a$())
   Debug a$(i)
Next

ComposeArray(a$, ret$)
Debug ret$

DebugArray(a$, "My zoo: ")

Debug "-----"

CreateArray(b$, "[|dog's collar|, |cat's tray|, |mouse's cheese|]", 1, "|")

For i = 0 To ArraySize(b$())
   Debug b$(i)
Next

ComposeArray(b$, ret$)
Debug ret$

DebugArray(b$)

Debug "-----"

CreateArray(x.d, "[1.5, 3.4, 5.3, 7.2, 9.1]")

For i = 0 To ArraySize(x())
   Debug StrD(x(i), 1)
Next

ComposeArray(x, ret$)
Debug ret$

DebugArray(x, "", "  <-- see here")

Debug "-----"

CreateArray(matrix.i, "[[1, 3, 5]," +
                      " [7, 8, 9]]", 2)

For i = 0 To ArraySize(matrix(), 1)
   ret$ = ""
   For k = 0 To ArraySize(matrix(), 2)
      ret$ + ", " + matrix(i, k)
   Next
   Debug "[" + Mid(ret$, 3) + "]"
Next

ComposeArray(matrix, ret$)
Debug ret$

DebugArray(matrix)

-------------------------------------------------

My best tricks & tips from 15+ years
Create arrays elegantly
Extended date library
Save JSON data with object members well-arranged
Evaluate and process math expressions
Functions for sets
Statistics with R
Thue-Morse sequence
Natural sorting
Sort array indexes and parallel arrays
Time profiling
VectorIcons
Generate focus events

Re: Small tricks with JSON

Posted: Sun Sep 21, 2014 12:17 pm
by Little John
Named parameters
Using named parameters for a procedure, the order of the parameters doesn't matter. This is the reason why handling optional parameters is very flexible when using named parameters. Since named parameters are self-documenting, using them results in good readable code.
The procedure in the following example has one normal parameter (which is always required), and three named parameters (which are optional).

Code: Select all

; PB 5.30+

EnableExplicit


Procedure Foo (alwaysRequired.i, optionalParams$)
   Protected x.d=10.5, y.d=20.3, msg.s="Hi!"   ; default values of parameters in 'optionalParams$'
   Protected.i jp, jv, jm
   
   ReplaceString(optionalParams$, "'", #DQUOTE$, #PB_String_InPlace)
   jp = ParseJSON(#PB_Any, "{"+optionalParams$+"}", #PB_JSON_NoCase)
   If jp
      jv = JSONValue(jp)
      
      jm = GetJSONMember(jv, "x")   : If jm : x   = GetJSONDouble(jm) : EndIf
      jm = GetJSONMember(jv, "y")   : If jm : y   = GetJSONDouble(jm) : EndIf
      jm = GetJSONMember(jv, "msg") : If jm : msg = GetJSONString(jm) : EndIf
      
      FreeJSON(jp)
   EndIf
   
   Debug alwaysRequired
   Debug x
   Debug y
   Debug msg
EndProcedure


Foo(-27, "'y':7.0, 'msg':'Hello, world!'")

Re: Small tricks with JSON

Posted: Mon Sep 22, 2014 8:59 am
by Derren
And here I thought the JSON lib was useless as you can't turn JS objects into PB objects (map) without writing your own parser, but this is actually great stuff right here.
The question is if the json lib is reasonable fast (overhead). Compared to two StringField()'s for the string parameter or direct memory peeks for example.

Re: Small tricks with JSON

Posted: Mon Sep 22, 2014 1:54 pm
by Little John
Derren wrote:And here I thought the JSON lib was useless as you can't turn JS objects into PB objects (map) without writing your own parser, but this is actually great stuff right here.
Thanks.
Derren wrote:The question is if the json lib is reasonable fast (overhead).
All I can say is, that the above code obviously is not optimized for speed.
In the above posts, I wanted to achieve the respective goal with code that is as simple as possible.
You'd have to do any speed tests yourself. :-)

Re: Small tricks with JSON

Posted: Tue Sep 23, 2014 8:20 am
by Kukulkan
Very nice! :D Especially the first one is really useful!

Thanks!

Re: Small tricks with JSON

Posted: Sat Jan 24, 2015 10:55 pm
by Little John
I've improved the code in the first post.
For details see remarks in that post.

Re: Small tricks with JSON

Posted: Thu Jan 24, 2019 9:58 pm
by djes
Nice tricks :)

Re: Small tricks with JSON

Posted: Sat Jan 26, 2019 2:10 pm
by the.weavster
Derren wrote:And here I thought the JSON lib was useless as you can't turn JS objects into PB objects (map) without writing your own parser...
I like JS objects because they can morph into different shapes but you can still have functions that work with all the different variations so long as they each have the common elements the function expects.

Re: Small tricks with JSON

Posted: Thu Oct 24, 2019 12:11 pm
by Little John
DebugStructure macro by infratec

see viewtopic.php?f=12&t=73871