0001:
0002:
0003:
0004:
0005:
0006:
0007:
0008:
0009:
0010:
0011:
0012:
0013:
0014:
0015:
0016:
0017:
0018:
0019:
0020:
0021:
0022:
0023:
0024:
0025:
0026:
0027:
0028:
0029:
0030:
0031:
0032:
0033:
0034:
0035:
0036:
0037:
0038:
0039:
0040:
0041:
0042:
0043:
0044:
0045:
0046:
0047:
0048:
0049:
0050:
0051:
0052:
0053:
0054:
0055:
0056:
0057:
0058:
0059:
0060:
0061:
0062:
0063:
0064:
0065:
0066:
0067:
0068:
0069:
0070:
0071:
0072:
0073:
0074:
0075:
0076:
0077:
0078:
0079:
0080:
0081:
0082:
0083:
0084:
0085:
0086:
0087:
0088:
0089:
0090:
0091:
0092:
0093:
0094:
0095:
0096:
0097:
0098:
0099:
0100:
0101:
0102:
0103:
0104:
0105:
0106:
0107:
0108:
0109:
0110:
0111:
0112:
0113:
0114:
0115:
0116:
0117:
0118:
0119:
0120:
0121:
0122:
0123:
0124:
0125:
0126:
0127:
0128:
0129:
0130:
0131:
0132:
0133:
0134:
0135:
0136:
0137:
0138:
0139:
0140:
0141:
0142:
0143:
0144:
0145:
0146:
0147:
0148:
0149:
0150:
0151:
0152:
0153:
0154:
0155:
0156:
0157:
0158:
0159:
0160:
0161:
0162:
0163:
0164:
0165:
0166:
0167:
0168:
0169:
0170:
0171:
0172:
0173:
0174:
0175:
0176:
0177:
0178:
0179:
0180:
0181:
0182:
0183:
0184:
0185:
0186:
0187:
0188:
0189:
0190:
0191:
0192:
0193:
0194:
0195:
0196:
0197:
0198:
0199:
0200:
0201:
0202:
0203:
0204:
0205:
0206:
0207:
0208:
0209:
0210:
0211:
0212:
0213:
0214:
0215:
0216:
0217:
0218:
0219:
0220:
0221:
0222:
0223:
0224:
0225:
0226:
0227:
0228:
0229:
0230:
0231:
0232:
0233:
0234:
0235:
0236:
0237:
0238:
0239:
0240:
0241:
0242:
0243:
0244:
0245:
0246:
0247:
0248:
0249:
0250:
0251:
0252:
0253:
0254:
0255:
0256:
0257:
0258:
0259:
0260:
0261:
0262:
0263:
0264:
0265:
0266:
0267:
0268:
0269:
0270:
0271:
0272:
0273:
0274:
0275:
0276:
0277:
0278:
0279:
0280:
0281:
0282:
0283:
0284:
0285:
0286:
0287:
0288:
0289:
0290:
0291:
0292:
0293:
0294:
0295:
0296:
0297:
0298:
0299:
0300:
0301:
0302:
0303:
0304:
0305:
0306:
0307:
0308:
0309:
0310:
0311:
0312:
0313:
0314:
0315:
0316:
0317:
0318:
0319:
0320:
0321:
0322:
0323:
0324:
0325:
0326:
0327:
0328:
0329:
0330:
0331:
0332:
0333:
0334:
0335:
0336:
0337:
0338:
0339:
0340:
0341:
0342:
0343:
0344:
0345:
0346:
0347:
0348:
0349:
0350:
0351:
0352:
0353:
0354:
0355:
0356:
0357:
0358:
0359:
0360:
0361:
0362:
0363:
0364:
0365:
0366:
0367:
0368:
0369:
0370:
0371:
0372:
0373:
0374:
0375:
0376:
0377:
0378:
0379:
0380:
0381:
0382:
0383:
0384:
0385:
0386:
0387:
0388:
0389:
0390:
0391:
0392:
0393:
0394:
0395:
0396:
0397:
0398:
0399:
0400:
0401:
0402:
0403:
0404:
0405:
0406:
0407:
0408:
0409:
0410:
0411:
0412:
0413:
0414:
0415:
0416:
0417:
0418:
0419:
0420:
0421:
0422:
0423:
0424:
0425:
0426:
0427:
0428:
0429:
0430:
0431:
0432:
0433:
0434:
0435:
0436:
0437:
0438:
0439:
0440:
0441:
0442:
0443:
0444:
0445:
0446:
0447:
0448:
0449:
0450:
0451:
0452:
0453:
0454:
0455:
0456:
0457:
0458:
0459:
0460:
0461:
0462:
0463:
0464:
0465:
0466:
0467:
0468:
0469:
0470:
0471:
0472:
0473:
0474:
0475:
0476:
0477:
0478:
0479:
0480:
0481:
0482:
0483:
0484:
0485:
0486:
0487:
0488:
0489:
0490:
0491:
0492:
0493:
0494:
0495:
0496:
0497:
0498:
0499:
0500:
0501:
0502:
0503:
0504:
0505:
0506:
0507:
0508:
0509:
0510:
0511:
0512:
0513:
0514:
0515:
0516:
0517:
0518:
0519:
0520:
0521:
0522:
0523:
0524:
0525:
0526:
0527:
0528:
0529:
0530:
0531:
0532:
0533:
0534:
0535:
0536:
0537:
0538:
0539:
0540:
0541:
0542:
0543:
0544:
0545:
0546:
0547:
0548:
0549:
0550:
0551:
0552:
0553:
0554:
0555:
0556:
0557:
0558:
0559:
0560:
0561:
0562:
0563:
0564:
0565:
0566:
0567:
0568:
0569:
0570:
0571:
0572:
0573:
0574:
0575:
0576:
0577:
0578:
0579:
0580:
0581:
0582:
0583:
0584:
0585:
0586:
0587:
0588:
0589:
0590:
0591:
0592:
0593:
0594:
0595:
0596:
0597:
0598:
0599:
0600:
0601:
0602:
0603:
0604:
0605:
0606:
0607:
0608:
0609:
0610:
0611:
0612:
0613:
0614:
0615:
0616:
0617:
0618:
0619:
0620:
0621:
0622:
0623:
0624:
0625:
0626:
0627:
0628:
0629:
0630:
0631:
0632:
0633:
0634:
0635:
0636:
0637:
0638:
0639:
0640:
0641:
0642:
0643:
0644:
0645:
0646:
0647:
0648:
0649:
0650:
0651:
0652:
0653:
0654:
0655:
0656:
0657:
0658:
0659:
0660:
0661:
0662:
0663:
0664:
0665:
0666:
0667:
0668:
0669:
0670:
0671:
0672:
0673:
0674:
0675:
0676:
0677:
0678:
0679:
0680:
0681:
0682:
0683:
0684:
0685:
0686:
0687:
0688:
0689:
0690:
0691:
0692:
0693:
0694:
0695:
0696:
0697:
0698:
0699:
0700:
0701:
0702:
0703:
0704:
0705:
0706:
0707:
0708:
0709:
0710:
0711:
0712:
0713:
0714:
0715:
0716:
0717:
0718:
0719:
0720:
0721:
0722:
0723:
0724:
0725:
0726:
0727:
0728:
0729:
0730:
0731:
0732:
0733:
0734:
0735:
0736:
0737:
0738:
0739:
0740:
0741:
0742:
0743:
0744:
0745:
0746:
0747:
0748:
0749:
0750:
0751:
0752:
0753:
0754:
0755:
0756:
0757:
0758:
0759:
0760:
0761:
0762:
0763:
0764:
0765:
0766:
0767:
0768:
0769:
0770:
0771:
0772:
0773:
0774:
0775:
0776:
0777:
0778:
0779:
0780:
0781:
0782:
0783:
0784:
0785:
0786:
0787:
0788:
0789:
0790:
0791:
0792:
0793:
0794:
0795:
0796:
0797:
0798:
0799:
0800:
0801:
0802:
0803:
0804:
0805:
0806:
0807:
0808:
0809:
0810:
0811:
0812:
0813:
0814:
0815:
0816:
0817:
0818:
0819:
0820:
0821:
0822:
0823:
0824:
0825:
0826:
0827:
0828:
0829:
0830:
0831:
0832:
0833:
0834:
0835:
0836:
0837:
0838:
0839:
0840:
0841:
0842:
0843:
0844:
0845:
0846:
0847:
0848:
0849:
0850:
0851:
0852:
0853:
0854:
0855:
0856:
0857:
0858:
0859:
0860:
0861:
0862:
0863:
0864:
0865:
0866:
0867:
0868:
0869:
0870:
0871:
0872:
0873:
0874:
0875:
0876:
0877:
0878:
0879:
0880:
0881:
0882:
0883:
0884:
0885:
0886:
0887:
0888:
0889:
0890:
0891:
0892:
0893:
0894:
0895:
0896:
0897:
0898:
0899:
0900:
0901:
0902:
0903:
0904:
0905:
0906:
0907:
0908:
0909:
0910:
0911:
0912:
0913:
0914:
0915:
0916:
0917:
0918:
0919:
0920:
0921:
0922:
0923:
0924:
0925:
0926:
0927:
0928:
0929:
0930:
0931:
0932:
0933:
0934:
0935:
0936:
0937:
0938:
0939:
0940:
0941:
0942:
0943:
0944:
0945:
0946:
0947:
0948:
0949:
0950:
0951:
0952:
0953:
0954:
0955:
0956:
0957:
0958:
0959:
0960:
0961:
0962:
0963:
0964:
0965:
0966:
0967:
0968:
0969:
0970:
0971:
0972:
0973:
0974:
0975:
0976:
0977:
0978:
0979:
0980:
0981:
0982:
0983:
0984:
0985:
0986:
0987:
0988:
0989:
0990:
0991:
0992:
0993:
0994:
0995:
0996:
0997:
0998:
0999:
1000:
1001:
1002:
1003:
1004:
1005:
1006:
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
1020:
1021:
1022:
1023:
1024:
1025:
1026:
1027:
1028:
1029:
1030:
1031:
1032:
1033:
1034:
1035:
1036:
1037:
1038:
1039:
1040:
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
1054:
1055:
1056:
1057:
1058:
1059:
1060:
1061:
1062:
1063:
1064:
1065:
1066:
1067:
1068:
1069:
1070:
1071:
1072:
1073:
1074:
1075:
1076:
1077:
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086:
1087:
1088:
1089:
1090:
1091:
1092:
1093:
1094:
1095:
1096:
1097:
1098:
1099:
1100:
1101:
1102:
1103:
1104:
1105:
1106:
1107:
1108:
1109:
1110:
1111:
1112:
1113:
1114:
1115:
1116:
1117:
1118:
1119:
1120:
1121:
1122:
1123:
1124:
1125:
1126:
1127:
1128:
1129:
1130:
1131:
1132:
1133:
1134:
1135:
1136:
1137:
1138:
1139:
1140:
1141:
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
1150:
1151:
1152:
1153:
1154:
1155:
1156:
1157:
1158:
1159:
1160:
1161:
1162:
1163:
1164:
1165:
1166:
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
1177:
1178:
1179:
1180:
1181:
1182:
1183:
1184:
1185:
1186:
1187:
1188:
1189:
1190:
1191:
1192:
1193:
1194:
1195:
1196:
1197:
1198:
1199:
1200:
1201:
1202:
1203:
1204:
1205:
1206:
1207:
1208:
1209:
1210:
1211:
1212:
1213:
1214:
1215:
1216:
1217:
1218:
1219:
1220:
1221:
1222:
1223:
1224:
1225:
1226:
1227:
1228:
1229:
1230:
1231:
1232:
1233:
1234:
1235:
1236:
1237:
1238:
1239:
1240:
1241:
1242:
1243:
1244:
1245:
1246:
1247:
1248:
1249:
1250:
1251:
1252:
1253:
1254:
1255:
1256:
1257:
1258:
1259:
1260:
1261:
1262:
1263:
1264:
1265:
1266:
1267:
1268:
1269:
1270:
1271:
1272:
1273:
1274:
1275:
1276:
1277:
1278:
1279:
1280:
1281:
1282:
1283:
1284:
1285:
1286:
1287:
1288:
1289:
1290:
1291:
1292:
1293:
1294:
1295:
1296:
1297:
1298:
1299:
1300:
1301:
1302:
1303:
1304:
1305:
1306:
1307:
1308:
1309:
1310:
1311:
1312:
1313:
1314:
1315:
1316:
1317:
1318:
1319:
1320:
1321:
1322:
1323:
1324:
1325:
1326:
1327:
1328:
1329:
1330:
1331:
1332:
1333:
1334:
1335:
1336:
1337:
1338:
1339:
1340:
1341:
1342:
1343:
1344:
1345:
1346:
1347:
1348:
1349:
1350:
1351:
1352:
1353:
1354:
1355:
1356:
1357:
1358:
1359:
1360:
1361:
1362:
1363:
1364:
1365:
1366:
1367:
1368:
1369:
1370:
1371:
1372:
1373:
1374:
1375:
1376:
1377:
1378:
1379:
1380:
1381:
1382:
1383:
1384:
1385:
1386:
1387:
1388:
1389:
1390:
1391:
1392:
1393:
1394:
1395:
1396:
1397:
1398:
1399:
1400:
1401:
1402:
1403:
1404:
1405:
1406:
1407:
1408:
1409:
1410:
1411:
1412:
1413:
1414:
1415:
1416:
1417:
1418:
1419:
1420:
1421:
1422:
1423:
1424:
1425:
1426:
1427:
1428:
1429:
1430:
1431:
1432:
1433:
1434:
1435:
1436:
1437:
1438:
1439:
1440:
1441:
1442:
1443:
1444:
1445:
1446:
1447:
1448:
1449:
1450:
1451:
1452:
1453:
1454:
1455:
1456:
1457:
1458:
1459:
1460:
1461:
1462:
1463:
1464:
1465:
1466:
1467:
1468:
1469:
1470:
1471:
1472:
1473:
1474:
1475:
1476:
1477:
1478:
1479:
1480:
1481:
1482:
1483:
1484:
1485:
1486:
1487:
1488:
1489:
1490:
1491:
1492:
1493:
1494:
1495:
1496:
1497:
1498:
1499:
1500:
1501:
1502:
1503:
1504:
1505:
1506:
1507:
1508:
1509:
1510:
1511:
1512:
1513:
1514:
1515:
1516:
1517:
1518:
1519:
1520:
1521:
1522:
1523:
1524:
1525:
1526:
1527:
1528:
1529:
1530:
1531:
1532:
1533:
1534:
1535:
1536:
1537:
1538:
1539:
1540:
1541:
1542:
1543:
1544:
1545:
1546:
1547:
1548:
1549:
1550:
1551:
1552:
1553:
1554:
1555:
1556:
1557:
1558:
1559:
1560:
1561:
1562:
1563:
1564:
1565:
1566:
1567:
1568:
1569:
1570:
1571:
1572:
1573:
1574:
1575:
1576:
1577:
1578:
1579:
1580:
1581:
1582:
1583:
1584:
1585:
1586:
1587:
1588:
1589:
1590:
1591:
1592:
1593:
1594:
1595:
1596:
1597:
1598:
1599:
1600:
1601:
1602:
1603:
1604:
1605:
1606:
1607:
1608:
1609:
1610:
1611:
1612:
1613:
1614:
1615:
1616:
1617:
1618:
1619:
1620:
1621:
1622:
1623:
1624:
1625:
1626:
1627:
1628:
1629:
1630:
1631:
1632:
1633:
1634:
1635:
1636:
1637:
1638:
1639:
1640:
1641:
1642:
1643:
1644:
1645:
1646:
1647:
1648:
1649:
1650:
1651:
1652:
1653:
1654:
1655:
1656:
1657:
1658:
1659:
1660:
1661:
1662:
1663:
1664:
1665:
1666:
1667:
1668:
1669:
1670:
1671:
1672:
1673:
1674:
1675:
1676:
Min/Max






































































































































































































































































































































Min/Max




























Min/Max
























































































































































































































































































































































Min/Max




















































Min/Max













































Min/Max





























































































































































































































































































































































































































































































































































































































































































































































Min/Max























































































Min/Max





















































/*
* Copyright (c), Zeriph Enterprises
* All rights reserved.
*
* Contributor(s):
* Zechariah Perez, omni (at) zeriph (dot) com
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(OMNI_STRING_UTIL_HPP)
#define OMNI_STRING_UTIL_HPP 1
#include <omni/defs/class_macros.hpp>
#include <omni/types/string_t.hpp>
#include <omni/sequence.hpp>
#include <omni/type.hpp>
#include <omni/defs/consts.hpp>
#include <omni/bits.hpp>
#include <bitset>

namespace omni {
    namespace string {
        class compare_options
        {
            public:
                typedef enum enum_t {
                    NONE = 0,
                    IGNORE_CASE = 1,
                    IGNORE_SYMBOLS = 4
                } enum_t;

                static inline unsigned short COUNT()
                {
                    return 3;
                }

                static inline enum_t DEFAULT_VALUE()
                {
                    return NONE;
                }
                
                static std::string to_string(enum_t v)
                {
                    return _to_val<std::stringstream>(v);
                }
            
                static std::wstring to_wstring(enum_t v)
                {
                    return _to_val<std::wstringstream>(v);
                }

                static enum_t parse(const std::string& val)
                {
                    return _parse(val);
                }

                static enum_t parse(const std::wstring& val)
                {
                    return _parse(val);
                }

                static bool try_parse(const std::string& val, enum_t& out)
                {
                    return _try_parse(val, out);
                }

                static bool try_parse(const std::wstring& val, enum_t& out)
                {
                    return _try_parse(val, out);
                }

                static bool try_parse(const std::string& val, compare_options& out)
                {
                    return _try_parse(val, out);
                }

                static bool try_parse(const std::wstring& val, compare_options& out)
                {
                    return _try_parse(val, out);
                }

                static bool is_valid(int32_t val)
                {
                    return _valid(val);
                }
                
                compare_options() :
                    OMNI_CTOR_FW(omni::string::compare_options)
                    m_val(DEFAULT_VALUE())
                { }

                compare_options(const compare_options& cp) :
                    OMNI_CPCTOR_FW(cp)
                    m_val(cp.m_val)
                { }

                compare_options(enum_t val) :
                    OMNI_CTOR_FW(omni::string::compare_options)
                    m_val(val)
                { }

                ~compare_options()
                {
                    OMNI_TRY_FW
                    OMNI_DTOR_FW
                    OMNI_CATCH_FW
                    OMNI_D5_FW("destroyed");
                }

                unsigned short count() const
                {
                    return COUNT();
                }

                bool has_flag(enum_t flag) const
                {
                    return (this->m_val & flag) == flag;
                }

                enum_t value() const
                {
                    return this->m_val;
                }

                std::string to_string() const
                {
                    return to_string(this->m_val);
                }

                std::wstring to_wstring() const
                {
                    return to_wstring(this->m_val);
                }

                bool operator!=(const compare_options& val) const
                {
                    return !(*this == val);
                }
                
                bool operator!=(enum_t val) const
                {
                    return (this->m_val != val);
                }
                
                compare_options& operator=(const compare_options& val)
                {
                    if (this != &val) {
                        OMNI_ASSIGN_FW(val)
                        this->m_val = val.m_val;
                    }
                    return *this;
                }

                compare_options& operator=(enum_t val)
                {
                    this->m_val = val;
                    return *this;
                }

                compare_options& operator=(int32_t val)
                {
                    if (!compare_options::is_valid(val)) {
                        OMNI_ERR_RET_FW("Invalid enumeration value specified.", omni::exceptions::invalid_enum(val));
                    } else {
                        this->m_val = static_cast<enum_t>(val);
                    }
                    return *this;
                }

                bool operator<(const compare_options& val) const
                {
                    return this->m_val < val.m_val;
                }

                bool operator<(enum_t val) const
                {
                    return this->m_val < val;
                }

                bool operator<(int32_t val) const
                {
                    return this->m_val < static_cast<enum_t>(val);
                }

                bool operator>(const compare_options& val) const
                {
                    return this->m_val > val.m_val;
                }

                bool operator>(enum_t val) const
                {
                    return this->m_val > val;
                }

                bool operator>(int32_t val) const
                {
                    return this->m_val > val;
                }

                bool operator==(const compare_options& val) const
                {
                    if (this == &val) { return true; }
                    return this->m_val == val.m_val
                            OMNI_EQUAL_FW(val);
                }

                bool operator==(enum_t val) const
                {
                    return this->m_val == val;
                }

                bool operator==(int32_t val) const
                {
                    return this->m_val == val;
                }

                operator enum_t() const
                {
                    return this->m_val;
                }

                operator std::string() const
                {
                    return this->to_string();
                }

                operator std::wstring() const
                {
                    return this->to_wstring();
                }

                OMNI_MEMBERS_FW(omni::string::compare_options) // disposing,name,type(),hash()

                OMNI_OSTREAM_FW(omni::string::compare_options)
                OMNI_OSTREAM_FN_FW(enum_t)

            private:
                enum_t m_val;

                template < typename S >
                static enum_t _parse(const S& val)
                {
                    enum_t ret;
                    if (_try_parse(val, ret)) { return ret; }
                    OMNI_ERR_FW("invalid enum parse", omni::exceptions::invalid_enum())
                    return DEFAULT_VALUE();
                }

                template < typename S >
                static bool _try_parse(const S& str, enum_t& out)
                {
                    return _try_parse(omni::string_util::to_upper(str), out);
                }

                template < typename S >
                static bool _try_parse(const S& val, compare_options& out)
                {
                    enum_t tmp;
                    if (_try_parse(val, tmp)) {
                        out.m_val = tmp;
                        return true;
                    }
                    return false;
                }

                static bool _try_parse(const std::wstring& val, enum_t& out)
                {
                    return _try_parse(omni::string_util::to_string(val), out);
                }

                static bool _try_parse(const std::string& val, enum_t& out)
                {
                    if (!val.empty()) {
                        OMNI_S2E_FW(NONE)
                        OMNI_S2E_FW(IGNORE_CASE)
                        OMNI_S2E_FW(IGNORE_SYMBOLS)
                    }
                    return false;
                }

                template < typename S >
                static std::basic_string< typename S::char_type > _to_val(enum_t v)
                {
                    S ss;
                    switch (v) {
                        OMNI_E2SS_FW(NONE);
                        OMNI_E2SS_FW(IGNORE_CASE);
                        OMNI_E2SS_FW(IGNORE_SYMBOLS);
                        default:
                            ss << "UNKNOWN (" << static_cast<int>(v) << ")";
                            break;
                    }
                    return ss.str();
                }

                static bool _valid(int32_t val)
                {
                    return (
                        OMNI_I2EV_FW(NONE) ||
                        OMNI_I2EV_FW(IGNORE_CASE) ||
                        OMNI_I2EV_FW(IGNORE_SYMBOLS)
                    );
                }
        };

        namespace util {
            template < typename std_string_t >
            bool is_numeric(const std_string_t& str, bool ignore_period)
            {
                if (str.empty()) { return false; }
                typename std_string_t::const_iterator itr = str.begin();
                // could be negative/decimal/euro ("-100"/".42"/",42")
                if (omni::char_util::helpers::is_nde(*itr)) {
                    if (++itr == str.end()) { return false; }
                }
                std::size_t pcnt = 0;
                while (itr != str.end()) {
                    if (!omni::char_util::is_digit(*itr)) {
                        if (omni::char_util::helpers::is_de(*itr)) {
                            /* if it is a period or comma and the flag is set then ignore it.
                            The logic here is that we do not want this function to guess
                            how a specific number might be formatted, but that we can assume
                            that if it is indeed a number, chances are good that it might
                            contain a period or comma, so ignore those. */
                            if (ignore_period) { ++itr; continue; }
                            // more than 1 period means non numeric (i.e. not decimal/whole)
                            if (++pcnt > 1) { return false; }
                        }
                        return false;
                    }
                    ++itr;
                }
                return true;
            }
            
            template < typename std_string_t >
            bool is_numeric(const std_string_t& str, typename std_string_t::value_type period_type, bool ignore_period)
            {
                if (str.empty()) { return false; }
                typename std_string_t::const_iterator itr = str.begin();
                // could be negative/decimal/euro ("-100"/".42"/",42")
                if (omni::char_util::helpers::is_neg(*itr)) {
                    if (++itr == str.end()) { return false; }
                }
                std::size_t pcnt = 0;
                while (itr != str.end()) {
                    if (!omni::char_util::is_digit(*itr)) {
                        if (*itr == period_type) {
                            /* if it is a period or comma and the flag is set then ignore it.
                            The logic here is that we do not want this function to guess
                            how a specific number might be formatted, but that we can assume
                            that if it is indeed a number, chances are good that it might
                            contain a period or comma, so ignore those. */
                            if (ignore_period) { ++itr; continue; }
                            // more than 1 period means non numeric (i.e. not decimal/whole)
                            if (++pcnt > 1) { return false; }
                        }
                        return false;
                    }
                    ++itr;
                }
                return true;
            }
            
            inline bool is_numeric(const std::wstring& str)
            {
                return omni::string::util::is_numeric(str, false);
            }
            
            inline bool is_numeric(const std::wstring& str, wchar_t period_type)
            {
                return omni::string::util::is_numeric(str, period_type, false);
            }
            
            inline bool is_numeric(const wchar_t* str)
            {
                if (str) { return omni::string::util::is_numeric(std::wstring(str)); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), false)
            }

            template < std::size_t X >
            inline bool is_numeric(const wchar_t (&str)[X])
            {
                return omni::string::util::is_numeric(std::wstring(str));
            }
            
            inline bool is_numeric(const wchar_t* str, bool ignore_period)
            {
                if (str) { return omni::string::util::is_numeric(std::wstring(str), ignore_period); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), false)
            }
            
            template < std::size_t X >
            inline bool is_numeric(const wchar_t (&str)[X], bool ignore_period)
            {
                return omni::string::util::is_numeric(std::wstring(str), ignore_period);
            }
            
            inline bool is_numeric(const wchar_t* str, wchar_t period_type)
            {
                if (str) { return omni::string::util::is_numeric(std::wstring(str), period_type, false); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), false)
            }
            
            template < std::size_t X >
            inline bool is_numeric(const wchar_t (&str)[X], wchar_t period_type)
            {
                return omni::string::util::is_numeric(std::wstring(str), period_type, false);
            }
            
            inline bool is_numeric(const wchar_t* str, wchar_t period_type, bool ignore_period)
            {
                if (str) { return omni::string::util::is_numeric(std::wstring(str), period_type, ignore_period); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), false)
            }
            
            template < std::size_t X >
            inline bool is_numeric(const wchar_t (&str)[X], wchar_t period_type, bool ignore_period)
            {
                return omni::string::util::is_numeric(std::wstring(str), period_type, ignore_period);
            }
            
            inline bool is_numeric(const std::string& str)
            {
                return omni::string::util::is_numeric(str, false);
            }
            
            inline bool is_numeric(const std::string& str, char period_type)
            {
                return omni::string::util::is_numeric(str, period_type, false);
            }
            
            inline bool is_numeric(const char* str)
            {
                if (str) { return omni::string::util::is_numeric(std::string(str)); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), false)
            }
            
            template < std::size_t X >
            inline bool is_numeric(const char (&str)[X])
            {
                return omni::string::util::is_numeric(std::string(str));
            }
            
            inline bool is_numeric(const char* str, bool ignore_period)
            {
                if (str) { return omni::string::util::is_numeric(std::string(str), ignore_period); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), false)
            }
            
            template < std::size_t X >
            inline bool is_numeric(const char (&str)[X], bool ignore_period)
            {
                return omni::string::util::is_numeric(std::string(str), ignore_period);
            }
            
            inline bool is_numeric(const char* str, char period_type)
            {
                if (str) { return omni::string::util::is_numeric(std::string(str), period_type, false); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), false)
            }
            
            template < std::size_t X >
            inline bool is_numeric(const char (&str)[X], char period_type)
            {
                return omni::string::util::is_numeric(std::string(str), period_type, false);
            }
            
            inline bool is_numeric(const char* str, char period_type, bool ignore_period)
            {
                if (str) { return omni::string::util::is_numeric(std::string(str), period_type, ignore_period); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), false)
            }
            
            template < std::size_t X >
            inline bool is_numeric(const char (&str)[X], char period_type, bool ignore_period)
            {
                return omni::string::util::is_numeric(std::string(str), period_type, ignore_period);
            }
            
            template < typename std_string_t >
            std_string_t to_lower(std_string_t str)
            {
                typename std_string_t::iterator it = str.begin();
                while (it != str.end()) {
                    *it = omni::char_util::to_lower(*it);
                    ++it;
                }
                return str;
            }
            
            template < std::size_t X >
            std::string to_lower(const char (&str)[X])
            {
                return omni::string::util::to_lower(std::string(str));
            }
            
            template < std::size_t X >
            std::wstring to_lower(const wchar_t (&str)[X])
            {
                return omni::string::util::to_lower(std::wstring(str));
            }

            template < typename std_string_t >
            std_string_t lcfirst(std_string_t str)
            {
                if (str.size() > 0) {
                    str[0] = omni::char_util::to_lower(str[0]);
                }
                return str;
            }
            
            template < std::size_t X >
            std::string lcfirst(const char (&str)[X])
            {
                return omni::string::util::lcfirst(std::string(str));
            }
            
            template < std::size_t X >
            std::wstring lcfirst(const wchar_t (&str)[X])
            {
                return omni::string::util::lcfirst(std::wstring(str));
            }
            
            template < typename std_string_t >
            std_string_t to_upper(std_string_t str)
            {
                typename std_string_t::iterator it = str.begin();
                while (it != str.end()) {
                    *it = omni::char_util::to_upper(*it);
                    ++it;
                }
                return str;
            }
            
            template < std::size_t X >
            std::string to_upper(const char (&str)[X])
            {
                return omni::string::util::to_upper(std::string(str));
            }
            
            template < std::size_t X >
            std::wstring to_upper(const wchar_t (&str)[X])
            {
                return omni::string::util::to_upper(std::wstring(str));
            }

            template < typename std_string_t >
            std_string_t ucfirst(std_string_t str)
            {
                if (str.size() > 0) {
                    str[0] = omni::char_util::to_upper(str[0]);
                }
                return str;
            }
            
            template < std::size_t X >
            std::string ucfirst(const char (&str)[X])
            {
                return omni::string::util::ucfirst(std::string(str));
            }
            
            template < std::size_t X >
            std::wstring ucfirst(const wchar_t (&str)[X])
            {
                return omni::string::util::ucfirst(std::wstring(str));
            }

            template < typename std_string_t >
            std_string_t ucwords(std_string_t str, const std::string& separators)
            {
                if (str.size() > 0) {
                    typename std_string_t::size_type pos = 0;
                    str[0] = omni::char_util::to_upper(str[0]);

                    std::string::const_iterator s_it = separators.begin();
                    while (s_it != separators.end()) {
                        while ((pos = str.find(*s_it, pos)) != std_string_t::npos) {
                            if ((++pos) < str.size()) {
                                str[pos] = omni::char_util::to_upper(str[pos]);
                            }
                        }
                        pos = 0;
                        ++s_it;
                    }
                }
                return str;
            }

            template < typename std_string_t >
            std_string_t ucwords(const std_string_t& str)
            {
                return omni::string::util::ucwords(str, std::string(OMNI_STRING_UCWORD_SEPARATORS));
            }
            
            template < std::size_t X >
            std::string ucwords(const char (&str)[X], const std::string& separators)
            {
                return omni::string::util::ucwords(std::string(str), separators);
            }
            
            template < std::size_t X >
            std::wstring ucwords(const wchar_t (&str)[X], const std::string& separators)
            {
                return omni::string::util::ucwords(std::wstring(str), separators);
            }

            template < std::size_t X >
            std::string ucwords(const char (&str)[X])
            {
                return omni::string::util::ucwords(std::string(str), std::string(OMNI_STRING_UCWORD_SEPARATORS));
            }
            
            template < std::size_t X >
            std::wstring ucwords(const wchar_t (&str)[X])
            {
                return omni::string::util::ucwords(std::wstring(str), std::string(OMNI_STRING_UCWORD_SEPARATORS));
            }

            template < typename std_string_t >
            std_string_t to_title_case(const std_string_t& str, const std::string& separators)
            {
                return omni::string::util::ucwords(omni::string::util::to_lower(str), separators);
            }

            template < typename std_string_t >
            std_string_t to_title_case(const std_string_t& str)
            {
                return omni::string::util::to_title_case(str, std::string(OMNI_STRING_UCWORD_SEPARATORS));
            }
            
            template < std::size_t X >
            std::string to_title_case(const char (&str)[X], const std::string& separators)
            {
                return omni::string::util::to_title_case(std::string(str), separators);
            }
            
            template < std::size_t X >
            std::wstring to_title_case(const wchar_t (&str)[X], const std::string& separators)
            {
                return omni::string::util::to_title_case(std::wstring(str), separators);
            }

            template < std::size_t X >
            std::string to_title_case(const char (&str)[X])
            {
                return omni::string::util::to_title_case(std::string(str), std::string(OMNI_STRING_UCWORD_SEPARATORS));
            }
            
            template < std::size_t X >
            std::wstring to_title_case(const wchar_t (&str)[X])
            {
                return omni::string::util::to_title_case(std::wstring(str), std::string(OMNI_STRING_UCWORD_SEPARATORS));
            }

            template < typename std_string_t >
            bool contains(const std_string_t& haystack, const std_string_t& needle, bool ignore_case)
            {
                if (haystack.length() >= needle.length()) {
                    if (ignore_case) {
                        std_string_t tmp = omni::string::util::to_lower(haystack);
                        std_string_t tf = omni::string::util::to_lower(needle);
                        return (tmp.find(tf) != std_string_t::npos);
                    }
                    return (haystack.find(needle) != std_string_t::npos);
                }
                return false;
            }
            
            template < typename std_string_t, std::size_t X >
            bool contains(const std_string_t& haystack, const typename std_string_t::value_type (&needle)[X], bool ignore_case)
            {
                return omni::string::util::contains(haystack, std_string_t(needle), ignore_case);
            }
            
            template < typename std_string_t >
            inline bool contains(const std_string_t& haystack, const std_string_t& needle)
            {
                if (haystack.length() >= needle.length()) {
                    return (haystack.find(needle) != std_string_t::npos);
                }
                return false;
            }
            
            template < typename std_string_t, std::size_t X >
            inline bool contains(const std_string_t& haystack, const typename std_string_t::value_type (&needle)[X])
            {
                return omni::string::util::contains(haystack, std_string_t(needle));
            }

            template < typename std_string_t >
            inline int32_t compare(const std_string_t& str1, std::size_t idx1, const std_string_t& str2, std::size_t idx2, std::size_t len, const omni::string::compare_options& options)
            {
                /*
                    Remarks
                    The substrings to compare start in strA at position indexA and in strB at position indexB. The length of the first substring is the
                    length of strA minus indexA. The length of the second substring is the length of strB minus indexB.

                    The number of characters to compare is the lesser of the lengths of the two substrings, and length. The indexA, indexB, and length
                    parameters must be nonnegative.

                    The comparison uses the culture parameter to obtain culture-specific information, such as casing rules and the alphabetical order of
                    individual characters. For example, a particular culture could specify that certain combinations of characters be treated as a single
                    character, that uppercase and lowercase characters be compared in a particular way, or that the sort order of a character depends on
                    the characters that precede or follow it.

                    Caution

                    The Compare(String, Int32, String, Int32, Int32, CultureInfo, CompareOptions) method is designed primarily for use in sorting or
                    alphabetizing operations. It should not be used when the primary purpose of the method call is to determine whether two substrings
                    are equivalent (that is, when the purpose of the method call is to test for a return value of zero). To determine whether two strings
                    are equivalent, call the Equals method.

                */
                if (idx1 > str1.size()) {
                    OMNI_ERR_RETV_FW("Index out of range", omni::exceptions::index_out_of_range(), 0)
                }
                if (idx2 > str2.size()) {
                    OMNI_ERR_RETV_FW("Index out of range", omni::exceptions::index_out_of_range(), 0)
                }
                if (str1.empty()) {
                    return str2.empty() ? 0 : -1;
                } else if (str2.empty()) {
                    return 1;
                }

                bool ignore_case = options.has_flag(omni::string::compare_options::IGNORE_CASE);
                bool ignore_symbols = options.has_flag(omni::string::compare_options::IGNORE_SYMBOLS);

                std_string_t a = (ignore_case ? omni::string::util::to_lower(str1) : str1).substr(idx1);
                std_string_t b = (ignore_case ? omni::string::util::to_lower(str2) : str2).substr(idx2);
                
                // The number of characters to compare is the lesser of the lengths of the two substrings, and length.
                std::size_t comp_size = std::min(std::min(a.size(), b.size()), len);
                for (std::size_t i = 0; i < comp_size; ++i) {
                    if (ignore_symbols && (!omni::char_util::is_alpha_digit(a[i]) || !omni::char_util::is_alpha_digit(b[i]))) {
                        continue;
                    }
                    if (a[i] < b[i]) {
                        return -1;
                    } else if (a[i] > b[i]) {
                        return 1;
                    }
                }

                return 0;
                /*
                    Value     Condition
                    Less than zero     The substring in strA precedes the substring in strB in the sort order.
                    Zero     The substrings occur in the same position in the sort order, or length is zero.
                    Greater than zero     The substring in strA follows the substring in strB in the sort order.
                */
            }
            
            template < typename std_string_t >
            inline int32_t compare(const std_string_t& str1, std::size_t idx1, std::size_t len1, const std_string_t& str2, std::size_t idx2, std::size_t len2, const omni::string::compare_options& options)
            {
                // Verify inputs
                if (idx1 > (str1.size() - len1)) {
                    OMNI_ERR_RETV_FW("offset1 greater than length", omni::exceptions::index_out_of_range("offset1 greater than length"), 0)
                }
                if (idx2 > (str2.size()- len2)) {
                    OMNI_ERR_RETV_FW("offset2 greater than length", omni::exceptions::index_out_of_range("offset2 greater than length"), 0)
                }

                // Check for the null case.
                if (str1.empty()) {
                    return str2.empty() ? 0 : -1;
                } else if (str2.empty()) {
                    return 1;
                }

                bool ignore_case = options.has_flag(omni::string::compare_options::IGNORE_CASE);
                bool ignore_symbols = options.has_flag(omni::string::compare_options::IGNORE_SYMBOLS);

                std_string_t a = (ignore_case ? omni::string::util::to_lower(str1) : str1).substr(idx1, len1);
                std_string_t b = (ignore_case ? omni::string::util::to_lower(str2) : str2).substr(idx2, len2);
                
                // The number of characters to compare is the lesser of the lengths of the two substrings, and length.
                std::size_t comp_size = std::min(a.size(), b.size());
                for (std::size_t i = 0; i < comp_size; ++i) {
                    if (ignore_symbols && (!omni::char_util::is_alpha_digit(a[i]) || !omni::char_util::is_alpha_digit(b[i]))) {
                        continue;
                    }
                    if (a[i] < b[i]) {
                        return -1;
                    } else if (a[i] > b[i]) {
                        return 1;
                    }
                }

                return 0;
                /*
                    Value     Condition
                    Less than zero     The substring in strA precedes the substring in strB in the sort order.
                    Zero     The substrings occur in the same position in the sort order, or length is zero.
                    Greater than zero     The substring in strA follows the substring in strB in the sort order.
                */
            }

            template < typename std_string_t >
            bool ends_with(const std_string_t& haystack, const std_string_t& needle, bool ignore_case)
            {
                if (haystack.length() >= needle.length()) {
                    if (ignore_case) {
                        std_string_t tmp = omni::string::util::to_lower(haystack);
                        std_string_t tf = omni::string::util::to_lower(needle);
                        return (tmp.compare(tmp.length() - tf.length(), tf.length(), tf) == 0);
                    }
                    return (haystack.compare(haystack.length() - needle.length(), needle.length(), needle) == 0);
                }
                return false;
            }
            
            template < typename std_string_t, std::size_t X >
            bool ends_with(const std_string_t& haystack, const typename std_string_t::value_type (&needle)[X], bool ignore_case)
            {
                return omni::string::util::ends_with(haystack, std_string_t(needle), ignore_case);
            }
            
            template < typename std_string_t >
            inline bool ends_with(const std_string_t& haystack, const std_string_t& needle)
            {
                if (haystack.length() >= needle.length()) {
                    return (haystack.compare(haystack.length() - needle.length(), needle.length(), needle) == 0);
                }
                return false;
            }
            
            template < typename std_string_t, std::size_t X >
            inline bool ends_with(const std_string_t& haystack, const typename std_string_t::value_type (&needle)[X])
            {
                return omni::string::util::ends_with(haystack, std_string_t(needle));
            }
            
            template < typename std_string_t, typename T >
            std_string_t lexical_cast(const T& val)
            {
                return omni::string_util::omni_internal<std_string_t>::lexical_cast(val);
            }
            
            template < typename std_string_t >
            std_string_t pad_left(std_string_t str, typename std_string_t::value_type pad, std::size_t count)
            {
                if ((count == 0) || (static_cast<int64_t>(count - str.size()) <= 0)) { return str; }
                return str.insert(0, count - str.size(), pad);
            }

            template < typename std_string_t >
            std_string_t pad_left_full(const std_string_t& str, const std_string_t& pad, std::size_t count)
            {
                if (count == 0) { return str; }
                std_string_t ret(pad);
                while (count > 1) {
                    ret.append(pad);
                    --count;
                }
                return ret + str;
            }
            
            template < typename std_string_t, std::size_t X >
            std_string_t pad_left_full(std_string_t str, const typename std_string_t::value_type (&pad)[X], std::size_t count)
            {
                return omni::string::util::pad_left_full(str, std_string_t(pad), count);
            }

            template < typename std_string_t >
            std_string_t pad_right(std_string_t str, typename std_string_t::value_type pad, std::size_t count)
            {
                if ((count == 0) || (static_cast<int64_t>(count - str.size()) <= 0)) { return str; }
                return str.append(count - str.size(), pad);
            }

            template < typename std_string_t >
            std_string_t pad_right_full(std_string_t str, const std_string_t& pad, std::size_t count)
            {
                while (count > 0) {
                    str.append(pad);
                    --count;
                }
                return str;
            }
            
            template < typename std_string_t, std::size_t X >
            std_string_t pad_right_full(std_string_t str, const typename std_string_t::value_type (&pad)[X], std::size_t count)
            {
                return omni::string::util::pad_right_full(str, std_string_t(pad), count);
            }

            template < typename std_string_t >
            std_string_t replace(std_string_t str, const std_string_t& fnd, const std_string_t& newstr, std::size_t pos, bool ignore_case)
            {
                if (str.empty()) { return str; }
                if (fnd.empty()) { return str; }
                if (pos > str.size()) {
                    OMNI_ERR_RETV_FW("Position cannot be greater than string length", omni::exceptions::invalid_size(), str)
                }
                std::size_t spos = std_string_t::npos;
                if (ignore_case) {
                    spos = (omni::string::util::to_lower(str)).find(omni::string::util::to_lower(fnd), pos);
                } else {
                    spos = str.find(fnd, pos);
                }
                if (spos != std_string_t::npos) {
                    str.replace(spos, fnd.length(), newstr);
                }
                return str;
            }
            
            template < typename std_string_t, std::size_t X, std::size_t Y >
            std_string_t replace(std_string_t str, const typename std_string_t::value_type (&fnd)[X], const typename std_string_t::value_type (&newstr)[Y], std::size_t pos, bool ignore_case)
            {
                return omni::string::util::replace(str, std_string_t(fnd), std_string_t(newstr), pos, ignore_case);
            }

            template < typename std_string_t >
            std_string_t replace_all(std_string_t str, const std_string_t& fnd, const std_string_t& newstr, std::size_t pos, bool ignore_case)
            {
                if (str.empty()) { return str; }
                if (fnd.empty()) { return str; }
                if (pos > str.size()) {
                    OMNI_ERR_RETV_FW("Position cannot be greater than string length", omni::exceptions::invalid_size(), str)
                }
                std::size_t nsz = newstr.size();
                std::size_t fsz = fnd.size();
                std::size_t spos = std_string_t::npos;
                if (ignore_case) {
                    std_string_t lstr = omni::string::util::to_lower(str);
                    std_string_t lfnd = omni::string::util::to_lower(fnd);
                    spos = lstr.find(lfnd, pos);
                    while (spos != std_string_t::npos) {
                        str.replace(spos, fsz, newstr);
                        lstr.replace(spos, fsz, newstr);
                        spos = lstr.find(lfnd, spos + nsz);
                    }
                } else {
                    spos = str.find(fnd, pos);
                    while (spos != std_string_t::npos) {
                        str.replace(spos, fsz, newstr);
                        spos = str.find(fnd, spos + nsz);
                    }
                }
                return str;
            }
            
            template < typename std_string_t, std::size_t X, std::size_t Y >
            std_string_t replace_all(const std_string_t& str, const typename std_string_t::value_type (&fnd)[X], const typename std_string_t::value_type (&newstr)[Y], std::size_t pos, bool ignore_case)
            {
                return omni::string::util::replace_all(str, std_string_t(fnd), std_string_t(newstr), pos, ignore_case);
            }

            template < typename std_string_t >
            std_string_t reverse(std_string_t str)
            {
                std::reverse(str.begin(), str.end());
                return str;
            }
            
            template < std::size_t X >
            inline std::wstring reverse(const wchar_t (&str)[X])
            {
                return omni::string::util::reverse(std::wstring(str));
            }
            
            template < std::size_t X >
            inline std::string reverse(const char (&str)[X])
            {
                return omni::string::util::reverse(std::string(str));
            }
            
            template < template < class, class > class std_seq_t, class std_string_t, class std_allocator_t >
            std_seq_t<std_string_t, std_allocator_t> split(std_string_t str, const std_string_t& delimeter, std::size_t max_val)
            {
                std_seq_t<std_string_t, std_allocator_t> ret;
                if (str.empty()) { return ret; }
                if (max_val == 1) { // If max is 1, then they only want 1 substring, which means the string they sent in
                    ret.push_back(str);
                    return ret;
                }
                if (delimeter.empty()) {
                    typename std_string_t::const_iterator citr = str.begin();
                    while (citr != str.end()) {
                        ret.push_back(std_string_t(citr, ++citr));
                        if ((max_val > 0) && (--max_val)) {
                            ret.push_back(std_string_t(citr, ++citr));
                            break;
                        }
                    }
                    if (citr != str.end()) {
                        typename std_string_t::const_iterator eitr = str.end();
                        ret.push_back(std_string_t(citr, eitr));
                    }
                } else {
                    std::size_t f = str.find(delimeter);
                    while (f != std::string::npos) {
                        ret.push_back(str.substr(0, f));
                        str.erase(0, f+delimeter.size());
                        f = str.find(delimeter);
                        if ((max_val > 0) && (--max_val)) {
                            break;
                        }
                    }
                    ret.push_back(str);
                }
                return ret;
            }
            
            template < template < class, class > class std_seq_t, class std_string_t >
            inline std_seq_t<std_string_t, std::allocator<std_string_t> > split(const std_string_t& str, const std_string_t& delimeter, std::size_t max_val)
            {
                return omni::string::util::split< std_seq_t, std_string_t, std::allocator<std_string_t> >(str, delimeter, max_val);
            }
            
            template < typename std_string_t >
            inline omni_sequence_t<std_string_t> split(const std_string_t& str, const std_string_t& delimeter, std::size_t max_val)
            {
                return omni::string::util::split< omni_sequence_t, std_string_t >(str, delimeter, max_val);
            }
            
            template < typename std_string_t >
            inline omni_sequence_t<std_string_t> split(const std_string_t& str, const std_string_t& delimeter)
            {
                return omni::string::util::split(str, delimeter, 0);
            }

            template < typename std_string_t, std::size_t X >
            inline omni_sequence_t<std::string> split(const std_string_t& str, const typename std_string_t::value_type (&delimeter)[X])
            {
                return omni::string::util::split(str, std_string_t(delimeter), 0);
            }
            
            template < std::size_t X, std::size_t Y >
            inline omni_sequence_t<std::string> split(const char (&str)[X], const char (&delimeter)[Y], std::size_t max_val)
            {
                return omni::string::util::split(std::string(str), std::string(delimeter), max_val);
            }
            
            template < std::size_t X, std::size_t Y >
            inline omni_sequence_t<std::string> split(const char (&str)[X], const char (&delimeter)[Y])
            {
                return omni::string::util::split(std::string(str), std::string(delimeter), 0);
            }
            
            template < std::size_t X, std::size_t Y >
            inline omni_sequence_t<std::wstring> split(const wchar_t (&str)[X], const wchar_t (&delimeter)[Y], std::size_t max_val)
            {
                return omni::string::util::split(std::wstring(str), std::wstring(delimeter), max_val);
            }
            
            template < std::size_t X, std::size_t Y >
            inline omni_sequence_t<std::wstring> split(const wchar_t (&str)[X], const wchar_t (&delimeter)[Y])
            {
                return omni::string::util::split(std::wstring(str), std::wstring(delimeter), 0);
            }
            
            inline omni_sequence_t<std::string> split(const char* str, const char* delimeter, std::size_t max_val)
            {
                return omni::string::util::split< omni_sequence_t >(std::string(str), std::string(delimeter), max_val);
            }
            
            inline omni_sequence_t<std::string> split(const char* str, const char* delimeter)
            {
                return omni::string::util::split< omni_sequence_t >(std::string(str), std::string(delimeter), 0);
            }
            
            inline omni_sequence_t<std::wstring> split(const wchar_t* str, const wchar_t* delimeter, std::size_t max_val)
            {
                return omni::string::util::split< omni_sequence_t >(std::wstring(str), std::wstring(delimeter), max_val);
            }
            
            inline omni_sequence_t<std::wstring> split(const wchar_t* str, const wchar_t* delimeter)
            {
                return omni::string::util::split< omni_sequence_t >(std::wstring(str), std::wstring(delimeter), 0);
            }

            template < typename std_string_t >
            bool starts_with(const std_string_t& haystack, const std_string_t& needle, bool ignore_case)
            {
                if (haystack.length() >= needle.length()) {
                    if (ignore_case) {
                        std_string_t tmp = omni::string::util::to_lower(haystack);
                        std_string_t tf = omni::string::util::to_lower(needle);
                        return (tmp.find(tf) == 0);
                    }
                    return (haystack.find(needle) == 0);
                }
                return false;
            }
            
            template < typename std_string_t, std::size_t X >
            bool starts_with(const std_string_t& haystack, const typename std_string_t::value_type (&needle)[X], bool ignore_case)
            {
                return omni::string::util::starts_with(haystack, std_string_t(needle), ignore_case);
            }
            
            template < typename std_string_t >
            inline bool starts_with(const std_string_t& haystack, const std_string_t& needle)
            {
                if (haystack.length() >= needle.length()) {
                    return (haystack.find(needle) == 0);
                }
                return false;
            }
            
            template < typename std_string_t, std::size_t X >
            inline bool starts_with(const std_string_t& haystack, const typename std_string_t::value_type (&needle)[X])
            {
                return omni::string::util::starts_with(haystack, std_string_t(needle));
            }
            
            template < typename T >
            inline std::string to_string(const T& val)
            {
                return omni::string_util::to_string(val);
            }
            
            template < std::size_t X >
            inline std::string to_string(const wchar_t (&str)[X])
            {
                return omni::string_util::to_string(std::wstring(str));
            }
            
            template < std::size_t X >
            inline std::string to_string(const char (&str)[X])
            {
                return std::string(str);
            }
            
            template < typename T >
            inline std::wstring to_wstring(const T& val)
            {
                return omni::string_util::to_wstring(val);
            }
            
            template < std::size_t X >
            inline std::wstring to_wstring(const wchar_t (&str)[X])
            {
                return std::wstring(str);
            }
            
            template < std::size_t X >
            inline std::wstring to_wstring(const char (&str)[X])
            {
                return omni::string_util::to_wstring(std::string(str));
            }
            
            template < typename T >
            inline omni::string_t to_string_t(const T& val)
            {
                return omni::string_util::to_string_t(val);
            }
            
            template < std::size_t X >
            inline omni::string_t to_string_t(const wchar_t (&str)[X])
            {
                return omni::string_util::to_string_t(std::wstring(str));
            }
            
            template < std::size_t X >
            inline omni::string_t to_string_t(const char (&str)[X])
            {
                return omni::string_util::to_string_t(std::string(str));
            }
            
            template < typename T >
            inline T to_type(const std::string& str)
            {
                if (str.empty()) { return T(); }
                T ret;                
                std::stringstream in(str);
                in >> ret;
                return ret;
            }
            
            template <>
            inline bool to_type<bool>(const std::string& str)
            {
                if (!str.empty()) {
                    std::string tmp(str);
                    std::size_t pos = tmp.find_first_not_of("\t \n\r\0");
                    if ((pos != std::string::npos) && (pos > 0)) {
                        tmp = tmp.substr(pos);
                    }
                    pos = tmp.find_last_not_of("\t \n\r\0");
                    if (pos != std::string::npos) {
                        tmp.erase(pos + 1);
                    } else {
                        tmp.clear();
                    }
                    std::size_t sz = tmp.size();
                    if (sz > 0) {
                        if (tmp.find_first_of("tTfF") == 0) {
                            // T/F or true/false??
                            switch (sz) {
                                case 1: {
                                    switch (tmp[0]) {
                                        case 't': case 'T': return true;
                                        case 'f': case 'F': return false;
                                    }
                                } break;
                                case 4: {
                                    if ((tmp[0] == 't' || tmp[0] == 'T') &&
                                        (tmp[1] == 'r' || tmp[1] == 'R') &&
                                        (tmp[2] == 'u' || tmp[2] == 'U') &&
                                        (tmp[3] == 'e' || tmp[3] == 'E'))
                                    {
                                        return true;
                                    }
                                } break;
                                case 5: {
                                    if ((tmp[0] == 'f' || tmp[0] == 'F') &&
                                        (tmp[1] == 'a' || tmp[1] == 'A') &&
                                        (tmp[2] == 'l' || tmp[2] == 'L') &&
                                        (tmp[3] == 's' || tmp[3] == 'S') &&
                                        (tmp[4] == 'e' || tmp[4] == 'E'))
                                    {
                                        return false;
                                    }
                                } break;
                            }
                            // it's not a true/false string, so fall through
                        }
                    }
                }
                OMNI_ERR_RETV_FW("Invalid boolean string specified", omni::exceptions::invalid_parse("Invalid boolean string specified"), false)
            }
            
            template < typename T >
            inline T to_type(const char* str)
            {
                if (str) { return omni::string::util::to_type<T>(std::string(str)); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), T())
            }
            
            template < typename T >
            inline T to_type(const std::wstring& str)
            {
                if (str.empty()) { return T(); }
                T ret;
                std::wstringstream in(str);
                in >> ret;
                return ret;
            }
            
            template <>
            inline bool to_type<bool>(const std::wstring& str)
            {
                if (!str.empty()) {
                    std::wstring tmp(str);
                    std::size_t pos = tmp.find_first_not_of(L"\t \n\r\0");
                    if ((pos != std::wstring::npos) && (pos > 0)) {
                        tmp = tmp.substr(pos);
                    }
                    pos = tmp.find_last_not_of(L"\t \n\r\0");
                    if (pos != std::wstring::npos) {
                        tmp.erase(pos + 1);
                    } else {
                        tmp.clear();
                    }
                    std::size_t sz = tmp.size();
                    if (sz > 0) {
                        if (tmp.find_first_of(L"tTfF") == 0) {
                            // T/F or true/false??
                            switch (sz) {
                                case 1: {
                                    switch (tmp[0]) {
                                        case L't': case L'T': return true;
                                        case L'f': case L'F': return false;
                                    }
                                } break;
                                case 4: {
                                    if ((tmp[0] == L't' || tmp[0] == L'T') &&
                                        (tmp[1] == L'r' || tmp[1] == L'R') &&
                                        (tmp[2] == L'u' || tmp[2] == L'U') &&
                                        (tmp[3] == L'e' || tmp[3] == L'E'))
                                    {
                                        return true;
                                    }
                                } break;
                                case 5: {
                                    if ((tmp[0] == L'f' || tmp[0] == L'F') &&
                                        (tmp[1] == L'a' || tmp[1] == L'A') &&
                                        (tmp[2] == L'l' || tmp[2] == L'L') &&
                                        (tmp[3] == L's' || tmp[3] == L'S') &&
                                        (tmp[4] == L'e' || tmp[4] == L'E'))
                                    {
                                        return false;
                                    }
                                } break;
                            }
                            // it's not a true/false string, so fall through
                        }
                    }
                }
                OMNI_ERR_RETV_FW("Invalid boolean string specified", omni::exceptions::invalid_parse("Invalid boolean string specified"), false)
            }
            
            template < typename T >
            inline T to_type(const wchar_t* str)
            {
                if (str) { return omni::string::util::to_type<T>(std::wstring(str)); }
                OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), T())
            }

            template < typename T >
            inline T to_type(const std::string& str, uint8_t base)
            {
                if (base == 10) {
                    return omni::string::util::to_type<T>(str);
                }
                return static_cast<T>(std::strtoul(str.c_str(), 0, base));
            }

            template <>
            inline bool to_type<bool>(const std::string& str, uint8_t base)
            {
                OMNI_UNUSED(base);
                return omni::string::util::to_type<bool>(str);
            }

            template < typename T >
            inline T to_type(const char* str, uint8_t base)
            {
                if (!str) { OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), T()) }
                return omni::string::util::to_type<T>(std::string(str), base);
            }

            template < typename T >
            inline T to_type(const std::wstring& str, uint8_t base)
            {
                if (base == 10) {
                    return omni::string::util::to_type<T>(str);
                }
                return static_cast<T>(std::strtoul(omni::string::util::to_string(str).c_str(), 0, base));
            }

            template <>
            inline bool to_type<bool>(const std::wstring& str, uint8_t base)
            {
                OMNI_UNUSED(base);
                return omni::string::util::to_type<bool>(str);
            }

            template < typename T >
            inline T to_type(const wchar_t* str, uint8_t base)
            {
                if (!str) { OMNI_ERR_RETV_FW("Null pointer specified", omni::exceptions::null_pointer_exception(), T()) }
                if (base == 10) {
                    return omni::string::util::to_type<T>(std::wstring(str));
                }
                return static_cast<T>(std::strtoul(omni::string::util::to_string(str).c_str(), 0, base));
            }
                        
            template < typename std_string_t >
            std_string_t trim_front_syschars(std_string_t str)
            {
                if (str.empty()) { return str; }
                std::size_t end = std_string_t::npos;
                for (std::size_t i = 0; i < str.length(); ++i) {
                    end = i;
                    if (static_cast<std::size_t>(str[i]) > 31) { break; }
                    ++end;
                }
                if (end > 0) { // if end == 0, that is the whole string, so only return if >0
                    if (end == str.length()) { // if end == len, there is nothing left, return empty
                        return std_string_t();
                    }
                    return str.substr(end);
                }
                return str;
            }
            
            template < typename std_string_t >
            std_string_t trim_front(std_string_t str, std_string_t params)
            {
                if (str.empty() || params.empty()) { return str; }
                std::size_t pos = str.find_first_not_of(params);
                if ((pos != std_string_t::npos) && (pos > 0)) {
                    return str.substr(pos);
                }
                return str;
            }
            
            template < typename std_string_t >
            std_string_t trim_front(std_string_t str)
            {
                return omni::string::util::trim_front(
                            omni::string::util::trim_front_syschars(str),
                            omni::string::util::lexical_cast<std_string_t>("\t \n\r\0")
                     );
            }
            
            template < typename std_string_t >
            std_string_t trim_front(std_string_t str, const typename std_string_t::value_type param)
            {
                std_string_t params(1, param);
                return omni::string::util::trim_front(str, params);
            }
            
            template < typename std_string_t, std::size_t X >
            std_string_t trim_front(std_string_t str, const typename std_string_t::value_type (&params)[X])
            {
                return omni::string::util::trim_front(str, std_string_t(params));
            }
            
            template < typename std_string_t, typename iterator_t >
            std_string_t trim_front(std_string_t str, iterator_t begin, iterator_t end)
            {
                std_string_t params(begin, end);
                return omni::string::util::trim_front(str, params);
            }
            
            template < typename std_string_t >
            std_string_t trim_end_syschars(std_string_t str)
            {
                if (str.empty()) { return str; }
                std::size_t end = str.length();
                for (std::size_t i = end; i > 0; --i, --end) {
                    if (static_cast<std::size_t>(str[i]) > 31) { break; }
                }
                if (++end < str.length()) { return str.substr(0, end); }
                return str;
            }
            
            template < typename std_string_t >
            std_string_t trim_end(std_string_t str, std_string_t params)
            {
                if (str.empty() || params.empty()) { return str; }
                std::size_t pos = str.find_last_not_of(params);
                if (pos != std_string_t::npos) {
                    str.erase(pos + 1);
                } else {
                    str.clear();
                }
                return str;
            }
            
            template < typename std_string_t >
            std_string_t trim_end(std_string_t str)
            {
                return omni::string::util::trim_end(
                            omni::string::util::trim_end_syschars(str),
                            omni::string::util::lexical_cast<std_string_t>("\t \n\r\0")
                     );
            }
            
            template < typename std_string_t >
            std_string_t trim_end(std_string_t str, const typename std_string_t::value_type param)
            {
                std_string_t params(1, param);
                return omni::string::util::trim_end(str, params);
            }
            
            template < typename std_string_t, std::size_t X >
            std_string_t trim_end(std_string_t str, const typename std_string_t::value_type (&params)[X])
            {
                return omni::string::util::trim_end(str, std_string_t(params));
            }
            
            template < typename std_string_t, typename iterator_t >
            std_string_t trim_end(std_string_t str, iterator_t begin, iterator_t end)
            {
                std_string_t params(begin, end);
                return omni::string::util::trim_end(str, params);
            }
            
            template < typename std_string_t >
            std_string_t trim(std_string_t str, std_string_t params)
            {
                if (str.empty()) { return str; }
                str = omni::string::util::trim_front(str, params);
                return omni::string::util::trim_end(str, params);
            }
            
            template < typename std_string_t >
            std_string_t trim_syschars(std_string_t str)
            {
                str = omni::string::util::trim_front_syschars(str);
                return omni::string::util::trim_end_syschars(str);
            }
            
            template < typename std_string_t >
            std_string_t trim(std_string_t str)
            {
                if (str.empty()) { return str; }
                // Trim Both leading and trailing spaces
                str = omni::string::util::trim_front(str);
                return omni::string::util::trim_end(str);
            }
            
            template < typename std_string_t >
            std_string_t trim(std_string_t str, const typename std_string_t::value_type param)
            {
                std_string_t params(1, param);
                return omni::string::util::trim(str, params);
            }
            
            template < typename std_string_t, std::size_t X >
            std_string_t trim(std_string_t str, const typename std_string_t::value_type (&params)[X])
            {
                return omni::string::util::trim(str, std_string_t(params));
            }
            
            template < typename std_string_t, typename iterator_t >
            std_string_t trim(std_string_t str, iterator_t begin, iterator_t end)
            {
                std_string_t params(begin, end);
                return omni::string::util::trim(str, params);
            }
            
            namespace binary {
                template < typename std_string_t >
                bool is_valid(const std_string_t& str)
                {
                    if (str.empty()) { return false; }
                    typename std_string_t::const_iterator itr = str.begin();
                    while (itr != str.end()) {
                        if (!omni::char_util::helpers::is_1or0(*itr)) { return false; }
                        ++itr;
                    }
                    return true;
                }
                
                template < typename std_string_t >
                std_string_t from_ulong(unsigned long val, bool trim)
                {
                    /* DEV_NOTE: some older compilers complain about the to_string, the workaround is
                    to give the full to_string template parameters with the char type (for a std::string) */
                    std::string ret = std::bitset<OMNI_SIZEOF_BITS(unsigned long)>
                        (static_cast<uint64_t>(val)).
                        to_string<char, std::char_traits<char>, std::allocator<char> >();
                    if (trim) {
                        std::string::iterator itr = ret.begin();
                        while (itr != ret.end()) {
                            if (*itr == '0') {
                                ret.erase(itr);
                                --itr;
                            }
                            else { break; }
                            ++itr;
                        }
                    }
                    return omni::string::util::lexical_cast<std_string_t>(ret);
                }
                
                template < typename std_string_t >
                std_string_t from_ulong(unsigned long val)
                {
                    return omni::string::util::binary::from_ulong<std_string_t>(val, true);
                }
                
                template < typename std_string_t >
                std_string_t from_uint(unsigned int val, bool trim)
                {
                    return omni::string::util::binary::from_ulong<std_string_t>(static_cast<unsigned long>(val), trim);
                }
                
                template < typename std_string_t >
                std_string_t from_uint(unsigned int val)
                {
                    return omni::string::util::binary::from_ulong<std_string_t>(static_cast<unsigned long>(val), true);
                }
                
                template < typename std_string_t >
                unsigned int to_uint(const std_string_t& str)
                {
                    if (!omni::string::util::binary::is_valid(str)) {
                        OMNI_ERR_RETV_FW(OMNI_STRING_INVALID_SIZE_STR, omni::exceptions::invalid_binary_size(), 0)
                    }
                    const std::size_t msz = OMNI_SIZEOF_BITS(unsigned int);
                    if (str.length() > msz) {
                        OMNI_ERR_RETV_FW(OMNI_STRING_INVALID_SIZE_STR, omni::exceptions::invalid_binary_size(), 0)
                    }
                    return static_cast<unsigned int>(std::bitset<msz>(omni::string::util::to_string(str)).to_ulong());
                }
                
                template < typename std_string_t >
                unsigned long to_ulong(const std_string_t& str)
                {
                    if (!omni::string::util::binary::is_valid(str)) {
                        OMNI_ERR_RETV_FW(OMNI_STRING_INVALID_SIZE_STR, omni::exceptions::invalid_binary_size(), 0)
                    }
                    const std::size_t msz = OMNI_SIZEOF_BITS(unsigned long);
                    if (str.length() > msz) {
                        OMNI_ERR_RETV_FW(OMNI_STRING_INVALID_SIZE_STR, omni::exceptions::invalid_binary_size(), 0)
                    }
                    return (std::bitset<msz>(omni::string::util::to_string(str)).to_ulong());
                }
                
                template < typename std_string_t >
                std::size_t to_size_t(const std_string_t& str)
                {
                    if (!omni::string::util::binary::is_valid(str)) {
                        OMNI_ERR_RETV_FW(OMNI_STRING_INVALID_SIZE_STR, omni::exceptions::invalid_binary_size(), 0)
                    }
                    if (str.length() > OMNI_SIZEOF_BITS(std::size_t)) {
                        OMNI_ERR_RETV_FW(OMNI_STRING_INVALID_SIZE_STR, omni::exceptions::invalid_binary_size(), 0)
                    }
                    const std::size_t msz = OMNI_SIZEOF_BITS(unsigned long);
                    std::string tmp(omni::string::util::to_string(str));
                    std::size_t len = tmp.length();
                    if (len % 2 != 0) {
                        tmp.insert(0, "0");
                        len = tmp.length();
                    }
                    std::size_t l2 = len / 2;
                    std::size_t hi = (std::bitset<msz>(tmp.substr(0, l2)).to_ulong());
                    unsigned long lo = (std::bitset<msz>(tmp.substr(l2)).to_ulong());
                    std::size_t ret = (hi << (sizeof(std::size_t)/2)) ^ lo;
                    return ret;
                }
            } // namespace binary
        } // namespace util

        /* DEV_NOTE: Some thoughts behind the separation of logic in string namespaces.
            
            If OMNI_UNICODE is defined, then
                the omni::string_t type is a std::wstring
            if it is not defined, then
                the omni::string_t type is a std::string
            
            The omni::cstring namespace functions operate on std::string types
            The omni::wstring namespace functions operate on std::wstring types
            The omni::string namespace functions operate on omni::string_t types
            
            So if OMNI_UNICODE is defined, then
                the omni::string_t type is a std::wstring
                so omni::string namespace functions can operate on omni::string_t and std::wstring
                and omni::wstring namespace functions can operate on std::wstring and omni::string_t
            if it is not defined, then
                the omni::string_t type is a std::string
                so omni::string namespace functions can operate on omni::string_t and std::string
                and omni::cstring namespace functions can operate on std::string and omni::string_t
                
            This gives a developer options to develop specific builds while still having access
            to different string utility functions. You might want to make a build with the
            omni::string_t as a std::wstring type, but might want to specifically check against
            a std::string type (i.e. ensure type safety), so you can still use the omni::string
            namespace functions as your default types then use the omni::cstring namespace
            to check on a std::string type.
            
            It should be noted that the omni::string/cstring/wstring namespaces are merely
            type safe convenience wrappers to the omni::string::util namespace, which contains
            the same functions, but templated for ease of reuse (e.g. you could call
            omni::string::util::trim<std::string>(str, "ABC"), or, if a specific 3rd party
            library had another type of base string type, you could potentially call
            omni::string::util::trim<SomeOtherStringType>(str, "ABC"))
        */
        #if defined(OMNI_UNICODE)
            // UTF-16/wchar_t/std::wstring/omni::wstring
            #define OMNI_CHAR_T_FW wchar_t
            #define OMNI_STRING_T_FW std::wstring
            #include <omni/xx/string.hxx>
            #undef OMNI_CHAR_T_FW
            #undef OMNI_STRING_T_FW
        #else
            // UTF-8/char/std::string/omni::cstring
            #define OMNI_CHAR_T_FW char
            #define OMNI_STRING_T_FW std::string
            #include <omni/xx/string.hxx>
            #undef OMNI_CHAR_T_FW
            #undef OMNI_STRING_T_FW
        #endif
    } // namespace string
}

#endif // OMNI_STRING_UTIL_HPP