| | 1542 | /** |
|---|
| | 1543 | * Returns $(D_PARAM true) if and only if the array $(D_PARAM longer) |
|---|
| | 1544 | * starts with array $(D_PARAM shorter). |
|---|
| | 1545 | */ |
|---|
| | 1546 | bool startsWith(A1, A2)(A1 longer, A2 shorter) |
|---|
| | 1547 | { |
|---|
| | 1548 | static if (is(typeof(longer[0 .. shorter.length] == shorter))) |
|---|
| | 1549 | { |
|---|
| | 1550 | // the easy way: arrays, directly comparable |
|---|
| | 1551 | return longer.length >= shorter.length && |
|---|
| | 1552 | longer[0 .. shorter.length] == shorter; |
|---|
| | 1553 | } |
|---|
| | 1554 | else |
|---|
| | 1555 | { |
|---|
| | 1556 | // different element types, etc. |
|---|
| | 1557 | static if (isSomeString!(A1) && isSomeString!(A2)) |
|---|
| | 1558 | { |
|---|
| | 1559 | // UTF-informed comparison |
|---|
| | 1560 | // find the largest character of the two |
|---|
| | 1561 | static if (longer[0].sizeof > shorter[0].sizeof) |
|---|
| | 1562 | { |
|---|
| | 1563 | alias typeof(longer[0]) Char; |
|---|
| | 1564 | if (shorter.length / Char.sizeof > longer.length) return false; |
|---|
| | 1565 | size_t i = 0; |
|---|
| | 1566 | foreach (Char c; shorter) |
|---|
| | 1567 | { |
|---|
| | 1568 | if (i == longer.length || longer[i] != c) return false; |
|---|
| | 1569 | ++i; |
|---|
| | 1570 | } |
|---|
| | 1571 | } |
|---|
| | 1572 | else |
|---|
| | 1573 | { |
|---|
| | 1574 | static assert(longer[0].sizeof < shorter[0].sizeof, |
|---|
| | 1575 | "Looks like there's a bug in the compiler"); |
|---|
| | 1576 | alias typeof(shorter[0]) Char; |
|---|
| | 1577 | if (shorter.length > longer.length) return false; |
|---|
| | 1578 | size_t i = 0; |
|---|
| | 1579 | foreach (Char c; longer) |
|---|
| | 1580 | { |
|---|
| | 1581 | if (i == shorter.length) return true; |
|---|
| | 1582 | if (shorter[i] != c) return false; |
|---|
| | 1583 | ++i; |
|---|
| | 1584 | } |
|---|
| | 1585 | } |
|---|
| | 1586 | } |
|---|
| | 1587 | else |
|---|
| | 1588 | { |
|---|
| | 1589 | // raw element-by-element comparison |
|---|
| | 1590 | if (longer.length < shorter.length) return false; |
|---|
| | 1591 | foreach (i, e; shorter) |
|---|
| | 1592 | { |
|---|
| | 1593 | if (longer[i] != e) return false; |
|---|
| | 1594 | } |
|---|
| | 1595 | } |
|---|
| | 1596 | } |
|---|
| | 1597 | return true; |
|---|
| | 1598 | } |
|---|
| | 1599 | |
|---|
| | 1600 | unittest |
|---|
| | 1601 | { |
|---|
| | 1602 | alias TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[]) |
|---|
| | 1603 | StringTypes; |
|---|
| | 1604 | alias TypeTuple!(ubyte[], int[], double[]) OtherTypes; |
|---|
| | 1605 | foreach (T1 ; StringTypes) |
|---|
| | 1606 | { |
|---|
| | 1607 | foreach (T2 ; StringTypes) |
|---|
| | 1608 | { |
|---|
| | 1609 | foreach (T3 ; OtherTypes) |
|---|
| | 1610 | { |
|---|
| | 1611 | auto a = to!(T1)("abcde"), b = to!(T2)("abcdefgh"), |
|---|
| | 1612 | c = to!(T2)(""); |
|---|
| | 1613 | auto d = to!(T3)([2, 3]); |
|---|
| | 1614 | assert(startsWith(b, a)); |
|---|
| | 1615 | assert(!startsWith(a, b)); |
|---|
| | 1616 | assert(startsWith(b, c)); |
|---|
| | 1617 | assert(startsWith(a, c)); |
|---|
| | 1618 | assert(!startsWith(c, b)); |
|---|
| | 1619 | assert(!startsWith(c, a)); |
|---|
| | 1620 | assert(!startsWith(a, d)); |
|---|
| | 1621 | assert(!startsWith(d, a)); |
|---|
| | 1622 | assert(!startsWith(b, d)); |
|---|
| | 1623 | assert(!startsWith(d, b)); |
|---|
| | 1624 | assert(!startsWith(c, d)); |
|---|
| | 1625 | assert(startsWith(d, c)); |
|---|
| | 1626 | } |
|---|
| | 1627 | } |
|---|
| | 1628 | } |
|---|
| | 1629 | } |
|---|
| | 1630 | |
|---|
| | 1631 | /** |
|---|
| | 1632 | * Returns $(D_PARAM true) if and only if the array $(D_PARAM longer) |
|---|
| | 1633 | * ends with array $(D_PARAM shorter). |
|---|
| | 1634 | */ |
|---|
| | 1635 | bool endsWith(A1, A2)(A1 longer, A2 shorter) |
|---|
| | 1636 | { |
|---|
| | 1637 | static if (is(typeof(longer[$ - shorter.length .. $] == shorter))) |
|---|
| | 1638 | { |
|---|
| | 1639 | // the easy way: arrays, directly comparable |
|---|
| | 1640 | return longer.length >= shorter.length && |
|---|
| | 1641 | longer[$ - shorter.length .. $] == shorter; |
|---|
| | 1642 | } |
|---|
| | 1643 | else |
|---|
| | 1644 | { |
|---|
| | 1645 | // different element types, etc. |
|---|
| | 1646 | static if (isSomeString!(A1) && isSomeString!(A2)) |
|---|
| | 1647 | { |
|---|
| | 1648 | // UTF-informed comparison |
|---|
| | 1649 | // find the largest character of the two |
|---|
| | 1650 | static if (longer[0].sizeof > shorter[0].sizeof) |
|---|
| | 1651 | { |
|---|
| | 1652 | alias typeof(longer[0]) Char; |
|---|
| | 1653 | if (shorter.length > longer.length * Char.sizeof) return false; |
|---|
| | 1654 | size_t i = longer.length - 1; |
|---|
| | 1655 | foreach_reverse (Char c; shorter) |
|---|
| | 1656 | { |
|---|
| | 1657 | if (i == 0 || longer[i] != c) return false; |
|---|
| | 1658 | --i; |
|---|
| | 1659 | } |
|---|
| | 1660 | } |
|---|
| | 1661 | else |
|---|
| | 1662 | { |
|---|
| | 1663 | static assert(longer[0].sizeof < shorter[0].sizeof, |
|---|
| | 1664 | "Looks like there's a bug in the compiler"); |
|---|
| | 1665 | alias typeof(shorter[0]) Char; |
|---|
| | 1666 | if (shorter.length > longer.length) return false; |
|---|
| | 1667 | if (!shorter.length) return true; |
|---|
| | 1668 | size_t i = shorter.length - 1; |
|---|
| | 1669 | foreach_reverse (Char c; longer) |
|---|
| | 1670 | { |
|---|
| | 1671 | if (i == 0) return true; |
|---|
| | 1672 | if (shorter[i] != c) return false; |
|---|
| | 1673 | --i; |
|---|
| | 1674 | } |
|---|
| | 1675 | } |
|---|
| | 1676 | } |
|---|
| | 1677 | else |
|---|
| | 1678 | { |
|---|
| | 1679 | // raw element-by-element comparison |
|---|
| | 1680 | if (longer.length < shorter.length) return false; |
|---|
| | 1681 | foreach (i, e; longer[$ - shorter.length .. $]) |
|---|
| | 1682 | { |
|---|
| | 1683 | if (longer[i] != e) return false; |
|---|
| | 1684 | } |
|---|
| | 1685 | } |
|---|
| | 1686 | } |
|---|
| | 1687 | return true; |
|---|
| | 1688 | } |
|---|
| | 1689 | |
|---|
| | 1690 | unittest |
|---|
| | 1691 | { |
|---|
| | 1692 | alias TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[]) |
|---|
| | 1693 | TestTypes; |
|---|
| | 1694 | alias TypeTuple!(ubyte[], int[], double[]) OtherTypes; |
|---|
| | 1695 | foreach (T1 ; TestTypes) |
|---|
| | 1696 | { |
|---|
| | 1697 | foreach (T2 ; TestTypes) |
|---|
| | 1698 | { |
|---|
| | 1699 | foreach (T3 ; OtherTypes) |
|---|
| | 1700 | { |
|---|
| | 1701 | auto a = to!(T1)("efgh"), b = to!(T2)("abcdefgh"), |
|---|
| | 1702 | c = to!(T2)(""), d = to!(T3)([1, 2]); |
|---|
| | 1703 | assert(endsWith(b, a)); |
|---|
| | 1704 | assert(!endsWith(a, b)); |
|---|
| | 1705 | assert(endsWith(b, c)); |
|---|
| | 1706 | assert(endsWith(a, c)); |
|---|
| | 1707 | assert(!endsWith(c, b)); |
|---|
| | 1708 | assert(!endsWith(c, a)); |
|---|
| | 1709 | assert(!endsWith(a, d)); |
|---|
| | 1710 | assert(!endsWith(d, a)); |
|---|
| | 1711 | assert(!endsWith(b, d)); |
|---|
| | 1712 | assert(!endsWith(d, b)); |
|---|
| | 1713 | assert(!endsWith(c, d)); |
|---|
| | 1714 | assert(endsWith(d, c)); |
|---|
| | 1715 | } |
|---|
| | 1716 | } |
|---|
| | 1717 | } |
|---|
| | 1718 | } |
|---|
| | 1719 | |
|---|