From 31ab8f7889aca9a2faecda3ec683f7b6368ddaef Mon Sep 17 00:00:00 2001
From: Xiaohe Yang <yangxiaohe2@huawei.com>
Date: Mon, 24 Aug 2020 16:41:58 +0800
Subject: [PATCH 1/2] address_space: move find_flat_range function to FlatView,
 return reference of FlatRange

1. Add FlatView's member function: find_flat_range.
2. Make find_flat_range function return reference of FlatRange, which can eliminate
   unnecessary copy operation when return.

Signed-off-by: Xiaohe Yang <yangxiaohe2@huawei.com>
---
 address_space/src/address_space.rs | 79 +++++++++++++-----------------
 address_space/src/region.rs        |  6 +--
 2 files changed, 36 insertions(+), 49 deletions(-)

diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs
index 4a53de3..7428938 100644
--- a/address_space/src/address_space.rs
+++ b/address_space/src/address_space.rs
@@ -15,12 +15,25 @@ use std::sync::{Arc, Mutex, RwLock};
 use util::byte_code::ByteCode;
 
 use crate::errors::{ErrorKind, Result, ResultExt};
-use crate::region::FlatView;
 use crate::{
     AddressRange, FlatRange, GuestAddress, Listener, ListenerReqType, Region, RegionIoEventFd,
     RegionType,
 };
 
+/// Contain a set of `FlatRange`.
+#[derive(Default, Clone)]
+pub struct FlatView(pub Vec<FlatRange>);
+
+impl FlatView {
+    fn find_flatrange(&self, addr: GuestAddress) -> Option<&FlatRange> {
+        match self.0.binary_search_by_key(&addr, |x| x.addr_range.base) {
+            Ok(x) => Some(&self.0[x]),
+            Err(x) if (x > 0 && addr < self.0[x - 1].addr_range.end_addr()) => Some(&self.0[x - 1]),
+            _ => None,
+        }
+    }
+}
+
 /// Address Space of memory.
 #[derive(Clone)]
 pub struct AddressSpace {
@@ -234,23 +247,15 @@ impl AddressSpace {
     ///
     /// * `addr` - Guest address.
     pub fn get_host_address(&self, addr: GuestAddress) -> Option<u64> {
-        let view = &self.flat_view.read().unwrap().0;
+        let view = &self.flat_view.read().unwrap();
 
-        match view.binary_search_by_key(&addr, |x| x.addr_range.base) {
-            Ok(x) => view[x]
+        view.find_flatrange(addr).and_then(|range| {
+            let offset = addr.offset_from(range.addr_range.base);
+            range
                 .owner
                 .get_host_address()
-                .map(|hva| hva + view[x].offset_in_region),
-            Err(x) if (x > 0 && addr < view[x - 1].addr_range.end_addr()) => {
-                let offset = addr.offset_from(view[x - 1].addr_range.base);
-                let offset_in_region = view[x - 1].offset_in_region;
-                view[x - 1]
-                    .owner
-                    .get_host_address()
-                    .map(|hva| hva + offset_in_region + offset)
-            }
-            _ => None,
-        }
+                .map(|host| host + range.offset_in_region + offset)
+        })
     }
 
     /// Check if the GuestAddress is in one of Ram region.
@@ -259,18 +264,12 @@ impl AddressSpace {
     ///
     /// * `addr` - Guest address.
     pub fn address_in_memory(&self, addr: GuestAddress, size: u64) -> bool {
-        let view = &self.flat_view.read().unwrap().0;
+        let view = &self.flat_view.read().unwrap();
 
-        match view.binary_search_by_key(&addr, |x| x.addr_range.base) {
-            Ok(x) => {
-                view[x].owner.region_type() == RegionType::Ram && size <= view[x].addr_range.size
-            }
-            Err(x) if (x > 0 && addr < view[x - 1].addr_range.end_addr()) => {
-                view[x - 1].owner.region_type() == RegionType::Ram
-                    && size <= view[x - 1].addr_range.end_addr().offset_from(addr)
-            }
-            _ => false,
-        }
+        view.find_flatrange(addr).map_or(false, |range| {
+            range.owner.region_type() == RegionType::Ram
+                && size <= range.addr_range.end_addr().offset_from(addr)
+        })
     }
 
     /// Return the biggest end address in all Ram regions in AddressSpace.
@@ -294,16 +293,12 @@ impl AddressSpace {
     ///
     /// Return Error if the `addr` is a invalid GuestAddress.
     pub fn read(&self, dst: &mut dyn std::io::Write, addr: GuestAddress, count: u64) -> Result<()> {
-        let view = &self.flat_view.read().unwrap().0;
+        let view = &self.flat_view.read().unwrap();
 
-        let (fr, offset) = match view.binary_search_by_key(&addr, |x| x.addr_range.base) {
-            Ok(x) => (&view[x], 0),
-            Err(x) if (x > 0 && addr < view[x - 1].addr_range.end_addr()) => {
-                let fr = &view[x - 1];
-                (fr, addr.offset_from(fr.addr_range.base))
-            }
-            _ => return Err(ErrorKind::AddrInvalid(addr.raw_value()).into()),
-        };
+        let (fr, offset) = view
+            .find_flatrange(addr)
+            .map(|fr| (fr, addr.offset_from(fr.addr_range.base)))
+            .chain_err(|| ErrorKind::AddrInvalid(addr.raw_value()))?;
 
         fr.owner.read(
             dst,
@@ -325,16 +320,12 @@ impl AddressSpace {
     ///
     /// Return Error if the `addr` is a invalid GuestAddress.
     pub fn write(&self, src: &mut dyn std::io::Read, addr: GuestAddress, count: u64) -> Result<()> {
-        let view = &self.flat_view.read().unwrap().0;
+        let view = &self.flat_view.read().unwrap();
 
-        let (fr, offset) = match view.binary_search_by_key(&addr, |x| x.addr_range.base) {
-            Ok(x) => (&view[x], 0),
-            Err(x) if (x > 0 && addr < view[x - 1].addr_range.end_addr()) => {
-                let fr = &view[x - 1];
-                (fr, addr.offset_from(fr.addr_range.base))
-            }
-            _ => return Err(ErrorKind::AddrInvalid(addr.raw_value()).into()),
-        };
+        let (fr, offset) = view
+            .find_flatrange(addr)
+            .map(|fr| (fr, addr.offset_from(fr.addr_range.base)))
+            .chain_err(|| ErrorKind::AddrInvalid(addr.raw_value()))?;
 
         fr.owner.write(
             src,
diff --git a/address_space/src/region.rs b/address_space/src/region.rs
index 236c095..d8fbca6 100644
--- a/address_space/src/region.rs
+++ b/address_space/src/region.rs
@@ -13,6 +13,7 @@
 use std::sync::atomic::{AtomicI32, AtomicU64, Ordering};
 use std::sync::{Arc, Mutex, RwLock, Weak};
 
+use crate::address_space::FlatView;
 use crate::errors::{ErrorKind, Result};
 use crate::{AddressRange, AddressSpace, GuestAddress, HostMemMapping, RegionOps};
 
@@ -112,11 +113,6 @@ pub struct FlatRange {
     pub offset_in_region: u64,
 }
 
-/// Contain a set of `FlatRange`.
-/// Note that flat ranges is sorted by implementing `PartialOrd` and `Ord` trait.
-#[derive(Default, Clone)]
-pub struct FlatView(pub Vec<FlatRange>);
-
 /// Implement PartialEq/Eq for comparison of Region.
 impl PartialEq for Region {
     fn eq(&self, other: &Region) -> bool {
-- 
2.27.0

