I made this class because i was bored, curious and tired, now i have no idea why it exists or what it means, so it must be art. In theory it can store more than 1 character per byte without any actual compression taking place. Code (Java): import java.util.Arrays; import java.util.TreeSet; import static terranova.util.MathUtils.*; /** Does stuff related to growing strings from seeds. Why did i waste precious minutes of my life creating this horror. */ public class StringGarden { private int len; private char[] charset; public byte[] grow(String in) { char[] ch = in.toCharArray(); int wchar=1; TreeSet<Character> cs = new TreeSet<>(); // because trees grow, right? for(char c : ch) { if(c > 256) wchar=2; cs.add(c); } int perm = (int)(0xFFFFFFFFL/64); // maximum permutations must be within 1/64th of the value range of an integer, adjusting this changes compression vs speed+reliability Character[] cst = cs.toArray(new Character[cs.size()]); charset = new char[cs.size()]; for(int n=0;n<cs.size();++n) charset[n]=cst[n]; len=0; int p=0; while(++len<in.length()) if(Math.pow(charset.length,len)>perm) { --len; break; } System.out.println("len "+Integer.toString(len)+", perm: "+Integer.toString((int) Math.pow(charset.length,len))); int[] sections = new int[ceil((double)in.length()/len)]; for(int n=0,i=-1; n<sections.length; ++n) { int ofs=n*len+len; sections[++i]=getSeed(Arrays.copyOfRange(ch,n*len,ofs>ch.length?ch.length:ofs)); } System.out.println(decode(sections,in.length(),len)); // ByteBuffer-lite, expands in set increments like a Vector and keeps track of filled space AutoByteArray out = new AutoByteArray(charset.length*wchar+sections.length*4+4,1); out.add(shortToBytes((short)charset.length)); // charset length out.add(len); // add length of each section for(int n=0;n<charset.length;++n) out.add(shortToBytes((short)charset[n])); // nobody cares about supplemental range right now, or at least i dont. out.add(shortToBytes((short)sections.length)); for(int n=0; n<sections.length;++n) out.add(intToBytes(sections[n])); return out.getFilled(); } // add methods for creating an environment with multiple strings private String decode(int[] sections, int length, int sectionlength) { StringBuilder s = new StringBuilder(length); for(int n=0,i=0; n<sections.length; ++n) { i+=sectionlength; if(length-i<0) s.append(decode(sections[n],sectionlength+(length-i))); else s.append(decode(sections[n],sectionlength)); } return s.toString(); } private String decode(int i, int ln) { char[] c = new char[ln]; XorshiftRandom r = new XorshiftRandom(); r.setSeed(i); for(int n=0;n<ln;++n) c[n]=charset[(r.nextInt()&0x7FFFFFFF)%charset.length]; return new String(c); } private int getSeed(char[] c) { XorshiftRandom r = new XorshiftRandom(); for(int n=Integer.MIN_VALUE;n<Integer.MAX_VALUE;++n) { boolean m=true; r.setSeed(n); for(int i=0;i<c.length;++i) if(charset[(r.nextInt()&0x7FFFFFFF)%charset.length]!=c[i]) m=false; if(m) return n; } return 0; } } Incidentally it does not really do anything, and definitely cannot decode the returned value yet, although it would be fairly easy.