@Override public <T> Path.Entry<T> get(ID eid, Content.Type<T> ct) throws IOException { updateContents(); ID tid = id.append(eid.get(0)); int idx = binarySearch(contents, nentries, tid); if (idx >= 0) { // At this point, we've found a matching index for the given ID. // However, there maybe multiple matching IDs with different // content types. Therefore, we need to check them all to see if // they match the requested entry. Path.Item item = contents[idx]; do { if (item instanceof Entry && eid.size() == 1) { // In this case, we're looking for and have found an exact // item. Entry entry = (Entry) item; if (entry.contentType() == ct) { return entry; } } else if (item instanceof Path.Folder && eid.size() > 1) { // In this case, the ID is indicates the item is not // contained in this folder. Path.Folder folder = (Path.Folder) item; return folder.get(eid.subpath(1, eid.size()), ct); } } while (++idx < nentries && (item = contents[idx]).id().equals(tid)); } // no dice return null; }
@Override public boolean contains(Path.Entry<?> e) throws IOException { updateContents(); Path.ID eid = e.id(); boolean contained; if (id == eid.parent()) { // The requested entry is contained in this folder. Therefore, we // need to search for it. contained = true; } else if (id == eid.subpath(0, id.size())) { // This folder is a parent of the requested entry. Therefore, we // need to looking for a matching folder entry. If we find one, then // we ask it for the requested entry. eid = eid.subpath(0, id.size() + 1); contained = false; } else { return false; } int idx = binarySearch(contents, nentries, eid); if (idx >= 0) { // At this point, we've found a matching index for the given ID. // However, there maybe multiple matching IDs (e.g. with different // content types). Therefore, we need to check them all to see if // they match the requested entry. Path.Item item = contents[idx]; do { if (item == e) { return true; } else if (!contained && item instanceof Path.Folder) { Path.Folder folder = (Path.Folder) item; return folder.contains(e); } } while (++idx < nentries && (item = contents[idx]).id().equals(eid)); } // no dice return false; }
@Override public <T> void getAll(Content.Filter<T> filter, Set<Path.ID> entries) throws IOException { updateContents(); // It would be nice to further optimise this loop. The key issue is that, // at some point, we might know the filter could never match. In which // case, we want to stop the recursion early, rather than exploring a // potentially largel subtree. for (int i = 0; i != nentries; ++i) { Path.Item item = contents[i]; if (item instanceof Entry) { Entry entry = (Entry) item; if (filter.matches(entry.id(), entry.contentType())) { entries.add(entry.id()); } } else if (item instanceof Path.Folder && filter.matchesSubpath(item.id())) { Path.Folder folder = (Path.Folder) item; folder.getAll(filter, entries); } } }
@Override public List<Entry<?>> getAll() throws IOException { ArrayList entries = new ArrayList(); updateContents(); // It would be nice to further optimise this loop. Basically, to avoid // creating so many ArrayList objects. However, it's tricky to get right // given Java's generic type system. for (int i = 0; i != nentries; ++i) { Path.Item item = contents[i]; if (item instanceof Entry) { Entry entry = (Entry) item; entries.add(entry); } else if (item instanceof Path.Folder) { Path.Folder folder = (Path.Folder) item; entries.addAll(folder.getAll()); } } return entries; }