Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / October 2007

Tip: Looking for answers? Try searching our database.

Primitive type arrays boxing utilities

Thread view: 
Piotr Kobzda - 07 Oct 2007 01:31 GMT
Below is the code generator of utility class that may possibly appear
useful extension for java.util.Arrays methods.

Basic usages of the generated class includes:

1) Lists backed with primitive arrays manipulation.

int[] array = { 1, 2, 3 };
Collections.shuffle(PrimitiveArrays.asList(array));

2) Simple primitive type arrays boxing/unboxing.

int[] array = { 1, 2, 3 };
Integer[] boxedArray = PrimitiveArrays.box(array);
array = PrimitiveArrays.unbox(boxedArray);

3) Type-safe, non-dimensions limited, extended boxing/unboxing of
primitive arrays.

int[][][] a = {{{ 1, 2, 3 }}};
Integer[][][] b = PrimitiveArrays.intBoxer().deeper().deeper().box(a);
// operate on b...
PrimitiveArrays.intBoxer().deeper().deeper().unbox(b, a);
// operate on updated a...

What do you think about that?  Is that worth of becoming a new Java RFE?

Regards,
piotr

import static java.lang.System.out;

public class Generator {
  static String[][] pairs = {
    {"boolean", "Boolean"},
    {"byte", "Byte"},
    {"char", "Character"},
    {"double", "Double"},
    {"float", "Float"},
    {"int", "Integer"},
    {"long", "Long"},
    {"short", "Short"},
  };

  public static void main(String[] args) {
  //  out.println("package java.util;");

    out.println("import java.lang.reflect.Array;");
    out.println("import java.util.AbstractList;");
    out.println("import java.util.List;");
    out.println("import java.util.RandomAccess;");
    out.println();
    out.println("public class PrimitiveArrays {");
    out.println();
    out.println("private static abstract class ArrayBackedList<E>");
    out.println("    extends AbstractList<E> implements RandomAccess {");
    out.println("}");
    out.println();

    generateAsListMethods();
    generateBoxersBase();
    generateBoxers();
    generateBoxingMethods();

    out.println("}");
  }

  static void generateAsListMethods() {
  new Object() {
    void gen(String from, String to) {
      out.println("public static List<"+ to +"> asList(final "+ from
+"[] array) {");
      out.println("  return new ArrayBackedList<"+ to +">() {");
      out.println();
      out.println("    @Override");
      out.println("    public int size() {");
      out.println("      return array.length;");
      out.println("    }");
      out.println();
      out.println("    @Override");
      out.println("    public "+ to +" get(int index) {");
      out.println("      return array[index];");
      out.println("    }");
      out.println();
      out.println("    @Override");
      out.println("    public "+ to +" set(int index, "+ to +" element)
{");
      out.println("      "+ to +" r = array[index];");
      out.println("      array[index] = element;");
      out.println("      return r;");
      out.println("    }");
      out.println("  };");
      out.println("}");
      out.println();
    }

    {
      for(String[] pair : pairs) {
        gen(pair[0], pair[1]);
      }
    }
  };
  }

  static void generateBoxersBase() {
    out.println("public static abstract class Boxer<S, T> {");
    out.println("  private Class<S> typeOfS;");
    out.println("  private Class<T> typeOfT;");
    out.println();
    out.println("  Boxer(Class<S> typeOfS, Class<T> typeOfT) {");
    out.println("    this.typeOfS = typeOfS;");
    out.println("    this.typeOfT = typeOfT;");
    out.println("  }");
    out.println();
    out.println("  private Boxer<S[], T[]> child;");
    out.println();
    out.println("  public Boxer<S[], T[]> deeper() {");
    out.println("    if (child != null) return child;");
    out.println();
    out.println("    final Boxer<S, T> parent = Boxer.this;");
    out.println("    return child = new Boxer<S[], T[]>(");
    out.println("        arrayType(typeOfS), arrayType(typeOfT)) {");
    out.println();
    out.println("      @Override");
    out.println("      public T[] box(S[] source) {");
    out.println("        T[] target = newArray(typeOfT, source.length);");
    out.println("        for(int i = 0, len = source.length; i < len;
++i)");
    out.println("          target[i] = parent.box(source[i]);");
    out.println("        return target;");
    out.println("      }");
    out.println();
    out.println("      @Override");
    out.println("      public T[] box(S[] source, T[] target) {");
    out.println("        for(int i = 0, len = source.length; i < len;
++i)");
    out.println("          parent.box(source[i], target[i]);");
    out.println("        return target;");
    out.println("      }");
    out.println();
    out.println("      @Override");
    out.println("      public S[] unbox(T[] source) {");
    out.println("        S[] target = newArray(typeOfS, source.length);");
    out.println("        for(int i = 0, len = source.length; i < len;
++i)");
    out.println("          target[i] = parent.unbox(source[i]);");
    out.println("        return target;");
    out.println("      }");
    out.println();
    out.println("      @Override");
    out.println("      public S[] unbox(T[] source, S[] target) {");
    out.println("        for(int i = 0, len = source.length; i < len;
++i)");
    out.println("          parent.unbox(source[i], target[i]);");
    out.println("        return target;");
    out.println("      }");
    out.println();
    out.println("      @Override");
    out.println("      public int dimensions() {");
    out.println("        return parent.dimensions() + 1;");
    out.println("      }");
    out.println();
    out.println("    };");
    out.println("  }");
    out.println();
    out.println("  public abstract T box(S source);");
    out.println();
    out.println("  public abstract T box(S source, T target);");
    out.println();
    out.println("  public abstract S unbox(T source);");
    out.println();
    out.println("  public abstract S unbox(T source, S target);");
    out.println();
    out.println();
    out.println("  public int dimensions() {");
    out.println("    return 1;");
    out.println("  }");
    out.println();
    out.println("  @SuppressWarnings(\"unchecked\")");
    out.println("  static <T> Class<T[]> arrayType(Class<T>
componentType) {");
    out.println("    return (Class<T[]>)
Array.newInstance(componentType, 0).getClass();");
    out.println("  }");
    out.println();
    out.println("  @SuppressWarnings(\"unchecked\")");
    out.println("  static <T> T[] newArray(Class<T> componentType, int
length) {");
    out.println("    return (T[]) Array.newInstance(componentType,
length);");
    out.println("  }");
    out.println();
    out.println("}");
    out.println();
  }

  static void generateBoxers() {
  new Object() {
    void genBoxer(String from, String to) {
      out.println("private static class "+ to +"Boxer extends Boxer<"+
from +"[], "+ to +"[]> {");
      out.println("  static final "+ to +"Boxer INSTANCE = new "+ to
+"Boxer();");
      out.println();
      out.println("  "+ to +"Boxer() {");
      out.println("    super("+ from +"[].class, "+ to +"[].class);");
      out.println("  }");
      out.println();
      out.println("  @Override");
      out.println("  public "+ to +"[] box("+ from +"[] source) {");
      out.println("    return box(source, new "+ to +"[source.length]);");
      out.println("  }");
      out.println();
      out.println("  @Override");
      out.println("  public "+ to +"[] box("+ from +"[] source, "+ to
+"[] target) {");
      out.println("    for(int i = 0, len = source.length; i < len; ++i)");
      out.println("      target[i] = source[i];");
      out.println("    return target;");
      out.println("  }");
      out.println();
      out.println("  @Override");
      out.println("  public "+ from +"[] unbox("+ to +"[] source) {");
      out.println("    return unbox(source, new "+ from
+"[source.length]);");
      out.println("  }");
      out.println();
      out.println("  @Override");
      out.println("  public "+ from +"[] unbox("+ to +"[] source, "+
from +"[] target) {");
      out.println("    for(int i = 0, len = source.length; i < len; ++i)");
      out.println("      target[i] = source[i];");
      out.println("    return target;");
      out.println("  }");
      out.println("}");
      out.println();
    }

    void genAccessMethod(String from, String to) {
      out.println("public static Boxer<"+ from +"[], "+ to +"[]> "+
from +"Boxer() {");
      out.println("  return "+ to +"Boxer.INSTANCE;");
      out.println("}");
      out.println();
    }

    {
      for(String[] pair : pairs) {
        genBoxer(pair[0], pair[1]);
      }
      for(String[] pair : pairs) {
        genAccessMethod(pair[0], pair[1]);
      }
    }
  };
  }

  static void generateBoxingMethods() {
  new Object(){
    void gen(String name, String from, String to, String boxer) {
      out.println("public static "+ to +"[] "+ name +"("+ from +"[]
source) {");
      out.println("  return "+ boxer +"Boxer.INSTANCE."+ name +
"(source);");
      out.println("}");
      out.println();
    }

    {
      for(String[] pair : pairs) {
        gen("box", pair[0], pair[1], pair[1]);
      }
      for(String[] pair : pairs) {
        gen("unbox", pair[1], pair[0], pair[1]);
      }
    }
  };
  }
}
Daniel Pitts - 07 Oct 2007 19:17 GMT
> Below is the code generator of utility class that may possibly appear
> useful extension for java.util.Arrays methods.
[quoted text clipped - 25 lines]
> Regards,
> piotr

[snip code]

Sure, and while your at it, suggest that List<Integer>.toArray(new
int[0]) works as expected. (Actually, I don't know that it doesn't work,
but I'm guessing it doesn't.)

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Piotr Kobzda - 07 Oct 2007 21:13 GMT
> Sure, and while your at it, suggest that List<Integer>.toArray(new
> int[0]) works as expected. (Actually, I don't know that it doesn't work,
> but I'm guessing it doesn't.)

That's impossible, because toArray() in List has the following two
overrides only:

    public Object[] toArray()
    public <T> T[]  toArray(T[] a)

And none of them allows to return/accept the int[] type.  Thus, the only
possibility is to preserve the original behavior of those methods here,
i.e. return array of objects.

There is also possibility to introduce additional toArray() overrides to
the list returned from asList() (internal ArrayBackedList may do that).
 However, that would require this extended type to be declared as
return type of asList() overrides, which will likely compromise the
usability of them).

However, using proposed boxing utilities it's not hard to achieve what
you expect from toArray() that way:

List<Integer> list = ...
int[] array = unbox(list.toArray(new Integer[list.size()]));

// or having already created array of ints, that way:

intBoxer().unbox(list.toArray(new Integer[array.length]), array);

Not big difference IMHO, just one auxiliary array more...

piotr
Stefan Ram - 07 Oct 2007 21:18 GMT
>> Sure, and while your at it, suggest that List<Integer>.toArray(new
>However, using proposed boxing utilities it's not hard to achieve what

 See also:

     »Commons Primitives provides a library of collections and
     utilities specially designed for use with primitive types.«

http://commons.apache.org/primitives/
Piotr Kobzda - 07 Oct 2007 23:37 GMT
>>> Sure, and while your at it, suggest that List<Integer>.toArray(new
>> However, using proposed boxing utilities it's not hard to achieve what
[quoted text clipped - 5 lines]
>
> http://commons.apache.org/primitives/

Well, I know that library, but never had need to use it -- most of my
typical needs are covered in my proposition.

There are also important differences between the library, and my
proposal.  Key differences includes: 1) the library classes are not
"generified"; 2) Lists offered by library do not supports backing by a
_given_ array; 3) that's much bigger library than a simple few methods
we have here.

My proposal is just an extension for bunch of utility methods already
defined in java.util.Arrays.  In addition to asList(), which just
box/unbox each access to the list elements (nothing revealing of
course), it adds a few simple boxing utilities (a bit advanced stuff in
implementation, but not mystic also), that's all.  BTW -- even being
such simple, there is functionality of boxing multidimensional arrays,
which is not offered by Commons Primitives, nor any other library I know.

The proposal was originally designed as possible addition to already
defined methods in java.util.Arrays in mind.  As a side effect, having
it all in Arrays might likely safe from accidental uses of asList(T...)
with primitive array passed to it.

Of course, those interested in more advanced functionality, that the
Commons Primitives library offer (primitive iterators, elements
removal/addition, etc.), may still use it when needed.

To sum it up a bit, I think it would be nice to have it all at hand in
standard Java library.  Of course, if anybody else (but Daniel, and me)
likes it as well. :-)

piotr
Stefan Ram - 08 Oct 2007 00:02 GMT
>My proposal is just an extension for bunch of utility methods already

 Your proposal uses Java like a preprocessor
 (to generate Java code).

 In fact, I am using a preprocessor to generate
 my Java code - sometimes also to abstract primitive
 types.

 For example, this is code to finde the middle value
 of two number from the library »ram.jar«:

public INTEGRAL_TYPE INTEGRAL_TYPE()'#floor middle'()
{ /* The calculation tries to avoid overflows, which
 might cause unwanted changes of sign and consequent
 errors in the calculation.
 Based on code by Peter Luschny. */
 final INTEGRAL_TYPE $result;
 result = INTEGRAL_TYPE_CAST
 ( ( this.number0 >> 1 )+( this.number1 >> 1 )+
   ( this.number0 & this.number1 & 1 ));
 return $result; }

 When the definitions are set for »int«, my preprocessor will
 generate the following from the above:

public int intFloorMiddle()
{ /* The calculation tries to avoid overflows, which
 might cause unwanted changes of sign and consequent
 errors in the calculation.
 Based on code by Peter Luschny. */
 final int result;
 result =
 ( ( this.number0 >> 1 )+( this.number1 >> 1 )+
   ( this.number0 & this.number1 & 1 ));
 return result; }

 For the web page

http://www.purl.org/stefan_ram/java/de/dclj/ram/type/pair/PairOfIntAndInt.java

 , this is automatically reformatted to use the common bracing
 and spacing style:

 public int intFloorMiddle() { /* The calculation tries to avoid overflows, which
  might cause unwanted changes of sign and consequent
  errors in the calculation.
  Based on code by Peter Luschny. */
   final int result;

   result = ((this.number0 >> 1) + (this.number1 >> 1) + (this.number0 & this.number1 & 1));
   return result;
 }
Piotr Kobzda - 08 Oct 2007 10:11 GMT
>   Your proposal uses Java like a preprocessor
>   (to generate Java code).

Yes.  And it was quite easy to write it to me.

The development of this code generator was supported by the following
simple Java tool:

public class CodePrintOutputter {
  public static void main(String[] args) {
    java.util.Scanner s = new java.util.Scanner(System.in);
    while(true) {
      String line = s.nextLine();
      if (line.trim().length() > 0) {
        line = line
            .replace("\\", "\\\\")
            .replace("\"", "\\\"");
        System.out.println("out.println(\""+ line +"\");");
      } else {
        System.out.println("out.println();");
      }
    }
  }
}

That way, my original code used to create the generator is fully
functional class, which just supports one primitive type (guess which
one? ;) ).  I'm able to experiment with that code, test it, choose from
alternatives, etc. directly from the IDE.  The final phase is almost
copying & pasting of the original code into the generator's code.  That
approach is usually easier to follow, then development based on some
proprietary preprocessor's language to me.

Ideally would be to have some standard preprocessor which works on
syntactically correct Java.  Preprocessor able to regenerate somehow a
given source.  Something similar to C preprocessor, but utilizing
annotations, comments, and possibly other Java features.  Anybody knows
such kind of Java preprocessor?

>   In fact, I am using a preprocessor to generate
>   my Java code - sometimes also to abstract primitive
>   types.

There are a lot of templating engines able to support it also.  But I'm
not sure that using one of them for demonstrating both, a concept, and
fully functional implementation would be better than simply give a Java
generator which everybody is able to run without any extra effort.

But thanks Stefan for mentioning your preprocessor, next time I'll need
to generate the code I'll likely take a closer look at it.

By the way...

>   For example, this is code to finde the middle value
>   of two number from the library »ram.jar«:

[...]

>     result = ((this.number0 >> 1) + (this.number1 >> 1) + (this.number0 & this.number1 & 1));
>     return result;
>   }

What about using possibly a bit faster approach here:

   result = ((this.number0 ^ this.number1) >> 1) + (this.number0 &
this.number1);

?

piotr


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.