This finishes one serialized object by generating the vtable if it's a table, comparing it against existing vtables, and writing the resulting vtable offset.
| 1516 | // table, comparing it against existing vtables, and writing the |
| 1517 | // resulting vtable offset. |
| 1518 | uoffset_t EndTable(uoffset_t start) { |
| 1519 | // If you get this assert, a corresponding StartTable wasn't called. |
| 1520 | FLATBUFFERS_ASSERT(nested); |
| 1521 | // Write the vtable offset, which is the start of any Table. |
| 1522 | // We fill it's value later. |
| 1523 | auto vtableoffsetloc = PushElement<soffset_t>(0); |
| 1524 | // Write a vtable, which consists entirely of voffset_t elements. |
| 1525 | // It starts with the number of offsets, followed by a type id, followed |
| 1526 | // by the offsets themselves. In reverse: |
| 1527 | // Include space for the last offset and ensure empty tables have a |
| 1528 | // minimum size. |
| 1529 | max_voffset_ = |
| 1530 | (std::max)(static_cast<voffset_t>(max_voffset_ + sizeof(voffset_t)), |
| 1531 | FieldIndexToOffset(0)); |
| 1532 | buf_.fill_big(max_voffset_); |
| 1533 | auto table_object_size = vtableoffsetloc - start; |
| 1534 | // Vtable use 16bit offsets. |
| 1535 | FLATBUFFERS_ASSERT(table_object_size < 0x10000); |
| 1536 | WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t), |
| 1537 | static_cast<voffset_t>(table_object_size)); |
| 1538 | WriteScalar<voffset_t>(buf_.data(), max_voffset_); |
| 1539 | // Write the offsets into the table |
| 1540 | for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc); |
| 1541 | it < buf_.scratch_end(); it += sizeof(FieldLoc)) { |
| 1542 | auto field_location = reinterpret_cast<FieldLoc *>(it); |
| 1543 | auto pos = static_cast<voffset_t>(vtableoffsetloc - field_location->off); |
| 1544 | // If this asserts, it means you've set a field twice. |
| 1545 | FLATBUFFERS_ASSERT( |
| 1546 | !ReadScalar<voffset_t>(buf_.data() + field_location->id)); |
| 1547 | WriteScalar<voffset_t>(buf_.data() + field_location->id, pos); |
| 1548 | } |
| 1549 | ClearOffsets(); |
| 1550 | auto vt1 = reinterpret_cast<voffset_t *>(buf_.data()); |
| 1551 | auto vt1_size = ReadScalar<voffset_t>(vt1); |
| 1552 | auto vt_use = GetSize(); |
| 1553 | // See if we already have generated a vtable with this exact same |
| 1554 | // layout before. If so, make it point to the old one, remove this one. |
| 1555 | if (dedup_vtables_) { |
| 1556 | for (auto it = buf_.scratch_data(); it < buf_.scratch_end(); |
| 1557 | it += sizeof(uoffset_t)) { |
| 1558 | auto vt_offset_ptr = reinterpret_cast<uoffset_t *>(it); |
| 1559 | auto vt2 = reinterpret_cast<voffset_t *>(buf_.data_at(*vt_offset_ptr)); |
| 1560 | auto vt2_size = ReadScalar<voffset_t>(vt2); |
| 1561 | if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue; |
| 1562 | vt_use = *vt_offset_ptr; |
| 1563 | buf_.pop(GetSize() - vtableoffsetloc); |
| 1564 | break; |
| 1565 | } |
| 1566 | } |
| 1567 | // If this is a new vtable, remember it. |
| 1568 | if (vt_use == GetSize()) { buf_.scratch_push_small(vt_use); } |
| 1569 | // Fill the vtable offset we created above. |
| 1570 | // The offset points from the beginning of the object to where the |
| 1571 | // vtable is stored. |
| 1572 | // Offsets default direction is downward in memory for future format |
| 1573 | // flexibility (storing all vtables at the start of the file). |
| 1574 | WriteScalar(buf_.data_at(vtableoffsetloc), |
| 1575 | static_cast<soffset_t>(vt_use) - |
nothing calls this directly
no test coverage detected