author | wenzelm |
Fri, 05 Jul 2024 00:18:51 +0200 | |
changeset 80505 | e3af424fdd1a |
parent 80480 | 972f7a4cdc0e |
permissions | -rw-r--r-- |
43780 | 1 |
/* Title: Pure/General/properties.scala |
2 |
Author: Makarius |
|
3 |
||
4 |
Property lists. |
|
5 |
*/ |
|
6 |
||
7 |
package isabelle |
|
8 |
||
9 |
||
75393 | 10 |
object Properties { |
65624 | 11 |
/* entries */ |
12 |
||
43780 | 13 |
type Entry = (java.lang.String, java.lang.String) |
14 |
type T = List[Entry] |
|
15 |
||
75393 | 16 |
object Eq { |
73715
bf51c23f3f99
clarified signature -- avoid odd warning about scala/bug#6675;
wenzelm
parents:
73712
diff
changeset
|
17 |
def apply(a: java.lang.String, b: java.lang.String): java.lang.String = a + "=" + b |
bf51c23f3f99
clarified signature -- avoid odd warning about scala/bug#6675;
wenzelm
parents:
73712
diff
changeset
|
18 |
def apply(entry: Entry): java.lang.String = apply(entry._1, entry._2) |
73712 | 19 |
|
75393 | 20 |
def unapply(str: java.lang.String): Option[Entry] = { |
73712 | 21 |
val i = str.indexOf('=') |
22 |
if (i <= 0) None else Some((str.substring(0, i), str.substring(i + 1))) |
|
23 |
} |
|
80505
e3af424fdd1a
more robust message header: prefer explicit props_length/props_chunks over odd YXML.embed_controls;
wenzelm
parents:
80480
diff
changeset
|
24 |
|
e3af424fdd1a
more robust message header: prefer explicit props_length/props_chunks over odd YXML.embed_controls;
wenzelm
parents:
80480
diff
changeset
|
25 |
def parse(s: java.lang.String): Entry = |
e3af424fdd1a
more robust message header: prefer explicit props_length/props_chunks over odd YXML.embed_controls;
wenzelm
parents:
80480
diff
changeset
|
26 |
unapply(s) getOrElse error("Bad property entry: " + quote(s)) |
73712 | 27 |
} |
28 |
||
64358 | 29 |
def defined(props: T, name: java.lang.String): java.lang.Boolean = |
30 |
props.exists({ case (x, _) => x == name }) |
|
31 |
||
32 |
def get(props: T, name: java.lang.String): Option[java.lang.String] = |
|
33 |
props.collectFirst({ case (x, y) if x == name => y }) |
|
34 |
||
75393 | 35 |
def put(props: T, entry: Entry): T = { |
64358 | 36 |
val (x, y) = entry |
37 |
def update(ps: T): T = |
|
38 |
ps match { |
|
39 |
case (p @ (x1, _)) :: rest => |
|
40 |
if (x1 == x) (x1, y) :: rest else p :: update(rest) |
|
41 |
case Nil => Nil |
|
42 |
} |
|
43 |
if (defined(props, x)) update(props) else entry :: props |
|
44 |
} |
|
45 |
||
46 |
||
65857 | 47 |
/* external storage */ |
48 |
||
75794
1c3c31319974
more robust data representation: notably for Store.read_session_timing with database_server;
wenzelm
parents:
75393
diff
changeset
|
49 |
def encode(ps: T): Bytes = { |
1c3c31319974
more robust data representation: notably for Store.read_session_timing with database_server;
wenzelm
parents:
75393
diff
changeset
|
50 |
if (ps.isEmpty) Bytes.empty |
80436
6e865cd22349
minor performance tuning: more direct YXML.bytes_of_body;
wenzelm
parents:
76351
diff
changeset
|
51 |
else YXML.bytes_of_body(XML.Encode.properties(ps)) |
75794
1c3c31319974
more robust data representation: notably for Store.read_session_timing with database_server;
wenzelm
parents:
75393
diff
changeset
|
52 |
} |
65857 | 53 |
|
75794
1c3c31319974
more robust data representation: notably for Store.read_session_timing with database_server;
wenzelm
parents:
75393
diff
changeset
|
54 |
def decode(bs: Bytes, cache: XML.Cache = XML.Cache.none): T = { |
1c3c31319974
more robust data representation: notably for Store.read_session_timing with database_server;
wenzelm
parents:
75393
diff
changeset
|
55 |
if (bs.is_empty) Nil |
80480
972f7a4cdc0e
clarified YXML.Source: more direct support for String and Bytes, instead of CharSequence;
wenzelm
parents:
80436
diff
changeset
|
56 |
else cache.props(XML.Decode.properties(YXML.parse_body(bs))) |
75794
1c3c31319974
more robust data representation: notably for Store.read_session_timing with database_server;
wenzelm
parents:
75393
diff
changeset
|
57 |
} |
65857 | 58 |
|
68018 | 59 |
def compress(ps: List[T], |
76351
2cee31cd92f0
generic support for XZ and Zstd compression in Isabelle/Scala;
wenzelm
parents:
76350
diff
changeset
|
60 |
options: Compress.Options = Compress.Options(), |
2cee31cd92f0
generic support for XZ and Zstd compression in Isabelle/Scala;
wenzelm
parents:
76350
diff
changeset
|
61 |
cache: Compress.Cache = Compress.Cache.none |
75393 | 62 |
): Bytes = { |
65857 | 63 |
if (ps.isEmpty) Bytes.empty |
68018 | 64 |
else { |
80436
6e865cd22349
minor performance tuning: more direct YXML.bytes_of_body;
wenzelm
parents:
76351
diff
changeset
|
65 |
YXML.bytes_of_body(XML.Encode.list(XML.Encode.properties)(ps)). |
68018 | 66 |
compress(options = options, cache = cache) |
67 |
} |
|
65857 | 68 |
} |
69 |
||
75393 | 70 |
def uncompress(bs: Bytes, cache: XML.Cache = XML.Cache.none): List[T] = { |
72885 | 71 |
if (bs.is_empty) Nil |
65857 | 72 |
else { |
68018 | 73 |
val ps = |
73031
f93f0597f4fb
clarified signature: absorb XZ.Cache into XML.Cache;
wenzelm
parents:
73024
diff
changeset
|
74 |
XML.Decode.list(XML.Decode.properties)( |
80480
972f7a4cdc0e
clarified YXML.Source: more direct support for String and Bytes, instead of CharSequence;
wenzelm
parents:
80436
diff
changeset
|
75 |
YXML.parse_body(bs.uncompress(cache = cache.compress))) |
73031
f93f0597f4fb
clarified signature: absorb XZ.Cache into XML.Cache;
wenzelm
parents:
73024
diff
changeset
|
76 |
if (cache.no_cache) ps else ps.map(cache.props) |
65857 | 77 |
} |
78 |
} |
|
79 |
||
80 |
||
65624 | 81 |
/* multi-line entries */ |
82 |
||
65932 | 83 |
def encode_lines(props: T): T = props.map({ case (a, b) => (a, Library.encode_lines(b)) }) |
84 |
def decode_lines(props: T): T = props.map({ case (a, b) => (a, Library.decode_lines(b)) }) |
|
65624 | 85 |
|
86 |
def lines_nonempty(x: java.lang.String, ys: List[java.lang.String]): Properties.T = |
|
87 |
if (ys.isEmpty) Nil else List((x, cat_lines(ys))) |
|
88 |
||
89 |
||
90 |
/* entry types */ |
|
64358 | 91 |
|
75393 | 92 |
class String(val name: java.lang.String) { |
43780 | 93 |
def apply(value: java.lang.String): T = List((name, value)) |
94 |
def unapply(props: T): Option[java.lang.String] = |
|
95 |
props.find(_._1 == name).map(_._2) |
|
72137 | 96 |
def get(props: T): java.lang.String = unapply(props).getOrElse("") |
43780 | 97 |
} |
98 |
||
75393 | 99 |
class Boolean(val name: java.lang.String) { |
48344 | 100 |
def apply(value: scala.Boolean): T = List((name, Value.Boolean(value))) |
101 |
def unapply(props: T): Option[scala.Boolean] = |
|
102 |
props.find(_._1 == name) match { |
|
103 |
case None => None |
|
104 |
case Some((_, value)) => Value.Boolean.unapply(value) |
|
105 |
} |
|
72137 | 106 |
def get(props: T): scala.Boolean = unapply(props).getOrElse(false) |
48344 | 107 |
} |
108 |
||
75393 | 109 |
class Int(val name: java.lang.String) { |
43780 | 110 |
def apply(value: scala.Int): T = List((name, Value.Int(value))) |
111 |
def unapply(props: T): Option[scala.Int] = |
|
112 |
props.find(_._1 == name) match { |
|
113 |
case None => None |
|
114 |
case Some((_, value)) => Value.Int.unapply(value) |
|
115 |
} |
|
72137 | 116 |
def get(props: T): scala.Int = unapply(props).getOrElse(0) |
43780 | 117 |
} |
118 |
||
75393 | 119 |
class Long(val name: java.lang.String) { |
43780 | 120 |
def apply(value: scala.Long): T = List((name, Value.Long(value))) |
121 |
def unapply(props: T): Option[scala.Long] = |
|
122 |
props.find(_._1 == name) match { |
|
123 |
case None => None |
|
124 |
case Some((_, value)) => Value.Long.unapply(value) |
|
125 |
} |
|
72137 | 126 |
def get(props: T): scala.Long = unapply(props).getOrElse(0) |
43780 | 127 |
} |
128 |
||
75393 | 129 |
class Double(val name: java.lang.String) { |
43780 | 130 |
def apply(value: scala.Double): T = List((name, Value.Double(value))) |
131 |
def unapply(props: T): Option[scala.Double] = |
|
132 |
props.find(_._1 == name) match { |
|
133 |
case None => None |
|
134 |
case Some((_, value)) => Value.Double.unapply(value) |
|
135 |
} |
|
72137 | 136 |
def get(props: T): scala.Double = unapply(props).getOrElse(0.0) |
43780 | 137 |
} |
138 |
} |