technician1 commited on
Commit
defb949
·
1 Parent(s): 434c5af

Upload 2 files

Browse files
Files changed (1) hide show
  1. ChatIPC.cpp +177 -55
ChatIPC.cpp CHANGED
@@ -309,7 +309,7 @@ static std::vector<std::string> tokenize_whitespace(const std::string &s){
309
  return out;
310
  }
311
 
312
- // Static helper to check dictionary presence using your existing pos cache
313
  static inline bool check_dictionary(const std::string &word) {
314
  return !dictionary_pos_for_token(word).empty();
315
  }
@@ -484,8 +484,78 @@ static std::optional<std::string> get_valid_base_form(const std::string &word) {
484
  return std::nullopt;
485
  }
486
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  static std::vector<std::string> tokenize_others(const std::string &s) {
488
- // Step A: Check if the entire input string already has a dictionary definition.
489
  if (check_dictionary(s)) {
490
  std::string lower_s;
491
  lower_s.reserve(s.size());
@@ -495,15 +565,29 @@ static std::vector<std::string> tokenize_others(const std::string &s) {
495
  return { lower_s };
496
  }
497
 
 
 
 
 
 
 
 
 
498
  std::vector<std::string> out;
499
  std::string cur;
500
 
501
- // Lambda to flush the accumulated token buffer, validate it, and add to output
502
  auto flush = [&]() {
503
  if (!cur.empty()) {
504
- auto valid_base = get_valid_base_form(cur);
505
- if (valid_base.has_value()) {
506
- out.push_back(valid_base.value());
 
 
 
 
 
 
 
507
  }
508
  cur.clear();
509
  }
@@ -513,26 +597,42 @@ static std::vector<std::string> tokenize_others(const std::string &s) {
513
  unsigned char uc = static_cast<unsigned char>(s[i]);
514
  char ch = static_cast<char>(uc);
515
 
516
- // Split on spaces, underscores, hyphens, and slashes
517
- if (ch == '_' || ch == '-' || ch == '/' || std::isspace(uc)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  flush();
519
  continue;
520
  }
521
 
522
  const bool is_upper = std::isupper(uc) != 0;
523
  bool camel_boundary = false;
524
-
525
  if (is_upper && !cur.empty()) {
526
  unsigned char prev = static_cast<unsigned char>(s[i - 1]);
527
  const bool prev_lower_or_digit = (std::islower(prev) != 0) || (std::isdigit(prev) != 0);
528
  const bool prev_upper = std::isupper(prev) != 0;
529
- const bool next_lower =
530
- (i + 1 < s.size()) && (std::islower(static_cast<unsigned char>(s[i + 1])) != 0);
531
-
532
  camel_boundary = prev_lower_or_digit || (prev_upper && next_lower);
533
  }
534
 
535
- // Split on transitions between alphabetical characters and digits (e.g., "book5read")
536
  bool digit_boundary = false;
537
  if (!cur.empty()) {
538
  unsigned char prev = static_cast<unsigned char>(s[i - 1]);
@@ -553,7 +653,6 @@ static std::vector<std::string> tokenize_others(const std::string &s) {
553
  flush();
554
  }
555
  }
556
-
557
  flush();
558
  return out;
559
  }
@@ -635,64 +734,87 @@ static void build_def_tokens_cache(){
635
  global_def_tokens_cache.clear();
636
  global_pos_cache.clear();
637
 
638
- global_def_tokens_cache.reserve(global_dictionary_entries.size());
639
- global_pos_cache.reserve(global_dictionary_entries.size());
640
 
641
- for (const auto &entry : global_dictionary_entries){
642
- // 1. Tokenize definitions once per entry to avoid redundant processing
643
- std::vector<std::string> all_def_toks;
644
- for (const auto &def : entry.definitions){
645
- auto toks = tokenize_others(def);
646
- all_def_toks.insert(all_def_toks.end(), toks.begin(), toks.end());
647
- }
648
 
649
- std::string pos = normalize_pos_tag(entry.pos);
 
 
650
 
651
- // 2. Split entry.word by semicolons or commas
652
- std::vector<std::string> sub_words;
653
- std::string current_sub;
654
- for (char c : entry.word) {
655
- if (c == ';' || c == ',') {
656
- if (!current_sub.empty()) {
657
- sub_words.push_back(current_sub);
658
- current_sub.clear();
659
- }
660
- } else {
661
- current_sub.push_back(c);
662
  }
663
- }
664
- if (!current_sub.empty()) {
665
- sub_words.push_back(current_sub);
666
- }
667
 
668
- // 3. Register each sub-word to the cache
669
- for (size_t i = 0; i < sub_words.size(); ++i) {
670
- const std::string key = normalize_dictionary_key(sub_words[i]);
671
- if (key.empty()) continue;
672
 
673
- if (!pos.empty()) {
674
- // Move on the final sub-word, copy otherwise
675
- if (i == sub_words.size() - 1) {
676
- global_pos_cache[key].push_back(std::move(pos));
 
 
 
 
677
  } else {
678
- global_pos_cache[key].push_back(pos);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
  }
 
 
680
  }
 
681
 
682
- auto &defs = global_def_tokens_cache[key];
683
- defs.insert(defs.end(), all_def_toks.begin(), all_def_toks.end());
 
 
 
 
 
 
 
 
684
  }
685
  }
686
 
687
- // 4. Keep existing sorting and deduplication logic intact
688
- for (auto &pr : global_def_tokens_cache){
689
- auto &v = pr.second;
 
 
 
 
 
690
  std::sort(v.begin(), v.end());
691
  v.erase(std::unique(v.begin(), v.end()), v.end());
692
  }
693
 
694
- for (auto &pr : global_pos_cache){
695
- auto &v = pr.second;
 
 
 
 
 
696
  std::sort(v.begin(), v.end());
697
  v.erase(std::unique(v.begin(), v.end()), v.end());
698
  }
 
309
  return out;
310
  }
311
 
312
+ // Static helper to check dictionary presence using the existing pos cache
313
  static inline bool check_dictionary(const std::string &word) {
314
  return !dictionary_pos_for_token(word).empty();
315
  }
 
484
  return std::nullopt;
485
  }
486
 
487
+ // Helper arrays for number-to-words
488
+ static const char* const ones[] = {"", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
489
+ "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
490
+ "seventeen", "eighteen", "nineteen"};
491
+ static const char* const tens[] = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
492
+ static const char* const scales[] = {"", "thousand", "million", "billion", "trillion", "quadrillion",
493
+ "quintillion", "sextillion", "septillion", "octillion", "nonillion",
494
+ "decillion", "undecillion", "duodecillion", "tredecillion",
495
+ "quattuordecillion", "quindecillion", "sexdecillion", "septendecillion",
496
+ "octodecillion", "novemdecillion", "vigintillion", "googol"};
497
+
498
+ static std::vector<std::string> digit_to_words(const std::string& s) {
499
+ std::vector<std::string> words;
500
+ if (s.empty()) return words;
501
+
502
+ // Strip leading zeros
503
+ size_t first_non_zero = s.find_first_not_of('0');
504
+ if (first_non_zero == std::string::npos) {
505
+ words.push_back("zero");
506
+ return words;
507
+ }
508
+ std::string num = s.substr(first_non_zero);
509
+
510
+ // If it's absurdly large (e.g. googolplex logic), fall back to single digits to prevent overflow
511
+ // and maintain semantic definitions of the numbers.
512
+ if (num.length() > 69) {
513
+ for (char c : num) {
514
+ words.push_back(ones[c - '0']);
515
+ }
516
+ return words;
517
+ }
518
+
519
+ int scale_idx = 0;
520
+ while (!num.empty()) {
521
+ int chunk_len = std::min<int>(3, num.length());
522
+ std::string chunk_str = num.substr(num.length() - chunk_len);
523
+ num = num.substr(0, num.length() - chunk_len);
524
+
525
+ int chunk = std::stoi(chunk_str);
526
+ if (chunk > 0) {
527
+ std::vector<std::string> chunk_words;
528
+ int h = chunk / 100;
529
+ int remainder = chunk % 100;
530
+
531
+ if (h > 0) {
532
+ chunk_words.push_back(ones[h]);
533
+ chunk_words.push_back("hundred");
534
+ }
535
+
536
+ if (remainder > 0) {
537
+ if (remainder < 20) {
538
+ chunk_words.push_back(ones[remainder]);
539
+ } else {
540
+ chunk_words.push_back(tens[remainder / 10]);
541
+ if (remainder % 10 > 0) {
542
+ chunk_words.push_back(ones[remainder % 10]);
543
+ }
544
+ }
545
+ }
546
+
547
+ if (scale_idx > 0 && scale_idx < static_cast<int>(sizeof(scales)/sizeof(scales[0]))) {
548
+ chunk_words.push_back(scales[scale_idx]);
549
+ }
550
+
551
+ words.insert(words.begin(), chunk_words.begin(), chunk_words.end());
552
+ }
553
+ scale_idx++;
554
+ }
555
+ return words;
556
+ }
557
+
558
  static std::vector<std::string> tokenize_others(const std::string &s) {
 
559
  if (check_dictionary(s)) {
560
  std::string lower_s;
561
  lower_s.reserve(s.size());
 
565
  return { lower_s };
566
  }
567
 
568
+ // Convert pure digits to words
569
+ bool is_all_digits = !s.empty() && std::all_of(s.begin(), s.end(), [](unsigned char c) {
570
+ return std::isdigit(c) != 0;
571
+ });
572
+ if (is_all_digits) {
573
+ return digit_to_words(s);
574
+ }
575
+
576
  std::vector<std::string> out;
577
  std::string cur;
578
 
 
579
  auto flush = [&]() {
580
  if (!cur.empty()) {
581
+ // Check numbers inside mixed tokens (e.g. "word123")
582
+ bool cur_all_digits = std::all_of(cur.begin(), cur.end(), [](unsigned char c) { return std::isdigit(c) != 0; });
583
+ if (cur_all_digits) {
584
+ auto words = digit_to_words(cur);
585
+ out.insert(out.end(), words.begin(), words.end());
586
+ } else {
587
+ auto valid_base = get_valid_base_form(cur);
588
+ if (valid_base.has_value()) {
589
+ out.push_back(valid_base.value());
590
+ }
591
  }
592
  cur.clear();
593
  }
 
597
  unsigned char uc = static_cast<unsigned char>(s[i]);
598
  char ch = static_cast<char>(uc);
599
 
600
+ // Check for Operator/Symbol extraction
601
+ if (std::ispunct(uc) || (std::isprint(uc) && !std::isalnum(uc) && !std::isspace(uc))) { flush();
602
+ std::string sym(1, ch);
603
+
604
+ // Check for double-character operators (==, <=, >=, !=, ++, --, &&, ||, <<, >>)
605
+ if (i + 1 < s.size()) {
606
+ unsigned char nxt_uc = static_cast<unsigned char>(s[i+1]);
607
+ if (std::ispunct(nxt_uc) || (std::isprint(nxt_uc) && !std::isalnum(nxt_uc) && !std::isspace(nxt_uc))) { std::string sym2 = sym + static_cast<char>(nxt_uc);
608
+ if (check_dictionary(sym2)) {
609
+ out.push_back(sym2);
610
+ ++i;
611
+ continue;
612
+ }
613
+ }
614
+ }
615
+ if (check_dictionary(sym)) {
616
+ out.push_back(sym);
617
+ }
618
+ continue;
619
+ }
620
+
621
+ if (std::isspace(uc)) {
622
  flush();
623
  continue;
624
  }
625
 
626
  const bool is_upper = std::isupper(uc) != 0;
627
  bool camel_boundary = false;
 
628
  if (is_upper && !cur.empty()) {
629
  unsigned char prev = static_cast<unsigned char>(s[i - 1]);
630
  const bool prev_lower_or_digit = (std::islower(prev) != 0) || (std::isdigit(prev) != 0);
631
  const bool prev_upper = std::isupper(prev) != 0;
632
+ const bool next_lower = (i + 1 < s.size()) && (std::islower(static_cast<unsigned char>(s[i + 1])) != 0);
 
 
633
  camel_boundary = prev_lower_or_digit || (prev_upper && next_lower);
634
  }
635
 
 
636
  bool digit_boundary = false;
637
  if (!cur.empty()) {
638
  unsigned char prev = static_cast<unsigned char>(s[i - 1]);
 
653
  flush();
654
  }
655
  }
 
656
  flush();
657
  return out;
658
  }
 
734
  global_def_tokens_cache.clear();
735
  global_pos_cache.clear();
736
 
737
+ const int num_entries = static_cast<int>(global_dictionary_entries.size());
 
738
 
739
+ #pragma omp parallel
740
+ {
741
+ std::unordered_map<std::string, std::vector<std::string>> local_def_cache;
742
+ std::unordered_map<std::string, std::vector<std::string>> local_pos_cache;
 
 
 
743
 
744
+ #pragma omp for schedule(guided) nowait
745
+ for (int i = 0; i < num_entries; ++i){
746
+ const auto &entry = global_dictionary_entries[i];
747
 
748
+ std::vector<std::string> all_def_toks;
749
+ for (const auto &def : entry.definitions){
750
+ auto toks = tokenize_others(def);
751
+ all_def_toks.insert(all_def_toks.end(), toks.begin(), toks.end());
 
 
 
 
 
 
 
752
  }
 
 
 
 
753
 
754
+ std::string pos = normalize_pos_tag(entry.pos);
 
 
 
755
 
756
+ std::vector<std::string> sub_words;
757
+ std::string current_sub;
758
+ for (char c : entry.word) {
759
+ if (c == ';' || c == ',') {
760
+ if (!current_sub.empty()) {
761
+ sub_words.push_back(current_sub);
762
+ current_sub.clear();
763
+ }
764
  } else {
765
+ current_sub.push_back(c);
766
+ }
767
+ }
768
+ if (!current_sub.empty()) sub_words.push_back(current_sub);
769
+
770
+ for (size_t j = 0; j < sub_words.size(); ++j) {
771
+ const std::string key = normalize_dictionary_key(sub_words[j]);
772
+ if (key.empty()) continue;
773
+
774
+ if (!pos.empty()) {
775
+ if (j == sub_words.size() - 1) {
776
+ local_pos_cache[key].push_back(std::move(pos));
777
+ } else {
778
+ local_pos_cache[key].push_back(pos);
779
+ }
780
  }
781
+ auto &defs = local_def_cache[key];
782
+ defs.insert(defs.end(), all_def_toks.begin(), all_def_toks.end());
783
  }
784
+ }
785
 
786
+ #pragma omp critical
787
+ {
788
+ for (auto &pr : local_def_cache) {
789
+ auto &vec = global_def_tokens_cache[pr.first];
790
+ vec.insert(vec.end(), std::make_move_iterator(pr.second.begin()), std::make_move_iterator(pr.second.end()));
791
+ }
792
+ for (auto &pr : local_pos_cache) {
793
+ auto &vec = global_pos_cache[pr.first];
794
+ vec.insert(vec.end(), std::make_move_iterator(pr.second.begin()), std::make_move_iterator(pr.second.end()));
795
+ }
796
  }
797
  }
798
 
799
+ // Extract keys to use OpenMP parallel-for deduplication over hash map structures
800
+ std::vector<std::string> def_keys;
801
+ def_keys.reserve(global_def_tokens_cache.size());
802
+ for (const auto &pr : global_def_tokens_cache) def_keys.push_back(pr.first);
803
+
804
+ #pragma omp parallel for schedule(dynamic)
805
+ for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(def_keys.size()); ++i){
806
+ auto &v = global_def_tokens_cache[def_keys[i]];
807
  std::sort(v.begin(), v.end());
808
  v.erase(std::unique(v.begin(), v.end()), v.end());
809
  }
810
 
811
+ std::vector<std::string> pos_keys;
812
+ pos_keys.reserve(global_pos_cache.size());
813
+ for (const auto &pr : global_pos_cache) pos_keys.push_back(pr.first);
814
+
815
+ #pragma omp parallel for schedule(dynamic)
816
+ for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(pos_keys.size()); ++i){
817
+ auto &v = global_pos_cache[pos_keys[i]];
818
  std::sort(v.begin(), v.end());
819
  v.erase(std::unique(v.begin(), v.end()), v.end());
820
  }