diff --git a/geomesa-accumulo/geomesa-accumulo-datastore/src/main/scala/org/locationtech/geomesa/accumulo/audit/AccumuloEventWriter.scala b/geomesa-accumulo/geomesa-accumulo-datastore/src/main/scala/org/locationtech/geomesa/accumulo/audit/AccumuloEventWriter.scala index 1ae557de4379..45a593ee1429 100644 --- a/geomesa-accumulo/geomesa-accumulo-datastore/src/main/scala/org/locationtech/geomesa/accumulo/audit/AccumuloEventWriter.scala +++ b/geomesa-accumulo/geomesa-accumulo-datastore/src/main/scala/org/locationtech/geomesa/accumulo/audit/AccumuloEventWriter.scala @@ -49,10 +49,10 @@ class AccumuloEventWriter(connector: AccumuloClient, table: String) extends Runn var toMutation = queue.poll() if (toMutation != null) { val writer = getWriter - do { + while (toMutation != null && running.get) { writer.addMutation(toMutation()) toMutation = queue.poll() - } while (toMutation != null && running.get) + } writer.flush() } } diff --git a/geomesa-accumulo/geomesa-accumulo-tools/src/main/scala/org/locationtech/geomesa/accumulo/tools/data/AddIndexCommand.scala b/geomesa-accumulo/geomesa-accumulo-tools/src/main/scala/org/locationtech/geomesa/accumulo/tools/data/AddIndexCommand.scala index af29f94d6eee..2f7fcf5db4af 100644 --- a/geomesa-accumulo/geomesa-accumulo-tools/src/main/scala/org/locationtech/geomesa/accumulo/tools/data/AddIndexCommand.scala +++ b/geomesa-accumulo/geomesa-accumulo-tools/src/main/scala/org/locationtech/geomesa/accumulo/tools/data/AddIndexCommand.scala @@ -158,13 +158,17 @@ class AddIndexCommandExecutor(override val params: AddIndexParameters) extends A if (result == 0) { setReadWrite() } else { - var response: String = null - do { - response = Prompt.read("Index back-fill job failed. You may:\n" + - " 1. Switch the indices to read-write mode without existing data (you may manually back-fill later)\n" + - " 2. Roll-back index creation\n" + - "Select an option: ") - } while (response != "1" && response != "2") + def readResponse(): String = { + Prompt.read("Index back-fill job failed. You may:\n" + + " 1. Switch the indices to read-write mode without existing data (you may manually back-fill later)\n" + + " 2. Roll-back index creation\n" + + "Select an option: ") + } + var response: String = readResponse() + while (response != "1" && response != "2") { + Command.user.error("Invalid response, please select 1 or 2") + response = readResponse() + } response match { case "1" => setReadWrite() case "2" => diff --git a/geomesa-arrow/geomesa-arrow-gt/src/main/scala/org/locationtech/geomesa/arrow/io/DeltaWriter.scala b/geomesa-arrow/geomesa-arrow-gt/src/main/scala/org/locationtech/geomesa/arrow/io/DeltaWriter.scala index 72ba02216cb5..cebe6de885dd 100644 --- a/geomesa-arrow/geomesa-arrow-gt/src/main/scala/org/locationtech/geomesa/arrow/io/DeltaWriter.scala +++ b/geomesa-arrow/geomesa-arrow-gt/src/main/scala/org/locationtech/geomesa/arrow/io/DeltaWriter.scala @@ -564,14 +564,16 @@ object DeltaWriter extends StrictLogging { result.clear() var resultIndex = 0 // copy the next sorted value and then queue and sort the next element out of the batch we copied from - do { - val next = queue.remove() - if (next.transfer(resultIndex)) { - queue.add(next) - } - result.underlying.setIndexDefined(resultIndex) - resultIndex += 1 - } while (!queue.isEmpty && resultIndex < batchSize) + while ({ + { + val next = queue.remove() + if (next.transfer(resultIndex)) { + queue.add(next) + } + result.underlying.setIndexDefined(resultIndex) + resultIndex += 1 + }; !queue.isEmpty && resultIndex < batchSize + })() if (writtenHeader) { unloader.unload(resultIndex) diff --git a/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serde/Version1BackwardsCompatTest.scala b/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serde/Version1BackwardsCompatTest.scala index 2e01537c92bd..690e3359c286 100644 --- a/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serde/Version1BackwardsCompatTest.scala +++ b/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serde/Version1BackwardsCompatTest.scala @@ -61,9 +61,9 @@ class Version1BackwardsCompatTest extends Specification { val fsr = SimpleFeatureDatumReader(AvroSerialization(oldType, Set.empty).schema, oldType) val sfList = new ListBuffer[SimpleFeature]() - do { + while (!decoder.isEnd) { sfList += fsr.read(null, decoder) - } while(!decoder.isEnd) + } fis.close() sfList.toList diff --git a/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serde/Version3CompatTest.scala b/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serde/Version3CompatTest.scala index a8aa48889995..fc818e7e22b9 100644 --- a/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serde/Version3CompatTest.scala +++ b/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serde/Version3CompatTest.scala @@ -66,9 +66,9 @@ class Version3CompatTest extends Specification { val fsr = SimpleFeatureDatumReader(AvroSerialization(sft, Set.empty).schema, sft) val sfList = new ListBuffer[SimpleFeature]() - do { + while (!decoder.isEnd) { sfList += fsr.read(null, decoder) - } while(!decoder.isEnd) + } fis.close() sfList.zip(v2Features).forall { case (v3, v2) => diff --git a/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serialization/SimpleFeatureDatumReaderTest.scala b/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serialization/SimpleFeatureDatumReaderTest.scala index 99275a8b2071..433290d351da 100644 --- a/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serialization/SimpleFeatureDatumReaderTest.scala +++ b/geomesa-features/geomesa-feature-avro/src/test/scala/org/locationtech/geomesa/features/avro/serialization/SimpleFeatureDatumReaderTest.scala @@ -72,9 +72,9 @@ class SimpleFeatureDatumReaderTest extends Specification with LazyLogging { val sfList = new ListBuffer[SimpleFeature]() - do { + while (!decoder.isEnd) { sfList += reader.read(null, decoder) - } while(!decoder.isEnd) + } fis.close() sfList.toList diff --git a/geomesa-features/geomesa-feature-kryo/src/main/scala/org/locationtech/geomesa/features/kryo/KryoBufferSimpleFeature.scala b/geomesa-features/geomesa-feature-kryo/src/main/scala/org/locationtech/geomesa/features/kryo/KryoBufferSimpleFeature.scala index 82e803bf1965..9bf6b6ca9b00 100644 --- a/geomesa-features/geomesa-feature-kryo/src/main/scala/org/locationtech/geomesa/features/kryo/KryoBufferSimpleFeature.scala +++ b/geomesa-features/geomesa-feature-kryo/src/main/scala/org/locationtech/geomesa/features/kryo/KryoBufferSimpleFeature.scala @@ -489,7 +489,7 @@ object KryoBufferSimpleFeature { if (i < offsets.length) { // attributes have been added to the sft since this feature was serialized missingAttributes = true - do { offsets(i) = -1; i += 1 } while (i < offsets.length) + while ({{ offsets(i) = -1; i += 1 }; i < offsets.length })() } else { missingAttributes = false } diff --git a/geomesa-features/geomesa-feature-kryo/src/main/scala/org/locationtech/geomesa/features/kryo/impl/LazyDeserialization.scala b/geomesa-features/geomesa-feature-kryo/src/main/scala/org/locationtech/geomesa/features/kryo/impl/LazyDeserialization.scala index 14aee018aafd..b15e77a658f8 100644 --- a/geomesa-features/geomesa-feature-kryo/src/main/scala/org/locationtech/geomesa/features/kryo/impl/LazyDeserialization.scala +++ b/geomesa-features/geomesa-feature-kryo/src/main/scala/org/locationtech/geomesa/features/kryo/impl/LazyDeserialization.scala @@ -306,7 +306,7 @@ trait LazyDeserialization extends KryoFeatureDeserialization { } if (i < offsets.length) { // attributes have been added to the sft since this feature was serialized - do { offsets(i) = -1; i += 1 } while (i < offsets.length) + while ({{ offsets(i) = -1; i += 1 }; i < offsets.length })() } val userDataOffset = input.position() diff --git a/geomesa-filter/src/main/scala/org/locationtech/geomesa/filter/FilterHelper.scala b/geomesa-filter/src/main/scala/org/locationtech/geomesa/filter/FilterHelper.scala index 0c5ed7108481..d65f656c7bc8 100644 --- a/geomesa-filter/src/main/scala/org/locationtech/geomesa/filter/FilterHelper.scala +++ b/geomesa-filter/src/main/scala/org/locationtech/geomesa/filter/FilterHelper.scala @@ -563,24 +563,24 @@ object FilterHelper { private [filter] def flattenAnd(filters: Seq[Filter]): ListBuffer[Filter] = { val remaining = ListBuffer.empty[Filter] ++ filters val result = ListBuffer.empty[Filter] - do { + while (remaining.nonEmpty) { remaining.remove(0) match { case f: And => remaining.appendAll(f.getChildren.asScala) case f => result.append(flatten(f)) } - } while (remaining.nonEmpty) + } result } private [filter] def flattenOr(filters: Seq[Filter]): ListBuffer[Filter] = { val remaining = ListBuffer.empty[Filter] ++ filters val result = ListBuffer.empty[Filter] - do { + while (remaining.nonEmpty) { remaining.remove(0) match { case f: Or => remaining.appendAll(f.getChildren.asScala) case f => result.append(flatten(f)) } - } while (remaining.nonEmpty) + } result } diff --git a/geomesa-hbase/geomesa-hbase-datastore/src/main/scala/org/locationtech/geomesa/hbase/data/HBaseBackedMetadata.scala b/geomesa-hbase/geomesa-hbase-datastore/src/main/scala/org/locationtech/geomesa/hbase/data/HBaseBackedMetadata.scala index 16b0e6290a50..50f9671a7d4e 100644 --- a/geomesa-hbase/geomesa-hbase-datastore/src/main/scala/org/locationtech/geomesa/hbase/data/HBaseBackedMetadata.scala +++ b/geomesa-hbase/geomesa-hbase-datastore/src/main/scala/org/locationtech/geomesa/hbase/data/HBaseBackedMetadata.scala @@ -19,9 +19,15 @@ import org.locationtech.geomesa.utils.io.WithClose import scala.collection.JavaConverters._ class HBaseBackedMetadata[T](connection: Connection, catalog: TableName, val serializer: MetadataSerializer[T]) - extends { private val table = connection.getTable(catalog) } with KeyValueStoreMetadata[T] { + extends KeyValueStoreMetadata[T] { import HBaseBackedMetadata._ + import state.table + + // state object to allow table val to be instantiated before superclass initializes + private object state { + val table: Table = connection.getTable(catalog) + } override protected def checkIfTableExists: Boolean = WithClose(connection.getAdmin)(_.tableExists(catalog)) diff --git a/geomesa-index-api/src/main/scala/org/locationtech/geomesa/index/utils/bin/BinSorter.scala b/geomesa-index-api/src/main/scala/org/locationtech/geomesa/index/utils/bin/BinSorter.scala index a95186180c2d..7b77b9c94e28 100644 --- a/geomesa-index-api/src/main/scala/org/locationtech/geomesa/index/utils/bin/BinSorter.scala +++ b/geomesa-index-api/src/main/scala/org/locationtech/geomesa/index/utils/bin/BinSorter.scala @@ -192,11 +192,14 @@ object BinSorter extends LazyLogging { */ // Skip the longest ascending sequence var i = left - do { + if (i >= right) { + return + } + while ({ i += binSize; compare(bytes, i , bytes, i - binSize) >= 0 }) { if (i >= right) { return } - } while ({ i += binSize; compare(bytes, i , bytes, i - binSize) >= 0 }) + } val a1 = Array.ofDim[Byte](binSize) val a2 = Array.ofDim[Byte](binSize) diff --git a/geomesa-utils-parent/geomesa-utils/src/main/scala/org/locationtech/geomesa/utils/conf/ArgResolver.scala b/geomesa-utils-parent/geomesa-utils/src/main/scala/org/locationtech/geomesa/utils/conf/ArgResolver.scala index b6e0a05d90b6..313b98152d94 100644 --- a/geomesa-utils-parent/geomesa-utils/src/main/scala/org/locationtech/geomesa/utils/conf/ArgResolver.scala +++ b/geomesa-utils-parent/geomesa-utils/src/main/scala/org/locationtech/geomesa/utils/conf/ArgResolver.scala @@ -45,7 +45,7 @@ trait ArgResolver[ReturnType, ParseMethodArgs] extends LazyLogging { var methods = parseMethodList assert(methods.nonEmpty, "subclass did not define any parse methods") - do { + while (methods.nonEmpty) { methods.head.apply(args) match { case Right(res) => return Right(res) // parse method succeeded, re-cast and return result @@ -57,7 +57,7 @@ trait ArgResolver[ReturnType, ParseMethodArgs] extends LazyLogging { } } methods = methods.tail - } while (methods.nonEmpty) + } // nothing passed, return the most relevant error Left(error) diff --git a/geomesa-utils-parent/geomesa-utils/src/main/scala/org/locationtech/geomesa/utils/index/ByteArrays.scala b/geomesa-utils-parent/geomesa-utils/src/main/scala/org/locationtech/geomesa/utils/index/ByteArrays.scala index c33c39c8b91f..fbe789eab099 100644 --- a/geomesa-utils-parent/geomesa-utils/src/main/scala/org/locationtech/geomesa/utils/index/ByteArrays.scala +++ b/geomesa-utils-parent/geomesa-utils/src/main/scala/org/locationtech/geomesa/utils/index/ByteArrays.scala @@ -582,7 +582,7 @@ object ByteArrays { bytes } else { // walk backwards to find the first byte we can increment, then take the sub-array to that point - do { i -= 1 } while (i >= 0 && bytes(i) == MaxByte) + while ({{ i -= 1 }; i >= 0 && bytes(i) == MaxByte })() if (i == -1) { Array.empty } else { val result = Array.ofDim[Byte](i + 1) diff --git a/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/LegacyYearZ3SFC.scala b/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/LegacyYearZ3SFC.scala index f8808bdd784f..b1094a0152d7 100644 --- a/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/LegacyYearZ3SFC.scala +++ b/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/LegacyYearZ3SFC.scala @@ -8,7 +8,9 @@ package org.locationtech.geomesa.curve +import org.locationtech.geomesa.curve.LegacyYearZ3SFC.LegacyYearZ3Dimensions import org.locationtech.geomesa.curve.NormalizedDimension.NormalizedTime +import org.locationtech.geomesa.curve.Z3SFC.{Z3Dimensions, StandardZ3Dimensions} import java.time.temporal.ChronoUnit @@ -17,19 +19,21 @@ import java.time.temporal.ChronoUnit * index keys and query ranges are consistent. Any dates that exceed the original max time will be dropped into * the last time bin, potentially degrading results for the last day or two of the year. * - * @param precision bits used per dimension - note all precisions must sum to less than 64 + * @param dims curve dimensions */ @deprecated("Z3SFC", "3.2.0") -class LegacyYearZ3SFC(precision: Int = 21) extends { - // need to use early instantiation here to prevent errors in creating parent class - // legacy incorrect time max duration - override val time: NormalizedDimension = - NormalizedTime(precision, ChronoUnit.WEEKS.getDuration.toMinutes * 52d) - } with Z3SFC(TimePeriod.Year, precision) { +class LegacyYearZ3SFC(dims: LegacyYearZ3Dimensions) extends Z3SFC(dims) { // the correct max time duration private val maxTime = BinnedTime.maxOffset(TimePeriod.Year) + /** + * Alternate constructor + * + * @param precision bits used per dimension - note all precisions must sum to less than 64 + */ + def this(precision: Int = 21) = this(LegacyYearZ3Dimensions(precision)) + override def index(x: Double, y: Double, t: Long, lenient: Boolean = false): Long = { if (t > time.max && t <= maxTime) { super.index(x, y, time.max.toLong, lenient) @@ -38,3 +42,16 @@ class LegacyYearZ3SFC(precision: Int = 21) extends { } } } + +@deprecated("Z3SFC", "3.2.0") +object LegacyYearZ3SFC { + + case class LegacyYearZ3Dimensions(precision: Int = 21) extends Z3Dimensions { + private val delegate = StandardZ3Dimensions(TimePeriod.Year, precision) + + override val lat: NormalizedDimension = delegate.lat + override val lon: NormalizedDimension = delegate.lon + // legacy incorrect time max duration + override val time: NormalizedDimension = NormalizedTime(precision, ChronoUnit.WEEKS.getDuration.toMinutes * 52d) + } +} diff --git a/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/LegacyZ3SFC.scala b/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/LegacyZ3SFC.scala index 89bf66b0f50c..e18f4ea960e1 100644 --- a/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/LegacyZ3SFC.scala +++ b/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/LegacyZ3SFC.scala @@ -8,22 +8,22 @@ package org.locationtech.geomesa.curve +import org.locationtech.geomesa.curve.LegacyZ3SFC.LegacyZ3Dimensions import org.locationtech.geomesa.curve.NormalizedDimension.{SemiNormalizedLat, SemiNormalizedLon, SemiNormalizedTime} import org.locationtech.geomesa.curve.TimePeriod.TimePeriod +import org.locationtech.geomesa.curve.Z3SFC.Z3Dimensions import org.locationtech.geomesa.zorder.sfcurve.Z3 @deprecated("Z3SFC", "1.3.2") -class LegacyZ3SFC(period: TimePeriod) extends { - // early initialization of lat/lon/time to allow for 'wholePeriod' val creation in Z3SFC - override val lon = SemiNormalizedLon(math.pow(2, 21).toLong - 1) - override val lat = SemiNormalizedLat(math.pow(2, 21).toLong - 1) - override val time = SemiNormalizedTime(math.pow(2, 20).toLong - 1, BinnedTime.maxOffset(period).toDouble) -} with Z3SFC(period, 21) { +class LegacyZ3SFC(dims: LegacyZ3Dimensions) extends Z3SFC(dims) { + + def this(period: TimePeriod) = this(LegacyZ3Dimensions(period)) + // old impl required for deleting existing values that may have been written override protected def lenientIndex(x: Double, y: Double, t: Long): Long = { - val nx = math.max(lon.min, math.ceil((x - lon.min) / (lon.max - lon.min) * lon.precision)).toInt - val ny = math.max(lat.min, math.ceil((y - lat.min) / (lat.max - lat.min) * lat.precision)).toInt - val nt = math.max(time.min, math.ceil((t - time.min) / (time.max - time.min) * time.precision)).toInt + val nx = math.max(lon.min, math.ceil((x - lon.min) / (lon.max - lon.min) * dims.lon.precision)).toInt + val ny = math.max(lat.min, math.ceil((y - lat.min) / (lat.max - lat.min) * dims.lat.precision)).toInt + val nt = math.max(time.min, math.ceil((t - time.min) / (time.max - time.min) * dims.time.precision)).toInt Z3(nx, ny, nt).z } } @@ -42,4 +42,12 @@ object LegacyZ3SFC { case TimePeriod.Month => SfcMonth case TimePeriod.Year => SfcYear } -} \ No newline at end of file + + case class LegacyZ3Dimensions(period: TimePeriod) extends Z3Dimensions { + override val lon: SemiNormalizedLon = SemiNormalizedLon(math.pow(2, 21).toLong - 1) + override val lat: SemiNormalizedLat = SemiNormalizedLat(math.pow(2, 21).toLong - 1) + override val time: SemiNormalizedTime = + SemiNormalizedTime(math.pow(2, 20).toLong - 1, BinnedTime.maxOffset(period).toDouble) + } +} + diff --git a/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/Z3SFC.scala b/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/Z3SFC.scala index 155f2aca9f4c..88d910dd9240 100644 --- a/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/Z3SFC.scala +++ b/geomesa-z3/src/main/scala/org/locationtech/geomesa/curve/Z3SFC.scala @@ -10,23 +10,29 @@ package org.locationtech.geomesa.curve import org.locationtech.geomesa.curve.NormalizedDimension._ import org.locationtech.geomesa.curve.TimePeriod.TimePeriod +import org.locationtech.geomesa.curve.Z3SFC.{Z3Dimensions, StandardZ3Dimensions} import org.locationtech.geomesa.zorder.sfcurve.{IndexRange, Z3, ZRange} /** * Z3 space filling curve * - * @param period time period used to bin results - * @param precision bits used per dimension - note all precisions must sum to less than 64 + * @param dims curve dimensions */ -class Z3SFC(period: TimePeriod, precision: Int = 21) extends SpaceTimeFillingCurve { +class Z3SFC(dims: Z3Dimensions) extends SpaceTimeFillingCurve { - require(precision > 0 && precision < 22, "Precision (bits) per dimension must be in [1,21]") + val lon: NormalizedDimension = dims.lon + val lat: NormalizedDimension = dims.lat + val time: NormalizedDimension = dims.time - val lon: NormalizedDimension = NormalizedLon(precision) - val lat: NormalizedDimension = NormalizedLat(precision) - val time: NormalizedDimension = NormalizedTime(precision, BinnedTime.maxOffset(period).toDouble) + val wholePeriod: Seq[(Long, Long)] = Seq((time.min.toLong, time.max.toLong)) - val wholePeriod = Seq((time.min.toLong, time.max.toLong)) + /** + * Alternate constructor + * + * @param period time period used to bin results + * @param precision bits used per dimension - note all precisions must sum to less than 64 + */ + def this(period: TimePeriod, precision: Int = 21) = this(StandardZ3Dimensions(period, precision)) override def index(x: Double, y: Double, t: Long, lenient: Boolean = false): Long = { try { @@ -76,4 +82,20 @@ object Z3SFC { case TimePeriod.Month => SfcMonth case TimePeriod.Year => SfcYear } -} \ No newline at end of file + + trait Z3Dimensions { + def lon: NormalizedDimension + def lat: NormalizedDimension + def time: NormalizedDimension + } + + case class StandardZ3Dimensions(period: TimePeriod, precision: Int = 21) extends Z3Dimensions { + + require(precision > 0 && precision < 22, "Precision (bits) per dimension must be in [1,21]") + + override val lon: NormalizedDimension = NormalizedLon(precision) + override val lat: NormalizedDimension = NormalizedLat(precision) + override val time: NormalizedDimension = NormalizedTime(precision, BinnedTime.maxOffset(period).toDouble) + } +} + diff --git a/geomesa-z3/src/main/scala/org/locationtech/geomesa/zorder/sfcurve/ZN.scala b/geomesa-z3/src/main/scala/org/locationtech/geomesa/zorder/sfcurve/ZN.scala index ebf0fbd96918..66553d9572d1 100644 --- a/geomesa-z3/src/main/scala/org/locationtech/geomesa/zorder/sfcurve/ZN.scala +++ b/geomesa-z3/src/main/scala/org/locationtech/geomesa/zorder/sfcurve/ZN.scala @@ -171,12 +171,12 @@ abstract class ZN { // bottom out and get all the ranges that partially overlapped but we didn't fully process // note: this method is only called when we know there are items remaining in the queue def bottomOut(): Unit = { - do { + while ({{ val minMax = remaining.poll if (!minMax.eq(LevelTerminator)) { ranges.add(IndexRange(minMax._1, minMax._2, contained = false)) } - } while (!remaining.isEmpty) + }; !remaining.isEmpty })() } // initial level - we just check the single quadrant @@ -190,7 +190,7 @@ abstract class ZN { val rangeStop = maxRanges.getOrElse(Int.MaxValue) val recurseStop = maxRecurse.getOrElse(ZN.DefaultRecurse) - do { + while ({{ val next = remaining.poll if (next.eq(LevelTerminator)) { // we've fully processed a level, increment our state @@ -215,7 +215,7 @@ abstract class ZN { bottomOut() } } - } while (!remaining.isEmpty) + }; !remaining.isEmpty })() // we've got all our ranges - now reduce them down by merging overlapping values ranges.sort(IndexRange.IndexRangeIsOrdered)