IncludeCPP 3.5.0__py3-none-any.whl → 3.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -546,16 +546,300 @@ class Array(list):
546
546
  return len(self)
547
547
 
548
548
 
549
+ class List(list):
550
+ """Python-like list with all standard operations.
551
+
552
+ Works exactly like Python lists with additional CSSL methods.
553
+
554
+ Usage:
555
+ list myList;
556
+ myList.append("item");
557
+ myList.insert(0, "first");
558
+ myList.pop();
559
+ myList.find("item"); # Returns index or -1
560
+ """
561
+
562
+ def __init__(self, element_type: str = 'dynamic'):
563
+ super().__init__()
564
+ self._element_type = element_type
565
+
566
+ def length(self) -> int:
567
+ """Return list length"""
568
+ return len(self)
569
+
570
+ def size(self) -> int:
571
+ """Return list size (alias for length)"""
572
+ return len(self)
573
+
574
+ def isEmpty(self) -> bool:
575
+ """Check if list is empty"""
576
+ return len(self) == 0
577
+
578
+ def first(self) -> Any:
579
+ """Get first element"""
580
+ return self[0] if self else None
581
+
582
+ def last(self) -> Any:
583
+ """Get last element"""
584
+ return self[-1] if self else None
585
+
586
+ def at(self, index: int) -> Any:
587
+ """Get item at index (safe access)"""
588
+ if 0 <= index < len(self):
589
+ return self[index]
590
+ return None
591
+
592
+ def set(self, index: int, value: Any) -> 'List':
593
+ """Set item at index"""
594
+ if 0 <= index < len(self):
595
+ self[index] = value
596
+ return self
597
+
598
+ def add(self, item: Any) -> 'List':
599
+ """Add item to end (alias for append)"""
600
+ self.append(item)
601
+ return self
602
+
603
+ def push(self, item: Any) -> 'List':
604
+ """Push item to end (alias for append)"""
605
+ self.append(item)
606
+ return self
607
+
608
+ def find(self, item: Any) -> int:
609
+ """Find index of item (-1 if not found)"""
610
+ try:
611
+ return self.index(item)
612
+ except ValueError:
613
+ return -1
614
+
615
+ def contains(self, item: Any) -> bool:
616
+ """Check if list contains item"""
617
+ return item in self
618
+
619
+ def indexOf(self, item: Any) -> int:
620
+ """Find index of item (-1 if not found)"""
621
+ return self.find(item)
622
+
623
+ def lastIndexOf(self, item: Any) -> int:
624
+ """Find last index of item (-1 if not found)"""
625
+ for i in range(len(self) - 1, -1, -1):
626
+ if self[i] == item:
627
+ return i
628
+ return -1
629
+
630
+ def removeAt(self, index: int) -> Any:
631
+ """Remove and return item at index"""
632
+ if 0 <= index < len(self):
633
+ return self.pop(index)
634
+ return None
635
+
636
+ def removeValue(self, value: Any) -> bool:
637
+ """Remove first occurrence of value"""
638
+ try:
639
+ self.remove(value)
640
+ return True
641
+ except ValueError:
642
+ return False
643
+
644
+ def removeAll(self, value: Any) -> int:
645
+ """Remove all occurrences of value, return count"""
646
+ count = 0
647
+ while value in self:
648
+ self.remove(value)
649
+ count += 1
650
+ return count
651
+
652
+ def slice(self, start: int, end: int = None) -> 'List':
653
+ """Return slice of list"""
654
+ result = List(self._element_type)
655
+ if end is None:
656
+ result.extend(self[start:])
657
+ else:
658
+ result.extend(self[start:end])
659
+ return result
660
+
661
+ def join(self, separator: str = ',') -> str:
662
+ """Join elements into string"""
663
+ return separator.join(str(item) for item in self)
664
+
665
+ def unique(self) -> 'List':
666
+ """Return list with unique elements"""
667
+ result = List(self._element_type)
668
+ seen = set()
669
+ for item in self:
670
+ key = item if isinstance(item, (int, str, float, bool)) else id(item)
671
+ if key not in seen:
672
+ seen.add(key)
673
+ result.append(item)
674
+ return result
675
+
676
+ def sorted(self, reverse: bool = False) -> 'List':
677
+ """Return sorted copy"""
678
+ result = List(self._element_type)
679
+ result.extend(sorted(self, reverse=reverse))
680
+ return result
681
+
682
+ def reversed(self) -> 'List':
683
+ """Return reversed copy"""
684
+ result = List(self._element_type)
685
+ result.extend(reversed(self))
686
+ return result
687
+
688
+ def shuffle(self) -> 'List':
689
+ """Shuffle list in place"""
690
+ import random
691
+ random.shuffle(self)
692
+ return self
693
+
694
+ def fill(self, value: Any, count: int = None) -> 'List':
695
+ """Fill list with value"""
696
+ if count is None:
697
+ for i in range(len(self)):
698
+ self[i] = value
699
+ else:
700
+ self.clear()
701
+ self.extend([value] * count)
702
+ return self
703
+
704
+ def begin(self) -> int:
705
+ """Return iterator to beginning"""
706
+ return 0
707
+
708
+ def end(self) -> int:
709
+ """Return iterator to end"""
710
+ return len(self)
711
+
712
+
713
+ class Dictionary(dict):
714
+ """Python-like dictionary with all standard operations.
715
+
716
+ Works exactly like Python dicts with additional CSSL methods.
717
+
718
+ Usage:
719
+ dictionary myDict;
720
+ myDict.set("key", "value");
721
+ myDict.get("key");
722
+ myDict.keys();
723
+ myDict.values();
724
+ """
725
+
726
+ def __init__(self, key_type: str = 'dynamic', value_type: str = 'dynamic'):
727
+ super().__init__()
728
+ self._key_type = key_type
729
+ self._value_type = value_type
730
+
731
+ def length(self) -> int:
732
+ """Return dictionary size"""
733
+ return len(self)
734
+
735
+ def size(self) -> int:
736
+ """Return dictionary size (alias for length)"""
737
+ return len(self)
738
+
739
+ def isEmpty(self) -> bool:
740
+ """Check if dictionary is empty"""
741
+ return len(self) == 0
742
+
743
+ def set(self, key: Any, value: Any) -> 'Dictionary':
744
+ """Set key-value pair"""
745
+ self[key] = value
746
+ return self
747
+
748
+ def hasKey(self, key: Any) -> bool:
749
+ """Check if key exists"""
750
+ return key in self
751
+
752
+ def hasValue(self, value: Any) -> bool:
753
+ """Check if value exists"""
754
+ return value in self.values()
755
+
756
+ def remove(self, key: Any) -> Any:
757
+ """Remove and return value for key"""
758
+ return self.pop(key, None)
759
+
760
+ def getOrDefault(self, key: Any, default: Any = None) -> Any:
761
+ """Get value or default if not found"""
762
+ return self.get(key, default)
763
+
764
+ def setDefault(self, key: Any, default: Any) -> Any:
765
+ """Set default if key doesn't exist, return value"""
766
+ if key not in self:
767
+ self[key] = default
768
+ return self[key]
769
+
770
+ def merge(self, other: dict) -> 'Dictionary':
771
+ """Merge another dictionary into this one"""
772
+ self.update(other)
773
+ return self
774
+
775
+ def keysList(self) -> list:
776
+ """Return keys as list"""
777
+ return list(self.keys())
778
+
779
+ def valuesList(self) -> list:
780
+ """Return values as list"""
781
+ return list(self.values())
782
+
783
+ def itemsList(self) -> list:
784
+ """Return items as list of tuples"""
785
+ return list(self.items())
786
+
787
+ def filter(self, predicate: Callable[[Any, Any], bool]) -> 'Dictionary':
788
+ """Filter dictionary by predicate(key, value)"""
789
+ result = Dictionary(self._key_type, self._value_type)
790
+ for k, v in self.items():
791
+ if predicate(k, v):
792
+ result[k] = v
793
+ return result
794
+
795
+ def map(self, func: Callable[[Any, Any], Any]) -> 'Dictionary':
796
+ """Apply function to all values"""
797
+ result = Dictionary(self._key_type, self._value_type)
798
+ for k, v in self.items():
799
+ result[k] = func(k, v)
800
+ return result
801
+
802
+ def forEach(self, func: Callable[[Any, Any], None]) -> 'Dictionary':
803
+ """Execute function for each key-value pair"""
804
+ for k, v in self.items():
805
+ func(k, v)
806
+ return self
807
+
808
+ def invert(self) -> 'Dictionary':
809
+ """Swap keys and values"""
810
+ result = Dictionary(self._value_type, self._key_type)
811
+ for k, v in self.items():
812
+ result[v] = k
813
+ return result
814
+
815
+ def find(self, value: Any) -> Optional[Any]:
816
+ """Find first key with given value"""
817
+ for k, v in self.items():
818
+ if v == value:
819
+ return k
820
+ return None
821
+
822
+ def findAll(self, value: Any) -> list:
823
+ """Find all keys with given value"""
824
+ return [k for k, v in self.items() if v == value]
825
+
826
+
549
827
  class Shuffled(list):
550
828
  """Unorganized fast storage for multiple returns.
551
829
 
552
830
  Stores data unorganized for fast and efficient access.
553
831
  Supports receiving multiple return values from functions.
832
+ Can be used as a function modifier to allow multiple returns.
554
833
 
555
834
  Usage:
556
835
  shuffled<string> results;
557
836
  results +<== someFunc(); # Catches all returns
558
837
  results.read() # Returns all content as list
838
+
839
+ # As return modifier:
840
+ shuffled string getData() {
841
+ return "name", "address"; # Returns multiple values
842
+ }
559
843
  """
560
844
 
561
845
  def __init__(self, element_type: str = 'dynamic'):
@@ -575,6 +859,49 @@ class Shuffled(list):
575
859
  self.append(result)
576
860
  return self
577
861
 
862
+ def add(self, *items) -> 'Shuffled':
863
+ """Add one or more items"""
864
+ for item in items:
865
+ if isinstance(item, (list, tuple)):
866
+ self.extend(item)
867
+ else:
868
+ self.append(item)
869
+ return self
870
+
871
+ def first(self) -> Any:
872
+ """Get first element"""
873
+ return self[0] if self else None
874
+
875
+ def last(self) -> Any:
876
+ """Get last element"""
877
+ return self[-1] if self else None
878
+
879
+ def length(self) -> int:
880
+ """Return shuffled length"""
881
+ return len(self)
882
+
883
+ def isEmpty(self) -> bool:
884
+ """Check if empty"""
885
+ return len(self) == 0
886
+
887
+ def contains(self, item: Any) -> bool:
888
+ """Check if contains item"""
889
+ return item in self
890
+
891
+ def at(self, index: int) -> Any:
892
+ """Get item at index"""
893
+ if 0 <= index < len(self):
894
+ return self[index]
895
+ return None
896
+
897
+ def toList(self) -> list:
898
+ """Convert to plain list"""
899
+ return list(self)
900
+
901
+ def toTuple(self) -> tuple:
902
+ """Convert to tuple"""
903
+ return tuple(self)
904
+
578
905
 
579
906
  class Iterator:
580
907
  """Advanced iterator with programmable tasks.
@@ -944,10 +1271,20 @@ def create_array(element_type: str = 'dynamic') -> Array:
944
1271
  return Array(element_type)
945
1272
 
946
1273
 
1274
+ def create_list(element_type: str = 'dynamic') -> List:
1275
+ """Create a List object"""
1276
+ return List(element_type)
1277
+
1278
+
1279
+ def create_dictionary(key_type: str = 'dynamic', value_type: str = 'dynamic') -> Dictionary:
1280
+ """Create a Dictionary object"""
1281
+ return Dictionary(key_type, value_type)
1282
+
1283
+
947
1284
  __all__ = [
948
1285
  'DataStruct', 'Shuffled', 'Iterator', 'Combo', 'DataSpace', 'OpenQuote',
949
- 'OpenFind', 'Parameter', 'Stack', 'Vector', 'Array',
1286
+ 'OpenFind', 'Parameter', 'Stack', 'Vector', 'Array', 'List', 'Dictionary',
950
1287
  'create_datastruct', 'create_shuffled', 'create_iterator',
951
1288
  'create_combo', 'create_dataspace', 'create_openquote', 'create_parameter',
952
- 'create_stack', 'create_vector', 'create_array'
1289
+ 'create_stack', 'create_vector', 'create_array', 'create_list', 'create_dictionary'
953
1290
  ]
@@ -429,7 +429,7 @@ class CsslLang:
429
429
  runtime._inline_payloads = {}
430
430
  runtime._inline_payloads[name] = code
431
431
 
432
- def share(self, instance: Any, name: str) -> str:
432
+ def share(self, instance: Any, name: str = None) -> str:
433
433
  """
434
434
  Share a Python object instance with CSSL scripts (LIVE sharing).
435
435
 
@@ -437,6 +437,14 @@ class CsslLang:
437
437
  will be reflected in the original Python object immediately.
438
438
  Call share() again with the same name to update the shared object.
439
439
 
440
+ Args:
441
+ instance: The Python object to share (or name if using old API)
442
+ name: The name to reference the object in CSSL ($name)
443
+
444
+ Note: Arguments can be passed in either order:
445
+ cssl.share(my_object, "name") # Preferred
446
+ cssl.share("name", my_object) # Also works
447
+
440
448
  Usage in Python:
441
449
  from includecpp import CSSL
442
450
  cssl = CSSL.CsslLang()
@@ -474,6 +482,21 @@ class CsslLang:
474
482
  global _live_objects
475
483
  runtime = self._get_runtime()
476
484
 
485
+ # Handle argument order flexibility: share(instance, name) or share(name, instance)
486
+ if name is None:
487
+ # Only one argument - use object type as name
488
+ name = type(instance).__name__
489
+ elif isinstance(instance, str) and not isinstance(name, str):
490
+ # Arguments are swapped: share("name", instance) -> swap them
491
+ instance, name = name, instance
492
+ elif not isinstance(name, str):
493
+ # name is not a string - use its type as name
494
+ name = type(name).__name__
495
+
496
+ # Sanitize filename: remove invalid characters for Windows
497
+ import re
498
+ safe_name = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '_', str(name))
499
+
477
500
  # Initialize shared objects registry
478
501
  if not hasattr(runtime, '_shared_objects'):
479
502
  runtime._shared_objects = {}
@@ -481,7 +504,7 @@ class CsslLang:
481
504
  # Generate unique filename: <name>.shareobj<7digits>
482
505
  random_suffix = ''.join([str(random.randint(0, 9)) for _ in range(7)])
483
506
  share_dir = _get_share_directory()
484
- filepath = share_dir / f"{name}.shareobj{random_suffix}"
507
+ filepath = share_dir / f"{safe_name}.shareobj{random_suffix}"
485
508
 
486
509
  # Remove old file if updating
487
510
  if name in runtime._shared_objects:
@@ -577,22 +600,65 @@ class CsslLang:
577
600
 
578
601
  return None
579
602
 
603
+ def shared(self, name: str) -> Optional[Any]:
604
+ """
605
+ Get a shared object by name (alias for get_shared).
606
+
607
+ Returns the actual live object reference, not a copy.
608
+ Works with both Python cssl.share() and CSSL ==> $name shared objects.
609
+
610
+ Usage:
611
+ from includecpp import CSSL
612
+ cssl = CSSL.CsslLang()
613
+
614
+ # Share an object
615
+ my_obj = {"value": 42}
616
+ cssl.share(my_obj, "data")
617
+
618
+ # Retrieve it later
619
+ obj = cssl.shared("data")
620
+ print(obj["value"]) # 42
621
+
622
+ Args:
623
+ name: Name of the shared object (without $ prefix)
624
+
625
+ Returns:
626
+ The live shared object or None if not found
627
+ """
628
+ return self.get_shared(name)
629
+
580
630
 
581
631
  # Global shared objects registry (for cross-instance sharing)
582
632
  _global_shared_objects: Dict[str, str] = {}
583
633
 
584
634
 
585
- def share(instance: Any, name: str) -> str:
635
+ def share(instance: Any, name: str = None) -> str:
586
636
  """
587
637
  Share a Python object globally for all CSSL instances (LIVE sharing).
588
638
 
589
639
  Changes made through CSSL will reflect back to the original object.
640
+
641
+ Args can be passed in either order:
642
+ share(my_object, "name") # Preferred
643
+ share("name", my_object) # Also works
590
644
  """
591
645
  global _live_objects
646
+ import re
647
+
648
+ # Handle argument order flexibility
649
+ if name is None:
650
+ name = type(instance).__name__
651
+ elif isinstance(instance, str) and not isinstance(name, str):
652
+ instance, name = name, instance
653
+ elif not isinstance(name, str):
654
+ name = type(name).__name__
655
+
656
+ # Sanitize filename
657
+ safe_name = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '_', str(name))
592
658
 
593
659
  random_suffix = ''.join([str(random.randint(0, 9)) for _ in range(7)])
594
660
  share_dir = _get_share_directory()
595
- filepath = share_dir / f"{name}.shareobj{random_suffix}"
661
+ filepath = share_dir / f"{safe_name}.shareobj{random_suffix}"
596
662
 
597
663
  # Remove old file if updating
598
664
  if name in _global_shared_objects:
@@ -645,6 +711,32 @@ def get_shared(name: str) -> Optional[Any]:
645
711
  return _live_objects.get(name)
646
712
 
647
713
 
714
+ def shared(name: str) -> Optional[Any]:
715
+ """
716
+ Get a shared object by name (alias for get_shared).
717
+
718
+ Works with both Python share() and CSSL ==> $name shared objects.
719
+
720
+ Usage:
721
+ from includecpp import CSSL
722
+
723
+ # Share an object
724
+ my_obj = {"value": 42}
725
+ CSSL.share(my_obj, "data")
726
+
727
+ # Retrieve it later
728
+ obj = CSSL.shared("data")
729
+ print(obj["value"]) # 42
730
+
731
+ Args:
732
+ name: Name of the shared object (without $ prefix)
733
+
734
+ Returns:
735
+ The live shared object or None if not found
736
+ """
737
+ return get_shared(name)
738
+
739
+
648
740
  # Singleton for convenience
649
741
  _default_instance: Optional[CsslLang] = None
650
742
 
@@ -783,4 +875,8 @@ __all__ = [
783
875
  'clear_output',
784
876
  'module',
785
877
  'makemodule',
878
+ 'share',
879
+ 'unshare',
880
+ 'shared',
881
+ 'get_shared',
786
882
  ]