Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 66661d78f531
Choose a base ref
...
head repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: e1a1240bc1a4
Choose a head ref

Commits on Apr 10, 2020

  1. Generated files pre-changes.

    pleroy committed Apr 10, 2020
    Copy the full SHA
    b22409b View commit details
  2. Copy the full SHA
    b4c92f9 View commit details
  3. Copy the full SHA
    055bac6 View commit details

Commits on Apr 11, 2020

  1. Copy the full SHA
    9a09898 View commit details
  2. Marshaling on return.

    pleroy committed Apr 11, 2020
    Copy the full SHA
    b810811 View commit details
  3. Copy the full SHA
    90886a5 View commit details
  4. Copy the full SHA
    271276a View commit details
  5. Copy the full SHA
    eaba8ef View commit details
  6. Copy the full SHA
    2081e62 View commit details
  7. Copy the full SHA
    e7a3c52 View commit details
  8. Copy the full SHA
    8d3b61a View commit details
  9. Ownership transfer on return.

    pleroy committed Apr 11, 2020
    Copy the full SHA
    7842cce View commit details
  10. Copy the full SHA
    158bf42 View commit details
  11. Copy the full SHA
    e7392ca View commit details
  12. Generated files post-changes.

    pleroy committed Apr 11, 2020
    Copy the full SHA
    8e9e882 View commit details
  13. Comment.

    pleroy committed Apr 11, 2020
    Copy the full SHA
    d85981b View commit details
  14. Remove generated files.

    pleroy committed Apr 11, 2020
    Copy the full SHA
    38cc89f View commit details
  15. Formatting.

    pleroy committed Apr 11, 2020
    Copy the full SHA
    4a23727 View commit details
  16. After egg's review.

    pleroy committed Apr 11, 2020
    Copy the full SHA
    6e91000 View commit details

Commits on Apr 23, 2020

  1. Copy the full SHA
    15e3baa View commit details
  2. After egg's review.

    pleroy committed Apr 23, 2020
    Copy the full SHA
    d845396 View commit details

Commits on Apr 24, 2020

  1. More C++20.

    pleroy committed Apr 24, 2020
    Copy the full SHA
    f89df8b View commit details
  2. Merge pull request #2526 from pleroy/2339f

    Support for marshaling optional fields in interchange messages
    pleroy authored Apr 24, 2020
    Copy the full SHA
    e1a1240 View commit details
9 changes: 9 additions & 0 deletions ksp_plugin/interface.cpp
Original file line number Diff line number Diff line change
@@ -437,6 +437,15 @@ double __cdecl principia__CurrentTime(Plugin const* const plugin) {
return m.Return(ToGameTime(*plugin, plugin->CurrentTime()));
}

void __cdecl principia__DeleteInterchange(void const** const native_pointer) {
journal::Method<journal::DeleteInterchange> m({native_pointer},
{native_pointer});
CHECK_NOTNULL(native_pointer);
::operator delete(const_cast<void*>(*native_pointer));
*native_pointer = nullptr;
return m.Return();
}

// Deletes and nulls |*plugin|.
// |plugin| must not be null. No transfer of ownership of |*plugin|, takes
// ownership of |**plugin|.
100 changes: 48 additions & 52 deletions ksp_plugin/interface_vessel.cpp
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@ XYZ __cdecl principia__VesselNormal(Plugin const* const plugin,
return m.Return(ToXYZ(plugin->VesselNormal(vessel_guid)));
}

OrbitAnalysis __cdecl principia__VesselRefreshAnalysis(
OrbitAnalysis* __cdecl principia__VesselRefreshAnalysis(
Plugin const* const plugin,
char const* const vessel_guid,
int const primary_index,
@@ -93,33 +93,30 @@ OrbitAnalysis __cdecl principia__VesselRefreshAnalysis(
Vessel& vessel = *plugin->GetVessel(vessel_guid);
vessel.RefreshOrbitAnalysis(plugin->GetCelestial(primary_index).body(),
mission_duration * Second);
OrbitAnalysis analysis{};
analysis.progress_of_next_analysis = vessel.progress_of_orbit_analysis();
OrbitAnalysis* const analysis = new OrbitAnalysis{};
analysis->progress_of_next_analysis = vessel.progress_of_orbit_analysis();
if (vessel.orbit_analysis() != nullptr) {
analysis.primary_index =
analysis->primary_index =
plugin->CelestialIndexOfBody(vessel.orbit_analysis()->primary());
analysis.mission_duration =
analysis->mission_duration =
vessel.orbit_analysis()->mission_duration() / Second;
analysis.elements_has_value =
vessel.orbit_analysis()->elements().has_value();
if (analysis.elements_has_value) {
if (vessel.orbit_analysis()->elements().has_value()) {
auto const& elements = *vessel.orbit_analysis()->elements();
analysis.elements.anomalistic_period =
elements.anomalistic_period() / Second;
analysis.elements.nodal_period = elements.nodal_period() / Second;
analysis.elements.sidereal_period = elements.sidereal_period() / Second;
analysis.elements.nodal_precession =
elements.nodal_precession() / (Radian / Second);
analysis.elements.mean_argument_of_periapsis =
ToInterval(elements.mean_argument_of_periapsis_interval());
analysis.elements.mean_eccentricity =
ToInterval(elements.mean_eccentricity_interval());
analysis.elements.mean_inclination =
ToInterval(elements.mean_inclination_interval());
analysis.elements.mean_longitude_of_ascending_nodes =
ToInterval(elements.mean_longitude_of_ascending_node_interval());
analysis.elements.mean_semimajor_axis =
ToInterval(elements.mean_semimajor_axis_interval());
analysis->elements = new OrbitalElements{
.sidereal_period = elements.sidereal_period() / Second,
.nodal_period = elements.nodal_period() / Second,
.anomalistic_period = elements.anomalistic_period() / Second,
.nodal_precession = elements.nodal_precession() / (Radian / Second),
.mean_semimajor_axis =
ToInterval(elements.mean_semimajor_axis_interval()),
.mean_eccentricity =
ToInterval(elements.mean_eccentricity_interval()),
.mean_inclination = ToInterval(elements.mean_inclination_interval()),
.mean_longitude_of_ascending_nodes =
ToInterval(elements.mean_longitude_of_ascending_node_interval()),
.mean_argument_of_periapsis =
ToInterval(elements.mean_argument_of_periapsis_interval()),
};
}
if (has_nominal_recurrence) {
int const Cᴛₒ =
@@ -133,36 +130,35 @@ OrbitAnalysis __cdecl principia__VesselRefreshAnalysis(
} else {
vessel.orbit_analysis()->ResetRecurrence();
}
analysis.recurrence_has_value =
vessel.orbit_analysis()->recurrence().has_value();
if (analysis.recurrence_has_value) {
if (vessel.orbit_analysis()->recurrence().has_value()) {
auto const& recurrence = *vessel.orbit_analysis()->recurrence();
analysis.recurrence.nuo = recurrence.νₒ();
analysis.recurrence.dto = recurrence.Dᴛₒ();
analysis.recurrence.cto = recurrence.Cᴛₒ();
analysis.recurrence.number_of_revolutions =
recurrence.number_of_revolutions();
analysis.recurrence.subcycle = recurrence.subcycle();
analysis.recurrence.equatorial_shift =
recurrence.equatorial_shift() / Radian;
analysis.recurrence.base_interval = recurrence.base_interval() / Radian;
analysis.recurrence.grid_interval = recurrence.grid_interval() / Radian;
analysis->recurrence = new OrbitRecurrence{
.nuo = recurrence.νₒ(),
.dto = recurrence.Dᴛₒ(),
.cto = recurrence.Cᴛₒ(),
.number_of_revolutions =
recurrence.number_of_revolutions(),
.equatorial_shift =
recurrence.equatorial_shift() / Radian,
.base_interval = recurrence.base_interval() / Radian,
.grid_interval = recurrence.grid_interval() / Radian,
.subcycle = recurrence.subcycle(),
};
}
analysis.ground_track_has_value =
vessel.orbit_analysis()->ground_track().has_value();
if (analysis.ground_track_has_value) {
if (vessel.orbit_analysis()->equatorial_crossings().has_value()) {
auto const& equatorial_crossings =
*vessel.orbit_analysis()->equatorial_crossings();
analysis.ground_track.equatorial_crossings
.longitudes_reduced_to_ascending_pass =
ToInterval(equatorial_crossings.longitudes_reduced_to_pass(
2 * ground_track_revolution - 1));
analysis.ground_track.equatorial_crossings
.longitudes_reduced_to_descending_pass =
ToInterval(equatorial_crossings.longitudes_reduced_to_pass(
2 * ground_track_revolution));
}
if (vessel.orbit_analysis()->ground_track().has_value() &&
vessel.orbit_analysis()->equatorial_crossings().has_value()) {
auto const& equatorial_crossings =
*vessel.orbit_analysis()->equatorial_crossings();
analysis->ground_track = new OrbitGroundTrack{
.equatorial_crossings = {
.longitudes_reduced_to_ascending_pass =
ToInterval(equatorial_crossings.longitudes_reduced_to_pass(
2 * ground_track_revolution - 1)),
.longitudes_reduced_to_descending_pass =
ToInterval(equatorial_crossings.longitudes_reduced_to_pass(
2 * ground_track_revolution)),
},
};
}
}

1 change: 1 addition & 0 deletions ksp_plugin_adapter/ksp_plugin_adapter.csproj
Original file line number Diff line number Diff line change
@@ -124,6 +124,7 @@
<Compile Include="main_window.cs" />
<Compile Include="map_node_pool.cs" />
<Compile Include="marshalers.generated.cs" />
<Compile Include="ownership_transfer_marshaler.cs" />
<Compile Include="repeated_marshaler.cs" />
<Compile Include="orbit_analyser.cs" />
<Compile Include="planetarium_camera_adjuster.cs" />
3 changes: 1 addition & 2 deletions ksp_plugin_adapter/mono_marshaler.cs
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ internal abstract class MonoMarshaler : ICustomMarshaler {
public abstract void CleanUpNativeDataImplementation(IntPtr native_data);
public abstract IntPtr MarshalManagedToNativeImplementation(
object managed_object);
public abstract object MarshalNativeToManaged(IntPtr native_data);

// We have no evidence that this method is ever called.
void ICustomMarshaler.CleanUpManagedData(object managed_object) {}
@@ -56,8 +57,6 @@ IntPtr ICustomMarshaler.MarshalManagedToNative(object managed_object) {
return result;
}

public abstract object MarshalNativeToManaged(IntPtr native_data);

// Since Mono calls CleanUpNativeData with IntPtrs that have not been
// allocated by MarshalManagedToNative, we track here all the values returned
// by MarshalManagedToNative and only process in CleanUpNativeData those that
4 changes: 0 additions & 4 deletions ksp_plugin_adapter/optional_marshaler.cs
Original file line number Diff line number Diff line change
@@ -6,10 +6,6 @@ namespace principia {
namespace ksp_plugin_adapter {

internal class OptionalMarshaler<T> : MonoMarshaler where T : struct {
// In addition to implementing the |ICustomMarshaler| interface, custom
// marshalers must implement a static method called |GetInstance| that accepts
// a |String| as a parameter and has a return type of |ICustomMarshaler|,
// see https://goo.gl/wwmBTa.
public static ICustomMarshaler GetInstance(string s) {
return instance_;
}
32 changes: 13 additions & 19 deletions ksp_plugin_adapter/orbit_analyser.cs
Original file line number Diff line number Diff line change
@@ -170,30 +170,23 @@ protected override void RenderWindow(int window_id) {
autodetect_recurrence_ ? null : (int?)days_per_cycle_,
ground_track_revolution_);
if (autodetect_recurrence_ &&
analysis.recurrence.number_of_revolutions != 0 &&
analysis.recurrence.cto != 0) {
revolutions_per_cycle_ = analysis.recurrence.number_of_revolutions;
days_per_cycle_ = analysis.recurrence.cto;
analysis.recurrence.HasValue &&
analysis.recurrence.Value.number_of_revolutions != 0 &&
analysis.recurrence.Value.cto != 0) {
revolutions_per_cycle_ =
analysis.recurrence.Value.number_of_revolutions;
days_per_cycle_ = analysis.recurrence.Value.cto;
}
UnityEngine.GUILayout.HorizontalScrollbar(
value : 0,
size : (float)analysis.progress_of_next_analysis,
leftValue : 0,
rightValue : 1);

OrbitalElements? elements = null;
OrbitRecurrence? recurrence = null;
OrbitGroundTrack? ground_track = null;
OrbitalElements? elements = analysis.elements;
OrbitRecurrence? recurrence = analysis.recurrence;
OrbitGroundTrack? ground_track = analysis.ground_track;
double mission_duration = analysis.mission_duration;
if (analysis.elements_has_value) {
elements = analysis.elements;
}
if (analysis.recurrence_has_value) {
recurrence = analysis.recurrence;
}
if (analysis.ground_track_has_value) {
ground_track = analysis.ground_track;
}
primary = FlightGlobals.Bodies[analysis.primary_index];

Style.HorizontalLine();
@@ -205,9 +198,10 @@ protected override void RenderWindow(int window_id) {
(int)(mission_duration / elements.Value.nodal_period);
int anomalistic_revolutions =
(int)(mission_duration / elements.Value.anomalistic_period);
int ground_track_cycles = analysis.recurrence_has_value
? nodal_revolutions / analysis.recurrence.number_of_revolutions
: 0;
int ground_track_cycles = analysis.recurrence.HasValue
? nodal_revolutions / analysis.recurrence.
Value.number_of_revolutions
: 0;
string duration_in_ground_track_cycles = ground_track_cycles > 0
? $" ({ground_track_cycles.FormatN(0)} ground track cycles)"
: "";
43 changes: 43 additions & 0 deletions ksp_plugin_adapter/ownership_transfer_marshaler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Runtime.InteropServices;

namespace principia {
namespace ksp_plugin_adapter {

// An adapter that uses TMarshaler to marshal objects of type T, but
// additionally takes ownership of the native data passed in the native-to-
// managed direction. T may be a struct or a class, but it *must* correspond to
// an interchange message defined in journal.proto.
internal class OwnershipTransferMarshaler<T, TMarshaler> : MonoMarshaler
where TMarshaler : MonoMarshaler {
public static ICustomMarshaler GetInstance(string s) {
return instance_;
}

public override void CleanUpNativeDataImplementation(IntPtr native_data) {
throw Log.Fatal("no transfer of ownership for in parameters");
}

public override IntPtr MarshalManagedToNativeImplementation(
object managed_object) {
throw Log.Fatal("no transfer of ownership for in parameters");
}

public override object MarshalNativeToManaged(IntPtr native_data) {
object managed_object =
t_marshaler_instance_.MarshalNativeToManaged(native_data);
Interface.DeleteInterchange(ref native_data);
return managed_object;
}

// The stupid language won't let us access a static method of a generic
// parameter type, so we go for reflection.
private static readonly MonoMarshaler t_marshaler_instance_ =
(MonoMarshaler)typeof(TMarshaler).GetMethod("GetInstance")?.
Invoke(null, new object[]{null});
private static readonly OwnershipTransferMarshaler<T, TMarshaler> instance_ =
new OwnershipTransferMarshaler<T, TMarshaler>();
}

} // namespace ksp_plugin_adapter
} // namespace principia
6 changes: 4 additions & 2 deletions principia.props
Original file line number Diff line number Diff line change
@@ -75,8 +75,10 @@
<AdditionalIncludeDirectories>C:\Program Files;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/bigobj /w14714 /Zc:char8_t-</AdditionalOptions>
<AdditionalOptions Condition="$(ProjectName) != serialization">/w14061 %(AdditionalOptions)</AdditionalOptions>
<LanguageStandard Condition="$(ProjectName) == astronomy">stdcpplatest</LanguageStandard>
<LanguageStandard Condition="$(ProjectName) != astronomy">stdcpp17</LanguageStandard>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard Condition="$(ProjectName) == astronomy or
$(ProjectName) == ksp_plugin or
$(ProjectName) == ksp_plugin_test">stdcpplatest</LanguageStandard>
<WarningLevel Condition="!$(PrincipiaCompilerClangLLVM)">Level3</WarningLevel>
<WarningLevel Condition="$(PrincipiaCompilerClangLLVM) and
$(ProjectName) == serialization">TurnOffAllWarnings</WarningLevel>
34 changes: 21 additions & 13 deletions serialization/journal.proto
Original file line number Diff line number Diff line change
@@ -204,20 +204,13 @@ message OrbitAnalysis {
required double progress_of_next_analysis = 1;
required int32 primary_index = 2;
required double mission_duration = 3;
// NOTE(egg): we currently have no support in the interface generator for
// optional non-string fields in interchange structs. We use separate
// booleans to denote the presence of a value, where the boolean denoting
// the presence of field F = f is field F_has_value = 10 + f.
required OrbitalElements elements = 4;
required bool elements_has_value = 14;
required OrbitRecurrence recurrence = 5;
required bool recurrence_has_value = 15;
required OrbitGroundTrack ground_track = 6;
required bool ground_track_has_value = 16;
optional OrbitalElements elements = 4 [(is_produced) = true];
optional OrbitRecurrence recurrence = 5 [(is_produced) = true];
optional OrbitGroundTrack ground_track = 6 [(is_produced) = true];
}

message Method {
extensions 5000 to 5999; // Last used: 5168.
extensions 5000 to 5999; // Last used: 5169.
}

message SetAngularMomentumConservation {
@@ -428,6 +421,21 @@ message CurrentTime {
optional Return return = 3;
}

message DeleteInterchange {
extend Method {
optional DeleteInterchange extension = 5169;
}
message In {
required fixed64 native_pointer = 1 [(pointer_to) = "void const",
(is_consumed) = true];
}
message Out {
required fixed64 native_pointer = 1 [(pointer_to) = "void const"];
}
optional In in = 1;
optional Out out = 2;
}

message DeletePlugin {
extend Method {
optional DeletePlugin extension = 5000;
@@ -2149,7 +2157,7 @@ message VesselRefreshAnalysis {
required int32 ground_track_revolution = 7;
}
message Return {
required OrbitAnalysis result = 1;
required OrbitAnalysis result = 1 [(is_produced) = true];
}
optional In in = 1;
optional Return return = 3;
@@ -2207,7 +2215,7 @@ extend google.protobuf.FieldOptions {

// For a fixed64 field, indicates whether the corresponding pointer is
// consumed (deleted or has its ownership transferred) or produced (allocated)
// by the interface.
// by the C++ side.
optional bool is_consumed = 50002;
optional bool is_produced = 50003;

238 changes: 189 additions & 49 deletions tools/journal_proto_processor.cpp

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions tools/journal_proto_processor.hpp
Original file line number Diff line number Diff line change
@@ -48,6 +48,8 @@ class JournalProtoProcessor final {
std::string const& cs_boxed_type,
std::string const& cs_unboxed_type,
std::string const& cxx_type);
void ProcessOptionalScalarField(FieldDescriptor const* descriptor,
std::string const& cxx_type);
void ProcessOptionalDoubleField(FieldDescriptor const* descriptor);
void ProcessOptionalInt32Field(FieldDescriptor const* descriptor);
void ProcessOptionalMessageField(FieldDescriptor const* descriptor);
@@ -106,6 +108,12 @@ class JournalProtoProcessor final {
// present in |in_out_| are not in |out_|.
std::set<FieldDescriptor const*> out_;

// The fields that are returned.
std::set<FieldDescriptor const*> return_;

// The fields that are part of interchange messages.
std::set<FieldDescriptor const*> interchange_;

// For all fields, a lambda that takes the name of a local variable containing
// data extracted (and deserialized) from the field and returns a list of
// expressions to be passed to the interface. Deals with passing by reference
@@ -182,7 +190,7 @@ class JournalProtoProcessor final {
std::string const& stmt)>>
field_cxx_optional_assignment_fn_;

// For all fields, a lambda that takes a condition to take for the presence
// For all fields, a lambda that takes a condition to check for the presence
// of an optional field (typically something like |message.in().has_bar()|)
// and a deserialized expression for reading the field (typically the result
// of |field_cxx_deserializer_fn_|) and returns a conditional expression for
@@ -285,7 +293,8 @@ class JournalProtoProcessor final {
std::map<Descriptor const*, std::string> cxx_serialize_definition_;

// For interchange messages that require deserialization storage, the
// arguments for the storage in the call to the Deserialize function.
// arguments for the storage in the call to the Deserialize function. Starts
// with a comma, arguments are comma-separated.
std::map<Descriptor const*, std::string>
cxx_deserialization_storage_arguments_;