From e3450fca17fdeb5f64df260b224916b6b2cbdb73 Mon Sep 17 00:00:00 2001 From: Andreas Fankhauser hiddenalpha.ch Date: Wed, 21 Dec 2022 00:10:40 +0100 Subject: Add misc setup files. Add few java classes. --- .gitignore | 2 + LICENSE.txt | 14 +++++ README.md | 7 +++ pom.xml | 24 +++++++++ xtra4j-misc/pom.xml | 18 +++++++ .../ch/hiddenalpha/xtra4j/format/FormatUtils.java | 49 +++++++++++++++++ .../ch/hiddenalpha/xtra4j/stream/StreamUtils.java | 58 ++++++++++++++++++++ .../java/ch/hiddenalpha/xtra4j/time/TimeUtils.java | 61 ++++++++++++++++++++++ 8 files changed, 233 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 pom.xml create mode 100644 xtra4j-misc/pom.xml create mode 100644 xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/format/FormatUtils.java create mode 100644 xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/stream/StreamUtils.java create mode 100644 xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/time/TimeUtils.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56256e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target/ +/*/target/ diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..8f302c9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,14 @@ + +Copyright (c) 2022 Andreas Fankhauser + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..2acd66a --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ + +xtra4j +====== + +Utilities the original author of this library did miss +in the JDK. + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d97fb24 --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ + + + + 4.0.0 + + ch.hiddenalpha.xtra4j + xtra4j-parent + 0.0.0-SNAPSHOT + + pom + + + UTF-8 + 8 + 8 + + + + xtra4j-misc + + + diff --git a/xtra4j-misc/pom.xml b/xtra4j-misc/pom.xml new file mode 100644 index 0000000..8172f36 --- /dev/null +++ b/xtra4j-misc/pom.xml @@ -0,0 +1,18 @@ + + + + 4.0.0 + + xtra4j-misc + + + ch.hiddenalpha.xtra4j + xtra4j-parent + 0.0.0-SNAPSHOT + + + jar + + diff --git a/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/format/FormatUtils.java b/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/format/FormatUtils.java new file mode 100644 index 0000000..fc10ab2 --- /dev/null +++ b/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/format/FormatUtils.java @@ -0,0 +1,49 @@ +package ch.hiddenalpha.xtra4j.format; + + +public class FormatUtils { + + /** + * Tries to format 'val' as a small integer. If not possible falls back + * to decimal representation. If also not possible, falls back to scientific + * notation. + * + * Handy in cases where we need to "just print that number" without having + * stupid amount of nonsense decimal places or bother readers with + * scientific notation where "just an int" would perfectly do the job. + * + * @param val + * The number to format. + * + * @param ndig + * How many significant digits to be printed. MUST be in range 1..7. + */ + public static String toStr( float val, int ndig ){ + int exp; + float limit; + String fmt; + if( val == 0 ){ + return "0"; + } + switch( ndig ){ + case 1: exp = 1; limit = 1e4F ; fmt = "%.1g"; break; + case 2: exp = 10; limit = 1e6F ; fmt = "%.2g"; break; + case 3: exp = 100; limit = 1e7F ; fmt = "%.3g"; break; + case 4: exp = 1000; limit = 1e8F ; fmt = "%.4g"; break; + case 5: exp = 10000; limit = 1e9F ; fmt = "%.5g"; break; + case 6: exp = 100000; limit = 1e10F; fmt = "%.6g"; break; + case 7: exp = 1000000; limit = 1e11F; fmt = "%.7g"; break; + default: throw new IllegalArgumentException("ndig "+ ndig +" not in expected range 1..7"); + } + if( val >= exp && val <= limit ){ + // Print simple numbers as int. + return String.valueOf((int)val); + }else{ + // Format too large or too small numbers with not wasting too much + // space. In addition, fix annoying locale chars as this function is + // about printing numbers and not ascii-art. + return String.format(fmt, val).replace(',', '.').replace("'", ""); + } + } + +} diff --git a/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/stream/StreamUtils.java b/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/stream/StreamUtils.java new file mode 100644 index 0000000..7aef622 --- /dev/null +++ b/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/stream/StreamUtils.java @@ -0,0 +1,58 @@ +package ch.hiddenalpha.xtra4j.stream; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.function.Predicate; + + +public class StreamUtils { + + /** + * Copies 'is' to 'os' until end of 'is' is reached. (Blocking) + * + *

BTW: Using this function makes no longer sense in projects using java + * 9 or later. Just use {@link java.io.InputStream#transferTo(java.io.OutputStream)} + * instead.

+ * + * @return + * Count of copied bytes. + */ + public static long copy( InputStream is, OutputStream os ) throws IOException { + byte[] buffer = new byte[8192]; + long totalBytes = 0; + int readLen; + while( -1 != (readLen=is.read(buffer,0,buffer.length)) ){ + totalBytes += readLen; + os.write(buffer, 0, readLen); + } + return totalBytes; + } + + /** + * Maps every value flowing through iterator using passed callback. + */ + public static Iterator map( Iterator src , Function mapper ){ + return new Iterator(){ + @Override public boolean hasNext() { return src.hasNext(); } + @Override public DST next() { return mapper.apply(src.next()); } + }; + } + + public static Predicate distinctBy(Function keyExtractor) { + Set seen = ConcurrentHashMap.newKeySet(); + return t -> seen.add(keyExtractor.apply(t)); + } + + /** + * Negates the passed predicate. + */ + public static Predicate not( Predicate p ){ + return e -> !p.test(e); + } + +} diff --git a/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/time/TimeUtils.java b/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/time/TimeUtils.java new file mode 100644 index 0000000..5bdc975 --- /dev/null +++ b/xtra4j-misc/src/main/java/ch/hiddenalpha/xtra4j/time/TimeUtils.java @@ -0,0 +1,61 @@ +package ch.hiddenalpha.xtra4j.time; + +import static java.lang.System.*; + + +public class TimeUtils { + + /** + * Delegates to {@link #nanosToEpochMillis(long, long, long)} and + * assumes that the 'nanos' value was measured in the same JVM + * process as this call here occurs and is not too long back. + */ + public static long nanosToEpochMillis( long nanos ){ + return nanosToEpochMillis(nanos, nanoTime(), currentTimeMillis()); + } + + public static long nanosToEpochMillis( long nanos, long referenceNanos, long referenceEpochMs ){ + long diffNs = nanos - referenceNanos; + if( diffNs < (Long.MIN_VALUE >> 1) || diffNs > (Long.MAX_VALUE>>1) ){ + // Looks as System.nanoTime() did overflow while measurement. So + // flip result. + diffNs -= Long.MAX_VALUE; + } + return referenceEpochMs + (diffNs / 1_000_000); + } + + /** + *

Find smallest distance assuming integers overflow "like a circle".

+ * + *

Just imagine integers more like a circle. So when we infinitely + * increment an integer, we assume it overflows and continues to walk around + * this (imaginary) circle continuing its steps in the far negative range + * towards zero again.

+ * + *

This function takes two of those numbers on this circle and returns + * the smallest distance to travel on the circle between them. Here some + * examples:

+ *
    + *
  • f(7, 13) = 6
  • + *
  • f(-7, +11) = 18
  • + *
  • f(LONG_MIN, LONG_MAX) = 1
  • + *
  • f(-9223372036854775805, 9223372036854775802) = 9
  • + *
+ * + *

This can be handy for example in conjunction with {@link System#nanoTime()}. + * Because in case of overflows between measuring begNs and endNs a simple + * subtraction would lead to uselessly large results. So we can use it as:

+ * + * long begNs = System.nanoTime();
+ * long endNs = System.nanoTime();
+ * long durationNs = nanosSmallDiff(endNs, begNs);
+ *
+ * + *

WARN: Do NOT use this if your distance can reach (LONG_MAX / 2). + * Because in this case you would get wrong (too small) results.

+ */ + public static long nanosSmallDiff( long a, long b ){ + return (a - b >= 0) ? a - b : b - a; + } + +} -- cgit v1.1