/** * Load a set of glyphs from a delimited reader, using the provided shaper and valuer. * * <p>This method creates concrete geometry, though it uses the implicit geometry system to * achieve it. * * @param glyphs Glyphset to load items into * @param reader Source of the glyph data * @param converter Convert read entries to indexed entries * @param shaper Convert the read item into a shape * @param valuer Convert the read item into a value * @return The glyphset passed in as a parameter (now with more glyphs) */ public static <G, I> Glyphset<G, I> load( Glyphset<G, I> glyphs, DelimitedReader reader, Indexed.Converter converter, Shaper<Indexed, G> shaper, Valuer<Indexed, I> valuer) { int count = 0; Method m; try { m = glyphs.getClass().getMethod("add", Glyph.class); } catch (NoSuchMethodException | SecurityException e1) { throw new IllegalArgumentException("Cannot access 'add' on the passed glypshet.", e1); } m.setAccessible( true); // Suppress java access checking. Allows access to (for example) public methods of // private classes while (reader.hasNext()) { String[] parts = reader.next(); if (parts == null) { continue; } Converter item = converter.applyTo(parts); I value = valuer.value(item); G shape = shaper.shape(item); Glyph<G, I> g = new SimpleGlyph<G, I>(shape, value); try { m.invoke(glyphs, g); } catch (Exception e) { throw new RuntimeException("Error loading item number " + count, e); } count++; } // The check below causes an issue if memory is tight...the check has a non-trivial overhead on // some glyphset types if (count != glyphs.size()) { throw new RuntimeException( String.format( "Error loading data; Read and retained glyph counts don't match (%s read vs %s retained).", count, glyphs.size())); } return glyphs; }