HollowObjectTypeDataElements join(HollowObjectTypeDataElements[] from) {
        final int fromMask = from.length - 1;
        final int fromOrdinalShift = 31 - Integer.numberOfLeadingZeros(from.length);
        long[] currentWriteVarLengthDataPointers;

        if (from.length<=0 || !((from.length&(from.length-1))==0)) {
            throw new IllegalStateException("No. of DataElements to be joined must be a power of 2");
        }

        HollowObjectTypeDataElements to = new HollowObjectTypeDataElements(from[0].schema, from[0].memoryMode, from[0].memoryRecycler);
        currentWriteVarLengthDataPointers = new long[from[0].schema.numFields()];

        populateStats(to, from);

        GapEncodedVariableLengthIntegerReader[] fromRemovals = new GapEncodedVariableLengthIntegerReader[from.length];
        for (int i=0;i<from.length;i++) {
            fromRemovals[i] = from[i].encodedRemovals;
        }
        to.encodedRemovals = GapEncodedVariableLengthIntegerReader.join(fromRemovals);

        for (HollowObjectTypeDataElements elements : from) {
            if (elements.encodedAdditions != null) {
                throw new IllegalStateException("Encountered encodedAdditions in data elements joiner- this is not expected " +
                        "since encodedAdditions only exist on delta data elements and they dont carry over to target data elements, " +
                        "delta data elements are never split/joined");
            }
        }

        for(int ordinal=0;ordinal<=to.maxOrdinal;ordinal++) {
            int fromIndex = ordinal & fromMask;
            int fromOrdinal = ordinal >> fromOrdinalShift;

            if (fromOrdinal <= from[fromIndex].maxOrdinal) {
                copyRecord(to, ordinal, from[fromIndex], fromOrdinal, currentWriteVarLengthDataPointers);
            } else {
                // lopsided shards could result for consumers that skip type shards with no additions
                writeNullRecord(to, ordinal, currentWriteVarLengthDataPointers);
            }
        }

        return to;
    }
@Test
    public void testJoinDifferentFieldWidths() throws IOException {
        HollowObjectTypeDataElementsJoiner joiner = new HollowObjectTypeDataElementsJoiner();

        HollowObjectTypeReadState typeReadStateSmall = populateTypeStateWith(new int[] {1});
        assertEquals(1, typeReadStateSmall.numShards());
        HollowObjectTypeDataElements dataElementsSmall = typeReadStateSmall.currentDataElements()[0];
        int intFieldPosSmall = dataElementsSmall.schema.getPosition("intField");
        int widthSmall = dataElementsSmall.bitsPerField[intFieldPosSmall];
        long valSmall = dataElementsSmall.fixedLengthData.getElementValue(dataElementsSmall.bitOffsetPerField[intFieldPosSmall], widthSmall);

        HollowObjectTypeReadState typeReadStateBig = populateTypeStateWith(new int[] {2});
        assertEquals(1, typeReadStateBig.numShards());
        HollowObjectTypeDataElements dataElementsBig = typeReadStateBig.currentDataElements()[0];
        int intFieldPosBig = dataElementsBig.schema.getPosition("intField");
        int widthBig = dataElementsBig.bitsPerField[intFieldPosBig];
        long valBig = dataElementsBig.fixedLengthData.getElementValue(dataElementsBig.bitOffsetPerField[intFieldPosBig], widthBig);

        assertTrue(widthBig > widthSmall);

        HollowObjectTypeDataElements dataElementsJoined = joiner.join(new HollowObjectTypeDataElements[]
                {dataElementsSmall, dataElementsBig});
        int intFieldPosJoined = dataElementsJoined.schema.getPosition("intField");
        int widthJoined = dataElementsJoined.bitsPerField[intFieldPosJoined];

        long val0 = dataElementsJoined.fixedLengthData.getElementValue(dataElementsJoined.bitOffsetPerField[intFieldPosJoined], widthJoined);
        long val1 = dataElementsJoined.fixedLengthData.getElementValue(dataElementsJoined.bitsPerRecord + dataElementsJoined.bitOffsetPerField[intFieldPosJoined], widthJoined);

        assertEquals(widthBig, widthJoined);
        assertEquals(valSmall, val0);
        assertEquals(valBig, val1);
    }