| 1782 | } |
| 1783 | |
| 1784 | Clay_LayoutElementHashMapItem* Clay__AddHashMapItem(Clay_ElementId elementId, Clay_LayoutElement* layoutElement) { |
| 1785 | Clay_Context* context = Clay_GetCurrentContext(); |
| 1786 | if (context->layoutElementsHashMapInternal.length == context->layoutElementsHashMapInternal.capacity - 1) { |
| 1787 | if (!context->booleanWarnings.hashMapCapacityExceeded) { |
| 1788 | context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { |
| 1789 | .errorType = CLAY_ERROR_TYPE_HASH_MAP_CAPACITY_EXCEEDED, |
| 1790 | .errorText = CLAY_STRING("Clay has run out of space in it's internal element ID hashmap. Try using Clay_SetMaxElementCount() with a higher value."), |
| 1791 | .userData = context->errorHandler.userData }); |
| 1792 | context->booleanWarnings.hashMapCapacityExceeded = true; |
| 1793 | } |
| 1794 | return NULL; |
| 1795 | } |
| 1796 | Clay_LayoutElementHashMapItem item = { .elementId = elementId, .layoutElement = layoutElement, .nextIndex = -1, .generation = context->generation + 1, .appearedThisFrame = true }; |
| 1797 | uint32_t hashBucket = elementId.id % context->layoutElementsHashMap.capacity; |
| 1798 | int32_t hashItemPrevious = -1; |
| 1799 | int32_t hashItemIndex = context->layoutElementsHashMap.internalArray[hashBucket]; |
| 1800 | while (hashItemIndex != -1) { // Just replace collision, not a big deal - leave it up to the end user |
| 1801 | Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Get(&context->layoutElementsHashMapInternal, hashItemIndex); |
| 1802 | if (hashItem->elementId.id == elementId.id) { // Collision - resolve based on generation |
| 1803 | item.nextIndex = hashItem->nextIndex; |
| 1804 | if (hashItem->generation <= context->generation) { // First collision - assume this is the "same" element |
| 1805 | hashItem->appearedThisFrame = hashItem->generation < context->generation; |
| 1806 | hashItem->elementId = elementId; // Make sure to copy this across. If the stringId reference has changed, we should update the hash item to use the new one. |
| 1807 | hashItem->generation = context->generation + 1; |
| 1808 | hashItem->layoutElement = layoutElement; |
| 1809 | hashItem->debugData.collision = false; |
| 1810 | hashItem->onHoverFunction = NULL; |
| 1811 | hashItem->hoverFunctionUserData = 0; |
| 1812 | } else { // Multiple collisions this frame - two elements have the same ID |
| 1813 | context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { |
| 1814 | .errorType = CLAY_ERROR_TYPE_DUPLICATE_ID, |
| 1815 | .errorText = CLAY_STRING("An element with this ID was already previously declared during this layout."), |
| 1816 | .userData = context->errorHandler.userData }); |
| 1817 | if (context->debugModeEnabled) { |
| 1818 | hashItem->debugData.collision = true; |
| 1819 | } |
| 1820 | } |
| 1821 | return hashItem; |
| 1822 | } |
| 1823 | hashItemPrevious = hashItemIndex; |
| 1824 | hashItemIndex = hashItem->nextIndex; |
| 1825 | } |
| 1826 | |
| 1827 | int32_t indexToUse = 0; |
| 1828 | if (context->layoutElementsHashMapFreeList.length > 0) { |
| 1829 | indexToUse = Clay__int32_tArray_GetValue(&context->layoutElementsHashMapFreeList, context->layoutElementsHashMapFreeList.length - 1); |
| 1830 | context->layoutElementsHashMapFreeList.length--; |
| 1831 | } else { |
| 1832 | indexToUse = context->layoutElementsHashMapInternal.length; |
| 1833 | } |
| 1834 | Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Set(&context->layoutElementsHashMapInternal, indexToUse, item); |
| 1835 | if (hashItemPrevious != -1) { |
| 1836 | Clay__LayoutElementHashMapItemArray_Get(&context->layoutElementsHashMapInternal, hashItemPrevious)->nextIndex = (int32_t)indexToUse; |
| 1837 | } else { |
| 1838 | context->layoutElementsHashMap.internalArray[hashBucket] = (int32_t)indexToUse; |
| 1839 | } |
| 1840 | return hashItem; |
| 1841 | } |
no test coverage detected