rice 4.6.0 → 4.6.1

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.
@@ -73,6 +73,7 @@ extern "C" typedef VALUE (*RUBY_VALUE_FUNC)(VALUE);
73
73
  // ========= rice_traits.hpp =========
74
74
 
75
75
  #include <ostream>
76
+ #include <tuple>
76
77
  #include <type_traits>
77
78
  #include <variant>
78
79
  #include <vector>
@@ -225,6 +226,17 @@ namespace Rice
225
226
  (callable(std::forward<decltype(args)>(args)), ...);
226
227
  }, std::forward<Tuple_T>(tuple));
227
228
  }
229
+
230
+ template<typename T, typename = void>
231
+ struct is_wrapped : std::true_type {};
232
+
233
+ template<typename T>
234
+ struct is_wrapped<T, std::enable_if_t<std::is_fundamental_v<detail::intrinsic_type<T>> ||
235
+ std::is_same_v<detail::intrinsic_type<T>, std::string>>
236
+ >: std::false_type {};
237
+
238
+ template<typename T>
239
+ constexpr bool is_wrapped_v = is_wrapped<T>::value;
228
240
  } // detail
229
241
  } // Rice
230
242
 
@@ -379,17 +391,17 @@ namespace Rice::detail
379
391
  template<typename Attribute_T>
380
392
  struct attribute_traits;
381
393
 
382
- template<typename Attr_T>
383
- struct attribute_traits<Attr_T*>
394
+ template<typename Attribute_T>
395
+ struct attribute_traits<Attribute_T*>
384
396
  {
385
- using attr_type = Attr_T;
397
+ using attr_type = Attribute_T;
386
398
  using class_type = std::nullptr_t;
387
399
  };
388
400
 
389
- template<typename Attr_T, typename Class_T>
390
- struct attribute_traits<Attr_T Class_T::*>
401
+ template<typename Attribute_T, typename Class_T>
402
+ struct attribute_traits<Attribute_T(Class_T::*)>
391
403
  {
392
- using attr_type = Attr_T;
404
+ using attr_type = Attribute_T;
393
405
  using class_type = Class_T;
394
406
  };
395
407
  }
@@ -588,6 +600,7 @@ namespace Rice::detail
588
600
  // ========= RubyFunction.ipp =========
589
601
 
590
602
  #include <any>
603
+ #include <tuple>
591
604
 
592
605
  namespace Rice::detail
593
606
  {
@@ -2711,6 +2724,9 @@ inline auto& define_constant(std::string name, Constant_T value)
2711
2724
  template<bool IsMethod, typename Function_T>
2712
2725
  void wrap_native_call(VALUE klass, std::string name, Function_T&& function, MethodInfo* methodInfo);
2713
2726
 
2727
+ template <typename Attribute_T>
2728
+ Data_Type<T>& define_attr_internal(VALUE klass, std::string name, Attribute_T attribute, AttrAccess access);
2729
+
2714
2730
  private:
2715
2731
  template<typename T_>
2716
2732
  friend class Data_Type;
@@ -3495,11 +3511,14 @@ namespace Rice
3495
3511
 
3496
3512
  namespace Rice
3497
3513
  {
3514
+ template<typename T, typename = void>
3515
+ class Buffer;
3516
+
3498
3517
  template<typename T>
3499
- class Buffer
3518
+ class Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>
3500
3519
  {
3501
3520
  public:
3502
- using type = T;
3521
+ using Element_T = T;
3503
3522
 
3504
3523
  Buffer(T* pointer);
3505
3524
  Buffer(T* pointer, size_t size);
@@ -3512,6 +3531,7 @@ namespace Rice
3512
3531
 
3513
3532
  Buffer& operator=(const Buffer& other) = delete;
3514
3533
  Buffer& operator=(Buffer&& other);
3534
+ T& operator[](size_t index);
3515
3535
 
3516
3536
  T* ptr();
3517
3537
  T& reference();
@@ -3521,7 +3541,7 @@ namespace Rice
3521
3541
  void setSize(size_t value);
3522
3542
 
3523
3543
  // Ruby API
3524
- // VALUE toString() const;
3544
+ VALUE toString() const;
3525
3545
 
3526
3546
  VALUE bytes() const;
3527
3547
  VALUE bytes(size_t count) const;
@@ -3529,15 +3549,12 @@ namespace Rice
3529
3549
  Array toArray() const;
3530
3550
  Array toArray(size_t count) const;
3531
3551
 
3532
- T get(size_t index) const;
3533
- void set(size_t index, T value);
3534
-
3535
3552
  bool isOwner() const;
3536
3553
  void setOwner(bool value);
3537
3554
 
3538
3555
  private:
3539
- void fromRubyType(VALUE value);
3540
- void fromDataType(VALUE value);
3556
+ void fromBuiltinType(VALUE value);
3557
+ void fromWrappedType(VALUE value);
3541
3558
 
3542
3559
  bool m_owner = false;
3543
3560
  size_t m_size = 0;
@@ -3546,10 +3563,10 @@ namespace Rice
3546
3563
  };
3547
3564
 
3548
3565
  template<typename T>
3549
- class Buffer<T*>
3566
+ class Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>
3550
3567
  {
3551
3568
  public:
3552
- using type = T*;
3569
+ using Element_T = Buffer<T>;
3553
3570
 
3554
3571
  Buffer(T** pointer);
3555
3572
  Buffer(T** pointer, size_t size);
@@ -3563,7 +3580,7 @@ namespace Rice
3563
3580
  Buffer& operator=(const Buffer& other) = delete;
3564
3581
  Buffer& operator=(Buffer&& other);
3565
3582
 
3566
- const Buffer<T>& operator[](size_t index);
3583
+ Element_T& operator[](size_t index);
3567
3584
 
3568
3585
  T** ptr();
3569
3586
  void release();
@@ -3572,7 +3589,7 @@ namespace Rice
3572
3589
  void setSize(size_t value);
3573
3590
 
3574
3591
  // Ruby API
3575
- // VALUE toString() const;
3592
+ VALUE toString() const;
3576
3593
 
3577
3594
  VALUE bytes() const;
3578
3595
  VALUE bytes(size_t count) const;
@@ -3590,6 +3607,50 @@ namespace Rice
3590
3607
  std::vector<Buffer<T>> m_inner;
3591
3608
  };
3592
3609
 
3610
+ template<typename T>
3611
+ class Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>
3612
+ {
3613
+ public:
3614
+ using Element_T = T*;
3615
+
3616
+ Buffer(T** pointer);
3617
+ Buffer(T** pointer, size_t size);
3618
+ Buffer(VALUE value);
3619
+
3620
+ ~Buffer();
3621
+
3622
+ Buffer(const Buffer& other) = delete;
3623
+ Buffer(Buffer&& other);
3624
+
3625
+ Buffer& operator=(const Buffer& other) = delete;
3626
+ Buffer& operator=(Buffer&& other);
3627
+
3628
+ Element_T& operator[](size_t index);
3629
+
3630
+ T** ptr();
3631
+ void release();
3632
+
3633
+ size_t size() const;
3634
+ void setSize(size_t value);
3635
+
3636
+ // Ruby API
3637
+ VALUE toString() const;
3638
+
3639
+ VALUE bytes() const;
3640
+ VALUE bytes(size_t count) const;
3641
+
3642
+ Array toArray() const;
3643
+ Array toArray(size_t count) const;
3644
+
3645
+ void setOwner(bool value);
3646
+ bool isOwner() const;
3647
+
3648
+ private:
3649
+ bool m_owner = false;
3650
+ size_t m_size = 0;
3651
+ T** m_buffer = nullptr;
3652
+ };
3653
+
3593
3654
  template<>
3594
3655
  class Buffer<void>
3595
3656
  {
@@ -3618,30 +3679,42 @@ namespace Rice
3618
3679
  {
3619
3680
  // ---- Buffer<T> -------
3620
3681
  template<typename T>
3621
- inline Buffer<T>::Buffer(T* pointer) : m_buffer(pointer)
3682
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Buffer(T* pointer) : m_buffer(pointer)
3622
3683
  {
3623
3684
  }
3624
3685
 
3625
3686
  template<typename T>
3626
- inline Buffer<T>::Buffer(T* pointer, size_t size) : m_size(size), m_buffer(pointer)
3687
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Buffer(T* pointer, size_t size) : m_size(size), m_buffer(pointer)
3627
3688
  {
3628
3689
  }
3629
3690
 
3630
3691
  template <typename T>
3631
- inline Buffer<T>::Buffer(VALUE value)
3692
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Buffer(VALUE value)
3632
3693
  {
3633
3694
  if constexpr (std::is_fundamental_v<T>)
3634
3695
  {
3635
- this->fromRubyType(value);
3696
+ this->fromBuiltinType(value);
3636
3697
  }
3637
3698
  else
3638
3699
  {
3639
- this->fromDataType(value);
3700
+ this->fromWrappedType(value);
3640
3701
  }
3641
3702
  }
3642
3703
 
3643
3704
  template <typename T>
3644
- inline void Buffer<T>::fromRubyType(VALUE value)
3705
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::~Buffer()
3706
+ {
3707
+ if constexpr (std::is_destructible_v<T>)
3708
+ {
3709
+ if (this->m_owner)
3710
+ {
3711
+ delete[] this->m_buffer;
3712
+ }
3713
+ }
3714
+ }
3715
+
3716
+ template <typename T>
3717
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::fromBuiltinType(VALUE value)
3645
3718
  {
3646
3719
  using Intrinsic_T = typename detail::intrinsic_type<T>;
3647
3720
  using RubyType_T = typename detail::RubyType<Intrinsic_T>;
@@ -3713,7 +3786,7 @@ namespace Rice
3713
3786
  }
3714
3787
 
3715
3788
  template <typename T>
3716
- inline void Buffer<T>::fromDataType(VALUE value)
3789
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::fromWrappedType(VALUE value)
3717
3790
  {
3718
3791
  using Intrinsic_T = typename detail::intrinsic_type<T>;
3719
3792
 
@@ -3745,19 +3818,7 @@ namespace Rice
3745
3818
  }
3746
3819
 
3747
3820
  template <typename T>
3748
- inline Buffer<T>::~Buffer()
3749
- {
3750
- if constexpr (std::is_destructible_v<T>)
3751
- {
3752
- if (this->m_owner)
3753
- {
3754
- delete[] this->m_buffer;
3755
- }
3756
- }
3757
- }
3758
-
3759
- template <typename T>
3760
- inline Buffer<T>::Buffer(Buffer<T>&& other) : m_owner(other.m_owner), m_size(other.m_size), m_buffer(other.m_buffer)
3821
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Buffer(Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>&& other) : m_owner(other.m_owner), m_size(other.m_size), m_buffer(other.m_buffer)
3761
3822
  {
3762
3823
  other.m_buffer = nullptr;
3763
3824
  other.m_size = 0;
@@ -3765,7 +3826,7 @@ namespace Rice
3765
3826
  }
3766
3827
 
3767
3828
  template <typename T>
3768
- inline Buffer<T>& Buffer<T>::operator=(Buffer<T>&& other)
3829
+ inline Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>& Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::operator=(Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>&& other)
3769
3830
  {
3770
3831
  this->m_buffer = other.m_buffer;
3771
3832
  other.m_buffer = nullptr;
@@ -3780,57 +3841,59 @@ namespace Rice
3780
3841
  }
3781
3842
 
3782
3843
  template <typename T>
3783
- inline size_t Buffer<T>::size() const
3844
+ inline size_t Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::size() const
3784
3845
  {
3785
3846
  return this->m_size;
3786
3847
  }
3787
3848
 
3788
3849
  template <typename T>
3789
- void Buffer<T>::setSize(size_t value)
3850
+ void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::setSize(size_t value)
3790
3851
  {
3791
3852
  this->m_size = value;
3792
3853
  }
3793
3854
 
3794
3855
  template <typename T>
3795
- inline T* Buffer<T>::ptr()
3856
+ inline T* Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::ptr()
3796
3857
  {
3797
3858
  return this->m_buffer;
3798
3859
  }
3799
3860
 
3800
3861
  template <typename T>
3801
- inline T& Buffer<T>::reference()
3862
+ inline T& Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::reference()
3802
3863
  {
3803
3864
  return *this->m_buffer;
3804
3865
  }
3805
3866
 
3806
3867
  template <typename T>
3807
- inline bool Buffer<T>::isOwner() const
3868
+ inline bool Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::isOwner() const
3808
3869
  {
3809
3870
  return this->m_owner;
3810
3871
  }
3811
3872
 
3812
3873
  template <typename T>
3813
- inline void Buffer<T>::setOwner(bool value)
3874
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::setOwner(bool value)
3814
3875
  {
3815
3876
  this->m_owner = value;
3816
3877
  }
3817
3878
 
3818
3879
  template <typename T>
3819
- inline void Buffer<T>::release()
3880
+ inline void Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::release()
3820
3881
  {
3821
3882
  this->m_owner = false;
3822
3883
  }
3823
3884
 
3824
- /* template<typename T>
3825
- inline VALUE Buffer<T>::toString() const
3885
+ template<typename T>
3886
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::toString() const
3826
3887
  {
3827
- std::string name = detail::typeName(typeid(T));
3828
- std::string result = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
3829
- return detail::To_Ruby<std::string>().convert(result);
3830
- }*/
3888
+ std::string name = detail::typeName(typeid(T*));
3889
+ std::string description = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
3890
+
3891
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
3892
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
3893
+ }
3831
3894
 
3832
3895
  template<typename T>
3833
- inline VALUE Buffer<T>::bytes(size_t count) const
3896
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::bytes(size_t count) const
3834
3897
  {
3835
3898
  if (!this->m_buffer)
3836
3899
  {
@@ -3844,13 +3907,13 @@ namespace Rice
3844
3907
  }
3845
3908
 
3846
3909
  template<typename T>
3847
- inline VALUE Buffer<T>::bytes() const
3910
+ inline VALUE Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::bytes() const
3848
3911
  {
3849
3912
  return this->bytes(this->m_size);
3850
3913
  }
3851
3914
 
3852
3915
  template<typename T>
3853
- inline Array Buffer<T>::toArray(size_t count) const
3916
+ inline Array Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::toArray(size_t count) const
3854
3917
  {
3855
3918
  if (!this->m_buffer)
3856
3919
  {
@@ -3877,13 +3940,13 @@ namespace Rice
3877
3940
  }
3878
3941
 
3879
3942
  template<typename T>
3880
- inline Array Buffer<T>::toArray() const
3943
+ inline Array Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::toArray() const
3881
3944
  {
3882
3945
  return this->toArray(this->m_size);
3883
3946
  }
3884
3947
 
3885
3948
  template<typename T>
3886
- inline T Buffer<T>::get(size_t index) const
3949
+ inline typename Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::Element_T& Buffer<T, std::enable_if_t<!std::is_pointer_v<T>>>::operator[](size_t index)
3887
3950
  {
3888
3951
  if (index >= this->m_size)
3889
3952
  {
@@ -3893,30 +3956,19 @@ namespace Rice
3893
3956
  return this->m_buffer[index];
3894
3957
  }
3895
3958
 
3959
+ // ---- Buffer<T*> - Builtin -------
3896
3960
  template<typename T>
3897
- inline void Buffer<T>::set(size_t index, T element)
3898
- {
3899
- if (index >= this->m_size)
3900
- {
3901
- throw Exception(rb_eIndexError, "index %ld outside of bounds: 0..%ld", index, this->m_size);
3902
- }
3903
-
3904
- this->m_buffer[index] = element;
3905
- }
3906
-
3907
- // ---- Buffer<T*> -------
3908
- template<typename T>
3909
- inline Buffer<T*>::Buffer(T** pointer) : m_outer(pointer)
3961
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(T** pointer) : m_outer(pointer)
3910
3962
  {
3911
3963
  }
3912
3964
 
3913
3965
  template<typename T>
3914
- inline Buffer<T*>::Buffer(T** pointer, size_t size) : m_outer(pointer), m_size(size)
3966
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(T** pointer, size_t size) : m_outer(pointer), m_size(size)
3915
3967
  {
3916
3968
  }
3917
3969
 
3918
3970
  template <typename T>
3919
- inline Buffer<T*>::Buffer(VALUE value)
3971
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(VALUE value)
3920
3972
  {
3921
3973
  ruby_value_type valueType = rb_type(value);
3922
3974
 
@@ -3956,7 +4008,7 @@ namespace Rice
3956
4008
  }
3957
4009
 
3958
4010
  template <typename T>
3959
- inline Buffer<T*>::~Buffer()
4011
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::~Buffer()
3960
4012
  {
3961
4013
  if (this->m_owner)
3962
4014
  {
@@ -3965,7 +4017,7 @@ namespace Rice
3965
4017
  }
3966
4018
 
3967
4019
  template <typename T>
3968
- inline Buffer<T*>::Buffer(Buffer<T*>&& other) : m_owner(other.m_owner), m_size(other.m_size),
4020
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Buffer(Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>&& other) : m_owner(other.m_owner), m_size(other.m_size),
3969
4021
  m_outer(other.m_outer), m_inner(std::move(other.m_inner))
3970
4022
  {
3971
4023
  other.m_outer = nullptr;
@@ -3975,7 +4027,7 @@ namespace Rice
3975
4027
  }
3976
4028
 
3977
4029
  template <typename T>
3978
- inline Buffer<T*>& Buffer<T*>::operator=(Buffer<T*>&& other)
4030
+ inline Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>& Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::operator=(Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>&& other)
3979
4031
  {
3980
4032
  this->m_outer = other.m_outer;
3981
4033
  other.m_outer = nullptr;
@@ -3993,57 +4045,59 @@ namespace Rice
3993
4045
  }
3994
4046
 
3995
4047
  template <typename T>
3996
- inline const Buffer<T>& Buffer<T*>::operator[](size_t index)
4048
+ inline typename Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::Element_T& Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::operator[](size_t index)
3997
4049
  {
3998
4050
  return this->m_inner[index];
3999
4051
  }
4000
4052
 
4001
4053
  template <typename T>
4002
- inline size_t Buffer<T*>::size() const
4054
+ inline size_t Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::size() const
4003
4055
  {
4004
4056
  return this->m_size;
4005
4057
  }
4006
4058
 
4007
4059
  template <typename T>
4008
- void Buffer<T*>::setSize(size_t value)
4060
+ void Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::setSize(size_t value)
4009
4061
  {
4010
4062
  this->m_size = value;
4011
4063
  }
4012
4064
 
4013
4065
  template <typename T>
4014
- inline T** Buffer<T*>::ptr()
4066
+ inline T** Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::ptr()
4015
4067
  {
4016
4068
  return this->m_outer;
4017
4069
  }
4018
4070
 
4019
4071
  template <typename T>
4020
- inline bool Buffer<T*>::isOwner() const
4072
+ inline bool Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::isOwner() const
4021
4073
  {
4022
4074
  return this->m_owner;
4023
4075
  }
4024
4076
 
4025
4077
  template <typename T>
4026
- inline void Buffer<T*>::setOwner(bool value)
4078
+ inline void Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::setOwner(bool value)
4027
4079
  {
4028
4080
  this->m_owner = value;
4029
4081
  }
4030
4082
 
4031
4083
  template <typename T>
4032
- inline void Buffer<T*>::release()
4084
+ inline void Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::release()
4033
4085
  {
4034
4086
  this->m_owner = false;
4035
4087
  }
4036
4088
 
4037
- /*template<typename T>
4038
- inline VALUE Buffer<T*>::toString() const
4089
+ template<typename T>
4090
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toString() const
4039
4091
  {
4040
4092
  std::string name = detail::typeName(typeid(T*));
4041
- std::string result = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
4042
- return detail::To_Ruby<std::string>().convert(result);
4043
- }*/
4093
+ std::string description = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
4094
+
4095
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
4096
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
4097
+ }
4044
4098
 
4045
4099
  template<typename T>
4046
- inline VALUE Buffer<T*>::bytes(size_t count) const
4100
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::bytes(size_t count) const
4047
4101
  {
4048
4102
  if (!this->m_outer)
4049
4103
  {
@@ -4058,13 +4112,13 @@ namespace Rice
4058
4112
  }
4059
4113
 
4060
4114
  template<typename T>
4061
- inline VALUE Buffer<T*>::bytes() const
4115
+ inline VALUE Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::bytes() const
4062
4116
  {
4063
4117
  return this->bytes(this->m_size);
4064
4118
  }
4065
4119
 
4066
4120
  template<typename T>
4067
- inline Array Buffer<T*>::toArray(size_t count) const
4121
+ inline Array Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toArray(size_t count) const
4068
4122
  {
4069
4123
  if (!this->m_outer)
4070
4124
  {
@@ -4087,7 +4141,188 @@ namespace Rice
4087
4141
  }
4088
4142
 
4089
4143
  template<typename T>
4090
- inline Array Buffer<T*>::toArray() const
4144
+ inline Array Buffer<T*, std::enable_if_t<!detail::is_wrapped_v<T>>>::toArray() const
4145
+ {
4146
+ return this->toArray(this->m_size);
4147
+ }
4148
+
4149
+ // ---- Buffer<T*> - Wrapped -------
4150
+ template<typename T>
4151
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(T** pointer) : m_buffer(pointer)
4152
+ {
4153
+ }
4154
+
4155
+ template<typename T>
4156
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(T** pointer, size_t size) : m_buffer(pointer), m_size(size)
4157
+ {
4158
+ }
4159
+
4160
+ template <typename T>
4161
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(VALUE value)
4162
+ {
4163
+ ruby_value_type valueType = rb_type(value);
4164
+
4165
+ switch (valueType)
4166
+ {
4167
+ case RUBY_T_ARRAY:
4168
+ {
4169
+ Array array(value);
4170
+ this->m_size = array.size();
4171
+ this->m_buffer = new T * [this->m_size]();
4172
+
4173
+ detail::From_Ruby<T> fromRuby;
4174
+ for (size_t i = 0; i < this->m_size; i++)
4175
+ {
4176
+ Data_Object<detail::intrinsic_type<T>> dataObject(array[i].value());
4177
+ this->m_buffer[i] = dataObject.get();
4178
+ }
4179
+
4180
+ this->m_owner = true;
4181
+ break;
4182
+ }
4183
+ default:
4184
+ {
4185
+ std::string typeName = detail::typeName(typeid(T));
4186
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s*)",
4187
+ detail::protect(rb_obj_classname, value), typeName.c_str());
4188
+ }
4189
+ }
4190
+ }
4191
+
4192
+ template <typename T>
4193
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::~Buffer()
4194
+ {
4195
+ if (this->m_owner)
4196
+ {
4197
+ delete[] this->m_buffer;
4198
+ }
4199
+ }
4200
+
4201
+ template <typename T>
4202
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Buffer(Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>&& other) : m_owner(other.m_owner), m_size(other.m_size),
4203
+ m_buffer(other.m_buffer)
4204
+ {
4205
+ other.m_buffer = nullptr;
4206
+ other.m_size = 0;
4207
+ other.m_owner = false;
4208
+ }
4209
+
4210
+ template <typename T>
4211
+ inline Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>& Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::operator=(Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>&& other)
4212
+ {
4213
+ this->m_buffer = other.m_buffer;
4214
+ other.m_buffer = nullptr;
4215
+
4216
+ this->m_size = other.m_size;
4217
+ other.m_size = 0;
4218
+
4219
+ this->m_owner = other.m_owner;
4220
+ other.m_owner = false;
4221
+
4222
+ return *this;
4223
+ }
4224
+
4225
+ template <typename T>
4226
+ inline typename Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::Element_T& Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::operator[](size_t index)
4227
+ {
4228
+ if (index >= this->m_size)
4229
+ {
4230
+ throw Exception(rb_eIndexError, "index %ld outside of bounds: 0..%ld", index, this->m_size);
4231
+ }
4232
+ return this->m_buffer[index];
4233
+ }
4234
+
4235
+ template <typename T>
4236
+ inline size_t Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::size() const
4237
+ {
4238
+ return this->m_size;
4239
+ }
4240
+
4241
+ template <typename T>
4242
+ void Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::setSize(size_t value)
4243
+ {
4244
+ this->m_size = value;
4245
+ }
4246
+
4247
+ template <typename T>
4248
+ inline T** Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::ptr()
4249
+ {
4250
+ return this->m_buffer;
4251
+ }
4252
+
4253
+ template <typename T>
4254
+ inline bool Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::isOwner() const
4255
+ {
4256
+ return this->m_owner;
4257
+ }
4258
+
4259
+ template <typename T>
4260
+ inline void Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::setOwner(bool value)
4261
+ {
4262
+ this->m_owner = value;
4263
+ }
4264
+
4265
+ template <typename T>
4266
+ inline void Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::release()
4267
+ {
4268
+ this->m_owner = false;
4269
+ }
4270
+
4271
+ template<typename T>
4272
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toString() const
4273
+ {
4274
+ std::string name = detail::typeName(typeid(T*));
4275
+ std::string description = "Buffer<type: " + detail::cppClassName(name) + ", size: " + std::to_string(this->m_size) + ">";
4276
+
4277
+ // We can't use To_Ruby because To_Ruby depends on Buffer - ie a circular reference
4278
+ return detail::protect(rb_utf8_str_new_cstr, description.c_str());
4279
+ }
4280
+
4281
+ template<typename T>
4282
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::bytes(size_t count) const
4283
+ {
4284
+ if (!this->m_buffer)
4285
+ {
4286
+ return Qnil;
4287
+ }
4288
+ else
4289
+ {
4290
+ T** begin = this->m_buffer;
4291
+ long length = (long)(count * sizeof(T*));
4292
+ return detail::protect(rb_str_new_static, (const char*)*begin, length);
4293
+ }
4294
+ }
4295
+
4296
+ template<typename T>
4297
+ inline VALUE Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::bytes() const
4298
+ {
4299
+ return this->bytes(this->m_size);
4300
+ }
4301
+
4302
+ template<typename T>
4303
+ inline Array Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toArray(size_t count) const
4304
+ {
4305
+ if (!this->m_buffer)
4306
+ {
4307
+ return Qnil;
4308
+ }
4309
+ else
4310
+ {
4311
+ Array result;
4312
+
4313
+ T** ptr = this->m_buffer;
4314
+ T** end = this->m_buffer + count;
4315
+
4316
+ for (; ptr < end; ptr++)
4317
+ {
4318
+ result.push(*ptr);
4319
+ }
4320
+ return result;
4321
+ }
4322
+ }
4323
+
4324
+ template<typename T>
4325
+ inline Array Buffer<T*, std::enable_if_t<detail::is_wrapped_v<T>>>::toArray() const
4091
4326
  {
4092
4327
  return this->toArray(this->m_size);
4093
4328
  }
@@ -4124,6 +4359,9 @@ namespace Rice
4124
4359
  if (klassName.empty())
4125
4360
  {
4126
4361
  std::string typeName = detail::typeName(typeid(Buffer_T));
4362
+ // This will end up as Buffer<T,void>. We want to remove the ,void part.
4363
+ auto removeVoidRegex = std::regex(",\\s?void");
4364
+ typeName = std::regex_replace(typeName, removeVoidRegex, "");
4127
4365
  klassName = detail::rubyClassName(typeName);
4128
4366
  }
4129
4367
 
@@ -4139,23 +4377,35 @@ namespace Rice
4139
4377
  define_constructor(Constructor<Buffer_T, VALUE>(), Arg("value").setValue()).
4140
4378
  define_method("size", &Buffer_T::size).
4141
4379
  define_method("size=", &Buffer_T::setSize).
4142
- // template define_method<VALUE(Buffer_T::*)() const>("to_s", &Buffer_T::toString, Return().setValue()).
4380
+ template define_method<VALUE(Buffer_T::*)() const>("to_s", &Buffer_T::toString, Return().setValue()).
4143
4381
  template define_method<VALUE(Buffer_T::*)(size_t) const>("bytes", &Buffer_T::bytes, Return().setValue()).
4144
4382
  template define_method<VALUE(Buffer_T::*)() const>("bytes", &Buffer_T::bytes, Return().setValue()).
4145
4383
  template define_method<Array(Buffer_T::*)(size_t) const>("to_ary", &Buffer_T::toArray, Return().setValue()).
4146
4384
  template define_method<Array(Buffer_T::*)() const>("to_ary", &Buffer_T::toArray, Return().setValue());
4147
4385
 
4148
- if constexpr (!std::is_pointer_v<T>)
4386
+ klass.
4387
+ define_method("[]", &Buffer_T::operator[], Arg("index"));
4388
+
4389
+ if constexpr (std::is_pointer_v<T> && detail::is_wrapped_v<T>)
4149
4390
  {
4150
- klass.
4151
- define_method("[]", [](const Buffer_T& self, size_t index) -> T
4152
- {
4153
- return self.get(index);
4154
- }).
4155
- define_method("[]=", [](Buffer_T& self, size_t index, T element) -> void
4156
- {
4157
- self.set(index, element);
4158
- });
4391
+ klass.define_method("[]=", [](Buffer_T& self, size_t index, typename Buffer_T::Element_T element) -> void
4392
+ {
4393
+ self[index] = element;
4394
+ });
4395
+ }
4396
+ else if constexpr (std::is_pointer_v<T> && !detail::is_wrapped_v<T>)
4397
+ {
4398
+ klass.define_method("[]=", [](Buffer_T& self, size_t index, typename Buffer_T::Element_T& element) -> void
4399
+ {
4400
+ self[index] = std::move(element);
4401
+ });
4402
+ }
4403
+ else
4404
+ {
4405
+ klass.define_method("[]=", [](Buffer_T& self, size_t index, typename Buffer_T::Element_T& element) -> void
4406
+ {
4407
+ self[index] = element;
4408
+ });
4159
4409
  }
4160
4410
 
4161
4411
  return klass;
@@ -8509,7 +8759,6 @@ namespace Rice::detail
8509
8759
  return base;
8510
8760
  }
8511
8761
 
8512
-
8513
8762
  inline std::string rubyClassName(const std::string& typeInfoName)
8514
8763
  {
8515
8764
  std::string base = cppClassName(typeInfoName);
@@ -9242,7 +9491,18 @@ namespace Rice::detail
9242
9491
  if constexpr (std::is_member_object_pointer_v<Attribute_T>)
9243
9492
  {
9244
9493
  Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
9245
- return To_Ruby<To_Ruby_T>().convert(nativeSelf->*attribute_);
9494
+
9495
+ if constexpr (std::is_fundamental_v<detail::intrinsic_type<To_Ruby_T>> ||
9496
+ (std::is_array_v<To_Ruby_T> && std::is_fundamental_v<std::remove_extent_t<To_Ruby_T>>))
9497
+ {
9498
+ return To_Ruby<To_Ruby_T>().convert(nativeSelf->*attribute_);
9499
+ }
9500
+ else
9501
+ {
9502
+ // If the attribute is an object return a reference to avoid a copy (and avoid issues with
9503
+ // attributes that are not assignable, copy constructible or move constructible)
9504
+ return To_Ruby<To_Ruby_T&>().convert(nativeSelf->*attribute_);
9505
+ }
9246
9506
  }
9247
9507
  else
9248
9508
  {
@@ -9302,39 +9562,21 @@ namespace Rice::detail
9302
9562
  template<typename Attribute_T>
9303
9563
  inline VALUE NativeAttributeSet<Attribute_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
9304
9564
  {
9305
- if constexpr (std::is_fundamental_v<intrinsic_type<Attr_T>> && std::is_pointer_v<Attr_T>)
9306
- {
9307
- static_assert(true, "An fundamental value, such as an integer, cannot be assigned to an attribute that is a pointer.");
9308
- }
9309
- else if constexpr (std::is_same_v<intrinsic_type<Attr_T>, std::string> && std::is_pointer_v<Attr_T>)
9310
- {
9311
- static_assert(true, "An string cannot be assigned to an attribute that is a pointer.");
9312
- }
9313
-
9314
9565
  if (argc != 1)
9315
9566
  {
9316
9567
  throw std::runtime_error("Incorrect number of parameters for setting attribute. Attribute: " + this->name_);
9317
9568
  }
9318
9569
 
9319
9570
  VALUE value = argv[0];
9320
-
9321
- if constexpr (!std::is_null_pointer_v<Receiver_T> &&
9322
- !std::is_const_v<Attr_T> &&
9323
- (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
9571
+
9572
+ if constexpr (!std::is_null_pointer_v<Receiver_T>)
9324
9573
  {
9325
9574
  Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
9326
9575
  nativeSelf->*attribute_ = From_Ruby<T_Unqualified>().convert(value);
9327
9576
  }
9328
- else if constexpr (std::is_null_pointer_v<Receiver_T> &&
9329
- !std::is_const_v<Attr_T> &&
9330
- (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
9331
- {
9332
- *attribute_ = From_Ruby<T_Unqualified>().convert(value);
9333
- }
9334
9577
  else
9335
9578
  {
9336
- // Should never get here because define_attr won't compile this code, but just in case!
9337
- throw std::invalid_argument("Could not set attribute. Attribute: " + this->name_);
9579
+ *attribute_ = From_Ruby<T_Unqualified>().convert(value);
9338
9580
  }
9339
9581
 
9340
9582
  return value;
@@ -9480,6 +9722,7 @@ namespace Rice::detail
9480
9722
  #include <array>
9481
9723
  #include <stdexcept>
9482
9724
  #include <sstream>
9725
+ #include <tuple>
9483
9726
 
9484
9727
  namespace Rice::detail
9485
9728
  {
@@ -10223,6 +10466,7 @@ namespace Rice::detail
10223
10466
 
10224
10467
  // ========= NativeCallbackFFI.ipp =========
10225
10468
  #ifdef HAVE_LIBFFI
10469
+ #include <tuple>
10226
10470
  #include <ffi.h>
10227
10471
 
10228
10472
  namespace Rice::detail
@@ -12360,7 +12604,7 @@ namespace Rice
12360
12604
 
12361
12605
  auto instances = unbound_instances();
12362
12606
  for (auto instance: instances)
12363
- {
12607
+ {
12364
12608
  instance->set_value(klass);
12365
12609
  }
12366
12610
  instances.clear();
@@ -12539,7 +12783,7 @@ namespace Rice
12539
12783
  return false;
12540
12784
  }
12541
12785
  }
12542
-
12786
+
12543
12787
  template<typename Base_T>
12544
12788
  inline Class get_superklass()
12545
12789
  {
@@ -12579,7 +12823,7 @@ namespace Rice
12579
12823
  Class superKlass = get_superklass<Base_T>();
12580
12824
  return define_class_under<T, Base_T>(parent, id, superKlass);
12581
12825
  }
12582
-
12826
+
12583
12827
  template<typename T, typename Base_T>
12584
12828
  inline Data_Type<T> define_class(char const* name)
12585
12829
  {
@@ -12613,42 +12857,53 @@ namespace Rice
12613
12857
  template <typename Attribute_T>
12614
12858
  inline Data_Type<T>& Data_Type<T>::define_attr(std::string name, Attribute_T attribute, AttrAccess access)
12615
12859
  {
12616
- // Make sure the Attribute type has been previously seen by Rice
12617
- detail::verifyType<typename detail::attribute_traits<Attribute_T>::attr_type>();
12618
-
12619
- // Define native attribute getter
12620
- if (access == AttrAccess::ReadWrite || access == AttrAccess::Read)
12621
- detail::NativeAttributeGet<Attribute_T>::define(klass_, name, std::forward<Attribute_T>(attribute));
12622
-
12623
- using Attr_T = typename detail::NativeAttributeSet<Attribute_T>::Attr_T;
12624
- if constexpr (!std::is_const_v<Attr_T> &&
12625
- (std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
12626
- {
12627
- // Define native attribute setter
12628
- if (access == AttrAccess::ReadWrite || access == AttrAccess::Write)
12629
- detail::NativeAttributeSet<Attribute_T>::define(klass_, name, std::forward<Attribute_T>(attribute));
12630
- }
12631
-
12632
- return *this;
12860
+ return this->define_attr_internal<Attribute_T>(this->klass_, name, std::forward<Attribute_T>(attribute), access);
12633
12861
  }
12634
12862
 
12635
12863
  template <typename T>
12636
12864
  template <typename Attribute_T>
12637
12865
  inline Data_Type<T>& Data_Type<T>::define_singleton_attr(std::string name, Attribute_T attribute, AttrAccess access)
12638
12866
  {
12639
- // Make sure the Attribute type has been previously seen by Rice
12640
- detail::verifyType<typename detail::attribute_traits<Attribute_T>::attr_type>();
12641
-
12642
- // Define native attribute
12643
12867
  VALUE singleton = detail::protect(rb_singleton_class, this->value());
12868
+ return this->define_attr_internal<Attribute_T>(singleton, name, std::forward<Attribute_T>(attribute), access);
12869
+ }
12644
12870
 
12645
- // Define native attribute getter
12871
+ template <typename T>
12872
+ template <typename Attribute_T>
12873
+ inline Data_Type<T>& Data_Type<T>::define_attr_internal(VALUE klass, std::string name, Attribute_T attribute, AttrAccess access)
12874
+ {
12875
+ using Attr_T = typename detail::attribute_traits<Attribute_T>::attr_type;
12876
+
12877
+ // Make sure the Attribute type has been previously seen by Rice
12878
+ detail::verifyType<Attr_T>();
12879
+
12880
+ // Define attribute getter
12646
12881
  if (access == AttrAccess::ReadWrite || access == AttrAccess::Read)
12647
- detail::NativeAttributeGet<Attribute_T>::define(singleton, name, std::forward<Attribute_T>(attribute));
12882
+ {
12883
+ detail::NativeAttributeGet<Attribute_T>::define(klass, name, std::forward<Attribute_T>(attribute));
12884
+ }
12648
12885
 
12649
- // Define native attribute setter
12886
+ // Define attribute setter
12650
12887
  if (access == AttrAccess::ReadWrite || access == AttrAccess::Write)
12651
- detail::NativeAttributeSet<Attribute_T>::define(singleton, name, std::forward<Attribute_T>(attribute));
12888
+ {
12889
+ if constexpr (std::is_const_v<Attr_T>)
12890
+ {
12891
+ throw std::runtime_error("Cannot define attribute writer for a const attribute: " + name);
12892
+ }
12893
+ else if constexpr (!std::is_fundamental_v<Attr_T> && !std::is_assignable_v<Attr_T, Attr_T>)
12894
+ {
12895
+ throw std::runtime_error("Cannot define attribute writer for a non assignable attribute: " + name);
12896
+ }
12897
+ else if constexpr (!std::is_fundamental_v<Attr_T> && !std::is_copy_constructible_v<Attr_T>)
12898
+ {
12899
+ throw std::runtime_error("Cannot define attribute writer for a non copy constructible attribute: " + name);
12900
+ }
12901
+ else
12902
+ {
12903
+ // Define native attribute setter
12904
+ detail::NativeAttributeSet<Attribute_T>::define(klass, name, std::forward<Attribute_T>(attribute));
12905
+ }
12906
+ }
12652
12907
 
12653
12908
  return *this;
12654
12909
  }