X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe-android/blobdiff_plain/8eabb4ff13562f3550499ee599297f7e97fa8754..25c3546915ef2105c0d53983939da840ddbde795:/util.scala diff --git a/util.scala b/util.scala index 8eba6f8..79ac861 100644 --- a/util.scala +++ b/util.scala @@ -45,17 +45,16 @@ def unreachable(msg: String): Nothing = throw new AssertionError(msg); /*----- Various pieces of implicit magic ----------------------------------*/ class InvalidCStringException(msg: String) extends Exception(msg); -type CString = Array[Byte]; -object Magic { +object Implicits { /* --- Syntactic sugar for locks --- */ implicit class LockOps(lk: Lock) { /* LK withLock { BODY } * LK.withLock(INTERRUPT) { BODY } - * LK.withLock(DUR, [INTERRUPT]) { BODY } orelse { ALT } - * LK.withLock(DL, [INTERRUPT]) { BODY } orelse { ALT } + * LK.withLock(DUR, [INTERRUPT]) { BODY } orElse { ALT } + * LK.withLock(DL, [INTERRUPT]) { BODY } orElse { ALT } * * Acquire a lock while executing a BODY. If a duration or deadline is * given then wait so long for the lock, and then give up and run ALT @@ -81,12 +80,12 @@ object Magic { def withLock[T](body: => T): T = withLock(true)(body); } - class PendingLock[T] private[Magic] + class PendingLock[T] private[Implicits] (val lk: Lock, val dur: Duration, val interrupt: Boolean, body: => T) { - /* An auxiliary class for LockOps; provides the `orelse' qualifier. */ + /* An auxiliary class for LockOps; provides the `orElse' qualifier. */ - def orelse(alt: => T): T = { + def orElse(alt: => T): T = { val locked = (dur, interrupt) match { case (Duration.Inf, true) => lk.lockInterruptibly(); true case (Duration.Inf, false) => lk.lock(); true @@ -98,86 +97,6 @@ object Magic { else try { body; } finally lk.unlock(); } } - - /* --- Conversion to/from C strings --- */ - - implicit class ConvertJStringToCString(s: String) { - /* Magic to convert a string into a C string (null-terminated bytes). */ - - def toCString: CString = { - /* Convert the receiver to a C string. - * - * We do this by hand, rather than relying on the JNI's built-in - * conversions, because we use the default encoding taken from the - * locale settings, rather than the ridiculous `modified UTF-8' which - * is (a) insensitive to the user's chosen locale and (b) not actually - * UTF-8 either. - */ - - val enc = Charset.defaultCharset.newEncoder; - val in = CharBuffer.wrap(s); - var sz: Int = (s.length*enc.averageBytesPerChar + 1).toInt; - var out = ByteBuffer.allocate(sz); - - while (true) { - /* If there's still stuff to encode, then encode it. Otherwise, - * there must be some dregs left in the encoder, so flush them out. - */ - val r = if (in.hasRemaining) enc.encode(in, out, true) - else enc.flush(out); - - /* Sift through the wreckage to figure out what to do. */ - if (r.isError) r.throwException(); - else if (r.isOverflow) { - /* No space in the buffer. Make it bigger. */ - - sz *= 2; - val newout = ByteBuffer.allocate(sz); - out.flip(); newout.put(out); - out = newout; - } else if (r.isUnderflow) { - /* All done. Check that there are no unexpected zero bytes -- so - * this will indeed be a valid C string -- and convert into a byte - * array that the C code will be able to pick apart. - */ - - out.flip(); val n = out.limit; val u = out.array; - if ({val z = u.indexOf(0); 0 <= z && z < n}) - throw new InvalidCStringException("null byte in encoding"); - val v = new Array[Byte](n + 1); - out.array.copyToArray(v, 0, n); - v(n) = 0; - return v; - } - } - - /* Placate the type checker. */ - unreachable("unreachable"); - } - } - - implicit class ConvertCStringToJString(v: CString) { - /* Magic to convert a C string into a `proper' string. */ - - def toJString: String = { - /* Convert the receiver to a C string. - * - * We do this by hand, rather than relying on the JNI's built-in - * conversions, because we use the default encoding taken from the - * locale settings, rather than the ridiculous `modified UTF-8' which - * is (a) insensitive to the user's chosen locale and (b) not actually - * UTF-8 either. - */ - - val inlen = v.indexOf(0) match { - case -1 => v.length - case n => n - } - val dec = Charset.defaultCharset.newDecoder; - val in = ByteBuffer.wrap(v, 0, inlen); - dec.decode(in).toString - } - } } /*----- Cleanup assistant -------------------------------------------------*/