📄 saveobj.sl
字号:
% This example shows how one can save the values of slang variables to a file% and then load those values back in another instance of the program.%% The following code defines two public functions:% % save_object (FILE, obj, ...);% (obj,...) = load_object (FILE);%% For example, % a = [1:20];% b = 2.4;% c = struct { d, e }; c.d = 2.7; c.e = "foobar";% save_object ("foo.save", a, b, c);% % saves the values of the variables a, b, c to a file called "foo.save".% These values may be retrieved later, e.g., by another program instance % via:% (a,b,c) = load_object ("foo.save");%% Caveats:% % 1. Not all object types are supported. The ones supported include:% % All integer types (Int_Type, Char_Type, Long_Type, ...)% Float_Type, Double_Type% String_Type, BString_Type% Null_Type% % as well as the container classes of the above objects:% Struct_Type, Array_Type% % 2. The algorithm for saving Struct_Type is recursive. This allows one to% save a linked-list of Struct_Type objects. However, due to the recursive% nature of the algorithm and the interpreter's finite stack size, such % linked-lists cannot be arbitrarily long.%% 3. Objects are saved in the native representation. As such, the files are% not portable across machine architectures.%% File Format:%% Each slang object is written to the file with the following format% Data_Type (integer)% Length of Data Bytes (unsigned integer)% Data Bytes%% Here, Data Bytes may specify other objects if the parent is a container% object.%_debug_info = 1;static variable Type_Map = Assoc_Type[Integer_Type, -1];static variable Write_Object_Funs = Assoc_Type[Ref_Type];static variable Read_Object_Funs = Assoc_Type[Ref_Type];!if (is_defined ("_Save_Object_Cache_Type"))typedef struct{ index}_Save_Object_Cache_Type;static variable Object_Cache;static variable Num_Cached;static define delete_cache (){ Object_Cache = NULL; Num_Cached = 0;}static define create_cache (){ delete_cache ();}% If the object does not need cached, return the object.% If the object needs cached but does not exist in the cache, cache it and % return it.% Otherwise, the object is in the cache, to return a _Save_Object_Cache_Type% representing the object.static define cache_object (obj){ variable t = typeof (obj); if ((t != Array_Type) and (0 == is_struct_type (obj))) return obj; variable n = Num_Cached; variable c = Object_Cache; while (n) { if (__eqs (c.obj, obj)) { obj = @_Save_Object_Cache_Type; obj.index = n; return obj; } c = c.next; n--; } c = struct {obj, next}; c.obj = obj; c.next = Object_Cache; Object_Cache = c; Num_Cached++; %vmessage ("%S added to cache", c.obj); return obj;}static define get_object_from_cache (index){ variable depth = Num_Cached - index; variable c = Object_Cache; while (depth) { c = c.next; depth--; } return c.obj;}static define get_type_id (type){ variable id; id = Type_Map[string (type)]; if (id == -1) verror ("Object %S is not supported", type); return id;} static define write_not_implemented (fp, object){ () = fprintf (stderr, "write for object %S not implemented\n", typeof (object)); return 0;}static define do_fwrite (a, fp){ %vmessage ("Writing %S", a); variable n = fwrite (a, fp); if (n == -1) verror ("fwrite failed: %s", errno_string (errno)); return n;}static define do_fread (t, n, fp){ variable b; if (n != fread (&b, t, n, fp)) verror ("fread failed: %s", errno_string (errno)); %vmessage ("Read %S", b); return b;}static define do_ftell (fp){ variable pos = ftell (fp); if (-1 == pos) verror ("ftell failed: %s", errno_string (errno)); return pos;}static define do_fseek (fp, ofs, whence){ if (-1 == fseek (fp, ofs, whence)) verror ("fseek failed: %s", errno_string (errno));}static define sizeof (t){ variable size; switch (t) { case Char_Type or case UChar_Type: size = 1; } { case Int16_Type or case UInt16_Type: size = 2; } { case Int32_Type or case UInt32_Type: size = 4; } { case Float_Type: size = 4; } { case Double_Type: size = 8; } { verror ("sizeof (%S) not implemented", t); } return size;} static define write_numbers (fp, a){ variable size = sizeof (_typeof (a)); variable num = do_fwrite (a, fp); return num * size;}static define read_numbers (fp, t, nbytes){ variable size = sizeof (t); nbytes /= size; return do_fread (t, nbytes, fp);}static define write_string (fp, a){ return do_fwrite (a, fp);}static define read_string (fp, t, nbytes){ t = do_fread (Char_Type, nbytes, fp); if (nbytes == 1) t = char (t); return t;}static define start_header (fp, id){ variable len = write_numbers (fp, id); variable pos = do_ftell (fp); len += write_numbers (fp, 0); % temporary variable h = struct { pos, len }; h.pos = pos; h.len = len; return h;}static define end_header (fp, h, num){ do_fseek (fp, h.pos, SEEK_SET); () = do_fwrite (num, fp); do_fseek (fp, 0, SEEK_END); return h.len + num;}static define id_to_datatype (id){ variable keys, values; keys = assoc_get_keys (Type_Map); values = assoc_get_values (Type_Map); variable i = where (values == id); !if (length (i)) verror ("Corrupt file? Unknown type-id (%d)", id); return eval (keys[i][0]);}static define write_scalars (fp, a){ variable id = get_type_id (typeof (a)); variable h = start_header (fp, id); variable len = write_numbers (fp, a); return end_header (fp, h, len);}static define read_null (fp, t, nbytes){ return NULL;}static define write_null (fp, a){ return 0;}static define write_object ();static define read_object ();% Array DataBytes: int num_dims, int dims[num_dims], type, Data...static define write_array (fp, a){ variable dims, num_dims, data_type; (dims, num_dims, data_type) = array_info (a); variable len; variable id = get_type_id (data_type); len = write_numbers (fp, num_dims) + write_numbers (fp, dims) + write_numbers (fp, id); % For now allow numbers or strings if (_typeof(a) == String_Type) { foreach (a) { variable elem = (); len += write_object (fp, elem); } return len; } len += write_numbers (fp, a); return len;}static define read_array (fp, type, nbytes){ variable num_dims = do_fread (Int_Type, 1, fp); variable dims = do_fread (Int_Type, num_dims, fp); type = do_fread (Int_Type, 1, fp); variable len; len = 1; foreach (dims) len *= (); type = id_to_datatype (type); variable v; if (type == String_Type) { v = String_Type [len]; _for (0,len-1,1) { variable i = (); v[i] = read_object (fp, NULL); } } else v = do_fread (type, len, fp); reshape (v, dims); return v;}% Data Bytes: int num_fields. String-Object [num_fields], Values[num_fields]static define write_struct (fp, a){ variable fields = get_struct_field_names (a); variable len = write_numbers (fp, typecast (length (fields), Int_Type)); foreach (fields) { variable f = (); len += write_object (fp, f); } foreach (fields) { f = (); len += write_object (fp, get_struct_field (a, f)); } return len;}static define read_struct (fp, type, nbytes){ variable num_fields = do_fread (Int_Type, 1, fp); variable fields = String_Type[num_fields]; variable i; _for (0, num_fields-1, 1) { i = (); fields[i] = read_object (fp, NULL); } variable s = @Struct_Type (fields); % make sure it is in the cache in case the fields refer to it. if (type != _Save_Object_Cache_Type) () = cache_object (s); _for (0, num_fields-1, 1) { i = (); set_struct_field (s, fields[i], read_object (fp, NULL)); } return s;}% Data Bytes: int indexstatic define write_cached_object (fp, a){ return write_numbers (fp, a.index);}static define read_cached_object (fp, type, nbytes){ variable index = read_numbers (fp, Int_Type, nbytes); return get_object_from_cache (index);}static define add_type (t, w, r, id){ t = string (t); Type_Map[t] = id; Write_Object_Funs[t] = w; Read_Object_Funs [t] = r;}add_type (Char_Type, &write_numbers, &read_numbers, 1);add_type (UChar_Type, &write_numbers, &read_numbers, 2);add_type (Short_Type, &write_numbers, &read_numbers, 3);add_type (UShort_Type, &write_numbers, &read_numbers, 4);add_type (Integer_Type, &write_numbers, &read_numbers, 5);add_type (UInteger_Type,&write_numbers, &read_numbers, 6);add_type (Long_Type, &write_numbers, &read_numbers, 7);add_type (ULong_Type, &write_numbers, &read_numbers, 8);add_type (Float_Type, &write_numbers, &read_numbers, 9);add_type (Double_Type, &write_numbers, &read_numbers, 10);add_type (String_Type, &write_string, &read_string, 11);add_type (BString_Type, &write_string, &read_string, 12);add_type (Struct_Type, &write_struct, &read_struct, 13);add_type (Array_Type, &write_array, &read_array, 14);add_type (Null_Type, &write_null, &read_null, 15);add_type (_Save_Object_Cache_Type, &write_cached_object, &read_cached_object, 1000);static define get_write_function (type){ variable key = string (type); if (assoc_key_exists (Write_Object_Funs, key)) return Write_Object_Funs[key]; verror ("No write method defined for %S", key);}static define get_read_function (type){ variable key = string (type); if (assoc_key_exists (Read_Object_Funs, key)) return Read_Object_Funs[key]; verror ("No read method defined for %S", key);}static define write_object (fp, a){ a = cache_object (a); variable id = get_type_id (typeof (a)); variable h = start_header (fp, id); variable f = get_write_function (typeof (a)); variable num = (@f)(fp, a); %vmessage ("Done Writing %S", a); return end_header (fp, h, num);}static define read_object (fp, statusp){ variable type, nbytes; variable status = fread (&type, Integer_Type, 1, fp); if (status == -1) { if (statusp == NULL) verror ("No more objects in file"); @statusp = 0; return 0; } nbytes = do_fread (Integer_Type, 1, fp); type = id_to_datatype (type); variable f = get_read_function (type); variable v = (@f)(fp, type, nbytes); % Necessary because String_Type may get written as BString_Type if (type != _Save_Object_Cache_Type) v = typecast (v, type); %vmessage ("Read %S", v); if (statusp != NULL) @statusp = 1; return v;}public define save_object (){ if (_NARGS < 2) usage ("save_object (file, obj1, ...)"); variable objs = __pop_args (_NARGS - 1); variable file = (); variable fp = fopen (file, "w+"); if (fp == NULL) verror ("Unable to open %s: %s", file, errno_string (errno)); create_cache (); foreach (objs) { variable obj = ().value; () = write_object (fp, obj); } delete_cache ();}public define load_object (file){ variable fp = fopen (file, "r"); if (fp == NULL) verror ("Unable to open %s: %s", file, errno_string (errno)); create_cache (); forever { variable status; variable obj = read_object (fp, &status); if (status == 0) break; obj; } delete_cache ();}#iffalse% Regression teststatic define failed (s, a, b){ vmessage ("Failed: %s: wrote: '%S', read '%S'\n", s, a, b);}static define test_eqs ();static define test_eqs (a, b){ if ((typeof (a) != typeof (b)) or (_typeof (a) != _typeof (b))) { failed ("typeof", typeof(a), typeof(b)); return 0; } if (typeof (a) != Struct_Type) { if (length (a) != length (b)) { failed ("test_eqs length", a, b); return 0; } if (length (where (a != b))) { failed ("test_eqs", a, b); return 0; } return 1; } variable fa, fb; fa = get_struct_field_names (a); fb = get_struct_field_names (b); !if (test_eqs (fa, fb)) { failed ("test_eqs: fa, fb"); return 0; } if (length (fa) != length (fb)) return 0; foreach (fa) { variable name = (); variable va, vb; va = get_struct_field (a, name); vb = get_struct_field (b, name); if ((typeof (va) == Struct_Type) and (typeof (vb) == Struct_Type)) { % void loop continue; } !if (test_eqs (va, vb)) return 0; } return 1;}static define test_save_object (){ variable x0 = 1278; variable x1 = 2.3; variable x2 = "foo"; variable x3 = struct { a, b, c, d }; variable x4 = [1:10]; variable x5 = ["a","b","c","d"]; x3.a = "foo"; x3.b = PI; x3.c = [1:20]; x3.d = x3; save_object ("foo.sv", x0,x1,x2,x3,x4,x5); variable y0,y1,y2,y3,y4,y5; (y0,y1,y2,y3,y4,y5) = load_object ("foo.sv"); !if (test_eqs (x0, y0)) failed ("x0", x0, y0); !if (test_eqs (x1, y1)) failed ("x1", x1, y1); !if (test_eqs (x2, y2)) failed ("x2", x2, y2); !if (test_eqs (x3, y3)) failed ("x3", x3, y3); !if (test_eqs (x4, y4)) failed ("x4", x4, y4); !if (test_eqs (x5, y5)) failed ("x5", x5, y5); vmessage ("Regression Test Done");}test_save_object ();#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -