4.3BSD/usr/contrib/icon/src/lib/size.icn

#	SIZE(2)
#
#	Size of Icon value
#
#	Ralph E. Griswold
#
#	Last modified 8/15/84
#

global v16, v32, T

procedure Size(x,X,Done)
   local i
   initial {
      v16 := table()		# 16-bit implementations
      v32 := table()		# 32-bit implementations
      v16["c"] := 34		# cset size
      v16["dr"] := 4		# descriptor
      v16["e"] := 2034		# co-expression
      v16["f"] := 10		# file
      v16["l"] := 12		# list
      v16["le"] := 18		# list element
      v16["li"] := 6		# long integer
      v16["p"] := 18		# procedure
      v16["r"] := 10		# real number
      v16["s"] := 54		# set
      v16["se"] := 12		# selement
      v16["t"] := 60		# table
      v16["te"] := 16		# table element
      v16["R"] := 6		# record overhead
      v32["c"] := 36		# cset size
      v32["dr"] := 8		# descriptor
      v32["e"] := 8068		# co-expression
      v32["f"] := 20		# file
      v32["l"] := 24		# list
      v32["le"] := 36		# list element
      v32["p"] := 36		# procedure
      v32["r"] := 12		# real number
      v32["s"] := 296		# set
      v32["se"] := 24		# set element
      v32["t"] := 304		# table
      v32["te"] := 32		# table element
      v32["R"] := 12		# record overhad
      }
   /Done := table()
   case X of {
      &null | 32:  T := v32
      16:          T := v16
      default:     stop("invalid second argument to Size")
      }
   if match("record ",image(x)) then return rsize(x,X,Done)
   else return case type(x) of {
      "co-expression": ifnew(x,T["e"],Done)
      "cset":  ifnew(x,T["c"],Done)
      "file":  ifnew(x,T["f"],Done)
      "integer": isize(x,X)
      "list":  lsize(x,X,Done)
      "null":  0
      "procedure": ifnew(x,T["p"],Done)
      "real":  ifnew(x,T["r"],Done)
      "set":  ssize(x,X,Done)
      "string":  *x
      "table": tsize(x,X,Done)
      default: stop("unknown type")
      }
end

#  size of list
#
procedure lsize(a,X,Done)
   local i
   if \Done[a]  then return 0
   Done[a] := 1
   i := T["l"]
   j := *a
   j <:= 8
   i := T["le"] + T["l"] + T["dr"] * j
   every i +:= Size(!a,X,Done)
   return i
end

#  size of record
#
procedure rsize(x,X,Done)
   local i
   if match("record constructor ",image(x)) then return 0
   if \Done[x] then return 0
   Done[x] := 1
   i := T["R"] + T["dr"] * *x
   every i+:= Size(!x,X,Done)
   return i
end

#  size of set
#
procedure ssize(s,X,Done)
   local i, a, a1
   if \Done[s] then return 0
   Done[s] := 1
   i := T["s"] + T["se"] * *s
   a := sort(s)
   every a1 := !a do
     i +:= Size(a1,X,Done)
   return i
end

#  size of table
#
procedure tsize(t,X,Done)
   local i, a, a1
   if \Done[t] then return 0
   Done[t] := 1
   i := T["t"] + T["te"] * *t
   a := sort(t)
   every a1 := !a do
     i +:= Size(a1[1],X,Done) + Size(a1[2],X,Done)
   return i
end

#  test if object already counted in total
#
procedure ifnew(x,i,Done)
   if \Done[x] then return 0
   Done[x] := 1
   return i
end

#  size of integer
#
procedure isize(i,X)
   if T === v32 then return 0
   if -(2 ^ 15) <= i <= (2 ^ 15 - 1) then return 0
   else return T["li"]
end