@@ -1531,5 +1531,315 @@ public void mixingLegacyOwner_newType_insideGenericClassMethod() {
15311531 );
15321532 }
15331533
1534+ @ Test
1535+ public void arrayListInClosure () {
1536+ testAssertOkLinesWithStdLib (true ,
1537+ "package Hello" ,
1538+ "import NoWurst" ,
1539+ "import Integer" ,
1540+ "import Printing" ,
1541+ "" ,
1542+ "native testSuccess()" ,
1543+ "" ,
1544+ "public class ArrayList<T:>" ,
1545+ " private static T array store" ,
1546+ " private static int nextFreeIndex = 0" ,
1547+ "" ,
1548+ " // Memory management structures" ,
1549+ " private static constant int MAX_FREE_SECTIONS = 256" ,
1550+ " private static int array freeSectionStart" ,
1551+ " private static int array freeSectionCapacity" ,
1552+ " private static int freeSectionCount = 0" ,
1553+ "" ,
1554+ " private int startIndex" ,
1555+ " private int capacity" ,
1556+ " private int size = 0" ,
1557+ " private static constant int INITIAL_CAPACITY = 16" ,
1558+ "" ,
1559+ " static function getNextFreeIndex() returns int" ,
1560+ " return nextFreeIndex" ,
1561+ "" ,
1562+ " /** Creates a new empty list with default capacity (16) */" ,
1563+ " construct()" ,
1564+ " allocateStorage(INITIAL_CAPACITY)" ,
1565+ "" ,
1566+ " /** Creates a new list with specified initial capacity - RECOMMENDED for performance */" ,
1567+ " construct(int initialCapacity)" ,
1568+ " allocateStorage(initialCapacity)" ,
1569+ "" ,
1570+ " /** Allocates storage section - tries to reuse freed sections first */" ,
1571+ " private function allocateStorage(int cap)" ,
1572+ " // Try to find a freed section that fits" ,
1573+ " for i = 0 to freeSectionCount - 1" ,
1574+ " if freeSectionCapacity[i] >= cap" ,
1575+ " startIndex = freeSectionStart[i]" ,
1576+ " capacity = freeSectionCapacity[i]" ,
1577+ "" ,
1578+ " // Remove this section from free list" ,
1579+ " for j = i to freeSectionCount - 2" ,
1580+ " freeSectionStart[j] = freeSectionStart[j + 1]" ,
1581+ " freeSectionCapacity[j] = freeSectionCapacity[j + 1]" ,
1582+ " freeSectionCount--" ,
1583+ " return" ,
1584+ "" ,
1585+ " // No suitable free section, allocate new" ,
1586+ " if nextFreeIndex + cap > JASS_MAX_ARRAY_SIZE" ,
1587+ " // Try to compact free sections" ,
1588+ " compactFreeList()" ,
1589+ "" ,
1590+ " if nextFreeIndex + cap > JASS_MAX_ARRAY_SIZE" ,
1591+ " // Still not enough, wrap around (dangerous!)" ,
1592+ " print(\" ArrayList: WARNING - Memory store exhausted, wrapping around!\" )" ,
1593+ " nextFreeIndex = 0" ,
1594+ "" ,
1595+ " startIndex = nextFreeIndex" ,
1596+ " capacity = cap" ,
1597+ " nextFreeIndex += cap" ,
1598+ "" ,
1599+ " /** Compacts the free list by merging adjacent sections */" ,
1600+ " private static function compactFreeList()" ,
1601+ " if freeSectionCount <= 1" ,
1602+ " return" ,
1603+ "" ,
1604+ " // Sort free sections by start index using insertion sort" ,
1605+ " for i = 1 to freeSectionCount - 1" ,
1606+ " let keyStart = freeSectionStart[i]" ,
1607+ " let keyCap = freeSectionCapacity[i]" ,
1608+ " var j = i - 1" ,
1609+ "" ,
1610+ " while j >= 0 and freeSectionStart[j] > keyStart" ,
1611+ " freeSectionStart[j + 1] = freeSectionStart[j]" ,
1612+ " freeSectionCapacity[j + 1] = freeSectionCapacity[j]" ,
1613+ " j--" ,
1614+ "" ,
1615+ " freeSectionStart[j + 1] = keyStart" ,
1616+ " freeSectionCapacity[j + 1] = keyCap" ,
1617+ "" ,
1618+ " // Merge adjacent sections" ,
1619+ " var writeIdx = 0" ,
1620+ " for readIdx = 0 to freeSectionCount - 1" ,
1621+ " if writeIdx > 0 and freeSectionStart[writeIdx - 1] + freeSectionCapacity[writeIdx - 1] == freeSectionStart[readIdx]" ,
1622+ " // Merge with previous" ,
1623+ " freeSectionCapacity[writeIdx - 1] += freeSectionCapacity[readIdx]" ,
1624+ " else" ,
1625+ " // Keep as separate section" ,
1626+ " if writeIdx != readIdx" ,
1627+ " freeSectionStart[writeIdx] = freeSectionStart[readIdx]" ,
1628+ " freeSectionCapacity[writeIdx] = freeSectionCapacity[readIdx]" ,
1629+ " writeIdx++" ,
1630+ "" ,
1631+ " freeSectionCount = writeIdx" ,
1632+ "" ,
1633+ " // Update nextFreeIndex if last section extends to it" ,
1634+ " if freeSectionCount > 0" ,
1635+ " let lastIdx = freeSectionCount - 1" ,
1636+ " if freeSectionStart[lastIdx] + freeSectionCapacity[lastIdx] == nextFreeIndex" ,
1637+ " nextFreeIndex = freeSectionStart[lastIdx]" ,
1638+ " freeSectionCount--" ,
1639+ "" ,
1640+ " /** Frees this list's storage section for reuse */" ,
1641+ " private function freeStorage()" ,
1642+ " if capacity <= 0" ,
1643+ " return" ,
1644+ "" ,
1645+ " // Add to free list if there's space" ,
1646+ " if freeSectionCount < MAX_FREE_SECTIONS" ,
1647+ " freeSectionStart[freeSectionCount] = startIndex" ,
1648+ " freeSectionCapacity[freeSectionCount] = capacity" ,
1649+ " freeSectionCount++" ,
1650+ "" ,
1651+ " // If this was at the end, we can reclaim it immediately" ,
1652+ " if startIndex + capacity == nextFreeIndex" ,
1653+ " nextFreeIndex = startIndex" ,
1654+ " freeSectionCount--" ,
1655+ " else" ,
1656+ " // Free list full, try to compact" ,
1657+ " compactFreeList()" ,
1658+ "" ,
1659+ " // Try again after compaction" ,
1660+ " if freeSectionCount < MAX_FREE_SECTIONS" ,
1661+ " freeSectionStart[freeSectionCount] = startIndex" ,
1662+ " freeSectionCapacity[freeSectionCount] = capacity" ,
1663+ " freeSectionCount++" ,
1664+ "" ,
1665+ " /** Grows the capacity (doubles it) - EXPENSIVE OPERATION! */" ,
1666+ " private function grow()" ,
1667+ " let newCapacity = capacity * 2" ,
1668+ " let oldStart = startIndex" ,
1669+ " let oldCapacity = capacity" ,
1670+ "" ,
1671+ " // Try to allocate new section" ,
1672+ " allocateStorage(newCapacity)" ,
1673+ "" ,
1674+ " // Copy elements to new location" ,
1675+ " for i = 0 to size - 1" ,
1676+ " store[startIndex + i] = store[oldStart + i]" ,
1677+ "" ,
1678+ " // Free old section" ,
1679+ " let tempStart = startIndex" ,
1680+ " let tempCap = capacity" ,
1681+ " startIndex = oldStart" ,
1682+ " capacity = oldCapacity" ,
1683+ " freeStorage()" ,
1684+ " startIndex = tempStart" ,
1685+ " capacity = tempCap" ,
1686+ "" ,
1687+ " ondestroy" ,
1688+ " // Clear references to allow garbage collection" ,
1689+ " for i = 0 to size - 1" ,
1690+ " store[startIndex + i] = null" ,
1691+ "" ,
1692+ " // Return storage to free pool" ,
1693+ " freeStorage()" ,
1694+ "" ,
1695+ " /** Debug function to get memory layout info */" ,
1696+ " function getMemoryInfo() returns string" ,
1697+ " return \" Start: \" + startIndex.toString() + \" , Capacity: \" + capacity.toString() + \" , Size: \" + size.toString()" ,
1698+ "" ,
1699+ " /** Static function to get global memory state */" ,
1700+ " static function getGlobalMemoryInfo() returns string" ,
1701+ " return \" NextFree: \" + nextFreeIndex.toString() + \" , FreeSections: \" + freeSectionCount.toString() + \" , Used: \" + (nextFreeIndex - freeSectionCount).toString()" ,
1702+ "" ,
1703+ " // ============================================================================" ,
1704+ " // BASIC OPERATIONS" ,
1705+ " // ============================================================================" ,
1706+ "" ,
1707+ " /** Adds one or more elements to the end of the list (amortized O(1)) */" ,
1708+ " function add(vararg T elems)" ,
1709+ " for elem in elems" ,
1710+ " if size >= capacity" ,
1711+ " grow()" ,
1712+ " store[startIndex + size] = elem" ,
1713+ " size++" ,
1714+ "" ,
1715+ " /** Returns the element at the specified index (O(1)) */" ,
1716+ " function get(int index) returns T" ,
1717+ " if index < 0 or index >= size" ,
1718+ " print(\" ArrayList: Index out of bounds: \" + index.toString())" ,
1719+ " return store[startIndex + index]" ,
1720+ "" ,
1721+ " /** Sets the element at the specified index (O(1)) */" ,
1722+ " function set(int index, T elem)" ,
1723+ " if index < 0 or index >= size" ,
1724+ " print(\" ArrayList: Index out of bounds: \" + index.toString())" ,
1725+ " store[startIndex + index] = elem" ,
1726+ "" ,
1727+ " /** Returns the index of the specified element or -1 if it doesn't exist (O(n)) */" ,
1728+ " function indexOf(T elem) returns int" ,
1729+ " for i = 0 to size - 1" ,
1730+ " if store[startIndex + i] == elem" ,
1731+ " return i" ,
1732+ " return -1" ,
1733+ "" ,
1734+ " /** Returns whether the list contains the specified element (O(n)) */" ,
1735+ " function has(T elem) returns boolean" ,
1736+ " return indexOf(elem) >= 0" ,
1737+ "" ,
1738+ " /** Removes the element at the given index and returns it (O(n) - shifts elements) */" ,
1739+ " function removeAt(int index) returns T" ,
1740+ " if index < 0 or index >= size" ,
1741+ " print(\" ArrayList: Index out of bounds: \" + index.toString())" ,
1742+ "" ,
1743+ " let elem = store[startIndex + index]" ,
1744+ "" ,
1745+ " // Shift elements left" ,
1746+ " for i = index to size - 2" ,
1747+ " store[startIndex + i] = store[startIndex + i + 1]" ,
1748+ "" ,
1749+ " size--" ,
1750+ " return elem" ,
1751+ "" ,
1752+ " /** Removes the element at the given index by swapping with last element (O(1) - DOES NOT PRESERVE ORDER!) */" ,
1753+ " function removeSwap(int index) returns T" ,
1754+ " if index < 0 or index >= size" ,
1755+ " print(\" ArrayList: Index out of bounds: \" + index.toString())" ,
1756+ "" ,
1757+ " let elem = store[startIndex + index]" ,
1758+ "" ,
1759+ " // Replace with last element" ,
1760+ " size--" ,
1761+ " if index < size" ,
1762+ " store[startIndex + index] = store[startIndex + size]" ,
1763+ "" ,
1764+ " return elem" ,
1765+ "" ,
1766+ " /** Removes the first occurrence of the element from the list (O(n)) */" ,
1767+ " function remove(T elem) returns bool" ,
1768+ " let index = indexOf(elem)" ,
1769+ " if index >= 0" ,
1770+ " removeAt(index)" ,
1771+ " return true" ,
1772+ " return false" ,
1773+ "" ,
1774+ " /** Returns the size of the list (O(1)) */" ,
1775+ " function size() returns int" ,
1776+ " return size" ,
1777+ "" ,
1778+ " /** Checks whether this list is empty (O(1)) */" ,
1779+ " function isEmpty() returns boolean" ,
1780+ " return size == 0" ,
1781+ "" ,
1782+ "" ,
1783+ "public function lazy<T:>(Lazy<T> l) returns Lazy<T>" ,
1784+ " return l" ,
1785+ "" ,
1786+ "public abstract class Lazy<T:>" ,
1787+ " T val = null" ,
1788+ " var wasRetrieved = false" ,
1789+ "" ,
1790+ " abstract function retrieve() returns T" ,
1791+ "" ,
1792+ " function get() returns T" ,
1793+ " if not wasRetrieved" ,
1794+ " val = retrieve()" ,
1795+ " wasRetrieved = true" ,
1796+ " return val" ,
1797+ "" ,
1798+ "public class CFBuilding" ,
1799+ " CFBuilding precursor = null" ,
1800+ " ArrayList<CFBuilding> upgrades = null" ,
1801+ "" ,
1802+ " Lazy<boolean> hasAAUpgrade = lazy<boolean>(() -> begin" ,
1803+ " var result = false" ,
1804+ " if upgrades != null" ,
1805+ " result = true" ,
1806+ " // perform iterative search through \" tree\" " ,
1807+ " var toCheck = new ArrayList<CFBuilding>()" ,
1808+ " // toCheck.addAll(upgrades)" ,
1809+ " while not toCheck.isEmpty()" ,
1810+ " let b = toCheck.removeAt(0)" ,
1811+ " if b.isAntiAir" ,
1812+ " result = true" ,
1813+ " break" ,
1814+ " if b.upgrades != null" ,
1815+ " // toCheck.addAll(b.upgrades)" ,
1816+ "" ,
1817+ " destroy toCheck" ,
1818+ " return result" ,
1819+ " end)" ,
1820+ "" ,
1821+ " var netWorthDiv100 = lazy<real>(() -> begin" ,
1822+ " var worth = 0" ,
1823+ " var cur = this" ,
1824+ " while cur != null" ,
1825+ " worth += cur.goldCost" ,
1826+ " cur = cur.precursor" ,
1827+ " return worth / 200." ,
1828+ " end)" ,
1829+ "" ,
1830+ " var goldCost = 0" ,
1831+ " var isAntiAir = false // Is the building an anti air unit" ,
1832+ "" ,
1833+ "init" ,
1834+ " let b = new CFBuilding()" ,
1835+ " b.upgrades = new ArrayList<CFBuilding>()" ,
1836+ " let aa = b" ,
1837+ " .hasAAUpgrade.get()" ,
1838+ " if aa == true" ,
1839+ " testSuccess()" ,
1840+ ""
1841+ );
1842+ }
1843+
15341844
15351845}
0 commit comments